diff options
| author | idontgetoutmuch <dominic@steinitz.org> | 2015-12-20 21:01:47 +0000 | 
|---|---|---|
| committer | idontgetoutmuch <dominic@steinitz.org> | 2015-12-20 21:01:47 +0000 | 
| commit | 2bdfda1fb2e0de696ca8c6f7a152b2f85a541be9 (patch) | |
| tree | cc29895f7d69f051cfec172bb0f8c2ef03552789 /haddock-api/src/Haddock/Interface | |
| parent | 5a57a24c44e06e964c4ea2276c842c722c4e93d9 (diff) | |
| parent | fa03f80d76f1511a811a0209ea7a6a8b6c58704f (diff) | |
Merge pull request #1 from haskell/ghc-head
Ghc head
Diffstat (limited to 'haddock-api/src/Haddock/Interface')
| -rw-r--r-- | haddock-api/src/Haddock/Interface/AttachInstances.hs | 52 | ||||
| -rw-r--r-- | haddock-api/src/Haddock/Interface/Create.hs | 151 | ||||
| -rw-r--r-- | haddock-api/src/Haddock/Interface/LexParseRn.hs | 70 | ||||
| -rw-r--r-- | haddock-api/src/Haddock/Interface/ParseModuleHeader.hs | 1 | ||||
| -rw-r--r-- | haddock-api/src/Haddock/Interface/Rename.hs | 236 | ||||
| -rw-r--r-- | haddock-api/src/Haddock/Interface/Specialize.hs | 406 | 
6 files changed, 725 insertions, 191 deletions
diff --git a/haddock-api/src/Haddock/Interface/AttachInstances.hs b/haddock-api/src/Haddock/Interface/AttachInstances.hs index 080de6ff..faf043aa 100644 --- a/haddock-api/src/Haddock/Interface/AttachInstances.hs +++ b/haddock-api/src/Haddock/Interface/AttachInstances.hs @@ -22,6 +22,7 @@ import Control.Arrow hiding ((<+>))  import Data.List  import Data.Ord (comparing)  import Data.Function (on) +import Data.Maybe ( maybeToList, mapMaybe )  import qualified Data.Map as Map  import qualified Data.Set as Set @@ -32,16 +33,15 @@ import FamInstEnv  import FastString  import GHC  import GhcMonad (withSession) -import Id  import InstEnv  import MonadUtils (liftIO)  import Name  import Outputable (text, sep, (<+>))  import PrelNames +import SrcLoc  import TcRnDriver (tcRnGetInfo) -import TcType (tcSplitSigmaTy)  import TyCon -import TypeRep +import TyCoRep  import TysPrim( funTyCon )  import Var hiding (varName)  #define FSLIT(x) (mkFastString# (x#)) @@ -68,25 +68,26 @@ attachToExportItem :: ExportInfo -> Interface -> IfaceMap -> InstIfaceMap                     -> Ghc (ExportItem Name)  attachToExportItem expInfo iface ifaceMap instIfaceMap export =    case attachFixities export of -    e@ExportDecl { expItemDecl = L _ (TyClD d) } -> do +    e@ExportDecl { expItemDecl = L eSpan (TyClD d) } -> do        mb_info <- getAllInfo (tcdName d)        insts <- case mb_info of          Just (_, _, cls_instances, fam_instances) -> -          let fam_insts = [ (synifyFamInst i opaque, n) +          let fam_insts = [ (synifyFamInst i opaque, doc,spanNameE n (synifyFamInst i opaque) (L eSpan (tcdName d)) )                            | i <- sortBy (comparing instFam) fam_instances -                          , let n = instLookup instDocMap (getName i) iface ifaceMap instIfaceMap +                          , let n = getName i +                          , let doc = instLookup instDocMap n iface ifaceMap instIfaceMap                            , not $ isNameHidden expInfo (fi_fam i)                            , not $ any (isTypeHidden expInfo) (fi_tys i)                            , let opaque = isTypeHidden expInfo (fi_rhs i)                            ] -              cls_insts = [ (synifyInstHead i, instLookup instDocMap n iface ifaceMap instIfaceMap) +              cls_insts = [ (synifyInstHead i, instLookup instDocMap n iface ifaceMap instIfaceMap, spanName n (synifyInstHead i) (L eSpan (tcdName d)))                            | let is = [ (instanceSig i, getName i) | i <- cls_instances ]                            , (i@(_,_,cls,tys), n) <- sortBy (comparing $ first instHead) is                            , not $ isInstanceHidden expInfo cls tys                            ]                -- fam_insts but with failing type fams filtered out -              cleanFamInsts = [ (fi, n) | (Right fi, n) <- fam_insts ] -              famInstErrs = [ errm | (Left errm, _) <- fam_insts ] +              cleanFamInsts = [ (fi, n, L l r) | (Right fi, n, L l (Right r)) <- fam_insts ] +              famInstErrs = [ errm | (Left errm, _, _) <- fam_insts ]            in do              dfs <- getDynFlags              let mkBug = (text "haddock-bug:" <+>) . text @@ -105,6 +106,18 @@ attachToExportItem expInfo iface ifaceMap instIfaceMap export =        ] }      attachFixities e = e +    -- spanName: attach the location to the name that is the same file as the instance location +    spanName s (InstHead { ihdClsName = clsn }) (L instL instn) = +        let s1 = getSrcSpan s +            sn = if srcSpanFileName_maybe s1 == srcSpanFileName_maybe instL +                    then instn +                    else clsn +        in L (getSrcSpan s) sn +    -- spanName on Either +    spanNameE s (Left e) _ =  L (getSrcSpan s) (Left e) +    spanNameE s (Right ok) linst = +      let L l r = spanName s ok linst +      in L l (Right r)  instLookup :: (InstalledInterface -> Map.Map Name a) -> Name @@ -146,18 +159,26 @@ instHead (_, _, cls, args)  argCount :: Type -> Int  argCount (AppTy t _) = argCount t + 1  argCount (TyConApp _ ts) = length ts -argCount (FunTy _ _ ) = 2 +argCount (ForAllTy (Anon _) _ ) = 2  argCount (ForAllTy _ t) = argCount t +argCount (CastTy t _) = argCount t  argCount _ = 0  simplify :: Type -> SimpleType +simplify (ForAllTy (Anon t1) t2) = SimpleType funTyConName [simplify t1, simplify t2]  simplify (ForAllTy _ t) = simplify t -simplify (FunTy t1 t2) = SimpleType funTyConName [simplify t1, simplify t2] -simplify (AppTy t1 t2) = SimpleType s (ts ++ [simplify t2]) +simplify (AppTy t1 t2) = SimpleType s (ts ++ maybeToList (simplify_maybe t2))    where (SimpleType s ts) = simplify t1  simplify (TyVarTy v) = SimpleType (tyVarName v) [] -simplify (TyConApp tc ts) = SimpleType (tyConName tc) (map simplify ts) +simplify (TyConApp tc ts) = SimpleType (tyConName tc) +                                       (mapMaybe simplify_maybe ts)  simplify (LitTy l) = SimpleTyLit l +simplify (CastTy ty _) = simplify ty +simplify (CoercionTy _) = error "simplify:Coercion" + +simplify_maybe :: Type -> Maybe SimpleType +simplify_maybe (CoercionTy {}) = Nothing +simplify_maybe ty              = Just (simplify ty)  -- Used for sorting  instFam :: FamInst -> ([Int], Name, [SimpleType], Int, SimpleType) @@ -207,9 +228,10 @@ isTypeHidden expInfo = typeHidden          TyVarTy {} -> False          AppTy t1 t2 -> typeHidden t1 || typeHidden t2          TyConApp tcon args -> nameHidden (getName tcon) || any typeHidden args -        FunTy t1 t2 -> typeHidden t1 || typeHidden t2 -        ForAllTy _ ty -> typeHidden ty +        ForAllTy bndr ty -> typeHidden (binderType bndr) || typeHidden ty          LitTy _ -> False +        CastTy ty _ -> typeHidden ty +        CoercionTy {} -> False      nameHidden :: Name -> Bool      nameHidden = isNameHidden expInfo diff --git a/haddock-api/src/Haddock/Interface/Create.hs b/haddock-api/src/Haddock/Interface/Create.hs index 9ef3d1b1..c41946f5 100644 --- a/haddock-api/src/Haddock/Interface/Create.hs +++ b/haddock-api/src/Haddock/Interface/Create.hs @@ -21,6 +21,9 @@ import Haddock.GhcUtils  import Haddock.Utils  import Haddock.Convert  import Haddock.Interface.LexParseRn +import Haddock.Backends.Hyperlinker.Types +import Haddock.Backends.Hyperlinker.Ast as Hyperlinker +import Haddock.Backends.Hyperlinker.Parser as Hyperlinker  import qualified Data.Map as M  import Data.Map (Map) @@ -45,7 +48,9 @@ import Bag  import RdrName  import TcRnTypes  import FastString (concatFS) +import BasicTypes ( StringLiteral(..) )  import qualified Outputable as O +import HsDecls ( gadtDeclDetails,getConDetails )  -- | Use a 'TypecheckedModule' to produce an 'Interface'.  -- To do this, we need access to already processed modules in the topological @@ -122,6 +127,8 @@ createInterface tm flags modMap instIfaceMap = do          mkAliasMap dflags $ tm_renamed_source tm        modWarn = moduleWarning dflags gre warnings +  tokenizedSrc <- mkMaybeTokenizedSrc flags tm +    return $! Interface {      ifaceMod             = mdl    , ifaceOrigFilename    = msHsFilePath ms @@ -145,6 +152,7 @@ createInterface tm flags modMap instIfaceMap = do    , ifaceFamInstances    = fam_instances    , ifaceHaddockCoverage = coverage    , ifaceWarningMap      = warningMap +  , ifaceTokenizedSrc    = tokenizedSrc    }  mkAliasMap :: DynFlags -> Maybe RenamedSource -> M.Map Module ModuleName @@ -157,21 +165,21 @@ mkAliasMap dflags mRenamedSource =          alias <- ideclAs impDecl          return $            (lookupModuleDyn dflags -             (fmap Module.fsToPackageKey $ -              ideclPkgQual impDecl) +             (fmap Module.fsToUnitId $ +              fmap sl_fs $ ideclPkgQual impDecl)               (case ideclName impDecl of SrcLoc.L _ name -> name),             alias))          impDecls  -- similar to GHC.lookupModule  lookupModuleDyn :: -  DynFlags -> Maybe PackageKey -> ModuleName -> Module +  DynFlags -> Maybe UnitId -> ModuleName -> Module  lookupModuleDyn _ (Just pkgId) mdlName =    Module.mkModule pkgId mdlName  lookupModuleDyn dflags Nothing mdlName =    case Packages.lookupModuleInAllPackages dflags mdlName of      (m,_):_ -> m -    [] -> Module.mkModule Module.mainPackageKey mdlName +    [] -> Module.mkModule Module.mainUnitId mdlName  ------------------------------------------------------------------------------- @@ -194,8 +202,8 @@ moduleWarning dflags gre (WarnAll w) = Just $ parseWarning dflags gre w  parseWarning :: DynFlags -> GlobalRdrEnv -> WarningTxt -> Doc Name  parseWarning dflags gre w = force $ case w of -  DeprecatedTxt _ msg -> format "Deprecated: " (concatFS $ map unLoc msg) -  WarningTxt    _ msg -> format "Warning: "    (concatFS $ map unLoc msg) +  DeprecatedTxt _ msg -> format "Deprecated: " (concatFS $ map (sl_fs . unLoc) msg) +  WarningTxt    _ msg -> format "Warning: "    (concatFS $ map (sl_fs . unLoc) msg)    where      format x xs = DocWarning . DocParagraph . DocAppend (DocString x)                    . processDocString dflags gre $ HsDocString xs @@ -328,30 +336,30 @@ subordinates instMap decl = case decl of      classSubs dd = [ (name, doc, typeDocs d) | (L _ d, doc) <- classDecls dd                     , name <- getMainDeclBinder d, not (isValD d)                     ] +    dataSubs :: HsDataDefn Name -> [(Name, [HsDocString], Map Int HsDocString)]      dataSubs dd = constrs ++ fields        where          cons = map unL $ (dd_cons dd)          constrs = [ (unL cname, maybeToList $ fmap unL $ con_doc c, M.empty) -                  | c <- cons, cname <- con_names c ] -        fields  = [ (unL n, maybeToList $ fmap unL doc, M.empty) -                  | RecCon flds <- map con_details cons +                  | c <- cons, cname <- getConNames c ] +        fields  = [ (selectorFieldOcc n, maybeToList $ fmap unL doc, M.empty) +                  | RecCon flds <- map getConDetails cons                    , L _ (ConDeclField ns _ doc) <- (unLoc flds) -                  , n <- ns ] +                  , L _ n <- ns ]  -- | Extract function argument docs from inside types.  typeDocs :: HsDecl Name -> Map Int HsDocString  typeDocs d =    let docs = go 0 in    case d of -    SigD (TypeSig _ ty _) -> docs (unLoc ty) -    SigD (PatSynSig _ _ req prov ty) -> -        let allTys = ty : concat [ unLoc req, unLoc prov ] -        in F.foldMap (docs . unLoc) allTys -    ForD (ForeignImport _ ty _ _) -> docs (unLoc ty) +    SigD (TypeSig _ ty)   -> docs (unLoc (hsSigWcType ty)) +    SigD (PatSynSig _ ty) -> docs (unLoc (hsSigType ty)) +    ForD (ForeignImport _ ty _ _)   -> docs (unLoc (hsSigType ty))      TyClD (SynDecl { tcdRhs = ty }) -> docs (unLoc ty)      _ -> M.empty    where -    go n (HsForAllTy _ _ _ _ ty) = go n (unLoc ty) +    go n (HsForAllTy { hst_body = ty }) = go n (unLoc ty) +    go n (HsQualTy   { hst_body = ty }) = go n (unLoc ty)      go n (HsFunTy (L _ (HsDocTy _ (L _ x))) (L _ ty)) = M.insert n x $ go (n+1) ty      go n (HsFunTy _ ty) = go (n+1) (unLoc ty)      go n (HsDocTy _ (L _ doc)) = M.singleton n doc @@ -394,7 +402,7 @@ ungroup group_ =    mkDecls (typesigs . hs_valds)  SigD   group_ ++    mkDecls (valbinds . hs_valds)  ValD   group_    where -    typesigs (ValBindsOut _ sigs) = filter isVanillaLSig sigs +    typesigs (ValBindsOut _ sigs) = filter isUserLSig sigs      typesigs _ = error "expected ValBindsOut"      valbinds (ValBindsOut binds _) = concatMap bagToList . snd . unzip $ binds @@ -426,7 +434,7 @@ filterDecls = filter (isHandled . unL . fst)      isHandled (ForD (ForeignImport {})) = True      isHandled (TyClD {}) = True      isHandled (InstD {}) = True -    isHandled (SigD d) = isVanillaLSig (reL d) +    isHandled (SigD d) = isUserLSig (reL d)      isHandled (ValD _) = True      -- we keep doc declarations to be able to get at named docs      isHandled (DocD _) = True @@ -439,7 +447,7 @@ filterClasses decls = [ if isClassD d then (L loc (filterClass d), doc) else x                        | x@(L loc d, doc) <- decls ]    where      filterClass (TyClD c) = -      TyClD $ c { tcdSigs = filter (liftA2 (||) isVanillaLSig isMinimalLSig) $ tcdSigs c } +      TyClD $ c { tcdSigs = filter (liftA2 (||) isUserLSig isMinimalLSig) $ tcdSigs c }      filterClass _ = error "expected TyClD" @@ -498,7 +506,7 @@ mkExportItems      lookupExport (IEVar (L _ x))         = declWith x      lookupExport (IEThingAbs (L _ t))    = declWith t      lookupExport (IEThingAll (L _ t))    = declWith t -    lookupExport (IEThingWith (L _ t) _) = declWith t +    lookupExport (IEThingWith (L _ t) _ _ _) = declWith t      lookupExport (IEModuleContents (L _ m)) =        moduleExports thisMod m dflags warnings gre exportedNames decls modMap instIfaceMap maps fixMap splices      lookupExport (IEGroup lev docStr)  = return $ @@ -517,7 +525,7 @@ mkExportItems        case findDecl t of          ([L l (ValD _)], (doc, _)) -> do            -- Top-level binding without type signature -          export <- hiValExportItem dflags t doc (l `elem` splices) $ M.lookup t fixMap +          export <- hiValExportItem dflags t l doc (l `elem` splices) $ M.lookup t fixMap            return [export]          (ds, docs_) | decl : _ <- filter (not . isValD . unLoc) ds ->            let declNames = getMainDeclBinder (unL decl) @@ -553,7 +561,7 @@ mkExportItems                    L loc (TyClD cl@ClassDecl{}) -> do                      mdef <- liftGhcToErrMsgGhc $ minimalDef t -                    let sig = maybeToList $ fmap (noLoc . MinimalSig mempty . fmap noLoc) mdef +                    let sig = maybeToList $ fmap (noLoc . MinimalSig mempty . noLoc . fmap noLoc) mdef                      return [ mkExportDecl t                        (L loc $ TyClD cl { tcdSigs = sig ++ tcdSigs cl }) docs_ ] @@ -620,13 +628,19 @@ hiDecl dflags t = do                     O.text "-- Please report this on Haddock issue tracker!"        bugWarn = O.showSDoc dflags . warnLine -hiValExportItem :: DynFlags -> Name -> DocForDecl Name -> Bool -> Maybe Fixity -> ErrMsgGhc (ExportItem Name) -hiValExportItem dflags name doc splice fixity = do +-- | This function is called for top-level bindings without type signatures. +-- It gets the type signature from GHC and that means it's not going to +-- have a meaningful 'SrcSpan'. So we pass down 'SrcSpan' for the +-- declaration and use it instead - 'nLoc' here. +hiValExportItem :: DynFlags -> Name -> SrcSpan -> DocForDecl Name -> Bool +                -> Maybe Fixity -> ErrMsgGhc (ExportItem Name) +hiValExportItem dflags name nLoc doc splice fixity = do    mayDecl <- hiDecl dflags name    case mayDecl of      Nothing -> return (ExportNoDecl name []) -    Just decl -> return (ExportDecl decl doc [] [] fixities splice) +    Just decl -> return (ExportDecl (fixSpan decl) doc [] [] fixities splice)    where +    fixSpan (L l t) = L (SrcLoc.combineSrcSpans l nLoc) t      fixities = case fixity of        Just f  -> [(name, f)]        Nothing -> [] @@ -689,8 +703,8 @@ moduleExports thisMod expMod dflags warnings gre _exports decls ifaceMap instIfa                      "documentation for exported module: " ++ pretty dflags expMod]              return []    where -    m = mkModule packageKey expMod -    packageKey = modulePackageKey thisMod +    m = mkModule unitId expMod +    unitId = moduleUnitId thisMod  -- Note [1]: @@ -724,8 +738,8 @@ fullModuleContents dflags warnings gre (docMap, argMap, subMap, declMap, instMap      expandSig = foldr f []        where          f :: LHsDecl name -> [LHsDecl name] -> [LHsDecl name] -        f (L l (SigD (TypeSig    names t nwcs)))     xs = foldr (\n acc -> L l (SigD (TypeSig    [n] t nwcs))     : acc) xs names -        f (L l (SigD (GenericSig names t)))          xs = foldr (\n acc -> L l (SigD (GenericSig [n] t))          : acc) xs names +        f (L l (SigD (TypeSig    names t)))   xs = foldr (\n acc -> L l (SigD (TypeSig      [n] t)) : acc) xs names +        f (L l (SigD (ClassOpSig b names t))) xs = foldr (\n acc -> L l (SigD (ClassOpSig b [n] t)) : acc) xs names          f x xs = x : xs      mkExportItem :: LHsDecl Name -> ErrMsgGhc (Maybe (ExportItem Name)) @@ -737,7 +751,7 @@ fullModuleContents dflags warnings gre (docMap, argMap, subMap, declMap, instMap        | name:_ <- collectHsBindBinders d, Just [L _ (ValD _)] <- M.lookup name declMap =            -- Top-level binding without type signature.            let (doc, _) = lookupDocs name warnings docMap argMap subMap in -          fmap Just (hiValExportItem dflags name doc (l `elem` splices) $ M.lookup name fixMap) +          fmap Just (hiValExportItem dflags name l doc (l `elem` splices) $ M.lookup name fixMap)        | otherwise = return Nothing      mkExportItem decl@(L l (InstD d))        | Just name <- M.lookup (getInstLoc d) instMap = @@ -745,7 +759,7 @@ fullModuleContents dflags warnings gre (docMap, argMap, subMap, declMap, instMap          return $ Just (ExportDecl decl doc subs [] (fixities name subs) (l `elem` splices))      mkExportItem (L l (TyClD cl@ClassDecl{ tcdLName = L _ name, tcdSigs = sigs })) = do        mdef <- liftGhcToErrMsgGhc $ minimalDef name -      let sig = maybeToList $ fmap (noLoc . MinimalSig mempty . fmap noLoc) mdef +      let sig = maybeToList $ fmap (noLoc . MinimalSig mempty . noLoc . fmap noLoc) mdef        expDecl (L l (TyClD cl { tcdSigs = sig ++ sigs })) l name      mkExportItem decl@(L l d)        | name:_ <- getMainDeclBinder d = expDecl decl l name @@ -769,64 +783,49 @@ extractDecl name mdl decl      case unLoc decl of        TyClD d@ClassDecl {} ->          let matches = [ sig | sig <- tcdSigs d, name `elem` sigName sig, -                        isVanillaLSig sig ] -- TODO: document fixity +                        isTypeLSig sig ] -- TODO: document fixity          in case matches of -          [s0] -> let (n, tyvar_names) = (tcdName d, getTyVars d) -                      L pos sig = extractClassDecl n tyvar_names s0 +          [s0] -> let (n, tyvar_names) = (tcdName d, tyClDeclTyVars d) +                      L pos sig = addClassContext n tyvar_names s0                    in L pos (SigD sig)            _ -> error "internal: extractDecl (ClassDecl)"        TyClD d@DataDecl {} -> -        let (n, tyvar_names) = (tcdName d, map toTypeNoLoc $ getTyVars d) -        in SigD <$> extractRecSel name mdl n tyvar_names (dd_cons (tcdDataDefn d)) +        let (n, tyvar_tys) = (tcdName d, lHsQTyVarsToTypes (tyClDeclTyVars d)) +        in SigD <$> extractRecSel name mdl n tyvar_tys (dd_cons (tcdDataDefn d))        InstD (DataFamInstD DataFamInstDecl { dfid_tycon = L _ n -                                          , dfid_pats = HsWB { hswb_cts = tys } +                                          , dfid_pats = HsIB { hsib_body = tys }                                            , dfid_defn = defn }) ->          SigD <$> extractRecSel name mdl n tys (dd_cons defn)        InstD (ClsInstD ClsInstDecl { cid_datafam_insts = insts }) ->          let matches = [ d | L _ d <- insts -                          , L _ ConDecl { con_details = RecCon rec } <- dd_cons (dfid_defn d) +                          -- , L _ ConDecl { con_details = RecCon rec } <- dd_cons (dfid_defn d) +                          , RecCon rec <- map (getConDetails . unLoc) (dd_cons (dfid_defn d))                            , ConDeclField { cd_fld_names = ns } <- map unLoc (unLoc rec)                            , L _ n <- ns -                          , n == name +                          , selectorFieldOcc n == name                        ]          in case matches of            [d0] -> extractDecl name mdl (noLoc . InstD $ DataFamInstD d0)            _ -> error "internal: extractDecl (ClsInstD)"        _ -> error "internal: extractDecl" -  where -    getTyVars = hsLTyVarLocNames . tyClDeclTyVars - - -toTypeNoLoc :: Located Name -> LHsType Name -toTypeNoLoc = noLoc . HsTyVar . unLoc - - -extractClassDecl :: Name -> [Located Name] -> LSig Name -> LSig Name -extractClassDecl c tvs0 (L pos (TypeSig lname ltype _)) = case ltype of -  L _ (HsForAllTy expl _ tvs (L _ preds) ty) -> -    L pos (TypeSig lname (noLoc (HsForAllTy expl Nothing tvs (lctxt preds) ty)) []) -  _ -> L pos (TypeSig lname (noLoc (HsForAllTy Implicit Nothing emptyHsQTvs (lctxt []) ltype)) []) -  where -    lctxt = noLoc . ctxt -    ctxt preds = nlHsTyConApp c (map toTypeNoLoc tvs0) : preds -extractClassDecl _ _ _ = error "extractClassDecl: unexpected decl" -  extractRecSel :: Name -> Module -> Name -> [LHsType Name] -> [LConDecl Name]                -> LSig Name  extractRecSel _ _ _ _ [] = error "extractRecSel: selector not found"  extractRecSel nm mdl t tvs (L _ con : rest) = -  case con_details con of -    RecCon (L _ fields) | ((n,L _ (ConDeclField _nn ty _)) : _) <- matching_fields fields -> -      L (getLoc n) (TypeSig [noLoc nm] (noLoc (HsFunTy data_ty (getBangType ty))) []) +  case getConDetails con of +    RecCon (L _ fields) | ((l,L _ (ConDeclField _nn ty _)) : _) <- matching_fields fields -> +      L l (TypeSig [noLoc nm] (mkEmptySigWcType (noLoc (HsFunTy data_ty (getBangType ty)))))      _ -> extractRecSel nm mdl t tvs rest   where -  matching_fields flds = [ (n,f) | f@(L _ (ConDeclField ns _ _)) <- flds, n <- ns, unLoc n == nm ] +  matching_fields :: [LConDeclField Name] -> [(SrcSpan, LConDeclField Name)] +  matching_fields flds = [ (l,f) | f@(L _ (ConDeclField ns _ _)) <- flds +                                 , L l n <- ns, selectorFieldOcc n == nm ]    data_ty -    | ResTyGADT _ ty <- con_res con = ty -    | otherwise = foldl' (\x y -> noLoc (HsAppTy x y)) (noLoc (HsTyVar t)) tvs - +    -- | ResTyGADT _ ty <- con_res con = ty +    | ConDeclGADT{} <- con = hsib_body $ con_type con +    | otherwise = foldl' (\x y -> noLoc (HsAppTy x y)) (noLoc (HsTyVar (noLoc t))) tvs  -- | Keep export items with docs.  pruneExportItems :: [ExportItem Name] -> [ExportItem Name] @@ -855,6 +854,30 @@ seqList :: [a] -> ()  seqList [] = ()  seqList (x : xs) = x `seq` seqList xs +mkMaybeTokenizedSrc :: [Flag] -> TypecheckedModule +                    -> ErrMsgGhc (Maybe [RichToken]) +mkMaybeTokenizedSrc flags tm +    | Flag_HyperlinkedSource `elem` flags = case renamedSource tm of +        Just src -> do +            tokens <- liftGhcToErrMsgGhc . liftIO $ mkTokenizedSrc summary src +            return $ Just tokens +        Nothing -> do +            liftErrMsg . tell . pure $ concat +                [ "Warning: Cannot hyperlink module \"" +                , moduleNameString . ms_mod_name $ summary +                , "\" because renamed source is not available" +                ] +            return Nothing +    | otherwise = return Nothing +  where +    summary = pm_mod_summary . tm_parsed_module $ tm + +mkTokenizedSrc :: ModSummary -> RenamedSource -> IO [RichToken] +mkTokenizedSrc ms src = +    Hyperlinker.enrich src . Hyperlinker.parse <$> rawSrc +  where +    rawSrc = readFile $ msHsFilePath ms +  -- | Find a stand-alone documentation comment by its name.  findNamedDoc :: String -> [HsDecl Name] -> ErrMsgM (Maybe HsDocString)  findNamedDoc name = search diff --git a/haddock-api/src/Haddock/Interface/LexParseRn.hs b/haddock-api/src/Haddock/Interface/LexParseRn.hs index ac823da3..3c14498c 100644 --- a/haddock-api/src/Haddock/Interface/LexParseRn.hs +++ b/haddock-api/src/Haddock/Interface/LexParseRn.hs @@ -18,20 +18,20 @@ module Haddock.Interface.LexParseRn    , processModuleHeader    ) where -import Control.Applicative  import Data.IntSet (toList)  import Data.List  import Documentation.Haddock.Doc (metaDocConcat) -import DynFlags (ExtensionFlag(..), languageExtensions) +import DynFlags (languageExtensions) +import qualified GHC.LanguageExtensions as LangExt  import FastString  import GHC  import Haddock.Interface.ParseModuleHeader  import Haddock.Parser  import Haddock.Types  import Name -import RdrHsSyn   ( setRdrNameSpace )  import Outputable ( showPpr )  import RdrName +import RnEnv (dataTcOccs)  processDocStrings :: DynFlags -> GlobalRdrEnv -> [HsDocString]                    -> Maybe (MDoc Name) @@ -65,7 +65,7 @@ processModuleHeader dflags gre safety mayStr = do              doc' = overDoc (rename dflags gre) doc          return (hmi', Just doc') -  let flags :: [ExtensionFlag] +  let flags :: [LangExt.Extension]        -- We remove the flags implied by the language setting and we display the language instead        flags = map toEnum (toList $ extensionFlags dflags) \\ languageExtensions (language dflags)    return (hmi { hmi_safety = Just $ showPpr dflags safety @@ -75,7 +75,13 @@ processModuleHeader dflags gre safety mayStr = do    where      failure = (emptyHaddockModInfo, Nothing) - +-- | Takes a 'GlobalRdrEnv' which (hopefully) contains all the +-- definitions and a parsed comment and we attempt to make sense of +-- where the identifiers in the comment point to. We're in effect +-- trying to convert 'RdrName's to 'Name's, with some guesswork and +-- fallbacks in case we can't locate the identifiers. +-- +-- See the comments in the source for implementation commentary.  rename :: DynFlags -> GlobalRdrEnv -> Doc RdrName -> Doc Name  rename dflags gre = rn    where @@ -83,19 +89,36 @@ rename dflags gre = rn        DocAppend a b -> DocAppend (rn a) (rn b)        DocParagraph doc -> DocParagraph (rn doc)        DocIdentifier x -> do -        let choices = dataTcOccs' x +        -- Generate the choices for the possible kind of thing this +        -- is. +        let choices = dataTcOccs x +        -- Try to look up all the names in the GlobalRdrEnv that match +        -- the names.          let names = concatMap (\c -> map gre_name (lookupGRE_RdrName c gre)) choices +          case names of +          -- We found no names in the env so we start guessing.            [] ->              case choices of                [] -> DocMonospaced (DocString (showPpr dflags x)) -              [a] -> outOfScope dflags a -              a:b:_ | isRdrTc a -> outOfScope dflags a -                    | otherwise -> outOfScope dflags b +              -- There was nothing in the environment so we need to +              -- pick some default from what's available to us. We +              -- diverge here from the old way where we would default +              -- to type constructors as we're much more likely to +              -- actually want anchors to regular definitions than +              -- type constructor names (such as in #253). So now we +              -- only get type constructor links if they are actually +              -- in scope. +              a:_ -> outOfScope dflags a + +          -- There is only one name in the environment that matches so +          -- use it.            [a] -> DocIdentifier a -          a:b:_ | isTyConName a -> DocIdentifier a | otherwise -> DocIdentifier b -              -- If an id can refer to multiple things, we give precedence to type -              -- constructors. +          -- But when there are multiple names available, default to +          -- type constructors: somewhat awfully GHC returns the +          -- values in the list positionally. +          a:b:_ | isTyConName a -> DocIdentifier a +                | otherwise -> DocIdentifier b        DocWarning doc -> DocWarning (rn doc)        DocEmphasis doc -> DocEmphasis (rn doc) @@ -116,21 +139,14 @@ rename dflags gre = rn        DocString str -> DocString str        DocHeader (Header l t) -> DocHeader $ Header l (rn t) -dataTcOccs' :: RdrName -> [RdrName] --- If the input is a data constructor, return both it and a type --- constructor.  This is useful when we aren't sure which we are --- looking at. --- --- We use this definition instead of the GHC's to provide proper linking to --- functions accross modules. See ticket #253 on Haddock Trac. -dataTcOccs' rdr_name -  | isDataOcc occ             = [rdr_name, rdr_name_tc] -  | otherwise                 = [rdr_name] -  where -    occ = rdrNameOcc rdr_name -    rdr_name_tc = setRdrNameSpace rdr_name tcName - - +-- | Wrap an identifier that's out of scope (i.e. wasn't found in +-- 'GlobalReaderEnv' during 'rename') in an appropriate doc. Currently +-- we simply monospace the identifier in most cases except when the +-- identifier is qualified: if the identifier is qualified then we can +-- still try to guess and generate anchors accross modules but the +-- users shouldn't rely on this doing the right thing. See tickets +-- #253 and #375 on the confusion this causes depending on which +-- default we pick in 'rename'.  outOfScope :: DynFlags -> RdrName -> Doc a  outOfScope dflags x =    case x of diff --git a/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs b/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs index d92e8b2a..e7d2a085 100644 --- a/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs +++ b/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs @@ -11,7 +11,6 @@  -----------------------------------------------------------------------------  module Haddock.Interface.ParseModuleHeader (parseModuleHeader) where -import Control.Applicative ((<$>))  import Control.Monad (mplus)  import Data.Char  import DynFlags diff --git a/haddock-api/src/Haddock/Interface/Rename.hs b/haddock-api/src/Haddock/Interface/Rename.hs index 56e5b07f..2478ce23 100644 --- a/haddock-api/src/Haddock/Interface/Rename.hs +++ b/haddock-api/src/Haddock/Interface/Rename.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE RecordWildCards #-}  ----------------------------------------------------------------------------  -- |  -- Module      :  Haddock.Interface.Rename @@ -13,7 +13,7 @@  module Haddock.Interface.Rename (renameInterface) where -import Data.Traversable (traverse, Traversable) +import Data.Traversable (mapM)  import Haddock.GhcUtils  import Haddock.Types @@ -21,14 +21,11 @@ import Haddock.Types  import Bag (emptyBag)  import GHC hiding (NoLink)  import Name -import NameSet -import Coercion  import Control.Applicative  import Control.Monad hiding (mapM)  import Data.List  import qualified Data.Map as Map hiding ( Map ) -import Data.Traversable (mapM)  import Prelude hiding (mapM) @@ -94,13 +91,13 @@ newtype RnM a =  instance Monad RnM where    (>>=) = thenRn -  return = returnRn +  return = pure  instance Functor RnM where    fmap f x = do a <- x; return (f a)  instance Applicative RnM where -  pure = return +  pure = returnRn    (<*>) = ap  returnRn :: a -> RnM a @@ -173,22 +170,51 @@ renameFnArgsDoc = mapM renameDoc  renameLType :: LHsType Name -> RnM (LHsType DocName)  renameLType = mapM renameType +renameLSigType :: LHsSigType Name -> RnM (LHsSigType DocName) +renameLSigType = renameImplicit renameLType + +renameLSigWcType :: LHsSigWcType Name -> RnM (LHsSigWcType DocName) +renameLSigWcType = renameImplicit (renameWc renameLType) +  renameLKind :: LHsKind Name -> RnM (LHsKind DocName)  renameLKind = renameLType  renameMaybeLKind :: Maybe (LHsKind Name) -> RnM (Maybe (LHsKind DocName))  renameMaybeLKind = traverse renameLKind +renameFamilyResultSig :: LFamilyResultSig Name -> RnM (LFamilyResultSig DocName) +renameFamilyResultSig (L loc NoSig) +    = return (L loc NoSig) +renameFamilyResultSig (L loc (KindSig ki)) +    = do { ki' <- renameLKind ki +         ; return (L loc (KindSig ki')) } +renameFamilyResultSig (L loc (TyVarSig bndr)) +    = do { bndr' <- renameLTyVarBndr bndr +         ; return (L loc (TyVarSig bndr')) } + +renameInjectivityAnn :: LInjectivityAnn Name -> RnM (LInjectivityAnn DocName) +renameInjectivityAnn (L loc (InjectivityAnn lhs rhs)) +    = do { lhs' <- renameL lhs +         ; rhs' <- mapM renameL rhs +         ; return (L loc (InjectivityAnn lhs' rhs')) } + +renameMaybeInjectivityAnn :: Maybe (LInjectivityAnn Name) +                          -> RnM (Maybe (LInjectivityAnn DocName)) +renameMaybeInjectivityAnn = traverse renameInjectivityAnn  renameType :: HsType Name -> RnM (HsType DocName)  renameType t = case t of -  HsForAllTy expl extra tyvars lcontext ltype -> do -    tyvars'   <- renameLTyVarBndrs tyvars +  HsForAllTy { hst_bndrs = tyvars, hst_body = ltype } -> do +    tyvars'   <- mapM renameLTyVarBndr tyvars +    ltype'    <- renameLType ltype +    return (HsForAllTy { hst_bndrs = tyvars', hst_body = ltype' }) + +  HsQualTy { hst_ctxt = lcontext , hst_body = ltype } -> do      lcontext' <- renameLContext lcontext      ltype'    <- renameLType ltype -    return (HsForAllTy expl extra tyvars' lcontext' ltype') +    return (HsQualTy { hst_ctxt = lcontext', hst_body = ltype' }) -  HsTyVar n -> return . HsTyVar =<< rename n +  HsTyVar (L l n) -> return . HsTyVar . L l =<< rename n    HsBangTy b ltype -> return . HsBangTy b =<< renameLType ltype    HsAppTy a b -> do @@ -208,11 +234,11 @@ renameType t = case t of    HsTupleTy b ts -> return . HsTupleTy b =<< mapM renameLType ts -  HsOpTy a (w, L loc op) b -> do +  HsOpTy a (L loc op) b -> do      op' <- rename op      a'  <- renameLType a      b'  <- renameLType b -    return (HsOpTy a' (w, L loc op') b') +    return (HsOpTy a' (L loc op') b')    HsParTy ty -> return . HsParTy =<< renameLType ty @@ -228,25 +254,24 @@ renameType t = case t of    HsTyLit x -> return (HsTyLit x) -  HsWrapTy a b            -> HsWrapTy a <$> renameType b    HsRecTy a               -> HsRecTy <$> mapM renameConDeclFieldField a    HsCoreTy a              -> pure (HsCoreTy a)    HsExplicitListTy  a b   -> HsExplicitListTy  a <$> mapM renameLType b    HsExplicitTupleTy a b   -> HsExplicitTupleTy a <$> mapM renameLType b    HsSpliceTy _ _          -> error "renameType: HsSpliceTy" -  HsWildcardTy            -> pure HsWildcardTy -  HsNamedWildcardTy a     -> HsNamedWildcardTy <$> rename a +  HsWildCardTy a          -> HsWildCardTy <$> renameWildCardInfo a +  HsAppsTy _              -> error "renameType: HsAppsTy" -renameLTyVarBndrs :: LHsTyVarBndrs Name -> RnM (LHsTyVarBndrs DocName) -renameLTyVarBndrs (HsQTvs { hsq_kvs = _, hsq_tvs = tvs }) +renameLHsQTyVars :: LHsQTyVars Name -> RnM (LHsQTyVars DocName) +renameLHsQTyVars (HsQTvs { hsq_implicit = _, hsq_explicit = tvs })    = do { tvs' <- mapM renameLTyVarBndr tvs -       ; return (HsQTvs { hsq_kvs = error "haddock:renameLTyVarBndrs", hsq_tvs = tvs' }) } +       ; return (HsQTvs { hsq_implicit = error "haddock:renameLHsQTyVars", hsq_explicit = tvs' }) }                  -- This is rather bogus, but I'm not sure what else to do  renameLTyVarBndr :: LHsTyVarBndr Name -> RnM (LHsTyVarBndr DocName) -renameLTyVarBndr (L loc (UserTyVar n)) +renameLTyVarBndr (L loc (UserTyVar (L l n)))    = do { n' <- rename n -       ; return (L loc (UserTyVar n')) } +       ; return (L loc (UserTyVar (L l n'))) }  renameLTyVarBndr (L loc (KindedTyVar (L lv n) kind))    = do { n' <- rename n         ; kind' <- renameLKind kind @@ -257,17 +282,29 @@ renameLContext (L loc context) = do    context' <- mapM renameLType context    return (L loc context') +renameWildCardInfo :: HsWildCardInfo Name -> RnM (HsWildCardInfo DocName) +renameWildCardInfo (AnonWildCard  (L l name)) = AnonWildCard . L l <$> rename name +renameWildCardInfo (NamedWildCard (L l name)) = NamedWildCard . L l <$> rename name +  renameInstHead :: InstHead Name -> RnM (InstHead DocName) -renameInstHead (className, k, types, rest) = do -  className' <- rename className -  k' <- mapM renameType k -  types' <- mapM renameType types -  rest' <- case rest of -    ClassInst cs -> ClassInst <$> mapM renameType cs +renameInstHead InstHead {..} = do +  cname <- rename ihdClsName +  kinds <- mapM renameType ihdKinds +  types <- mapM renameType ihdTypes +  itype <- case ihdInstType of +    ClassInst { .. } -> ClassInst +        <$> mapM renameType clsiCtx +        <*> renameLHsQTyVars clsiTyVars +        <*> mapM renameSig clsiSigs +        <*> mapM renamePseudoFamilyDecl clsiAssocTys      TypeInst  ts -> TypeInst  <$> traverse renameType ts      DataInst  dd -> DataInst  <$> renameTyClD dd -  return (className', k', types', rest') - +  return InstHead +    { ihdClsName = cname +    , ihdKinds = kinds +    , ihdTypes = types +    , ihdInstType = itype +    }  renameLDecl :: LHsDecl Name -> RnM (LHsDecl DocName)  renameLDecl (L loc d) = return . L loc =<< renameDecl d @@ -301,13 +338,13 @@ renameTyClD d = case d of    SynDecl { tcdLName = lname, tcdTyVars = tyvars, tcdRhs = rhs, tcdFVs = _fvs } -> do      lname'    <- renameL lname -    tyvars'   <- renameLTyVarBndrs tyvars +    tyvars'   <- renameLHsQTyVars tyvars      rhs'     <- renameLType rhs      return (SynDecl { tcdLName = lname', tcdTyVars = tyvars', tcdRhs = rhs', tcdFVs = placeHolderNames })    DataDecl { tcdLName = lname, tcdTyVars = tyvars, tcdDataDefn = defn, tcdFVs = _fvs } -> do      lname'    <- renameL lname -    tyvars'   <- renameLTyVarBndrs tyvars +    tyvars'   <- renameLHsQTyVars tyvars      defn'     <- renameDataDefn defn      return (DataDecl { tcdLName = lname', tcdTyVars = tyvars', tcdDataDefn = defn', tcdFVs = placeHolderNames }) @@ -315,7 +352,7 @@ renameTyClD d = case d of              , tcdFDs = lfundeps, tcdSigs = lsigs, tcdATs = ats, tcdATDefs = at_defs } -> do      lcontext' <- renameLContext lcontext      lname'    <- renameL lname -    ltyvars'  <- renameLTyVarBndrs ltyvars +    ltyvars'  <- renameLHsQTyVars ltyvars      lfundeps' <- mapM renameLFunDep lfundeps      lsigs'    <- mapM renameLSig lsigs      ats'      <- mapM (renameLThing renameFamilyDecl) ats @@ -335,13 +372,26 @@ renameTyClD d = case d of  renameFamilyDecl :: FamilyDecl Name -> RnM (FamilyDecl DocName)  renameFamilyDecl (FamilyDecl { fdInfo = info, fdLName = lname -                             , fdTyVars = ltyvars, fdKindSig = tckind }) = do -    info'    <- renameFamilyInfo info -    lname'   <- renameL lname -    ltyvars' <- renameLTyVarBndrs ltyvars -    tckind'  <- renameMaybeLKind tckind +                             , fdTyVars = ltyvars, fdResultSig = result +                             , fdInjectivityAnn = injectivity }) = do +    info'        <- renameFamilyInfo info +    lname'       <- renameL lname +    ltyvars'     <- renameLHsQTyVars ltyvars +    result'      <- renameFamilyResultSig result +    injectivity' <- renameMaybeInjectivityAnn injectivity      return (FamilyDecl { fdInfo = info', fdLName = lname' -                       , fdTyVars = ltyvars', fdKindSig = tckind' }) +                       , fdTyVars = ltyvars', fdResultSig = result' +                       , fdInjectivityAnn = injectivity' }) + + +renamePseudoFamilyDecl :: PseudoFamilyDecl Name +                       -> RnM (PseudoFamilyDecl DocName) +renamePseudoFamilyDecl (PseudoFamilyDecl { .. }) =  PseudoFamilyDecl +    <$> renameFamilyInfo pfdInfo +    <*> renameL pfdLName +    <*> mapM renameLType pfdTyVars +    <*> renameFamilyResultSig pfdKindSig +  renameFamilyInfo :: FamilyInfo Name -> RnM (FamilyInfo DocName)  renameFamilyInfo DataFamily     = return DataFamily @@ -361,17 +411,16 @@ renameDataDefn (HsDataDefn { dd_ND = nd, dd_ctxt = lcontext, dd_cType = cType                         , dd_kindSig = k', dd_cons = cons', dd_derivs = Nothing })  renameCon :: ConDecl Name -> RnM (ConDecl DocName) -renameCon decl@(ConDecl { con_names = lnames, con_qvars = ltyvars -                        , con_cxt = lcontext, con_details = details -                        , con_res = restype, con_doc = mbldoc }) = do -      lnames'   <- mapM renameL lnames -      ltyvars'  <- renameLTyVarBndrs ltyvars -      lcontext' <- renameLContext lcontext +renameCon decl@(ConDeclH98 { con_name = lname, con_qvars = ltyvars +                           , con_cxt = lcontext, con_details = details +                           , con_doc = mbldoc }) = do +      lname'    <- renameL lname +      ltyvars'  <- traverse renameLHsQTyVars ltyvars +      lcontext' <- traverse renameLContext lcontext        details'  <- renameDetails details -      restype'  <- renameResType restype        mbldoc'   <- mapM renameLDocHsSyn mbldoc -      return (decl { con_names = lnames', con_qvars = ltyvars', con_cxt = lcontext' -                   , con_details = details', con_res = restype', con_doc = mbldoc' }) +      return (decl { con_name = lname', con_qvars = ltyvars', con_cxt = lcontext' +                   , con_details = details', con_doc = mbldoc' })    where      renameDetails (RecCon (L l fields)) = do @@ -383,35 +432,47 @@ renameCon decl@(ConDecl { con_names = lnames, con_qvars = ltyvars        b' <- renameLType b        return (InfixCon a' b') -    renameResType (ResTyH98) = return ResTyH98 -    renameResType (ResTyGADT l t) = return . ResTyGADT l =<< renameLType t - +renameCon decl@(ConDeclGADT { con_names = lnames +                            , con_type = lty +                            , con_doc = mbldoc }) = do +      lnames'   <- mapM renameL lnames +      lty'      <- renameLSigType lty +      mbldoc'   <- mapM renameLDocHsSyn mbldoc +      return (decl { con_names = lnames' +                   , con_type = lty', con_doc = mbldoc' })  renameConDeclFieldField :: LConDeclField Name -> RnM (LConDeclField DocName)  renameConDeclFieldField (L l (ConDeclField names t doc)) = do -  names' <- mapM renameL names +  names' <- mapM renameLFieldOcc names    t'   <- renameLType t    doc' <- mapM renameLDocHsSyn doc    return $ L l (ConDeclField names' t' doc') +renameLFieldOcc :: LFieldOcc Name -> RnM (LFieldOcc DocName) +renameLFieldOcc (L l (FieldOcc lbl sel)) = do +  sel' <- rename sel +  return $ L l (FieldOcc lbl sel')  renameSig :: Sig Name -> RnM (Sig DocName)  renameSig sig = case sig of -  TypeSig lnames ltype _ -> do +  TypeSig lnames ltype -> do      lnames' <- mapM renameL lnames -    ltype' <- renameLType ltype -    return (TypeSig lnames' ltype' PlaceHolder) -  PatSynSig lname (flag, qtvs) lreq lprov lty -> do +    ltype' <- renameLSigWcType ltype +    return (TypeSig lnames' ltype') +  ClassOpSig is_default lnames sig_ty -> do +    lnames' <- mapM renameL lnames +    ltype' <- renameLSigType sig_ty +    return (ClassOpSig is_default lnames' ltype') +  PatSynSig lname sig_ty -> do      lname' <- renameL lname -    qtvs' <- renameLTyVarBndrs qtvs -    lreq' <- renameLContext lreq -    lprov' <- renameLContext lprov -    lty' <- renameLType lty -    return $ PatSynSig lname' (flag, qtvs') lreq' lprov' lty' +    sig_ty' <- renameLSigType sig_ty +    return $ PatSynSig lname' sig_ty'    FixSig (FixitySig lnames fixity) -> do      lnames' <- mapM renameL lnames      return $ FixSig (FixitySig lnames' fixity) -  MinimalSig src s -> MinimalSig src <$> traverse renameL s +  MinimalSig src (L l s) -> do +    s' <- traverse renameL s +    return $ MinimalSig src (L l s')    -- we have filtered out all other kinds of signatures in Interface.Create    _ -> error "expected TypeSig" @@ -419,11 +480,11 @@ renameSig sig = case sig of  renameForD :: ForeignDecl Name -> RnM (ForeignDecl DocName)  renameForD (ForeignImport lname ltype co x) = do    lname' <- renameL lname -  ltype' <- renameLType ltype +  ltype' <- renameLSigType ltype    return (ForeignImport lname' ltype' co x)  renameForD (ForeignExport lname ltype co x) = do    lname' <- renameL lname -  ltype' <- renameLType ltype +  ltype' <- renameLSigType ltype    return (ForeignExport lname' ltype' co x) @@ -442,7 +503,7 @@ renameClsInstD :: ClsInstDecl Name -> RnM (ClsInstDecl DocName)  renameClsInstD (ClsInstDecl { cid_overlap_mode = omode                              , cid_poly_ty =ltype, cid_tyfam_insts = lATs                              , cid_datafam_insts = lADTs }) = do -  ltype' <- renameLType ltype +  ltype' <- renameLSigType ltype    lATs'  <- mapM (mapM renameTyFamInstD) lATs    lADTs' <- mapM (mapM renameDataFamInstD) lADTs    return (ClsInstDecl { cid_overlap_mode = omode @@ -458,33 +519,48 @@ renameTyFamInstD (TyFamInstDecl { tfid_eqn = eqn })                                 , tfid_fvs = placeHolderNames }) }  renameLTyFamInstEqn :: LTyFamInstEqn Name -> RnM (LTyFamInstEqn DocName) -renameLTyFamInstEqn (L loc (TyFamEqn { tfe_tycon = tc, tfe_pats = pats_w_bndrs, tfe_rhs = rhs })) +renameLTyFamInstEqn (L loc (TyFamEqn { tfe_tycon = tc, tfe_pats = pats, tfe_rhs = rhs }))    = do { tc' <- renameL tc -       ; pats' <- mapM renameLType (hswb_cts pats_w_bndrs) +       ; pats' <- renameImplicit (mapM renameLType) pats         ; rhs' <- renameLType rhs         ; return (L loc (TyFamEqn { tfe_tycon = tc' -                                 , tfe_pats = HsWB pats' PlaceHolder PlaceHolder PlaceHolder +                                 , tfe_pats = pats'                                   , tfe_rhs = rhs' })) }  renameLTyFamDefltEqn :: LTyFamDefltEqn Name -> RnM (LTyFamDefltEqn DocName)  renameLTyFamDefltEqn (L loc (TyFamEqn { tfe_tycon = tc, tfe_pats = tvs, tfe_rhs = rhs })) -  = do { tc' <- renameL tc -       ; tvs'  <- renameLTyVarBndrs tvs +  = do { tc'  <- renameL tc +       ; tvs' <- renameLHsQTyVars tvs         ; rhs' <- renameLType rhs         ; return (L loc (TyFamEqn { tfe_tycon = tc'                                   , tfe_pats = tvs'                                   , tfe_rhs = rhs' })) }  renameDataFamInstD :: DataFamInstDecl Name -> RnM (DataFamInstDecl DocName) -renameDataFamInstD (DataFamInstDecl { dfid_tycon = tc, dfid_pats = pats_w_bndrs, dfid_defn = defn }) +renameDataFamInstD (DataFamInstDecl { dfid_tycon = tc, dfid_pats = pats, dfid_defn = defn })    = do { tc' <- renameL tc -       ; pats' <- mapM renameLType (hswb_cts pats_w_bndrs) +       ; pats' <- renameImplicit (mapM renameLType) pats         ; defn' <- renameDataDefn defn         ; return (DataFamInstDecl { dfid_tycon = tc' -                                 , dfid_pats -                                       = HsWB pats' PlaceHolder PlaceHolder PlaceHolder +                                 , dfid_pats = pats'                                   , dfid_defn = defn', dfid_fvs = placeHolderNames }) } +renameImplicit :: (in_thing -> RnM out_thing) +               -> HsImplicitBndrs Name in_thing +               -> RnM (HsImplicitBndrs DocName out_thing) +renameImplicit rn_thing (HsIB { hsib_body = thing }) +  = do { thing' <- rn_thing thing +       ; return (HsIB { hsib_body = thing' +                      , hsib_vars = PlaceHolder }) } + +renameWc :: (in_thing -> RnM out_thing) +         -> HsWildCardBndrs Name in_thing +         -> RnM (HsWildCardBndrs DocName out_thing) +renameWc rn_thing (HsWC { hswc_body = thing }) +  = do { thing' <- rn_thing thing +       ; return (HsWC { hswc_body = thing' +                      , hswc_wcs = PlaceHolder, hswc_ctx = Nothing }) } +  renameExportItem :: ExportItem Name -> RnM (ExportItem DocName)  renameExportItem item = case item of    ExportModule mdl -> return (ExportModule mdl) @@ -495,10 +571,11 @@ renameExportItem item = case item of      decl' <- renameLDecl decl      doc'  <- renameDocForDecl doc      subs' <- mapM renameSub subs -    instances' <- forM instances $ \(inst, idoc) -> do +    instances' <- forM instances $ \(inst, idoc, L l n) -> do        inst' <- renameInstHead inst +      n' <- rename n        idoc' <- mapM renameDoc idoc -      return (inst', idoc') +      return (inst', idoc',L l n')      fixities' <- forM fixities $ \(name, fixity) -> do        name' <- lookupRn name        return (name', fixity) @@ -517,12 +594,3 @@ renameSub (n,doc) = do    n' <- rename n    doc' <- renameDocForDecl doc    return (n', doc') - -type instance PostRn DocName NameSet  = PlaceHolder -type instance PostRn DocName Fixity   = PlaceHolder -type instance PostRn DocName Bool     = PlaceHolder -type instance PostRn DocName [Name]   = PlaceHolder - -type instance PostTc DocName Kind     = PlaceHolder -type instance PostTc DocName Type     = PlaceHolder -type instance PostTc DocName Coercion = PlaceHolder diff --git a/haddock-api/src/Haddock/Interface/Specialize.hs b/haddock-api/src/Haddock/Interface/Specialize.hs new file mode 100644 index 00000000..ab719fe8 --- /dev/null +++ b/haddock-api/src/Haddock/Interface/Specialize.hs @@ -0,0 +1,406 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE Rank2Types #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE RecordWildCards #-} + + +module Haddock.Interface.Specialize +    ( specializeInstHead +    ) where + + +import Haddock.Syb +import Haddock.Types + +import GHC +import Name +import FastString + +import Control.Monad +import Control.Monad.Trans.Reader +import Control.Monad.Trans.State + +import Data.Data +import qualified Data.List as List +import Data.Maybe +import Data.Map (Map) +import qualified Data.Map as Map +import Data.Set (Set) +import qualified Data.Set as Set + + +-- | Instantiate all occurrences of given name with particular type. +specialize :: (Eq name, Typeable name) +           => Data a +           => name -> HsType name -> a -> a +specialize name details = +    everywhere $ mkT step +  where +    step (HsTyVar (L _ name')) | name == name' = details +    step typ = typ + + +-- | Instantiate all occurrences of given names with corresponding types. +-- +-- It is just a convenience function wrapping 'specialize' that supports more +-- that one specialization. +specialize' :: (Eq name, Typeable name) +            => Data a +            => [(name, HsType name)] -> a -> a +specialize' = flip $ foldr (uncurry specialize) + + +-- | Instantiate given binders with corresponding types. +-- +-- Again, it is just a convenience function around 'specialize'. Note that +-- length of type list should be the same as the number of binders. +specializeTyVarBndrs :: (Eq name, DataId name) +                     => Data a +                     => LHsQTyVars name -> [HsType name] +                     -> a -> a +specializeTyVarBndrs bndrs typs = +    specialize' $ zip bndrs' typs +  where +    bndrs' = map (bname . unLoc) . hsq_explicit $ bndrs +    bname (UserTyVar (L _ name)) = name +    bname (KindedTyVar (L _ name) _) = name + + +specializePseudoFamilyDecl :: (Eq name, DataId name) +                           => LHsQTyVars name -> [HsType name] +                           -> PseudoFamilyDecl name +                           -> PseudoFamilyDecl name +specializePseudoFamilyDecl bndrs typs decl = +    decl { pfdTyVars = map specializeTyVars (pfdTyVars decl) } +  where +    specializeTyVars = specializeTyVarBndrs bndrs typs + + +specializeSig :: forall name . (Eq name, DataId name, SetName name) +              => LHsQTyVars name -> [HsType name] +              -> Sig name +              -> Sig name +specializeSig bndrs typs (TypeSig lnames typ) = +    TypeSig lnames (typ { hsib_body = (hsib_body typ) { hswc_body = noLoc typ'}}) +  where +    true_type :: HsType name +    true_type = unLoc (hswc_body (hsib_body typ)) +    typ' :: HsType name +    typ' = rename fv . sugar $ specializeTyVarBndrs bndrs typs true_type +    fv = foldr Set.union Set.empty . map freeVariables $ typs +specializeSig _ _ sig = sig + + +-- | Make all details of instance head (signatures, associated types) +-- specialized to that particular instance type. +specializeInstHead :: (Eq name, DataId name, SetName name) +                   => InstHead name -> InstHead name +specializeInstHead ihd@InstHead { ihdInstType = clsi@ClassInst { .. }, .. } = +    ihd { ihdInstType = instType' } +  where +    instType' = clsi +        { clsiSigs = map specializeSig' clsiSigs +        , clsiAssocTys = map specializeFamilyDecl' clsiAssocTys +        } +    specializeSig' = specializeSig clsiTyVars ihdTypes +    specializeFamilyDecl' = specializePseudoFamilyDecl clsiTyVars ihdTypes +specializeInstHead ihd = ihd + + +-- | Make given type use tuple and list literals where appropriate. +-- +-- After applying 'specialize' function some terms may not use idiomatic list +-- and tuple literals resulting in types like @[] a@ or @(,,) a b c@. This +-- can be fixed using 'sugar' function, that will turn such types into @[a]@ +-- and @(a, b, c)@. +sugar :: forall name. (NamedThing name, DataId name) +      => HsType name -> HsType name +sugar = +    everywhere $ mkT step +  where +    step :: HsType name -> HsType name +    step = sugarOperators . sugarTuples . sugarLists + + +sugarLists :: NamedThing name => HsType name -> HsType name +sugarLists (HsAppTy (L _ (HsTyVar (L _ name))) ltyp) +    | isBuiltInSyntax name' && strName == "[]" = HsListTy ltyp +  where +    name' = getName name +    strName = occNameString . nameOccName $ name' +sugarLists typ = typ + + +sugarTuples :: NamedThing name => HsType name -> HsType name +sugarTuples typ = +    aux [] typ +  where +    aux apps (HsAppTy (L _ ftyp) atyp) = aux (atyp:apps) ftyp +    aux apps (HsParTy (L _ typ')) = aux apps typ' +    aux apps (HsTyVar (L _ name)) +        | isBuiltInSyntax name' && suitable = HsTupleTy HsBoxedTuple apps +      where +        name' = getName name +        strName = occNameString . nameOccName $ name' +        suitable = case parseTupleArity strName of +            Just arity -> arity == length apps +            Nothing -> False +    aux _ _ = typ + + +sugarOperators :: NamedThing name => HsType name -> HsType name +sugarOperators (HsAppTy (L _ (HsAppTy (L _ (HsTyVar (L l name))) la)) lb) +    | isSymOcc $ getOccName name' = mkHsOpTy la (L l name) lb +    | isBuiltInSyntax name' && getOccString name == "(->)" = HsFunTy la lb +  where +    name' = getName name +sugarOperators typ = typ + + +-- | Compute arity of given tuple operator. +-- +-- >>> parseTupleArity "(,,)" +-- Just 3 +-- +-- >>> parseTupleArity "(,,,,)" +-- Just 5 +-- +-- >>> parseTupleArity "abc" +-- Nothing +-- +-- >>> parseTupleArity "()" +-- Nothing +parseTupleArity :: String -> Maybe Int +parseTupleArity ('(':commas) = do +    n <- parseCommas commas +    guard $ n /= 0 +    return $ n + 1 +  where +    parseCommas (',':rest) = (+ 1) <$> parseCommas rest +    parseCommas ")" = Just 0 +    parseCommas _ = Nothing +parseTupleArity _ = Nothing + + +-- | Haskell AST type representation. +-- +-- This type is used for renaming (more below), essentially the ambiguous (!) +-- version of 'Name'. So, why is this 'FastString' instead of 'OccName'? Well, +-- it was 'OccName' before, but turned out that 'OccName' sometimes also +-- contains namespace information, differentiating visually same types. +-- +-- And 'FastString' is used because it is /visual/ part of 'OccName' - it is +-- not converted to 'String' or alike to avoid new allocations. Additionally, +-- since it is stored mostly in 'Set', fast comparison of 'FastString' is also +-- quite nice. +type NameRep = FastString + +getNameRep :: NamedThing name => name -> NameRep +getNameRep = occNameFS . getOccName + +nameRepString :: NameRep -> String +nameRepString = unpackFS + +stringNameRep :: String -> NameRep +stringNameRep = mkFastString + +setInternalNameRep :: SetName name => NameRep -> name -> name +setInternalNameRep = setInternalOccName . mkVarOccFS + +setInternalOccName :: SetName name => OccName -> name -> name +setInternalOccName occ name = +    setName nname' name +  where +    nname = getName name +    nname' = mkInternalName (nameUnique nname) occ (nameSrcSpan nname) + + +-- | Compute set of free variables of given type. +freeVariables :: forall name. (NamedThing name, DataId name) +              => HsType name -> Set NameRep +freeVariables = +    everythingWithState Set.empty Set.union query +  where +    query term ctx = case cast term :: Maybe (HsType name) of +        Just (HsForAllTy bndrs _) -> +            (Set.empty, Set.union ctx (bndrsNames bndrs)) +        Just (HsTyVar (L _ name)) +            | getName name `Set.member` ctx -> (Set.empty, ctx) +            | otherwise -> (Set.singleton $ getNameRep name, ctx) +        _ -> (Set.empty, ctx) +    bndrsNames = Set.fromList . map (getName . tyVarName . unLoc) + + +-- | Make given type visually unambiguous. +-- +-- After applying 'specialize' method, some free type variables may become +-- visually ambiguous - for example, having @a -> b@ and specializing @a@ to +-- @(a -> b)@ we get @(a -> b) -> b@ where first occurrence of @b@ refers to +-- different type variable than latter one. Applying 'rename' function +-- will fix that type to be visually unambiguous again (making it something +-- like @(a -> c) -> b@). +rename :: SetName name => Set NameRep -> HsType name -> HsType name +rename fv typ = runReader (renameType typ) $ RenameEnv +    { rneFV = fv +    , rneCtx = Map.empty +    } + + +-- | Renaming monad. +type Rename name = Reader (RenameEnv name) + +-- | Binding generation monad. +type Rebind name = State (RenameEnv name) + +data RenameEnv name = RenameEnv +    { rneFV :: Set NameRep +    , rneCtx :: Map Name name +    } + + +renameType :: SetName name => HsType name -> Rename name (HsType name) +renameType (HsForAllTy bndrs lt) = rebind bndrs $ \bndrs' -> +    HsForAllTy +        <$> pure bndrs' +        <*> renameLType lt +renameType (HsQualTy lctxt lt) = +  HsQualTy +        <$> located renameContext lctxt +        <*> renameLType lt +renameType (HsTyVar name) = HsTyVar <$> located renameName name +renameType (HsAppTy lf la) = HsAppTy <$> renameLType lf <*> renameLType la +renameType (HsFunTy la lr) = HsFunTy <$> renameLType la <*> renameLType lr +renameType (HsListTy lt) = HsListTy <$> renameLType lt +renameType (HsPArrTy lt) = HsPArrTy <$> renameLType lt +renameType (HsTupleTy srt lt) = HsTupleTy srt <$> mapM renameLType lt +renameType (HsOpTy la lop lb) = +    HsOpTy <$> renameLType la <*> located renameName lop <*> renameLType lb +renameType (HsParTy lt) = HsParTy <$> renameLType lt +renameType (HsIParamTy ip lt) = HsIParamTy ip <$> renameLType lt +renameType (HsEqTy la lb) = HsEqTy <$> renameLType la <*> renameLType lb +renameType (HsKindSig lt lk) = HsKindSig <$> renameLType lt <*> pure lk +renameType t@(HsSpliceTy _ _) = pure t +renameType (HsDocTy lt doc) = HsDocTy <$> renameLType lt <*> pure doc +renameType (HsBangTy bang lt) = HsBangTy bang <$> renameLType lt +renameType t@(HsRecTy _) = pure t +renameType t@(HsCoreTy _) = pure t +renameType (HsExplicitListTy ph ltys) = +    HsExplicitListTy ph <$> renameLTypes ltys +renameType (HsExplicitTupleTy phs ltys) = +    HsExplicitTupleTy phs <$> renameLTypes ltys +renameType t@(HsTyLit _) = pure t +renameType (HsWildCardTy wc) = pure (HsWildCardTy wc) +renameType (HsAppsTy _) = error "HsAppsTy: Only used before renaming" + + +renameLType :: SetName name => LHsType name -> Rename name (LHsType name) +renameLType = located renameType + + +renameLTypes :: SetName name => [LHsType name] -> Rename name [LHsType name] +renameLTypes = mapM renameLType + + +renameContext :: SetName name => HsContext name -> Rename name (HsContext name) +renameContext = renameLTypes + +{- +renameLTyOp :: SetName name => LHsTyOp name -> Rename name (LHsTyOp name) +renameLTyOp (wrap, lname) = (,) wrap <$> located renameName lname +-} + + +renameName :: SetName name => name -> Rename name name +renameName name = do +    RenameEnv { rneCtx = ctx } <- ask +    pure $ fromMaybe name (Map.lookup (getName name) ctx) + + +rebind :: SetName name +       => [LHsTyVarBndr name] -> ([LHsTyVarBndr name] -> Rename name a) +       -> Rename name a +rebind lbndrs action = do +    (lbndrs', env') <- runState (rebindLTyVarBndrs lbndrs) <$> ask +    local (const env') (action lbndrs') + + +rebindLTyVarBndrs :: SetName name +                  => [LHsTyVarBndr name] -> Rebind name [LHsTyVarBndr name] +rebindLTyVarBndrs lbndrs = mapM (located rebindTyVarBndr) lbndrs + + +rebindTyVarBndr :: SetName name +                => HsTyVarBndr name -> Rebind name (HsTyVarBndr name) +rebindTyVarBndr (UserTyVar (L l name)) = +    UserTyVar . L l <$> rebindName name +rebindTyVarBndr (KindedTyVar name kinds) = +    KindedTyVar <$> located rebindName name <*> pure kinds + + +rebindName :: SetName name => name -> Rebind name name +rebindName name = do +    RenameEnv { .. } <- get +    taken <- takenNames +    case Map.lookup (getName name) rneCtx of +        Just name' -> pure name' +        Nothing | getNameRep name `Set.member` taken -> freshName name +        Nothing -> reuseName name + + +-- | Generate fresh occurrence name, put it into context and return. +freshName :: SetName name => name -> Rebind name name +freshName name = do +    env@RenameEnv { .. } <- get +    taken <- takenNames +    let name' = setInternalNameRep (findFreshName taken rep) name +    put $ env { rneCtx = Map.insert nname name' rneCtx } +    return name' +  where +    nname = getName name +    rep = getNameRep nname + + +reuseName :: SetName name => name -> Rebind name name +reuseName name = do +    env@RenameEnv { .. } <- get +    put $ env { rneCtx = Map.insert (getName name) name rneCtx } +    return name + + +takenNames :: NamedThing name => Rebind name (Set NameRep) +takenNames = do +    RenameEnv { .. } <- get +    return $ Set.union rneFV (ctxElems rneCtx) +  where +    ctxElems = Set.fromList . map getNameRep . Map.elems + + +findFreshName :: Set NameRep -> NameRep -> NameRep +findFreshName taken = +    fromJust . List.find isFresh . alternativeNames +  where +    isFresh = not . flip Set.member taken + + +alternativeNames :: NameRep -> [NameRep] +alternativeNames name +    | [_] <- nameRepString name = letterNames ++ alternativeNames' name +  where +    letterNames = map (stringNameRep . pure) ['a'..'z'] +alternativeNames name = alternativeNames' name + + +alternativeNames' :: NameRep -> [NameRep] +alternativeNames' name = +    [ stringNameRep $ str ++ show i | i :: Int <- [0..] ] +  where +    str = nameRepString name + + +located :: Functor f => (a -> f b) -> Located a -> f (Located b) +located f (L loc e) = L loc <$> f e + + +tyVarName :: HsTyVarBndr name -> name +tyVarName (UserTyVar name) = unLoc name +tyVarName (KindedTyVar (L _ name) _) = name  | 
