diff options
| author | alexbiehl <alex.biehl@gmail.com> | 2017-08-21 20:05:42 +0200 | 
|---|---|---|
| committer | alexbiehl <alex.biehl@gmail.com> | 2017-08-21 20:05:42 +0200 | 
| commit | 7a71af839bd71992a36d97650004c73bf11fa436 (patch) | |
| tree | e64afbc9df5c97fde6ac6433e42f28df8a4acf49 /haddock-api/src/Haddock/Interface | |
| parent | c8a01b83be52e45d3890db173ffe7b09ccd4f351 (diff) | |
| parent | 740458ac4d2acf197f2ef8dc94a66f9b160b9c3c (diff) | |
Merge remote-tracking branch 'origin/master' into ghc-head
Diffstat (limited to 'haddock-api/src/Haddock/Interface')
| -rw-r--r-- | haddock-api/src/Haddock/Interface/AttachInstances.hs | 16 | ||||
| -rw-r--r-- | haddock-api/src/Haddock/Interface/Create.hs | 384 | ||||
| -rw-r--r-- | haddock-api/src/Haddock/Interface/Json.hs | 109 | ||||
| -rw-r--r-- | haddock-api/src/Haddock/Interface/LexParseRn.hs | 81 | ||||
| -rw-r--r-- | haddock-api/src/Haddock/Interface/Rename.hs | 12 | ||||
| -rw-r--r-- | haddock-api/src/Haddock/Interface/Specialize.hs | 186 | 
6 files changed, 501 insertions, 287 deletions
diff --git a/haddock-api/src/Haddock/Interface/AttachInstances.hs b/haddock-api/src/Haddock/Interface/AttachInstances.hs index 1eb227b9..0e5811b1 100644 --- a/haddock-api/src/Haddock/Interface/AttachInstances.hs +++ b/haddock-api/src/Haddock/Interface/AttachInstances.hs @@ -19,14 +19,13 @@ import Haddock.Types  import Haddock.Convert  import Haddock.GhcUtils +import Control.Applicative  import Control.Arrow hiding ((<+>))  import Data.List  import Data.Ord (comparing) -import Data.Function (on)  import Data.Maybe ( maybeToList, mapMaybe, fromMaybe )  import qualified Data.Map as Map  import qualified Data.Set as Set -import Control.Monad  import Class  import DynFlags @@ -35,7 +34,6 @@ import ErrUtils  import FamInstEnv  import FastString  import GHC -import GhcMonad (withSession)  import InstEnv  import MonadUtils (liftIO)  import Name @@ -118,13 +116,17 @@ attachToExportItem index expInfo iface ifaceMap instIfaceMap export =        return $ e { expItemInstances = insts }      e -> return e    where -    attachFixities e@ExportDecl{ expItemDecl = L _ d } = e { expItemFixities = -      nubBy ((==) `on` fst) $ expItemFixities e ++ +    attachFixities e@ExportDecl{ expItemDecl = L _ d +                               , expItemPats = patsyns +                               } = e { expItemFixities = +      nubByName fst $ expItemFixities e ++        [ (n',f) | n <- getMainDeclBinder d -              , Just subs <- [instLookup instSubMap n iface ifaceMap instIfaceMap] -              , n' <- n : subs +              , Just subs <- [instLookup instSubMap n iface ifaceMap instIfaceMap <|> Just []] +              , n' <- n : (subs ++ patsyn_names)                , Just f <- [instLookup instFixMap n' iface ifaceMap instIfaceMap]        ] } +      where +        patsyn_names = concatMap (getMainDeclBinder . fst) patsyns      attachFixities e = e      -- spanName: attach the location to the name that is the same file as the instance location diff --git a/haddock-api/src/Haddock/Interface/Create.hs b/haddock-api/src/Haddock/Interface/Create.hs index 2b352d90..292680a7 100644 --- a/haddock-api/src/Haddock/Interface/Create.hs +++ b/haddock-api/src/Haddock/Interface/Create.hs @@ -20,6 +20,7 @@  module Haddock.Interface.Create (createInterface) where  import Documentation.Haddock.Doc (metaDocAppend) +import Documentation.Haddock.Utf8 as Utf8  import Haddock.Types  import Haddock.Options  import Haddock.GhcUtils @@ -30,6 +31,8 @@ import Haddock.Backends.Hyperlinker.Types  import Haddock.Backends.Hyperlinker.Ast as Hyperlinker  import Haddock.Backends.Hyperlinker.Parser as Hyperlinker +import Data.Bitraversable +import qualified Data.ByteString as BS  import qualified Data.Map as M  import Data.Map (Map)  import Data.List @@ -37,10 +40,9 @@ import Data.Maybe  import Data.Monoid  import Data.Ord  import Control.Applicative -import Control.Arrow (second) -import Control.DeepSeq +import Control.Exception (evaluate)  import Control.Monad -import Data.Function (on) +import Data.Traversable  import qualified Packages  import qualified Module @@ -48,6 +50,7 @@ import qualified SrcLoc  import GHC  import HscTypes  import Name +import NameSet  import Bag  import RdrName  import TcRnTypes @@ -76,9 +79,12 @@ createInterface tm flags modMap instIfaceMap = do        dflags         = ms_hspp_opts ms        !instances     = modInfoInstances mi        !fam_instances = md_fam_insts md -      !exportedNames = modInfoExports mi +      !exportedNames = modInfoExportsWithSelectors mi -      (TcGblEnv {tcg_rdr_env = gre, tcg_warns = warnings}, md) = tm_internals_ tm +      (TcGblEnv { tcg_rdr_env = gre +                , tcg_warns   = warnings +                , tcg_patsyns = patsyns +                }, md) = tm_internals_ tm    -- The renamed source should always be available to us, but it's best    -- to be on the safe side. @@ -98,6 +104,27 @@ createInterface tm flags modMap instIfaceMap = do    (!info, mbDoc) <- liftErrMsg $ processModuleHeader dflags gre safety mayDocHeader    let declsWithDocs = topDecls group_ + +      exports0 = fmap (reverse . map unLoc) mayExports +      exports +        | OptIgnoreExports `elem` opts = Nothing +        | otherwise = exports0 + +      localBundledPatSyns :: Map Name [Name] +      localBundledPatSyns = +        case exports of +          Nothing  -> M.empty +          Just ies -> +            M.map (nubByName id) $ +            M.fromListWith (++) [ (ieWrappedName ty_name, bundled_patsyns) +                                | IEThingWith (L _ ty_name) _ exported _ <- ies +                                , let bundled_patsyns = +                                        filter is_patsyn (map (ieWrappedName . unLoc) exported) +                                , not (null bundled_patsyns) +                                ] +        where +          is_patsyn name = elemNameSet name (mkNameSet (map getName patsyns)) +        fixMap = mkFixMap group_        (decls, _) = unzip declsWithDocs        localInsts = filter (nameIsLocalOrFrom sem_mdl) @@ -106,21 +133,17 @@ createInterface tm flags modMap instIfaceMap = do        -- Locations of all TH splices        splices = [ l | L l (SpliceD _) <- hsmodDecls hsm ] -      maps@(!docMap, !argMap, !subMap, !declMap, _) = -        mkMaps dflags gre localInsts declsWithDocs +  warningMap <- liftErrMsg (mkWarningMap dflags warnings gre exportedNames) -  let exports0 = fmap (reverse . map unLoc) mayExports -      exports -        | OptIgnoreExports `elem` opts = Nothing -        | otherwise = exports0 -      warningMap = mkWarningMap dflags warnings gre exportedNames +  maps@(!docMap, !argMap, !subMap, !declMap, _) <- +    liftErrMsg (mkMaps dflags gre localInsts declsWithDocs)    let allWarnings = M.unions (warningMap : map ifaceWarningMap (M.elems modMap))    -- The MAIN functionality: compute the export items which will    -- each be the actual documentation of this module.    exportItems <- mkExportItems is_sig modMap mdl sem_mdl allWarnings gre exportedNames decls -                   maps fixMap splices exports instIfaceMap dflags +                   maps localBundledPatSyns fixMap splices exports instIfaceMap dflags    let !visibleNames = mkVisibleNames maps exportItems opts @@ -139,37 +162,39 @@ createInterface tm flags modMap instIfaceMap = do    let !aliases =          mkAliasMap dflags $ tm_renamed_source tm -      modWarn = moduleWarning dflags gre warnings + +  modWarn <- liftErrMsg (moduleWarning dflags gre warnings)    tokenizedSrc <- mkMaybeTokenizedSrc flags tm    return $! Interface { -    ifaceMod             = mdl -  , ifaceIsSig           = is_sig -  , ifaceOrigFilename    = msHsFilePath ms -  , ifaceInfo            = info -  , ifaceDoc             = Documentation mbDoc modWarn -  , ifaceRnDoc           = Documentation Nothing Nothing -  , ifaceOptions         = opts -  , ifaceDocMap          = docMap -  , ifaceArgMap          = argMap -  , ifaceRnDocMap        = M.empty -  , ifaceRnArgMap        = M.empty -  , ifaceExportItems     = prunedExportItems -  , ifaceRnExportItems   = [] -  , ifaceExports         = exportedNames -  , ifaceVisibleExports  = visibleNames -  , ifaceDeclMap         = declMap -  , ifaceSubMap          = subMap -  , ifaceFixMap          = fixMap -  , ifaceModuleAliases   = aliases -  , ifaceInstances       = instances -  , ifaceFamInstances    = fam_instances +    ifaceMod               = mdl +  , ifaceIsSig             = is_sig +  , ifaceOrigFilename      = msHsFilePath ms +  , ifaceInfo              = info +  , ifaceDoc               = Documentation mbDoc modWarn +  , ifaceRnDoc             = Documentation Nothing Nothing +  , ifaceOptions           = opts +  , ifaceDocMap            = docMap +  , ifaceArgMap            = argMap +  , ifaceRnDocMap          = M.empty +  , ifaceRnArgMap          = M.empty +  , ifaceExportItems       = prunedExportItems +  , ifaceRnExportItems     = [] +  , ifaceExports           = exportedNames +  , ifaceVisibleExports    = visibleNames +  , ifaceDeclMap           = declMap +  , ifaceBundledPatSynMap  = localBundledPatSyns +  , ifaceSubMap            = subMap +  , ifaceFixMap            = fixMap +  , ifaceModuleAliases     = aliases +  , ifaceInstances         = instances +  , ifaceFamInstances      = fam_instances    , ifaceOrphanInstances   = [] -- Filled in `attachInstances`    , ifaceRnOrphanInstances = [] -- Filled in `renameInterface` -  , ifaceHaddockCoverage = coverage -  , ifaceWarningMap      = warningMap -  , ifaceTokenizedSrc    = tokenizedSrc +  , ifaceHaddockCoverage   = coverage +  , ifaceWarningMap        = warningMap +  , ifaceTokenizedSrc      = tokenizedSrc    }  -- | Given all of the @import M as N@ declarations in a package, @@ -222,27 +247,29 @@ lookupModuleDyn dflags Nothing mdlName =  -- Warnings  ------------------------------------------------------------------------------- -mkWarningMap :: DynFlags -> Warnings -> GlobalRdrEnv -> [Name] -> WarningMap +mkWarningMap :: DynFlags -> Warnings -> GlobalRdrEnv -> [Name] -> ErrMsgM WarningMap  mkWarningMap dflags warnings gre exps = case warnings of -  NoWarnings  -> M.empty -  WarnAll _   -> M.empty +  NoWarnings  -> pure M.empty +  WarnAll _   -> pure M.empty    WarnSome ws -> -    let ws' = [ (n, w) | (occ, w) <- ws, elt <- lookupGlobalRdrEnv gre occ +    let ws' = [ (n, w) +              | (occ, w) <- ws +              , elt <- lookupGlobalRdrEnv gre occ                , let n = gre_name elt, n `elem` exps ] -    in M.fromList $ map (second $ parseWarning dflags gre) ws' +    in M.fromList <$> traverse (bitraverse pure (parseWarning dflags gre)) ws' -moduleWarning :: DynFlags -> GlobalRdrEnv -> Warnings -> Maybe (Doc Name) -moduleWarning _ _ NoWarnings = Nothing -moduleWarning _ _ (WarnSome _) = Nothing -moduleWarning dflags gre (WarnAll w) = Just $ parseWarning dflags gre w +moduleWarning :: DynFlags -> GlobalRdrEnv -> Warnings -> ErrMsgM (Maybe (Doc Name)) +moduleWarning _ _ NoWarnings = pure Nothing +moduleWarning _ _ (WarnSome _) = pure Nothing +moduleWarning dflags gre (WarnAll w) = Just <$> parseWarning dflags gre w -parseWarning :: DynFlags -> GlobalRdrEnv -> WarningTxt -> Doc Name -parseWarning dflags gre w = force $ case w of +parseWarning :: DynFlags -> GlobalRdrEnv -> WarningTxt -> ErrMsgM (Doc Name) +parseWarning dflags gre w = case w of    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 +                  <$> processDocString dflags gre (HsDocString xs)  ------------------------------------------------------------------------------- @@ -290,10 +317,15 @@ mkMaps :: DynFlags         -> GlobalRdrEnv         -> [Name]         -> [(LHsDecl GhcRn, [HsDocString])] -       -> Maps -mkMaps dflags gre instances decls = -  let (a, b, c, d) = unzip4 $ map mappings decls -  in (f' $ map (nubBy ((==) `on` fst)) a , f b, f c, f d, instanceMap) +       -> ErrMsgM Maps +mkMaps dflags gre instances decls = do +  (a, b, c, d) <- unzip4 <$> traverse mappings decls +  pure ( f' (map (nubByName fst) a) +       , f  (filterMapping (not . M.null) b) +       , f  (filterMapping (not . null) c) +       , f  (filterMapping (not . null) d) +       , instanceMap +       )    where      f :: (Ord a, Monoid b) => [[(a, b)]] -> Map a b      f = M.fromListWith (<>) . concat @@ -301,36 +333,46 @@ mkMaps dflags gre instances decls =      f' :: [[(Name, MDoc Name)]] -> Map Name (MDoc Name)      f' = M.fromListWith metaDocAppend . concat +    filterMapping :: (b -> Bool) ->  [[(a, b)]] -> [[(a, b)]] +    filterMapping p = map (filter (p . snd)) +      mappings :: (LHsDecl GhcRn, [HsDocString]) -             -> ( [(Name, MDoc Name)] -                , [(Name, Map Int (MDoc Name))] -                , [(Name, [Name])] -                , [(Name,  [LHsDecl GhcRn])] -                ) -    mappings (ldecl, docStrs) = +             -> ErrMsgM ( [(Name, MDoc Name)] +                        , [(Name, Map Int (MDoc Name))] +                        , [(Name, [Name])] +                        , [(Name,  [LHsDecl GhcRn])] +                        ) +    mappings (ldecl, docStrs) = do        let L l decl = ldecl            declDoc :: [HsDocString] -> Map Int HsDocString -                  -> (Maybe (MDoc Name), Map Int (MDoc Name)) -          declDoc strs m = -            let doc' = processDocStrings dflags gre strs -                m' = M.map (processDocStringParas dflags gre) m -            in (doc', m') -          (doc, args) = declDoc docStrs (typeDocs decl) +                  -> ErrMsgM (Maybe (MDoc Name), Map Int (MDoc Name)) +          declDoc strs m = do +            doc' <- processDocStrings dflags gre strs +            m'   <- traverse (processDocStringParas dflags gre) m +            pure (doc', m') + +      (doc, args) <- declDoc docStrs (typeDocs decl) + +      let            subs :: [(Name, [HsDocString], Map Int HsDocString)]            subs = subordinates instanceMap decl -          (subDocs, subArgs) = unzip $ map (\(_, strs, m) -> declDoc strs m) subs + +      (subDocs, subArgs) <- unzip <$> traverse (\(_, strs, m) -> declDoc strs m) subs + +      let            ns = names l decl            subNs = [ n | (n, _, _) <- subs ]            dm = [ (n, d) | (n, Just d) <- zip ns (repeat doc) ++ zip subNs subDocs ]            am = [ (n, args) | n <- ns ] ++ zip subNs subArgs            sm = [ (n, subNs) | n <- ns ]            cm = [ (n, [ldecl]) | n <- ns ++ subNs ] -      in seqList ns `seq` -          seqList subNs `seq` -          doc `seq` -          seqList subDocs `seq` -          seqList subArgs `seq` -          (dm, am, sm, cm) + +      seqList ns `seq` +        seqList subNs `seq` +        doc `seq` +        seqList subDocs `seq` +        seqList subArgs `seq` +        pure (dm, am, sm, cm)      instanceMap :: Map SrcSpan Name      instanceMap = M.fromList [ (getSrcSpan n, n) | n <- instances ] @@ -359,7 +401,9 @@ mkMaps dflags gre instances decls =  -- | Get all subordinate declarations inside a declaration, and their docs.  -- A subordinate declaration is something like the associate type or data  -- family of a type class. -subordinates :: InstMap -> HsDecl GhcRn -> [(Name, [HsDocString], Map Int HsDocString)] +subordinates :: InstMap +             -> HsDecl GhcRn +             -> [(Name, [HsDocString], Map Int HsDocString)]  subordinates instMap decl = case decl of    InstD (ClsInstD d) -> do      DataFamInstDecl { dfid_tycon = L l _ @@ -395,8 +439,9 @@ typeDocs :: HsDecl GhcRn -> Map Int HsDocString  typeDocs d =    let docs = go 0 in    case d of -    SigD (TypeSig _ ty)   -> docs (unLoc (hsSigWcType ty)) -    SigD (PatSynSig _ ty) -> docs (unLoc (hsSigType ty)) +    SigD (TypeSig _ ty)      -> docs (unLoc (hsSigWcType ty)) +    SigD (ClassOpSig _ _ ty) -> docs (unLoc (hsSigType ty)) +    SigD (PatSynSig _ ty)    -> docs (unLoc (hsSigType ty))      ForD (ForeignImport _ ty _ _)   -> docs (unLoc (hsSigType ty))      TyClD (SynDecl { tcdRhs = ty }) -> docs (unLoc ty)      _ -> M.empty @@ -536,6 +581,7 @@ mkExportItems    -> [Name]             -- exported names (orig)    -> [LHsDecl GhcRn]     -- renamed source declarations    -> Maps +  -> Map Name [Name]    -> FixMap    -> [SrcSpan]          -- splice locations    -> Maybe [IE GhcRn] @@ -544,15 +590,21 @@ mkExportItems    -> ErrMsgGhc [ExportItem GhcRn]  mkExportItems    is_sig modMap thisMod semMod warnings gre exportedNames decls -  maps@(docMap, argMap, subMap, declMap, instMap) fixMap splices optExports instIfaceMap dflags = +  maps@(docMap, argMap, subMap, declMap, instMap) patSynMap fixMap splices optExports instIfaceMap dflags =    case optExports of      Nothing -> fullModuleContents dflags warnings gre maps fixMap splices decls      Just exports -> liftM concat $ mapM lookupExport exports    where -    lookupExport (IEVar (L _ x))         = declWith $ ieWrappedName x -    lookupExport (IEThingAbs (L _ t))    = declWith $ ieWrappedName t -    lookupExport (IEThingAll (L _ t))    = declWith $ ieWrappedName t -    lookupExport (IEThingWith (L _ t) _ _ _) = declWith $ ieWrappedName t +    lookupExport (IEVar (L _ x))         = declWith [] $ ieWrappedName x +    lookupExport (IEThingAbs (L _ t))    = declWith [] $ ieWrappedName t +    lookupExport (IEThingAll (L _ t))    = do +      let name     = ieWrappedName t +      pats <- findBundledPatterns name +      declWith pats name +    lookupExport (IEThingWith (L _ t) _ _ _) = do +      let name     = ieWrappedName t +      pats <- findBundledPatterns name +      declWith pats name      lookupExport (IEModuleContents (L _ m)) =        -- TODO: We could get more accurate reporting here if IEModuleContents        -- also recorded the actual names that are exported here.  We CAN @@ -560,19 +612,23 @@ mkExportItems        -- do so.        -- NB: Pass in identity module, so we can look it up in index correctly        moduleExports thisMod m dflags warnings gre exportedNames decls modMap instIfaceMap maps fixMap splices -    lookupExport (IEGroup lev docStr)  = return $ -      return . ExportGroup lev "" $ processDocString dflags gre docStr +    lookupExport (IEGroup lev docStr)  = liftErrMsg $ do +      doc <- processDocString dflags gre docStr +      return [ExportGroup lev "" doc] -    lookupExport (IEDoc docStr)        = return $ -      return . ExportDoc $ processDocStringParas dflags gre docStr +    lookupExport (IEDoc docStr)        = liftErrMsg $ do +      doc <- processDocStringParas dflags gre docStr +      return [ExportDoc doc]      lookupExport (IEDocNamed str)      = liftErrMsg $ -      findNamedDoc str [ unL d | d <- decls ] >>= return . \case -        Nothing -> [] -        Just doc -> return . ExportDoc $ processDocStringParas dflags gre doc - -    declWith :: Name -> ErrMsgGhc [ ExportItem GhcRn ] -    declWith t = do +      findNamedDoc str [ unL d | d <- decls ] >>= \case +        Nothing -> return  [] +        Just docStr -> do +          doc <- processDocStringParas dflags gre docStr +          return [ExportDoc doc] + +    declWith :: [(HsDecl GhcRn, DocForDecl Name)] -> Name -> ErrMsgGhc [ ExportItem GhcRn ] +    declWith pats t = do        r <- findDecl t        case r of          ([L l (ValD _)], (doc, _)) -> do @@ -609,15 +665,15 @@ mkExportItems                      -- fromJust is safe since we already checked in guards                      -- that 't' is a name declared in this declaration.                      let newDecl = L loc . SigD . fromJust $ filterSigNames (== t) sig -                    in return [ mkExportDecl t newDecl docs_ ] +                    in return [ mkExportDecl t newDecl pats docs_ ]                    L loc (TyClD cl@ClassDecl{}) -> do                      mdef <- liftGhcToErrMsgGhc $ minimalDef t                      let sig = maybeToList $ fmap (noLoc . MinimalSig NoSourceText . noLoc . fmap noLoc) mdef                      return [ mkExportDecl t -                      (L loc $ TyClD cl { tcdSigs = sig ++ tcdSigs cl }) docs_ ] +                      (L loc $ TyClD cl { tcdSigs = sig ++ tcdSigs cl }) pats docs_ ] -                  _ -> return [ mkExportDecl t decl docs_ ] +                  _ -> return [ mkExportDecl t decl pats docs_ ]          -- Declaration from another package          ([], _) -> do @@ -634,24 +690,27 @@ mkExportItems                     liftErrMsg $ tell                        ["Warning: Couldn't find .haddock for export " ++ pretty dflags t]                     let subs_ = [ (n, noDocForDecl) | (n, _, _) <- subordinates instMap (unLoc decl) ] -                   return [ mkExportDecl t decl (noDocForDecl, subs_) ] +                   return [ mkExportDecl t decl pats (noDocForDecl, subs_) ]                  Just iface -> -                   return [ mkExportDecl t decl (lookupDocs t warnings (instDocMap iface) (instArgMap iface) (instSubMap iface)) ] +                   return [ mkExportDecl t decl pats (lookupDocs t warnings (instDocMap iface) (instArgMap iface) (instSubMap iface)) ]          _ -> return [] -    mkExportDecl :: Name -> LHsDecl GhcRn -> (DocForDecl Name, [(Name, DocForDecl Name)]) -> ExportItem GhcRn -    mkExportDecl name decl (doc, subs) = decl' +    mkExportDecl :: Name -> LHsDecl GhcRn -> [(HsDecl GhcRn, DocForDecl Name)] +                 -> (DocForDecl Name, [(Name, DocForDecl Name)]) -> ExportItem GhcRn +    mkExportDecl name decl pats (doc, subs) = decl'        where -        decl' = ExportDecl (restrictTo sub_names (extractDecl name decl)) doc subs' [] fixities False +        decl' = ExportDecl (restrictTo sub_names (extractDecl name decl)) pats' doc subs' [] fixities False          subs' = filter (isExported . fst) subs +        pats' = [ d | d@(patsyn_decl, _) <- pats +                    , all isExported (getMainDeclBinder patsyn_decl) ]          sub_names = map fst subs' -        fixities = [ (n, f) | n <- name:sub_names, Just f <- [M.lookup n fixMap] ] - - -    isExported = (`elem` exportedNames) +        pat_names = [ n | (patsyn_decl, _) <- pats', n <- getMainDeclBinder patsyn_decl] +        fixities = [ (n, f) | n <- name:sub_names++pat_names, Just f <- [M.lookup n fixMap] ] +    exportedNameSet = mkNameSet exportedNames +    isExported n = elemNameSet n exportedNameSet      findDecl :: Name -> ErrMsgGhc ([LHsDecl GhcRn], (DocForDecl Name, [(Name, DocForDecl Name)]))      findDecl n @@ -682,6 +741,40 @@ mkExportItems        where          m = nameModule n +    findBundledPatterns :: Name -> ErrMsgGhc [(HsDecl GhcRn, DocForDecl Name)] +    findBundledPatterns t = +      let +        m = nameModule t + +        local_bundled_patsyns = +          M.findWithDefault [] t patSynMap + +        iface_bundled_patsyns +          | Just iface <- M.lookup (semToIdMod (moduleUnitId thisMod) m) modMap +          , Just patsyns <- M.lookup t (ifaceBundledPatSynMap iface) +          = patsyns + +          | Just iface <- M.lookup m instIfaceMap +          , Just patsyns <- M.lookup t (instBundledPatSynMap iface) +          = patsyns + +          | otherwise +          = [] + +        patsyn_decls = do +          for (local_bundled_patsyns ++ iface_bundled_patsyns) $ \patsyn_name -> do +            -- call declWith here so we don't have to prepare the pattern synonym for +            -- showing ourselves. +            export_items <- declWith [] patsyn_name +            pure [ (unLoc patsyn_decl, patsyn_doc) +                 | ExportDecl { +                       expItemDecl  = patsyn_decl +                     , expItemMbDoc = patsyn_doc +                     } <- export_items +                 ] + +      in concat <$> patsyn_decls +  -- | Given a 'Module' from a 'Name', convert it into a 'Module' that  -- we can actually find in the 'IfaceMap'.  semToIdMod :: UnitId -> Module -> Module @@ -716,7 +809,7 @@ hiValExportItem dflags name nLoc doc splice fixity = do    mayDecl <- hiDecl dflags name    case mayDecl of      Nothing -> return (ExportNoDecl name []) -    Just decl -> return (ExportDecl (fixSpan 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 @@ -817,26 +910,39 @@ fullModuleContents :: DynFlags                     -> [LHsDecl GhcRn]    -- ^ All the renamed declarations                     -> ErrMsgGhc [ExportItem GhcRn]  fullModuleContents dflags warnings gre (docMap, argMap, subMap, declMap, instMap) fixMap splices decls = -  liftM catMaybes $ mapM mkExportItem (expandSig decls) +  liftM catMaybes $ mapM mkExportItem (expandSigDecls decls)    where      -- A type signature can have multiple names, like:      --   foo, bar :: Types..      --      -- We go through the list of declarations and expand type signatures, so      -- that every type signature has exactly one name! -    expandSig :: [LHsDecl name] -> [LHsDecl name] -    expandSig = foldr f [] +    expandSigDecls :: [LHsDecl name] -> [LHsDecl name] +    expandSigDecls = concatMap f        where -        f :: LHsDecl name -> [LHsDecl name] -> [LHsDecl name] -        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 +        f (L l (SigD sig))              = [ L l (SigD s) | s <- expandSig sig ] + +        -- also expand type signatures for class methods +        f (L l (TyClD cls@ClassDecl{})) = +          [ L l (TyClD cls { tcdSigs = concatMap expandLSig (tcdSigs cls) }) ] +        f x = [x] + +    expandLSig :: LSig name -> [LSig name] +    expandLSig (L l sig) = [ L l s | s <- expandSig sig ] + +    expandSig :: Sig name -> [Sig name] +    expandSig (TypeSig names t)      = [ TypeSig [n] t      | n <- names ] +    expandSig (ClassOpSig b names t) = [ ClassOpSig b [n] t | n <- names ] +    expandSig (PatSynSig names t)    = [ PatSynSig [n] t    | n <- names ] +    expandSig x                      = [x]      mkExportItem :: LHsDecl GhcRn -> ErrMsgGhc (Maybe (ExportItem GhcRn))      mkExportItem (L _ (DocD (DocGroup lev docStr))) = do -      return . Just . ExportGroup lev "" $ processDocString dflags gre docStr +      doc <- liftErrMsg (processDocString dflags gre docStr) +      return . Just . ExportGroup lev "" $ doc      mkExportItem (L _ (DocD (DocCommentNamed _ docStr))) = do -      return . Just . ExportDoc $ processDocStringParas dflags gre docStr +      doc <- liftErrMsg (processDocStringParas dflags gre docStr) +      return . Just . ExportDoc $ doc      mkExportItem (L l (ValD d))        | name:_ <- collectHsBindBinders d, Just [L _ (ValD _)] <- M.lookup name declMap =            -- Top-level binding without type signature. @@ -860,12 +966,12 @@ fullModuleContents dflags warnings gre (docMap, argMap, subMap, declMap, instMap      fixities name subs = [ (n,f) | n <- name : map fst subs                                   , Just f <- [M.lookup n fixMap] ] -    expDecl decl l name = return $ Just (ExportDecl decl doc subs [] (fixities name subs) (l `elem` splices)) +    expDecl decl l name = return $ Just (ExportDecl decl [] doc subs [] (fixities name subs) (l `elem` splices))        where (doc, subs) = lookupDocs name warnings docMap argMap subMap      expInst decl l name =          let (doc, subs) = lookupDocs name warnings docMap argMap subMap in -        return $ Just (ExportDecl decl doc subs [] (fixities name subs) (l `elem` splices)) +        return $ Just (ExportDecl decl [] doc subs [] (fixities name subs) (l `elem` splices))  -- | Sometimes the declaration we want to export is not the "main" declaration: @@ -895,7 +1001,9 @@ extractDecl name decl                                           O.$$ O.nest 4 (O.ppr matches))        TyClD d@DataDecl {} ->          let (n, tyvar_tys) = (tcdName d, lHsQTyVarsToTypes (tyClDeclTyVars d)) -        in SigD <$> extractRecSel name n tyvar_tys (dd_cons (tcdDataDefn d)) +        in if isDataConName name +           then SigD <$> extractPatternSyn name n tyvar_tys (dd_cons (tcdDataDefn d)) +           else SigD <$> extractRecSel name n tyvar_tys (dd_cons (tcdDataDefn d))        InstD (DataFamInstD DataFamInstDecl { dfid_tycon = L _ n                                            , dfid_pats = HsIB { hsib_body = tys }                                            , dfid_defn = defn }) -> @@ -913,6 +1021,36 @@ extractDecl name decl            _ -> error "internal: extractDecl (ClsInstD)"        _ -> error "internal: extractDecl" +extractPatternSyn :: Name -> Name -> [LHsType GhcRn] -> [LConDecl GhcRn] -> LSig GhcRn +extractPatternSyn nm t tvs cons = +  case filter matches cons of +    [] -> error "extractPatternSyn: constructor pattern not found" +    con:_ -> extract <$> con + where +  matches :: LConDecl GhcRn -> Bool +  matches (L _ con) = nm `elem` (unLoc <$> getConNames con) +  extract :: ConDecl GhcRn -> Sig GhcRn +  extract con = +    let args = +          case getConDetails con of +            PrefixCon args' -> args' +            RecCon (L _ fields) -> cd_fld_type . unLoc <$> fields +            InfixCon arg1 arg2 -> [arg1, arg2] +        typ = longArrow args (data_ty con) +        typ' = +          case con of +            ConDeclH98 { con_cxt = Just cxt } -> noLoc (HsQualTy cxt typ) +            _ -> typ +        typ'' = noLoc (HsQualTy (noLoc []) typ') +    in PatSynSig [noLoc nm] (mkEmptyImplicitBndrs typ'') + +  longArrow :: [LHsType name] -> LHsType name -> LHsType name +  longArrow inputs output = foldr (\x y -> noLoc (HsFunTy x y)) output inputs + +  data_ty con +    | ConDeclGADT{} <- con = hsib_body $ con_type con +    | otherwise = foldl' (\x y -> noLoc (HsAppTy x y)) (noLoc (HsTyVar NotPromoted (noLoc t))) tvs +  extractRecSel :: Name -> Name -> [LHsType GhcRn] -> [LConDecl GhcRn]                -> LSig GhcRn  extractRecSel _ _ _ [] = error "extractRecSel: selector not found" @@ -945,8 +1083,9 @@ mkVisibleNames (_, _, _, _, instMap) exports opts    | otherwise = let ns = concatMap exportName exports                  in seqList ns `seq` ns    where -    exportName e@ExportDecl {} = name ++ subs -      where subs = map fst (expItemSubDocs e) +    exportName e@ExportDecl {} = name ++ subs ++ patsyns +      where subs    = map fst (expItemSubDocs e) +            patsyns = concatMap (getMainDeclBinder . fst) (expItemPats e)              name = case unLoc $ expItemDecl e of                InstD d -> maybeToList $ M.lookup (getInstLoc d) instMap                decl    -> getMainDeclBinder decl @@ -977,10 +1116,11 @@ mkMaybeTokenizedSrc flags tm      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 +mkTokenizedSrc ms src = do +  -- make sure to read the whole file at once otherwise +  -- we run out of file descriptors (see #495) +  rawSrc <- BS.readFile (msHsFilePath ms) >>= evaluate +  return $ Hyperlinker.enrich src (Hyperlinker.parse (decodeUtf8 rawSrc))  -- | Find a stand-alone documentation comment by its name.  findNamedDoc :: String -> [HsDecl GhcRn] -> ErrMsgM (Maybe HsDocString) diff --git a/haddock-api/src/Haddock/Interface/Json.hs b/haddock-api/src/Haddock/Interface/Json.hs new file mode 100644 index 00000000..9a569204 --- /dev/null +++ b/haddock-api/src/Haddock/Interface/Json.hs @@ -0,0 +1,109 @@ +{-# LANGUAGE RecordWildCards #-} +module Haddock.Interface.Json ( +    jsonInstalledInterface +  , jsonInterfaceFile +  , renderJson +  ) where + +import BasicTypes +import Json +import Module +import Name +import Outputable + +import Control.Arrow +import Data.Map (Map) +import Data.Bifunctor +import qualified Data.Map as Map + +import Haddock.Types +import Haddock.InterfaceFile + +jsonInterfaceFile :: InterfaceFile -> JsonDoc +jsonInterfaceFile InterfaceFile{..} = +  jsonObject [ ("link_env" , jsonMap nameStableString (jsonString . moduleNameString . moduleName) ifLinkEnv) +             , ("inst_ifaces", jsonArray (map jsonInstalledInterface ifInstalledIfaces)) +             ] + +jsonInstalledInterface :: InstalledInterface -> JsonDoc +jsonInstalledInterface InstalledInterface{..} = jsonObject properties +  where +    properties = +      [ ("module"          , jsonModule instMod) +      , ("is_sig"          , jsonBool instIsSig) +      , ("info"            , jsonHaddockModInfo instInfo) +      , ("doc_map"         , jsonMap nameStableString jsonMDoc instDocMap) +      , ("arg_map"         , jsonMap nameStableString (jsonMap show jsonMDoc) instArgMap) +      , ("exports"         , jsonArray (map jsonName instExports)) +      , ("visible_exports" , jsonArray (map jsonName instVisibleExports)) +      , ("options"         , jsonArray (map (jsonString . show) instOptions)) +      , ("sub_map"         , jsonMap nameStableString (jsonArray . map jsonName) instSubMap) +      , ("bundled_patsyns" , jsonMap nameStableString (jsonArray . map jsonName) instBundledPatSynMap) +      , ("fix_map"         , jsonMap nameStableString jsonFixity instFixMap) +      ] + +jsonHaddockModInfo :: HaddockModInfo Name -> JsonDoc +jsonHaddockModInfo HaddockModInfo{..} = +  jsonObject [ ("description" , jsonMaybe jsonDoc hmi_description) +             , ("copyright"   , jsonMaybe jsonString hmi_copyright) +             , ("maintainer"  , jsonMaybe jsonString hmi_maintainer) +             , ("stability"   , jsonMaybe jsonString hmi_stability) +             , ("protability" , jsonMaybe jsonString hmi_portability) +             , ("safety"      , jsonMaybe jsonString hmi_safety) +             , ("language"    , jsonMaybe (jsonString . show) hmi_language) +             , ("extensions"  , jsonArray (map (jsonString . show) hmi_extensions)) +             ] + +jsonMap :: (a -> String) -> (b -> JsonDoc) -> Map a b -> JsonDoc +jsonMap f g = jsonObject . map (f *** g) . Map.toList + +jsonMDoc :: MDoc Name -> JsonDoc +jsonMDoc MetaDoc{..} = +  jsonObject [ ("meta", jsonObject [("version", jsonMaybe (jsonString . show) (_version _meta))]) +             , ("doc",  jsonDoc _doc) +             ] + +jsonDoc :: Doc Name -> JsonDoc +jsonDoc doc = jsonString (show (bimap (moduleNameString . fst) nameStableString doc)) + +jsonModule :: Module -> JsonDoc +jsonModule = JSString . moduleStableString + +jsonName :: Name -> JsonDoc +jsonName = JSString . nameStableString + +jsonFixity :: Fixity -> JsonDoc +jsonFixity (Fixity _ prec dir) = +  jsonObject [ ("prec"      , jsonInt prec) +             , ("direction" , jsonFixityDirection dir) +             ] + +jsonFixityDirection :: FixityDirection -> JsonDoc +jsonFixityDirection InfixL = jsonString "infixl" +jsonFixityDirection InfixR = jsonString "infixr" +jsonFixityDirection InfixN = jsonString "infix" + +renderJson :: JsonDoc -> SDoc +renderJson = renderJSON + +jsonMaybe :: (a -> JsonDoc) -> Maybe a -> JsonDoc +jsonMaybe = maybe jsonNull + +jsonString :: String -> JsonDoc +jsonString = JSString + +jsonObject :: [(String, JsonDoc)] -> JsonDoc +jsonObject = JSObject + +jsonArray :: [JsonDoc] -> JsonDoc +jsonArray = JSArray + +jsonNull :: JsonDoc +jsonNull = JSNull + +jsonInt :: Int -> JsonDoc +jsonInt = JSInt + +jsonBool :: Bool -> JsonDoc +jsonBool = JSBool + diff --git a/haddock-api/src/Haddock/Interface/LexParseRn.hs b/haddock-api/src/Haddock/Interface/LexParseRn.hs index 608344ad..75b2f223 100644 --- a/haddock-api/src/Haddock/Interface/LexParseRn.hs +++ b/haddock-api/src/Haddock/Interface/LexParseRn.hs @@ -35,20 +35,21 @@ import EnumSet  import RnEnv (dataTcOccs)  processDocStrings :: DynFlags -> GlobalRdrEnv -> [HsDocString] -                  -> Maybe (MDoc Name) -processDocStrings dflags gre strs = -  case metaDocConcat $ map (processDocStringParas dflags gre) strs of +                  -> ErrMsgM (Maybe (MDoc Name)) +processDocStrings dflags gre strs = do +  mdoc <- metaDocConcat <$> traverse (processDocStringParas dflags gre) strs +  case mdoc of      -- We check that we don't have any version info to render instead      -- of just checking if there is no comment: there may not be a      -- comment but we still want to pass through any meta data. -    MetaDoc { _meta = Meta { _version = Nothing }, _doc = DocEmpty } -> Nothing -    x -> Just x +    MetaDoc { _meta = Meta { _version = Nothing }, _doc = DocEmpty } -> pure Nothing +    x -> pure (Just x) -processDocStringParas :: DynFlags -> GlobalRdrEnv -> HsDocString -> MDoc Name +processDocStringParas :: DynFlags -> GlobalRdrEnv -> HsDocString -> ErrMsgM (MDoc Name)  processDocStringParas dflags gre (HsDocString fs) = -  overDoc (rename dflags gre) $ parseParas dflags (unpackFS fs) +  overDocF (rename dflags gre) $ parseParas dflags (unpackFS fs) -processDocString :: DynFlags -> GlobalRdrEnv -> HsDocString -> Doc Name +processDocString :: DynFlags -> GlobalRdrEnv -> HsDocString -> ErrMsgM (Doc Name)  processDocString dflags gre (HsDocString fs) =    rename dflags gre $ parseString dflags (unpackFS fs) @@ -61,9 +62,11 @@ processModuleHeader dflags gre safety mayStr = do        Just (L _ (HsDocString fs)) -> do          let str = unpackFS fs              (hmi, doc) = parseModuleHeader dflags str -            !descr = rename dflags gre <$> hmi_description hmi -            hmi' = hmi { hmi_description = descr } -            doc' = overDoc (rename dflags gre) doc +        !descr <- case hmi_description hmi of +                    Just hmi_descr -> Just <$> rename dflags gre hmi_descr +                    Nothing        -> pure Nothing +        let hmi' = hmi { hmi_description = descr } +        doc'  <- overDocF (rename dflags gre) doc          return (hmi', Just doc')    let flags :: [LangExt.Extension] @@ -83,12 +86,12 @@ processModuleHeader dflags gre safety mayStr = do  -- 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 :: DynFlags -> GlobalRdrEnv -> Doc RdrName -> ErrMsgM (Doc Name)  rename dflags gre = rn    where      rn d = case d of -      DocAppend a b -> DocAppend (rn a) (rn b) -      DocParagraph doc -> DocParagraph (rn doc) +      DocAppend a b -> DocAppend <$> rn a <*> rn b +      DocParagraph doc -> DocParagraph <$> rn doc        DocIdentifier x -> do          -- Generate the choices for the possible kind of thing this          -- is. @@ -101,7 +104,7 @@ rename dflags gre = rn            -- We found no names in the env so we start guessing.            [] ->              case choices of -              [] -> DocMonospaced (DocString (showPpr dflags x)) +              [] -> pure (DocMonospaced (DocString (showPpr dflags x)))                -- 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 @@ -110,37 +113,37 @@ rename dflags gre = rn                -- 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 +              a:_ -> pure (outOfScope dflags a)            -- There is only one name in the environment that matches so            -- use it. -          [a] -> DocIdentifier a +          [a] -> pure (DocIdentifier a)            -- 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 +          a:b:_ | isTyConName a -> pure (DocIdentifier a) +                | otherwise -> pure (DocIdentifier b) -      DocWarning doc -> DocWarning (rn doc) -      DocEmphasis doc -> DocEmphasis (rn doc) -      DocBold doc -> DocBold (rn doc) -      DocMonospaced doc -> DocMonospaced (rn doc) -      DocUnorderedList docs -> DocUnorderedList (map rn docs) -      DocOrderedList docs -> DocOrderedList (map rn docs) -      DocDefList list -> DocDefList [ (rn a, rn b) | (a, b) <- list ] -      DocCodeBlock doc -> DocCodeBlock (rn doc) -      DocIdentifierUnchecked x -> DocIdentifierUnchecked x -      DocModule str -> DocModule str -      DocHyperlink l -> DocHyperlink l -      DocPic str -> DocPic str -      DocMathInline str -> DocMathInline str -      DocMathDisplay str -> DocMathDisplay str -      DocAName str -> DocAName str -      DocProperty p -> DocProperty p -      DocExamples e -> DocExamples e -      DocEmpty -> DocEmpty -      DocString str -> DocString str -      DocHeader (Header l t) -> DocHeader $ Header l (rn t) +      DocWarning doc -> DocWarning <$> rn doc +      DocEmphasis doc -> DocEmphasis <$> rn doc +      DocBold doc -> DocBold <$> rn doc +      DocMonospaced doc -> DocMonospaced <$> rn doc +      DocUnorderedList docs -> DocUnorderedList <$> traverse rn docs +      DocOrderedList docs -> DocOrderedList <$> traverse rn docs +      DocDefList list -> DocDefList <$> traverse (\(a, b) -> (,) <$> rn a <*> rn b) list +      DocCodeBlock doc -> DocCodeBlock <$> rn doc +      DocIdentifierUnchecked x -> pure (DocIdentifierUnchecked x) +      DocModule str -> pure (DocModule str) +      DocHyperlink l -> pure (DocHyperlink l) +      DocPic str -> pure (DocPic str) +      DocMathInline str -> pure (DocMathInline str) +      DocMathDisplay str -> pure (DocMathDisplay str) +      DocAName str -> pure (DocAName str) +      DocProperty p -> pure (DocProperty p) +      DocExamples e -> pure (DocExamples e) +      DocEmpty -> pure (DocEmpty) +      DocString str -> pure (DocString str) +      DocHeader (Header l t) -> DocHeader . Header l <$> rn t  -- | Wrap an identifier that's out of scope (i.e. wasn't found in  -- 'GlobalReaderEnv' during 'rename') in an appropriate doc. Currently diff --git a/haddock-api/src/Haddock/Interface/Rename.hs b/haddock-api/src/Haddock/Interface/Rename.hs index 70846b31..2e9a311a 100644 --- a/haddock-api/src/Haddock/Interface/Rename.hs +++ b/haddock-api/src/Haddock/Interface/Rename.hs @@ -55,7 +55,7 @@ renameInterface dflags renamingEnv warnings iface =        -- combine the missing names and filter out the built-ins, which would        -- otherwise always be missing. -      missingNames = nub $ filter isExternalName  -- XXX: isExternalName filters out too much +      missingNames = nubByName id $ filter isExternalName  -- XXX: isExternalName filters out too much                      (missingNames1 ++ missingNames2 ++ missingNames3                       ++ missingNames4 ++ missingNames5) @@ -314,6 +314,11 @@ renameInstHead InstHead {..} = do  renameLDecl :: LHsDecl GhcRn -> RnM (LHsDecl DocNameI)  renameLDecl (L loc d) = return . L loc =<< renameDecl d +renamePats :: [(HsDecl GhcRn, DocForDecl Name)] -> RnM [(HsDecl DocNameI, DocForDecl DocName)] +renamePats = mapM +  (\(d,doc) -> do { d'   <- renameDecl d +                  ; doc' <- renameDocForDecl doc +                  ; return (d',doc')})  renameDecl :: HsDecl GhcRn -> RnM (HsDecl DocNameI)  renameDecl decl = case decl of @@ -601,15 +606,16 @@ renameExportItem item = case item of    ExportGroup lev id_ doc -> do      doc' <- renameDoc doc      return (ExportGroup lev id_ doc') -  ExportDecl decl doc subs instances fixities splice -> do +  ExportDecl decl pats doc subs instances fixities splice -> do      decl' <- renameLDecl decl +    pats' <- renamePats pats      doc'  <- renameDocForDecl doc      subs' <- mapM renameSub subs      instances' <- forM instances renameDocInstance      fixities' <- forM fixities $ \(name, fixity) -> do        name' <- lookupRn name        return (name', fixity) -    return (ExportDecl decl' doc' subs' instances' fixities' splice) +    return (ExportDecl decl' pats' doc' subs' instances' fixities' splice)    ExportNoDecl x subs -> do      x'    <- lookupRn x      subs' <- mapM lookupRn subs diff --git a/haddock-api/src/Haddock/Interface/Specialize.hs b/haddock-api/src/Haddock/Interface/Specialize.hs index d8bdecec..0c8e89c2 100644 --- a/haddock-api/src/Haddock/Interface/Specialize.hs +++ b/haddock-api/src/Haddock/Interface/Specialize.hs @@ -1,9 +1,9 @@  {-# LANGUAGE FlexibleContexts #-}  {-# LANGUAGE Rank2Types #-}  {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-}  {-# LANGUAGE RecordWildCards #-} -  module Haddock.Interface.Specialize      ( specializeInstHead      ) where @@ -17,7 +17,6 @@ import Name  import FastString  import Control.Monad -import Control.Monad.Trans.Reader  import Control.Monad.Trans.State  import Data.Data @@ -28,72 +27,64 @@ 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 (IdP name), Typeable name) -           => Data a -           => IdP 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 (IdP name), Typeable name) +specialize :: forall name a. (Ord (IdP name), DataId name, NamedThing (IdP name))              => Data a              => [(IdP name, HsType name)] -> a -> a -specialize' = flip $ foldr (uncurry specialize) +specialize specs = go +  where +    go :: forall x. Data x => x -> x +    go = everywhereButType @name $ mkT $ sugar . specialize_ty_var +    specialize_ty_var (HsTyVar _ (L _ name')) +      | Just t <- Map.lookup name' spec_map = t +    specialize_ty_var typ = typ +    -- This is a tricky recursive definition that is guaranteed to terminate +    -- because a type binder cannot be instantiated with a type that depends +    -- on that binder. i.e. @a -> Maybe a@ is invalid +    spec_map = Map.fromList [ (n, go t) | (n, t) <- specs]  -- | 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 (IdP name), DataId name) +specializeTyVarBndrs :: (Ord (IdP name), DataId name, NamedThing (IdP name))                       => Data a                       => LHsQTyVars name -> [HsType name]                       -> a -> a  specializeTyVarBndrs bndrs typs = -    specialize' $ zip 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 (IdP name), DataId name) +specializePseudoFamilyDecl :: (Ord (IdP name), DataId name, NamedThing (IdP name))                             => LHsQTyVars name -> [HsType name]                             -> PseudoFamilyDecl name                             -> PseudoFamilyDecl name  specializePseudoFamilyDecl bndrs typs decl = -    decl { pfdTyVars = map specializeTyVars (pfdTyVars decl) } -  where -    specializeTyVars = specializeTyVarBndrs bndrs typs - +  decl {pfdTyVars = map (specializeTyVarBndrs bndrs typs) (pfdTyVars decl)} -specializeSig :: forall name . (Eq (IdP name), DataId name, SetName (IdP name)) +specializeSig :: forall name . (Ord (IdP name), DataId name, SetName (IdP name), NamedThing (IdP name))                => LHsQTyVars name -> [HsType name]                -> Sig name                -> Sig name  specializeSig bndrs typs (TypeSig lnames typ) = -    TypeSig lnames (typ { hswc_body = (hswc_body typ) { hsib_body = noLoc typ'}}) +  TypeSig lnames (typ {hswc_body = (hswc_body typ) {hsib_body = noLoc typ'}})    where      true_type :: HsType name      true_type = unLoc (hsSigWcType typ)      typ' :: HsType name -    typ' = rename fv . sugar $ specializeTyVarBndrs bndrs typs true_type +    typ' = rename fv $ 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 (IdP name), DataId name, SetName (IdP name)) +specializeInstHead :: (Ord (IdP name), DataId name, SetName (IdP name), NamedThing (IdP name))                     => InstHead name -> InstHead name  specializeInstHead ihd@InstHead { ihdInstType = clsi@ClassInst { .. }, .. } =      ihd { ihdInstType = instType' } @@ -115,12 +106,7 @@ specializeInstHead ihd = ihd  -- and @(a, b, c)@.  sugar :: forall name. (NamedThing (IdP name), DataId name)        => HsType name -> HsType name -sugar = -    everywhere $ mkT step -  where -    step :: HsType name -> HsType name -    step = sugarOperators . sugarTuples . sugarLists - +sugar = sugarOperators . sugarTuples . sugarLists  sugarLists :: NamedThing (IdP name) => HsType name -> HsType name  sugarLists (HsAppTy (L _ (HsTyVar _ (L _ name))) ltyp) @@ -217,7 +203,7 @@ setInternalOccName occ name =  -- | Compute set of free variables of given type.  freeVariables :: forall name. (NamedThing (IdP name), DataId name) -              => HsType name -> Set NameRep +              => HsType name -> Set Name  freeVariables =      everythingWithState Set.empty Set.union query    where @@ -226,7 +212,7 @@ freeVariables =              (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) +            | otherwise -> (Set.singleton $ getName name, ctx)          _ -> (Set.empty, ctx)      bndrsNames = Set.fromList . map (getName . tyVarName . unLoc) @@ -238,33 +224,36 @@ freeVariables =  -- @(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 (IdP name) => Set NameRep -> HsType name -> HsType name -rename fv typ = runReader (renameType typ) $ RenameEnv -    { rneFV = fv -    , rneCtx = Map.empty -    } - +-- like @(a -> b0) -> b@). +rename :: (Eq (IdP name), DataId name, SetName (IdP name)) +       => Set Name-> HsType name -> HsType name +rename fv typ = evalState (renameType typ) env +  where +    env = RenameEnv +      { rneHeadFVs = Map.fromList . map mkPair . Set.toList $ fv +      , rneSigFVs = Set.map getNameRep $ freeVariables typ +      , rneCtx = Map.empty +      } +    mkPair name = (getNameRep name, name)  -- | Renaming monad. -type Rename name = Reader (RenameEnv name) - --- | Binding generation monad. -type Rebind name = State (RenameEnv name) +type Rename name = State (RenameEnv name)  data RenameEnv name = RenameEnv -    { rneFV :: Set NameRep -    , rneCtx :: Map Name name -    } +  { rneHeadFVs :: Map NameRep Name +  , rneSigFVs :: Set NameRep +  , rneCtx :: Map Name name +  } -renameType :: SetName (IdP name) => HsType name -> Rename (IdP name) (HsType name) -renameType (HsForAllTy bndrs lt) = rebind bndrs $ \bndrs' -> +renameType :: (Eq (IdP name), SetName (IdP name)) +           => HsType name -> Rename (IdP name) (HsType name) +renameType (HsForAllTy bndrs lt) =      HsForAllTy -        <$> pure bndrs' +        <$> mapM (located renameBinder) bndrs          <*> renameLType lt  renameType (HsQualTy lctxt lt) = -  HsQualTy +    HsQualTy          <$> located renameContext lctxt          <*> renameLType lt  renameType (HsTyVar ip name) = HsTyVar ip <$> located renameName name @@ -294,85 +283,58 @@ renameType (HsWildCardTy wc) = pure (HsWildCardTy wc)  renameType (HsAppsTy _) = error "HsAppsTy: Only used before renaming" -renameLType :: SetName (IdP name) => LHsType name -> Rename (IdP name) (LHsType name) +renameLType :: (Eq (IdP name), SetName (IdP name)) +            => LHsType name -> Rename (IdP name) (LHsType name)  renameLType = located renameType -renameLTypes :: SetName (IdP name) => [LHsType name] -> Rename (IdP name) [LHsType name] +renameLTypes :: (Eq (IdP name), SetName (IdP name)) +             => [LHsType name] -> Rename (IdP name) [LHsType name]  renameLTypes = mapM renameLType -renameContext :: SetName (IdP name) => HsContext name -> Rename (IdP name) (HsContext name) +renameContext :: (Eq (IdP name), SetName (IdP name)) +              => HsContext name -> Rename (IdP name) (HsContext name)  renameContext = renameLTypes -{- -renameLTyOp :: SetName (IdP name) => LHsTyOp name -> Rename name (LHsTyOp name) -renameLTyOp (wrap, lname) = (,) wrap <$> located renameName lname --} +renameBinder :: (Eq (IdP name), SetName (IdP name)) +             => HsTyVarBndr name -> Rename (IdP name) (HsTyVarBndr name) +renameBinder (UserTyVar lname) = UserTyVar <$> located renameName lname +renameBinder (KindedTyVar lname lkind) = +  KindedTyVar <$> located renameName lname <*> located renameType lkind -renameName :: SetName name => name -> Rename name name +-- | Core renaming logic. +renameName :: (Eq name, SetName name) => name -> Rename name name  renameName name = do -    RenameEnv { rneCtx = ctx } <- ask -    pure $ fromMaybe name (Map.lookup (getName name) ctx) - - -rebind :: SetName (IdP name) -       => [LHsTyVarBndr name] -> ([LHsTyVarBndr name] -> Rename (IdP name) a) -       -> Rename (IdP name) a -rebind lbndrs action = do -    (lbndrs', env') <- runState (rebindLTyVarBndrs lbndrs) <$> ask -    local (const env') (action lbndrs') - - -rebindLTyVarBndrs :: SetName (IdP name) -                  => [LHsTyVarBndr name] -> Rebind (IdP name) [LHsTyVarBndr name] -rebindLTyVarBndrs lbndrs = mapM (located rebindTyVarBndr) lbndrs - - -rebindTyVarBndr :: SetName (IdP name) -                => HsTyVarBndr name -> Rebind (IdP 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 +      Nothing +        | Just headTv <- Map.lookup (getNameRep name) rneHeadFVs +        , headTv /= getName name -> freshName name +      Just name' -> return name' +      _ -> return name  -- | Generate fresh occurrence name, put it into context and return. -freshName :: SetName name => name -> Rebind name name +freshName :: SetName name => name -> Rename 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 } +    modify $ \rne -> rne +      { rneCtx = Map.insert (getName name) name' (rneCtx rne) }      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 :: NamedThing name => Rename name (Set NameRep)  takenNames = do      RenameEnv { .. } <- get -    return $ Set.union rneFV (ctxElems rneCtx) +    return $ Set.unions [headReps rneHeadFVs, rneSigFVs, ctxElems rneCtx]    where +    headReps = Set.fromList . Map.keys      ctxElems = Set.fromList . map getNameRep . Map.elems @@ -384,15 +346,7 @@ findFreshName 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 = +alternativeNames name =      [ stringNameRep $ str ++ show i | i :: Int <- [0..] ]    where      str = nameRepString name  | 
