X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2FhsSyn%2FHsDecls.lhs;h=3a610024a35beb222102eb33d60697775c9a52eb;hb=423d477bfecd490de1449c59325c8776f91d7aac;hp=a0955a00f85acaf53c7cce4057563ea5c23fc9e2;hpb=b965e6721c7337e7ad9e45af0a16974f3794d50c;p=ghc-hetmet.git diff --git a/ghc/compiler/hsSyn/HsDecls.lhs b/ghc/compiler/hsSyn/HsDecls.lhs index a0955a0..3a61002 100644 --- a/ghc/compiler/hsSyn/HsDecls.lhs +++ b/ghc/compiler/hsSyn/HsDecls.lhs @@ -3,44 +3,52 @@ % \section[HsDecls]{Abstract syntax: global declarations} -Definitions for: @TyDecl@ and @ConDecl@, @ClassDecl@, +Definitions for: @TyDecl@ and @oCnDecl@, @ClassDecl@, @InstDecl@, @DefaultDecl@ and @ForeignDecl@. \begin{code} module HsDecls ( - HsDecl(..), TyClDecl(..), InstDecl(..), RuleDecl(..), RuleBndr(..), - DefaultDecl(..), ForeignDecl(..), ForKind(..), - ExtName(..), isDynamicExtName, extNameStatic, - ConDecl(..), ConDetails(..), - BangType(..), getBangType, - DeprecDecl(..), DeprecTxt, - hsDeclName, instDeclName, tyClDeclName, tyClDeclNames, tyClDeclSysNames, - isClassDecl, isSynDecl, isDataDecl, isIfaceSigDecl, countTyClDecls, - mkClassDeclSysNames, isIfaceRuleDecl, ifaceRuleDeclName, - getClassDeclSysNames, conDetailsTys + HsDecl(..), LHsDecl, TyClDecl(..), LTyClDecl, + InstDecl(..), LInstDecl, NewOrData(..), + RuleDecl(..), LRuleDecl, RuleBndr(..), + DefaultDecl(..), LDefaultDecl, HsGroup(..), SpliceDecl(..), + ForeignDecl(..), LForeignDecl, ForeignImport(..), ForeignExport(..), + CImportSpec(..), FoType(..), + ConDecl(..), LConDecl, + LBangType, BangType(..), HsBang(..), + getBangType, getBangStrictness, unbangedType, + DeprecDecl(..), LDeprecDecl, + tcdName, tyClDeclNames, tyClDeclTyVars, + isClassDecl, isSynDecl, isDataDecl, + countTyClDecls, + conDetailsTys, + collectRuleBndrSigTys, ) where #include "HsVersions.h" -- friends: -import HsBinds ( HsBinds, MonoBinds, Sig(..), FixitySig(..) ) -import HsExpr ( HsExpr ) +import {-# SOURCE #-} HsExpr( HsExpr, pprExpr ) + -- Because Expr imports Decls via HsBracket + +import HsBinds ( HsBindGroup, HsBind, LHsBinds, + Sig(..), LSig, LFixitySig, pprLHsBinds ) +import HsPat ( HsConDetails(..), hsConArgs ) +import HsImpExp ( pprHsVar ) import HsTypes -import PprCore ( pprCoreRule ) -import HsCore ( UfExpr, UfBinder, HsIdInfo, pprHsIdInfo, - eq_ufBinders, eq_ufExpr, pprUfExpr - ) -import CoreSyn ( CoreRule(..) ) -import BasicTypes ( NewOrData(..) ) -import CallConv ( CallConv, pprCallConv ) +import HscTypes ( DeprecTxt ) +import CoreSyn ( RuleName ) +import BasicTypes ( Activation(..) ) +import ForeignCall ( CCallTarget(..), DNCallSpec, CCallConv, Safety, + CExportSpec(..), CLabelString ) -- others: -import Name ( NamedThing ) import FunDeps ( pprFundeps ) -import Class ( FunDep, DefMeth(..) ) -import CStrings ( CLabelString, pprCLabelString ) +import Class ( FunDep ) import Outputable -import SrcLoc ( SrcLoc ) +import Util ( count ) +import SrcLoc ( Located(..), unLoc ) +import FastString \end{code} @@ -51,18 +59,21 @@ import SrcLoc ( SrcLoc ) %************************************************************************ \begin{code} -data HsDecl name pat - = TyClD (TyClDecl name pat) - | InstD (InstDecl name pat) - | DefD (DefaultDecl name) - | ValD (HsBinds name pat) - | ForD (ForeignDecl name) - | FixD (FixitySig name) - | DeprecD (DeprecDecl name) - | RuleD (RuleDecl name pat) +type LHsDecl id = Located (HsDecl id) + +data HsDecl id + = TyClD (TyClDecl id) + | InstD (InstDecl id) + | ValD (HsBind id) + | SigD (Sig id) + | DefD (DefaultDecl id) + | ForD (ForeignDecl id) + | DeprecD (DeprecDecl id) + | RuleD (RuleDecl id) + | SpliceD (SpliceDecl id) -- NB: all top-level fixity decls are contained EITHER --- EITHER FixDs +-- EITHER SigDs -- OR in the ClassDecls in TyClDs -- -- The former covers @@ -73,40 +84,65 @@ data HsDecl name pat -- d) top level decls -- -- The latter is for class methods only -\end{code} - -\begin{code} -#ifdef DEBUG -hsDeclName :: (NamedThing name, Outputable name, Outputable pat) - => HsDecl name pat -> name -#endif -hsDeclName (TyClD decl) = tyClDeclName decl -hsDeclName (InstD decl) = instDeclName decl -hsDeclName (ForD (ForeignDecl name _ _ _ _ _)) = name -hsDeclName (FixD (FixitySig name _ _)) = name --- Others don't make sense -#ifdef DEBUG -hsDeclName x = pprPanic "HsDecls.hsDeclName" (ppr x) -#endif - - -instDeclName :: InstDecl name pat -> name -instDeclName (InstDecl _ _ _ (Just name) _) = name +-- A [HsDecl] is categorised into a HsGroup before being +-- fed to the renamer. +data HsGroup id + = HsGroup { + hs_valds :: [HsBindGroup id], + -- Before the renamer, this is a single big HsBindGroup, + -- with all the bindings, and all the signatures. + -- The renamer does dependency analysis, splitting it up + -- into several HsBindGroups. + + hs_tyclds :: [LTyClDecl id], + hs_instds :: [LInstDecl 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_depds :: [LDeprecDecl id], + hs_ruleds :: [LRuleDecl id] + } \end{code} \begin{code} -instance (NamedThing name, Outputable name, Outputable pat) - => Outputable (HsDecl name pat) where - +instance OutputableBndr 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 (ForD fd) = ppr fd - ppr (FixD fd) = ppr fd + ppr (SigD sd) = ppr sd ppr (RuleD rd) = ppr rd ppr (DeprecD dd) = ppr dd + ppr (SpliceD dd) = ppr dd + +instance OutputableBndr name => Outputable (HsGroup name) where + ppr (HsGroup { hs_valds = val_decls, + hs_tyclds = tycl_decls, + hs_instds = inst_decls, + hs_fixds = fix_decls, + hs_depds = deprec_decls, + hs_fords = foreign_decls, + hs_defds = default_decls, + hs_ruleds = rule_decls }) + = vcat [ppr_ds fix_decls, ppr_ds default_decls, + ppr_ds deprec_decls, ppr_ds rule_decls, + ppr val_decls, + ppr_ds tycl_decls, ppr_ds inst_decls, + ppr_ds foreign_decls] + where + ppr_ds [] = empty + ppr_ds ds = text "" $$ vcat (map ppr ds) + +data SpliceDecl id = SpliceDecl (Located (HsExpr id)) -- Top level splice + +instance OutputableBndr name => Outputable (SpliceDecl name) where + ppr (SpliceDecl e) = ptext SLIT("$") <> parens (pprExpr (unLoc e)) \end{code} @@ -116,10 +152,15 @@ instance (NamedThing name, Outputable name, Outputable pat) %* * %************************************************************************ -Type and class declarations carry 'implicit names'. In particular: + -------------------------------- + THE NAMING STORY + -------------------------------- -Type A. -~~~~~~~ +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 @@ -129,7 +170,8 @@ Type A. the worker for that constructor a selector for each superclass -All have occurrence names that are derived uniquely from their parent declaration. +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 @@ -137,75 +179,164 @@ interface files, of course. Any such occurrence must haul in the relevant type or class decl. Plan of attack: - - Make up their occurrence names immediately - - 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 DefMeth field. + (DefMeth is defined in Class.lhs) + +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 :: + op2 :: + op1 = ... + We generate a binding for $dmop1 but not for $dmop2. + The Class for Foo has a NoDefMeth for op2 and a DefMeth 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 = :: -- NB the '=' + op2 :: + 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} + +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 - - When renaming the decl look them up in the name cache, - ensure correct module and provenance is set -Type B: Default methods and dictionary functions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Have their own binding in an interface file. +\begin{code} +-- TyClDecls are precisely the kind of declarations that can +-- appear in interface files; or (internally) in GHC's interface +-- for a module. That's why (despite the misnomer) IfaceSig and ForeignType +-- are both in TyClDecl -Default methods : occurrence name is derived uniquely from the class decl. -Dict functions : occurrence name is derived from the instance decl, plus a unique number. +type LTyClDecl name = Located (TyClDecl name) -Plan of attack: - - Do *not* make them point to the parent class decl - - Interface-file decls: treat just like Type A - - Source-file decls: the names aren't in the decl at all; - instead the typechecker makes them up - -\begin{code} -data TyClDecl name pat - = IfaceSig { tcdName :: name, -- It may seem odd to classify an interface-file signature - tcdType :: HsType name, -- as a 'TyClDecl', but it's very convenient. These three - tcdIdInfo :: [HsIdInfo name], -- are the kind that appear in interface files. - tcdLoc :: SrcLoc - } +data TyClDecl name + = ForeignType { + tcdLName :: Located name, + tcdExtName :: Maybe FastString, + tcdFoType :: FoType + } | TyData { tcdND :: NewOrData, - tcdCtxt :: HsContext name, -- context - tcdName :: name, -- type constructor - tcdTyVars :: [HsTyVarBndr name], -- type variables - tcdCons :: [ConDecl name], -- data constructors (empty if abstract) - tcdNCons :: Int, -- Number of data constructors (valid even if type is abstract) - tcdDerivs :: Maybe [name], -- derivings; Nothing => not specified - -- (i.e., derive default); Just [] => derive - -- *nothing*; Just => as you would - -- expect... - tcdSysNames :: DataSysNames name, -- Generic converter functions - tcdLoc :: SrcLoc + tcdCtxt :: LHsContext name, -- Context + tcdLName :: Located name, -- Type constructor + tcdTyVars :: [LHsTyVarBndr name], -- Type variables + tcdCons :: [LConDecl name], -- Data constructors + tcdDerivs :: Maybe [LHsType name] + -- Derivings; Nothing => not specified + -- Just [] => derive exactly what is asked + -- These "types" must be of form + -- forall ab. C ty1 ty2 + -- Typically the foralls and ty args are empty, but they + -- are non-empty for the newtype-deriving case } - | TySynonym { tcdName :: name, -- type constructor - tcdTyVars :: [HsTyVarBndr name], -- type variables - tcdSynRhs :: HsType name, -- synonym expansion - tcdLoc :: SrcLoc + | TySynonym { tcdLName :: Located name, -- type constructor + tcdTyVars :: [LHsTyVarBndr name], -- type variables + tcdSynRhs :: LHsType name -- synonym expansion } - | ClassDecl { tcdCtxt :: HsContext name, -- Context... - tcdName :: name, -- Name of the class - tcdTyVars :: [HsTyVarBndr name], -- The class type variables - tcdFDs :: [FunDep name], -- Functional dependencies - tcdSigs :: [Sig name], -- Methods' signatures - tcdMeths :: Maybe (MonoBinds name pat), -- Default methods - -- Nothing for imported class decls - -- Just bs for source class decls - tcdSysNames :: ClassSysNames name, - tcdLoc :: SrcLoc + | ClassDecl { tcdCtxt :: LHsContext name, -- Context... + tcdLName :: Located name, -- Name of the class + tcdTyVars :: [LHsTyVarBndr name], -- Class type variables + tcdFDs :: [Located (FunDep name)], -- Functional deps + tcdSigs :: [LSig name], -- Methods' signatures + tcdMeths :: LHsBinds name -- Default methods } + +data NewOrData + = NewType -- "newtype Blah ..." + | DataType -- "data Blah ..." + deriving( Eq ) -- Needed because Demand derives Eq \end{code} Simple classifiers \begin{code} -isIfaceSigDecl, isDataDecl, isSynDecl, isClassDecl :: TyClDecl name pat -> Bool - -isIfaceSigDecl (IfaceSig {}) = True -isIfaceSigDecl other = False +isDataDecl, isSynDecl, isClassDecl :: TyClDecl name -> Bool isSynDecl (TySynonym {}) = True isSynDecl other = False @@ -220,164 +351,85 @@ isClassDecl other = False Dealing with names \begin{code} --------------------------------- -tyClDeclName :: TyClDecl name pat -> name -tyClDeclName tycl_decl = tcdName tycl_decl +tcdName :: TyClDecl name -> name +tcdName decl = unLoc (tcdLName decl) --------------------------------- -tyClDeclNames :: Eq name => TyClDecl name pat -> [(name, SrcLoc)] --- Returns all the binding names of the decl, along with their SrcLocs +tyClDeclNames :: Eq name => TyClDecl name -> [Located name] +-- Returns all the *binding* names of the decl, along with their SrcLocs -- The first one is guaranteed to be the name of the decl -- For record fields, the first one counts as the SrcLoc -- We use the equality to filter out duplicate field names -tyClDeclNames (TySynonym {tcdName = name, tcdLoc = loc}) = [(name,loc)] -tyClDeclNames (IfaceSig {tcdName = name, tcdLoc = loc}) = [(name,loc)] - -tyClDeclNames (ClassDecl {tcdName = cls_name, tcdSigs = sigs, tcdLoc = loc}) - = (cls_name,loc) : [(n,loc) | ClassOpSig n _ _ loc <- sigs] - -tyClDeclNames (TyData {tcdName = tc_name, tcdCons = cons, tcdLoc = loc}) - = (tc_name,loc) : conDeclsNames cons - +tyClDeclNames (TySynonym {tcdLName = name}) = [name] +tyClDeclNames (ForeignType {tcdLName = name}) = [name] --------------------------------- --- The "system names" are extra implicit names. --- They are kept in a list rather than a tuple --- to make the renamer easier. +tyClDeclNames (ClassDecl {tcdLName = cls_name, tcdSigs = sigs}) + = cls_name : [n | L _ (Sig n _) <- sigs] -type ClassSysNames name = [name] --- For class decls they are: --- [tycon, datacon wrapper, datacon worker, --- superclass selector 1, ..., superclass selector n] +tyClDeclNames (TyData {tcdLName = tc_name, tcdCons = cons}) + = tc_name : conDeclsNames (map unLoc cons) -type DataSysNames name = [name] --- For data decls they are --- [from, to] --- where from :: T -> Tring --- to :: Tring -> T - -tyClDeclSysNames :: TyClDecl name pat -> [(name, SrcLoc)] --- Similar to tyClDeclNames, but returns the "implicit" --- or "system" names of the declaration - -tyClDeclSysNames (ClassDecl {tcdSysNames = names, tcdLoc = loc, tcdSigs = sigs}) - = [(n,loc) | n <- names] ++ - [(n,loc) | ClassOpSig _ (DefMeth n) _ loc <- sigs] -tyClDeclSysNames (TyData {tcdCons = cons, tcdSysNames = names, tcdLoc = loc}) - = [(n,loc) | n <- names] ++ - [(wkr_name,loc) | ConDecl _ wkr_name _ _ _ loc <- cons] -tyClDeclSysNames decl = [] - - -mkClassDeclSysNames :: (name, name, name, [name]) -> [name] -getClassDeclSysNames :: [name] -> (name, name, name, [name]) -mkClassDeclSysNames (a,b,c,ds) = a:b:c:ds -getClassDeclSysNames (a:b:c:ds) = (a,b,c,ds) -\end{code} - -\begin{code} -instance (NamedThing name, Ord name) => Eq (TyClDecl name pat) where - -- Used only when building interface files - (==) d1@(IfaceSig {}) d2@(IfaceSig {}) - = tcdName d1 == tcdName d2 && - tcdType d1 == tcdType d2 && - tcdIdInfo d1 == tcdIdInfo d2 - - (==) d1@(TyData {}) d2@(TyData {}) - = tcdName d1 == tcdName d2 && - tcdND d1 == tcdND d2 && - eqWithHsTyVars (tcdTyVars d1) (tcdTyVars d2) (\ env -> - eq_hsContext env (tcdCtxt d1) (tcdCtxt d2) && - eqListBy (eq_ConDecl env) (tcdCons d1) (tcdCons d2) - ) - - (==) d1@(TySynonym {}) d2@(TySynonym {}) - = tcdName d1 == tcdName d2 && - eqWithHsTyVars (tcdTyVars d1) (tcdTyVars d2) (\ env -> - eq_hsType env (tcdSynRhs d1) (tcdSynRhs d2) - ) - - (==) d1@(ClassDecl {}) d2@(ClassDecl {}) - = tcdName d1 == tcdName d2 && - eqWithHsTyVars (tcdTyVars d1) (tcdTyVars d2) (\ env -> - eq_hsContext env (tcdCtxt d1) (tcdCtxt d2) && - eqListBy (eq_hsFD env) (tcdFDs d1) (tcdFDs d2) && - eqListBy (eq_cls_sig env) (tcdSigs d1) (tcdSigs d2) - ) - - (==) _ _ = False -- default case - -eq_hsFD env (ns1,ms1) (ns2,ms2) - = eqListBy (eq_hsVar env) ns1 ns2 && eqListBy (eq_hsVar env) ms1 ms2 - -eq_cls_sig env (ClassOpSig n1 dm1 ty1 _) (ClassOpSig n2 dm2 ty2 _) - = n1==n2 && dm1 `eq_dm` dm2 && eq_hsType env ty1 ty2 - where - -- Ignore the name of the default method for (DefMeth id) - -- This is used for comparing declarations before putting - -- them into interface files, and the name of the default - -- method isn't relevant - NoDefMeth `eq_dm` NoDefMeth = True - GenDefMeth `eq_dm` GenDefMeth = True - DefMeth _ `eq_dm` DefMeth _ = True - dm1 `eq_dm` dm2 = False - - +tyClDeclTyVars (TySynonym {tcdTyVars = tvs}) = tvs +tyClDeclTyVars (TyData {tcdTyVars = tvs}) = tvs +tyClDeclTyVars (ClassDecl {tcdTyVars = tvs}) = tvs +tyClDeclTyVars (ForeignType {}) = [] \end{code} \begin{code} -countTyClDecls :: [TyClDecl name pat] -> (Int, Int, Int, Int, Int) +countTyClDecls :: [TyClDecl name] -> (Int, Int, Int, Int) -- class, data, newtype, synonym decls countTyClDecls decls - = (length [() | ClassDecl {} <- decls], - length [() | TySynonym {} <- decls], - length [() | IfaceSig {} <- decls], - length [() | TyData {tcdND = DataType} <- decls], - length [() | TyData {tcdND = NewType} <- decls]) + = (count isClassDecl decls, + count isSynDecl decls, + count isDataTy decls, + count isNewTy decls) + where + isDataTy TyData{tcdND=DataType} = True + isDataTy _ = False + + isNewTy TyData{tcdND=NewType} = True + isNewTy _ = False \end{code} \begin{code} -instance (NamedThing name, Outputable name, Outputable pat) - => Outputable (TyClDecl name pat) where +instance OutputableBndr name + => Outputable (TyClDecl name) where - ppr (IfaceSig {tcdName = var, tcdType = ty, tcdIdInfo = info}) - = hsep [ppr var, dcolon, ppr ty, pprHsIdInfo info] + ppr (ForeignType {tcdLName = ltycon}) + = hsep [ptext SLIT("foreign import type dotnet"), ppr ltycon] - ppr (TySynonym {tcdName = tycon, tcdTyVars = tyvars, tcdSynRhs = mono_ty}) - = hang (ptext SLIT("type") <+> pp_decl_head [] tycon tyvars <+> equals) + ppr (TySynonym {tcdLName = ltycon, tcdTyVars = tyvars, tcdSynRhs = mono_ty}) + = hang (ptext SLIT("type") <+> pp_decl_head [] ltycon tyvars <+> equals) 4 (ppr mono_ty) - ppr (TyData {tcdND = new_or_data, tcdCtxt = context, tcdName = tycon, - tcdTyVars = tyvars, tcdCons = condecls, tcdNCons = ncons, + ppr (TyData {tcdND = new_or_data, tcdCtxt = context, tcdLName = ltycon, + tcdTyVars = tyvars, tcdCons = condecls, tcdDerivs = derivings}) - = pp_tydecl (ptext keyword <+> pp_decl_head context tycon tyvars <+> equals) - (pp_condecls condecls ncons) + = pp_tydecl (ppr new_or_data <+> pp_decl_head (unLoc context) ltycon tyvars) + (pp_condecls condecls) derivings - where - keyword = case new_or_data of - NewType -> SLIT("newtype") - DataType -> SLIT("data") - ppr (ClassDecl {tcdCtxt = context, tcdName = clas, tcdTyVars = tyvars, tcdFDs = fds, + ppr (ClassDecl {tcdCtxt = context, tcdLName = lclas, tcdTyVars = tyvars, tcdFDs = fds, tcdSigs = sigs, tcdMeths = methods}) | null sigs -- No "where" part = top_matter | otherwise -- Laid out = sep [hsep [top_matter, ptext SLIT("where {")], - nest 4 (sep [sep (map ppr_sig sigs), pp_methods, char '}'])] + nest 4 (sep [sep (map ppr_sig sigs), ppr methods, char '}'])] where - top_matter = ptext SLIT("class") <+> pp_decl_head context clas tyvars <+> pprFundeps fds + top_matter = ptext SLIT("class") <+> pp_decl_head (unLoc context) lclas tyvars <+> pprFundeps (map unLoc fds) ppr_sig sig = ppr sig <> semi - pp_methods = getPprStyle $ \ sty -> - if ifaceStyle sty then empty else ppr methods - -pp_decl_head :: Outputable name => HsContext name -> name -> [HsTyVarBndr name] -> SDoc -pp_decl_head context thing tyvars = hsep [pprHsContext context, ppr thing, interppSP tyvars] -pp_condecls [] ncons = ptext SLIT("{- abstract with") <+> int ncons <+> ptext SLIT("constructors -}") -pp_condecls (c:cs) ncons = sep (ppr c : map (\ c -> ptext SLIT("|") <+> ppr c) cs) +pp_decl_head :: OutputableBndr name + => HsContext name + -> Located name + -> [LHsTyVarBndr name] + -> SDoc +pp_decl_head context thing tyvars + = hsep [pprHsContext context, ppr thing, interppSP tyvars] + +pp_condecls cs = equals <+> sep (punctuate (ptext SLIT(" |")) (map ppr cs)) pp_tydecl pp_head pp_decl_rhs derivings = hang pp_head 4 (sep [ @@ -386,6 +438,10 @@ pp_tydecl pp_head pp_decl_rhs derivings Nothing -> empty Just ds -> hsep [ptext SLIT("deriving"), parens (interpp'SP ds)] ]) + +instance Outputable NewOrData where + ppr NewType = ptext SLIT("newtype") + ppr DataType = ptext SLIT("data") \end{code} @@ -396,118 +452,82 @@ pp_tydecl pp_head pp_decl_rhs derivings %************************************************************************ \begin{code} +type LConDecl name = Located (ConDecl name) + data ConDecl name - = ConDecl name -- Constructor name; this is used for the + = ConDecl (Located name) -- Constructor name; this is used for the -- DataCon itself, and for the user-callable wrapper Id - name -- Name of the constructor's 'worker Id' - -- Filled in as the ConDecl is built - - [HsTyVarBndr name] -- Existentially quantified type variables - (HsContext name) -- ...and context + [LHsTyVarBndr name] -- Existentially quantified type variables + (LHsContext name) -- ...and context -- If both are empty then there are no existentials - (ConDetails name) - SrcLoc - -data ConDetails name - = VanillaCon -- prefix-style con decl - [BangType name] - - | InfixCon -- infix-style con decl - (BangType name) - (BangType name) - - | RecCon -- record-style con decl - [([name], BangType name)] -- list of "fields" + (HsConDetails name (LBangType name)) \end{code} \begin{code} -conDeclsNames :: Eq name => [ConDecl name] -> [(name,SrcLoc)] +conDeclsNames :: Eq name => [ConDecl name] -> [Located name] -- See tyClDeclNames 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 conDeclsNames cons = snd (foldl do_one ([], []) cons) where - do_one (flds_seen, acc) (ConDecl name _ _ _ details loc) - = do_details ((name,loc):acc) details + do_one (flds_seen, acc) (ConDecl lname _ _ (RecCon flds)) + = (map unLoc new_flds ++ flds_seen, lname : [f | f <- new_flds] ++ acc) where - do_details acc (RecCon flds) = foldl do_fld (flds_seen, acc) flds - do_details acc other = (flds_seen, acc) - - do_fld acc (flds, _) = foldl do_fld1 acc flds + new_flds = [ f | (f,_) <- flds, not (unLoc f `elem` flds_seen) ] - do_fld1 (flds_seen, acc) fld - | fld `elem` flds_seen = (flds_seen,acc) - | otherwise = (fld:flds_seen, (fld,loc):acc) -\end{code} + do_one (flds_seen, acc) (ConDecl lname _ _ _) + = (flds_seen, lname:acc) -\begin{code} -conDetailsTys :: ConDetails name -> [HsType name] -conDetailsTys (VanillaCon btys) = map getBangType btys -conDetailsTys (InfixCon bty1 bty2) = [getBangType bty1, getBangType bty2] -conDetailsTys (RecCon fields) = [getBangType bty | (_, bty) <- fields] - - -eq_ConDecl env (ConDecl n1 _ tvs1 cxt1 cds1 _) - (ConDecl n2 _ tvs2 cxt2 cds2 _) - = n1 == n2 && - (eq_hsTyVars env tvs1 tvs2 $ \ env -> - eq_hsContext env cxt1 cxt2 && - eq_ConDetails env cds1 cds2) - -eq_ConDetails env (VanillaCon bts1) (VanillaCon bts2) - = eqListBy (eq_btype env) bts1 bts2 -eq_ConDetails env (InfixCon bta1 btb1) (InfixCon bta2 btb2) - = eq_btype env bta1 bta2 && eq_btype env btb1 btb2 -eq_ConDetails env (RecCon fs1) (RecCon fs2) - = eqListBy (eq_fld env) fs1 fs2 -eq_ConDetails env _ _ = False - -eq_fld env (ns1,bt1) (ns2, bt2) = ns1==ns2 && eq_btype env bt1 bt2 +conDetailsTys details = map getBangType (hsConArgs details) \end{code} \begin{code} -data BangType name - = Banged (HsType name) -- HsType: to allow Haskell extensions - | Unbanged (HsType name) -- (MonoType only needed for straight Haskell) - | Unpacked (HsType name) -- Field is strict and to be unpacked if poss. - -getBangType (Banged ty) = ty -getBangType (Unbanged ty) = ty -getBangType (Unpacked ty) = ty - -eq_btype env (Banged t1) (Banged t2) = eq_hsType env t1 t2 -eq_btype env (Unbanged t1) (Unbanged t2) = eq_hsType env t1 t2 -eq_btype env (Unpacked t1) (Unpacked t2) = eq_hsType env t1 t2 -eq_btype env _ _ = False +type LBangType name = Located (BangType name) + +data BangType name = BangType HsBang (LHsType name) + +data HsBang = HsNoBang + | HsStrict -- ! + | HsUnbox -- {-# UNPACK #-} ! (GHC extension, meaning "unbox") + +getBangType (BangType _ ty) = ty +getBangStrictness (BangType s _) = s + +unbangedType :: LHsType id -> LBangType id +unbangedType ty@(L loc _) = L loc (BangType HsNoBang ty) \end{code} \begin{code} -instance (Outputable name) => Outputable (ConDecl name) where - ppr (ConDecl con _ tvs cxt con_details loc) - = sep [pprHsForAll tvs cxt, ppr_con_details con con_details] +instance (OutputableBndr name) => Outputable (ConDecl name) where + ppr (ConDecl con tvs cxt con_details) + = sep [pprHsForAll Explicit tvs cxt, ppr_con_details con con_details] ppr_con_details con (InfixCon ty1 ty2) - = hsep [ppr_bang ty1, ppr con, ppr_bang ty2] + = hsep [ppr ty1, ppr con, ppr ty2] -ppr_con_details con (VanillaCon tys) - = ppr con <+> hsep (map (ppr_bang) tys) +-- ConDecls generated by MkIface.ifaceTyThing always have a PrefixCon, even +-- if the constructor is an infix one. This is because in an interface file +-- we don't distinguish between the two. Hence when printing these for the +-- user, we need to parenthesise infix constructor names. +ppr_con_details con (PrefixCon tys) + = hsep (pprHsVar con : map ppr tys) ppr_con_details con (RecCon fields) - = ppr con <+> braces (hsep (punctuate comma (map ppr_field fields))) + = ppr con <+> braces (sep (punctuate comma (map ppr_field fields))) where - ppr_field (ns, ty) = hsep (map (ppr) ns) <+> - dcolon <+> - ppr_bang ty - -instance Outputable name => Outputable (BangType name) where - ppr = ppr_bang + ppr_field (n, ty) = ppr n <+> dcolon <+> ppr ty -ppr_bang (Banged ty) = ptext SLIT("!") <> pprParendHsType ty -ppr_bang (Unbanged ty) = pprParendHsType ty -ppr_bang (Unpacked ty) = ptext SLIT("! !") <> pprParendHsType ty +instance OutputableBndr name => Outputable (BangType name) where + ppr (BangType is_strict ty) + = bang <> pprParendHsType (unLoc ty) + where + bang = case is_strict of + HsNoBang -> empty + HsStrict -> char '!' + HsUnbox -> ptext SLIT("!!") \end{code} @@ -518,47 +538,23 @@ ppr_bang (Unpacked ty) = ptext SLIT("! !") <> pprParendHsType ty %************************************************************************ \begin{code} -data InstDecl name pat - = InstDecl (HsType name) -- Context => Class Instance-type +type LInstDecl name = Located (InstDecl name) + +data InstDecl name + = InstDecl (LHsType name) -- Context => Class Instance-type -- Using a polytype means that the renamer conveniently -- figures out the quantified type variables for us. + (LHsBinds name) + [LSig name] -- User-supplied pragmatic info - (MonoBinds name pat) - - [Sig name] -- User-supplied pragmatic info +instance (OutputableBndr name) => Outputable (InstDecl name) where - (Maybe name) -- Name for the dictionary function - -- Nothing for source-file instance decls - - SrcLoc + ppr (InstDecl inst_ty binds uprags) + = vcat [hsep [ptext SLIT("instance"), ppr inst_ty, ptext SLIT("where")], + nest 4 (ppr uprags), + nest 4 (pprLHsBinds binds) ] \end{code} -\begin{code} -instance (Outputable name, Outputable pat) - => Outputable (InstDecl name pat) where - - ppr (InstDecl inst_ty binds uprags maybe_dfun_name src_loc) - = getPprStyle $ \ sty -> - if ifaceStyle sty then - hsep [ptext SLIT("instance"), ppr inst_ty, equals, pp_dfun] - else - vcat [hsep [ptext SLIT("instance"), ppr inst_ty, ptext SLIT("where")], - nest 4 (ppr uprags), - nest 4 (ppr binds) ] - where - pp_dfun = case maybe_dfun_name of - Just df -> ppr df - Nothing -> empty -\end{code} - -\begin{code} -instance Ord name => Eq (InstDecl name pat) where - -- Used for interface comparison only, so don't compare bindings - (==) (InstDecl inst_ty1 _ _ dfun1 _) (InstDecl inst_ty2 _ _ dfun2 _) - = inst_ty1 == inst_ty2 && dfun1 == dfun2 -\end{code} - - %************************************************************************ %* * \subsection[DefaultDecl]{A @default@ declaration} @@ -570,14 +566,15 @@ 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. \begin{code} +type LDefaultDecl name = Located (DefaultDecl name) + data DefaultDecl name - = DefaultDecl [HsType name] - SrcLoc + = DefaultDecl [LHsType name] -instance (Outputable name) +instance (OutputableBndr name) => Outputable (DefaultDecl name) where - ppr (DefaultDecl tys src_loc) + ppr (DefaultDecl tys) = ptext SLIT("default") <+> parens (interpp'SP tys) \end{code} @@ -588,57 +585,107 @@ instance (Outputable name) %************************************************************************ \begin{code} -data ForeignDecl name = - ForeignDecl - name - ForKind - (HsType name) - ExtName - CallConv - SrcLoc - -instance (Outputable name) - => Outputable (ForeignDecl name) where - - ppr (ForeignDecl nm imp_exp ty ext_name cconv src_loc) - = ptext SLIT("foreign") <+> ppr_imp_exp <+> pprCallConv cconv <+> - ppr ext_name <+> ppr_unsafe <+> ppr nm <+> dcolon <+> ppr ty - where - (ppr_imp_exp, ppr_unsafe) = - case imp_exp of - FoLabel -> (ptext SLIT("label"), empty) - FoExport -> (ptext SLIT("export"), empty) - FoImport us - | us -> (ptext SLIT("import"), ptext SLIT("unsafe")) - | otherwise -> (ptext SLIT("import"), empty) - -data ForKind - = FoLabel - | FoExport - | FoImport Bool -- True => unsafe call. - -data ExtName - = Dynamic - | ExtName CLabelString -- The external name of the foreign thing, - (Maybe CLabelString) -- and optionally its DLL or module name - -- Both of these are completely unencoded; - -- we just print them as they are - -isDynamicExtName :: ExtName -> Bool -isDynamicExtName Dynamic = True -isDynamicExtName _ = False - -extNameStatic :: ExtName -> CLabelString -extNameStatic (ExtName f _) = f -extNameStatic Dynamic = panic "staticExtName: Dynamic - shouldn't ever happen." - -instance Outputable ExtName where - ppr Dynamic = ptext SLIT("dynamic") - ppr (ExtName nm mb_mod) = - case mb_mod of { Nothing -> empty; Just m -> doubleQuotes (ptext m) } <+> - doubleQuotes (pprCLabelString nm) + +-- 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 +-- +type LForeignDecl name = Located (ForeignDecl name) + +data ForeignDecl name + = ForeignImport (Located name) (LHsType name) ForeignImport Bool -- defines name + | ForeignExport (Located name) (LHsType name) ForeignExport Bool -- uses name + +-- 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 CCallConv -- ccall or stdcall + Safety -- safe or unsafe + FastString -- name of C header + FastString -- name of library object + CImportSpec -- details of the C entity + + -- import of a .NET function + -- + | DNImport DNCallSpec + +-- 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.) + +-- specification of an externally exported entity in dependence on the calling +-- convention +-- +data ForeignExport = CExport CExportSpec -- contains the calling convention + | DNExport -- presently unused + +-- abstract type imported from .NET +-- +data FoType = DNType -- In due course we'll add subtype stuff + deriving (Eq) -- Used for equality instance for TyClDecl + + +-- pretty printing of foreign declarations +-- + +instance OutputableBndr name => Outputable (ForeignDecl name) where + ppr (ForeignImport n ty fimport _) = + ptext SLIT("foreign import") <+> ppr fimport <+> + ppr n <+> dcolon <+> ppr ty + ppr (ForeignExport n ty fexport _) = + ptext SLIT("foreign export") <+> ppr fexport <+> + ppr n <+> dcolon <+> ppr ty + +instance Outputable ForeignImport where + ppr (DNImport spec) = + ptext SLIT("dotnet") <+> ppr spec + ppr (CImport cconv safety header lib spec) = + ppr cconv <+> ppr safety <+> + char '"' <> pprCEntity header lib spec <> char '"' + where + pprCEntity header lib (CLabel lbl) = + ptext SLIT("static") <+> ftext header <+> char '&' <> + pprLib lib <> ppr lbl + pprCEntity header lib (CFunction (StaticTarget lbl)) = + ptext SLIT("static") <+> ftext header <+> char '&' <> + pprLib lib <> ppr lbl + pprCEntity header lib (CFunction (DynamicTarget)) = + ptext SLIT("dynamic") + pprCEntity _ _ (CWrapper) = ptext SLIT("wrapper") + -- + pprLib lib | nullFastString lib = empty + | otherwise = char '[' <> ppr lib <> char ']' + +instance Outputable ForeignExport where + ppr (CExport (CExportStatic lbl cconv)) = + ppr cconv <+> char '"' <> ppr lbl <> char '"' + ppr (DNExport ) = + ptext SLIT("dotnet") <+> ptext SLIT("\"\"") + +instance Outputable FoType where + ppr DNType = ptext SLIT("type dotnet") \end{code} + %************************************************************************ %* * \subsection{Transformation rules} @@ -646,69 +693,33 @@ instance Outputable ExtName where %************************************************************************ \begin{code} -data RuleDecl name pat +type LRuleDecl name = Located (RuleDecl name) + +data RuleDecl name = HsRule -- Source rule - FAST_STRING -- Rule name - [name] -- Forall'd tyvars, filled in by the renamer with - -- tyvars mentioned in sigs; then filled out by typechecker - [RuleBndr name] -- Forall'd term vars - (HsExpr name pat) -- LHS - (HsExpr name pat) -- RHS - SrcLoc - - | IfaceRule -- One that's come in from an interface file; pre-typecheck - FAST_STRING - [UfBinder name] -- Tyvars and term vars - name -- Head of lhs - [UfExpr name] -- Args of LHS - (UfExpr name) -- Pre typecheck - SrcLoc - - | IfaceRuleOut -- Post typecheck - name -- Head of LHS - CoreRule - -isIfaceRuleDecl (HsRule _ _ _ _ _ _) = False -isIfaceRuleDecl other = True - -ifaceRuleDeclName :: RuleDecl name pat -> name -ifaceRuleDeclName (IfaceRule _ _ n _ _ _) = n -ifaceRuleDeclName (IfaceRuleOut n r) = n -ifaceRuleDeclName (HsRule fs _ _ _ _ _) = pprPanic "ifaceRuleDeclName" (ppr fs) + RuleName -- Rule name + Activation + [RuleBndr name] -- Forall'd vars; after typechecking this includes tyvars + (Located (HsExpr name)) -- LHS + (Located (HsExpr name)) -- RHS data RuleBndr name - = RuleBndr name - | RuleBndrSig name (HsType name) - -instance (NamedThing name, Ord name) => Eq (RuleDecl name pat) where - -- Works for IfaceRules only; used when comparing interface file versions - (IfaceRule n1 bs1 f1 es1 rhs1 _) == (IfaceRule n2 bs2 f2 es2 rhs2 _) - = n1==n2 && f1 == f2 && - eq_ufBinders emptyEqHsEnv bs1 bs2 (\env -> - eqListBy (eq_ufExpr env) (rhs1:es1) (rhs2:es2)) - -instance (NamedThing name, Outputable name, Outputable pat) - => Outputable (RuleDecl name pat) where - ppr (HsRule name tvs ns lhs rhs loc) - = sep [text "{-# RULES" <+> doubleQuotes (ptext name), - pp_forall, ppr lhs, equals <+> ppr rhs, - text "#-}" ] - where - pp_forall | null tvs && null ns = empty - | otherwise = text "forall" <+> - fsep (map ppr tvs ++ map ppr ns) - <> dot + = RuleBndr (Located name) + | RuleBndrSig (Located name) (LHsType name) - ppr (IfaceRule name tpl_vars fn tpl_args rhs loc) - = hsep [ doubleQuotes (ptext name), - ptext SLIT("__forall") <+> braces (interppSP tpl_vars), - ppr fn <+> sep (map (pprUfExpr parens) tpl_args), - ptext SLIT("=") <+> ppr rhs - ] <+> semi +collectRuleBndrSigTys :: [RuleBndr name] -> [LHsType name] +collectRuleBndrSigTys bndrs = [ty | RuleBndrSig _ ty <- bndrs] - ppr (IfaceRuleOut fn rule) = pprCoreRule (ppr fn) rule +instance OutputableBndr name => Outputable (RuleDecl name) where + ppr (HsRule name act ns lhs rhs) + = sep [text "{-# RULES" <+> doubleQuotes (ftext name) <+> ppr act, + nest 4 (pp_forall <+> pprExpr (unLoc lhs)), + nest 4 (equals <+> pprExpr (unLoc rhs) <+> text "#-}") ] + where + pp_forall | null ns = empty + | otherwise = text "forall" <+> fsep (map ppr ns) <> dot -instance Outputable name => Outputable (RuleBndr name) where +instance OutputableBndr name => Outputable (RuleBndr name) where ppr (RuleBndr name) = ppr name ppr (RuleBndrSig name ty) = ppr name <> dcolon <> ppr ty \end{code} @@ -723,11 +734,11 @@ instance Outputable name => Outputable (RuleBndr name) where We use exported entities for things to deprecate. \begin{code} -data DeprecDecl name = Deprecation name DeprecTxt SrcLoc +type LDeprecDecl name = Located (DeprecDecl name) -type DeprecTxt = FAST_STRING -- reason/explanation for deprecation +data DeprecDecl name = Deprecation name DeprecTxt -instance Outputable name => Outputable (DeprecDecl name) where - ppr (Deprecation thing txt _) +instance OutputableBndr name => Outputable (DeprecDecl name) where + ppr (Deprecation thing txt) = hsep [text "{-# DEPRECATED", ppr thing, doubleQuotes (ppr txt), text "#-}"] \end{code}