diff --git a/.gitignore b/.gitignore index d65138d11d..60b0ad9530 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,10 @@ /latex-test/out/ /hoogle-test/out/ +# ignore interface files +*.hi +*.dyn_hi + /doc/haddock /doc/haddock.ps /doc/haddock.pdf diff --git a/doc/cheatsheet/haddocks.md b/doc/cheatsheet/haddocks.md index 5ee285b3ac..1b4f851808 100644 --- a/doc/cheatsheet/haddocks.md +++ b/doc/cheatsheet/haddocks.md @@ -109,14 +109,13 @@ definitions with "[thing]" Omit this module from the docs {-# OPTIONS_HADDOCK prune #-} Omit definitions without docs -{-# OPTIONS_HADDOCK ignore-exports #-} - Treat this module as though all - top-level items are exported {-# OPTIONS_HADDOCK not-home #-} Do not treat this module as the "home" of identifiers it exports {-# OPTIONS_HADDOCK show-extensions #-} Show all enabled LANGUAGE extensions +{-# OPTIONS_HADDOCK print-explicit-runtime-reps #-} + Show all `RuntimeRep` type variables ``` # Grid tables diff --git a/doc/invoking.rst b/doc/invoking.rst index 5397dacf52..a056065610 100644 --- a/doc/invoking.rst +++ b/doc/invoking.rst @@ -246,10 +246,6 @@ The following options are available: name. Note that for the per-entity URLs this is the name of the *exporting* module. - - The string ``%F`` or ``%{FILE}`` is replaced by the original - source file name. Note that for the per-entity URLs this is the - name of the *defining* module. - - The string ``%N`` or ``%{NAME}`` is replaced by the name of the exported value or type. This is only valid for the :option:`--source-entity` option. @@ -264,9 +260,6 @@ The following options are available: - The string ``%%`` is replaced by ``%``. - For example, if your sources are online under some directory, you - would say ``haddock --source-base=url/ --source-module=url/%F`` - If you have html versions of your sources online with anchors for each type and function name, you would say ``haddock --source-base=url/ --source-module=url/%M.html --source-entity=url/%M.html#%N`` @@ -277,11 +270,6 @@ The following options are available: characters in a file name). To replace it with a character c use ``%{MODULE/./c}``. - Similarly, for the ``%{FILE}`` substitution you may want to replace - the ``/`` character in the file names with some other character - (especially for links to colourised entity source code with a shared - css file). To replace it with a character c use ``%{FILE///c}``/ - One example of a tool that can generate syntax-highlighted HTML from your source code, complete with anchors suitable for use from haddock, is @@ -474,13 +462,6 @@ The following options are available: :option:`-i` or :option:`--read-interface`). This is used to generate a single contents and/or index for multiple sets of Haddock documentation. -.. option:: --ignore-all-exports - - Causes Haddock to behave as if every module has the - ``ignore-exports`` attribute (:ref:`module-attrs`). This might be useful for - generating implementation documentation rather than interface - documentation, for example. - .. option:: --hide Causes Haddock to behave as if module module has the ``hide`` diff --git a/doc/markup.rst b/doc/markup.rst index 9fb0209aac..f6a12496b1 100644 --- a/doc/markup.rst +++ b/doc/markup.rst @@ -749,7 +749,7 @@ specified in a comma-separated list in an ``{-# OPTIONS_HADDOCK ... #-}`` pragma at the top of the module, either before or after the module description. For example: :: - {-# OPTIONS_HADDOCK hide, prune, ignore-exports #-} + {-# OPTIONS_HADDOCK hide, prune #-} -- |Module description module A where @@ -768,11 +768,6 @@ The following attributes are currently understood by Haddock: Omit definitions that have no documentation annotations from the generated documentation. -``ignore-exports`` - Ignore the export list. Generate documentation as if the module had - no export list - i.e. all the top-level declarations are exported, - and section headings may be given in the body of the module. - ``not-home`` Indicates that the current module should not be considered to be the home module for each entity it exports, unless that entity is not @@ -787,6 +782,12 @@ The following attributes are currently understood by Haddock: be rendered, including those implied by their more powerful versions. +``print-explicit-runtime-reps`` + Print type variables that have kind ``RuntimeRep``. By default, these + are defaulted to ``LiftedRep`` so that end users don't have to see the + underlying levity polymorphism. This flag is analogous to GHC's + ``-fprint-explicit-runtime-reps`` flag. + .. _markup: Markup diff --git a/haddock-api/src/Documentation/Haddock.hs b/haddock-api/src/Documentation/Haddock.hs index 10d6849ae6..314c5d0f9c 100644 --- a/haddock-api/src/Documentation/Haddock.hs +++ b/haddock-api/src/Documentation/Haddock.hs @@ -43,7 +43,6 @@ module Documentation.Haddock ( DocMarkupH(..), Documentation(..), ArgMap, - AliasMap, WarningMap, DocMap, HaddockModInfo(..), diff --git a/haddock-api/src/Haddock.hs b/haddock-api/src/Haddock.hs index 358e5c3a4d..4a047db6f8 100644 --- a/haddock-api/src/Haddock.hs +++ b/haddock-api/src/Haddock.hs @@ -500,8 +500,19 @@ withGhc' libDir needHieFiles flags ghcActs = runGhc (Just libDir) $ do parseGhcFlags dynflags = do -- TODO: handle warnings? - let extra_opts | needHieFiles = [Opt_WriteHie, Opt_Haddock] - | otherwise = [Opt_Haddock] + let extra_opts = + [ Opt_Haddock + -- Include docstrings in .hi-files. + + , Opt_SkipIfaceVersionCheck + -- Ignore any aspects of .hi-files except docs. + + , Opt_WriteInterface + -- If we can't use an old .hi-file, save the new one. + ] ++ + [ Opt_WriteHie | needHieFiles + -- Generate .hie-files + ] dynflags' = (foldl' gopt_set dynflags extra_opts) { hscTarget = HscNothing , ghcMode = CompManager diff --git a/haddock-api/src/Haddock/Backends/Hoogle.hs b/haddock-api/src/Haddock/Backends/Hoogle.hs index 16ec582e34..9e3186e5e2 100644 --- a/haddock-api/src/Haddock/Backends/Hoogle.hs +++ b/haddock-api/src/Haddock/Backends/Hoogle.hs @@ -263,8 +263,13 @@ ppCtor dflags dat subdocs con@ConDeclH98 {} -- docs for con_names on why it is a list to begin with. name = commaSeparate dflags . map unL $ getConNames con - resType = apps $ map (reL . HsTyVar NoExt NotPromoted . reL) $ - (tcdName dat) : [hsTyVarName v | L _ v@(UserTyVar _ _) <- hsQTvExplicit $ tyClDeclTyVars dat] + tyVarArg (UserTyVar _ n) = HsTyVar NoExt NotPromoted n + tyVarArg (KindedTyVar _ n lty) = HsKindSig NoExt (reL (HsTyVar NoExt NotPromoted n)) lty + tyVarArg _ = panic "ppCtor" + + resType = apps $ map reL $ + (HsTyVar NoExt NotPromoted (reL (tcdName dat))) : + map (tyVarArg . unLoc) (hsQTvExplicit $ tyClDeclTyVars dat) ppCtor dflags _dat subdocs con@(ConDeclGADT { }) = concatMap (lookupCon dflags subdocs) (getConNames con) ++ f diff --git a/haddock-api/src/Haddock/Backends/Hyperlinker/Renderer.hs b/haddock-api/src/Haddock/Backends/Hyperlinker/Renderer.hs index a4dcb77b68..a7cc7e3ed8 100644 --- a/haddock-api/src/Haddock/Backends/Hyperlinker/Renderer.hs +++ b/haddock-api/src/Haddock/Backends/Hyperlinker/Renderer.hs @@ -250,7 +250,7 @@ hyperlink (srcs, srcs') ident = case ident of Just SrcLocal -> Html.anchor content ! [ Html.href $ hypSrcModuleNameUrl mdl name ] Just (SrcExternal path) -> Html.anchor content ! - [ Html.href $ spliceURL Nothing (Just mdl) (Just name) Nothing (".." path) ] + [ Html.href $ spliceURL (Just mdl) (Just name) Nothing (".." path) ] Nothing -> content where mdl = nameModule name @@ -260,7 +260,7 @@ hyperlink (srcs, srcs') ident = case ident of Just SrcLocal -> Html.anchor content ! [ Html.href $ hypSrcModuleUrl' moduleName ] Just (SrcExternal path) -> Html.anchor content ! - [ Html.href $ spliceURL' Nothing (Just moduleName) Nothing Nothing (".." path) ] + [ Html.href $ spliceURL' (Just moduleName) Nothing Nothing (".." path) ] Nothing -> content diff --git a/haddock-api/src/Haddock/Backends/Hyperlinker/Utils.hs b/haddock-api/src/Haddock/Backends/Hyperlinker/Utils.hs index 4e8b88d23f..403de38b22 100644 --- a/haddock-api/src/Haddock/Backends/Hyperlinker/Utils.hs +++ b/haddock-api/src/Haddock/Backends/Hyperlinker/Utils.hs @@ -39,7 +39,7 @@ hypSrcModuleFile m = moduleNameString (moduleName m) <.> "html" hypSrcModuleFile' :: ModuleName -> FilePath hypSrcModuleFile' mdl = spliceURL' - Nothing (Just mdl) Nothing Nothing moduleFormat + (Just mdl) Nothing Nothing moduleFormat hypSrcModuleUrl :: Module -> String hypSrcModuleUrl = hypSrcModuleFile diff --git a/haddock-api/src/Haddock/Backends/LaTeX.hs b/haddock-api/src/Haddock/Backends/LaTeX.hs index 12256a00a6..12edd9ea1b 100644 --- a/haddock-api/src/Haddock/Backends/LaTeX.hs +++ b/haddock-api/src/Haddock/Backends/LaTeX.hs @@ -27,7 +27,7 @@ import qualified Pretty import BasicTypes ( PromotionFlag(..) ) import GHC import OccName -import Name ( nameOccName ) +import Name ( getOccString, nameOccName, tidyNameOcc ) import RdrName ( rdrNameOcc ) import FastString ( unpackFS ) import Outputable ( panic) @@ -295,7 +295,7 @@ ppDecl decl pats (doc, fnArgsDoc) instances subdocs _fxts = case unLoc decl of -- | Just _ <- tcdTyPats d -> ppTyInst False loc doc d unicode -- Family instances happen via FamInst now TyClD _ d@ClassDecl{} -> ppClassDecl instances doc subdocs d unicode - SigD _ (TypeSig _ lnames ty) -> ppFunSig (doc, fnArgsDoc) (map unLoc lnames) (hsSigWcType ty) unicode + SigD _ (TypeSig _ lnames ty) -> ppFunSig Nothing (doc, fnArgsDoc) (map unLoc lnames) (hsSigWcType ty) unicode SigD _ (PatSynSig _ lnames ty) -> ppLPatSig (doc, fnArgsDoc) (map unLoc lnames) ty unicode ForD _ d -> ppFor (doc, fnArgsDoc) d unicode InstD _ _ -> empty @@ -307,7 +307,7 @@ ppDecl decl pats (doc, fnArgsDoc) instances subdocs _fxts = case unLoc decl of ppFor :: DocForDecl DocName -> ForeignDecl DocNameI -> Bool -> LaTeX ppFor doc (ForeignImport _ (L _ name) typ _) unicode = - ppFunSig doc [name] (hsSigType typ) unicode + ppFunSig Nothing doc [name] (hsSigType typ) unicode ppFor _ _ _ = error "ppFor error in Haddock.Backends.LaTeX" -- error "foreign declarations are currently not supported by --latex" @@ -414,17 +414,23 @@ ppTySyn _ _ _ = error "declaration not supported by ppTySyn" ------------------------------------------------------------------------------- -ppFunSig :: DocForDecl DocName -> [DocName] -> LHsType DocNameI - -> Bool -> LaTeX -ppFunSig doc docnames (L _ typ) unicode = +ppFunSig + :: Maybe LaTeX -- ^ a prefix to put right before the signature + -> DocForDecl DocName -- ^ documentation + -> [DocName] -- ^ pattern names in the pattern signature + -> LHsType DocNameI -- ^ type of the pattern synonym + -> Bool -- ^ unicode + -> LaTeX +ppFunSig leader doc docnames (L _ typ) unicode = ppTypeOrFunSig typ doc - ( ppTypeSig names typ False - , hsep . punctuate comma $ map ppSymName names + ( lead $ ppTypeSig names typ False + , lead $ hsep . punctuate comma $ map ppSymName names , dcolon unicode ) unicode where names = map getName docnames + lead = maybe id (<+>) leader -- | Pretty-print a pattern synonym ppLPatSig :: DocForDecl DocName -- ^ documentation @@ -433,15 +439,7 @@ ppLPatSig :: DocForDecl DocName -- ^ documentation -> Bool -- ^ unicode -> LaTeX ppLPatSig doc docnames ty unicode - = ppTypeOrFunSig typ doc - ( keyword "pattern" <+> ppTypeSig names typ False - , keyword "pattern" <+> (hsep . punctuate comma $ map ppSymName names) - , dcolon unicode - ) - unicode - where - typ = unLoc (hsSigType ty) - names = map getName docnames + = ppFunSig (Just (keyword "pattern")) doc docnames (hsSigType ty) unicode -- | Pretty-print a type, adding documentation to the whole type and its -- arguments as needed. @@ -587,6 +585,7 @@ ppFds fds unicode = hsep (map (ppDocName . unLoc) vars2) +-- TODO: associated types, associated type defaults, docs on default methods ppClassDecl :: [DocInstance DocNameI] -> Documentation DocName -> [(DocName, DocForDecl DocName)] -> TyClDecl DocNameI -> Bool -> LaTeX @@ -612,13 +611,21 @@ ppClassDecl instances doc subdocs methodTable = text "\\haddockpremethods{}" <> emph (text "Methods") $$ - vcat [ ppFunSig doc names (hsSigWcType typ) unicode - | L _ (TypeSig _ lnames typ) <- lsigs + vcat [ ppFunSig leader doc names (hsSigType typ) unicode + | L _ (ClassOpSig _ is_def lnames typ) <- lsigs , let doc = lookupAnySubdoc (head names) subdocs - names = map unLoc lnames ] - -- FIXME: is taking just the first name ok? Is it possible that - -- there are different subdocs for different names in a single - -- type signature? + names = map (cleanName . unLoc) lnames + leader = if is_def then Just (keyword "default") else Nothing + ] + -- N.B. taking just the first name is ok. Signatures with multiple + -- names are expanded so that each name gets its own signature. + + -- Get rid of the ugly '$dm' prefix on default method names + cleanName n + | isDefaultMethodOcc (occName n) + , '$':'d':'m':occStr <- getOccString n + = setName (tidyNameOcc (getName n) (mkOccName varName occStr)) n + | otherwise = n instancesBit = ppDocInstances unicode instances @@ -960,7 +967,7 @@ ppContext cxt unicode = ppContextNoLocs (map unLoc cxt) unicode pp_hs_context :: [HsType DocNameI] -> Bool -> LaTeX pp_hs_context [] _ = empty -pp_hs_context [p] unicode = ppType unicode p +pp_hs_context [p] unicode = ppCtxType unicode p pp_hs_context cxt unicode = parenList (map (ppType unicode) cxt) @@ -995,11 +1002,11 @@ ppLType unicode y = ppType unicode (unLoc y) ppLParendType unicode y = ppParendType unicode (unLoc y) ppLFunLhType unicode y = ppFunLhType unicode (unLoc y) - -ppType, ppParendType, ppFunLhType :: Bool -> HsType DocNameI -> LaTeX +ppType, ppParendType, ppFunLhType, ppCtxType :: Bool -> HsType DocNameI -> LaTeX ppType unicode ty = ppr_mono_ty (reparenTypePrec PREC_TOP ty) unicode ppParendType unicode ty = ppr_mono_ty (reparenTypePrec PREC_TOP ty) unicode ppFunLhType unicode ty = ppr_mono_ty (reparenTypePrec PREC_FUN ty) unicode +ppCtxType unicode ty = ppr_mono_ty (reparenTypePrec PREC_CTX ty) unicode ppLHsTypeArg :: Bool -> LHsTypeArg DocNameI -> LaTeX ppLHsTypeArg unicode (HsValArg ty) = ppLParendType unicode ty @@ -1045,7 +1052,7 @@ ppr_mono_ty (HsTupleTy _ con tys) u = tupleParens con (map (ppLType u) tys) ppr_mono_ty (HsSumTy _ tys) u = sumParens (map (ppLType u) tys) ppr_mono_ty (HsKindSig _ ty kind) u = parens (ppr_mono_lty ty u <+> dcolon u <+> ppLKind u kind) ppr_mono_ty (HsListTy _ ty) u = brackets (ppr_mono_lty ty u) -ppr_mono_ty (HsIParamTy _ (L _ n) ty) u = brackets (ppIPName n <+> dcolon u <+> ppr_mono_lty ty u) +ppr_mono_ty (HsIParamTy _ (L _ n) ty) u = ppIPName n <+> dcolon u <+> ppr_mono_lty ty u ppr_mono_ty (HsSpliceTy {}) _ = error "ppr_mono_ty HsSpliceTy" ppr_mono_ty (HsRecTy {}) _ = text "{..}" ppr_mono_ty (XHsType (NHsCoreTy {})) _ = error "ppr_mono_ty HsCoreTy" @@ -1110,7 +1117,7 @@ ppVerbOccName :: OccName -> LaTeX ppVerbOccName = text . latexFilter . occNameString ppIPName :: HsIPName -> LaTeX -ppIPName ip = text $ unpackFS $ hsIPNameFS ip +ppIPName = text . ('?':) . unpackFS . hsIPNameFS ppOccName :: OccName -> LaTeX ppOccName = text . occNameString @@ -1177,32 +1184,35 @@ latexMonoMunge c s = latexMunge c s parLatexMarkup :: (a -> LaTeX) -> DocMarkup a (StringContext -> LaTeX) parLatexMarkup ppId = Markup { - markupParagraph = \p v -> p v <> text "\\par" $$ text "", + markupParagraph = \p v -> blockElem $ p v <> text "\\par", markupEmpty = \_ -> empty, markupString = \s v -> text (fixString v s), markupAppend = \l r v -> l v <> r v, markupIdentifier = markupId ppId, markupIdentifierUnchecked = markupId (ppVerbOccName . snd), markupModule = \m _ -> let (mdl,_ref) = break (=='#') m in tt (text mdl), - markupWarning = \p v -> emph (p v), + markupWarning = \p v -> p v, markupEmphasis = \p v -> emph (p v), markupBold = \p v -> bold (p v), markupMonospaced = \p _ -> tt (p Mono), - markupUnorderedList = \p v -> itemizedList (map ($v) p) $$ text "", + markupUnorderedList = \p v -> blockElem $ itemizedList (map ($v) p), markupPic = \p _ -> markupPic p, markupMathInline = \p _ -> markupMathInline p, - markupMathDisplay = \p _ -> markupMathDisplay p, - markupOrderedList = \p v -> enumeratedList (map ($v) p) $$ text "", - markupDefList = \l v -> descriptionList (map (\(a,b) -> (a v, b v)) l), - markupCodeBlock = \p _ -> quote (verb (p Verb)) $$ text "", + markupMathDisplay = \p _ -> blockElem $ markupMathDisplay p, + markupOrderedList = \p v -> blockElem $ enumeratedList (map ($v) p), + markupDefList = \l v -> blockElem $ descriptionList (map (\(a,b) -> (a v, b v)) l), + markupCodeBlock = \p _ -> blockElem $ quote (verb (p Verb)), markupHyperlink = \(Hyperlink u l) p -> markupLink u (fmap ($p) l), markupAName = \_ _ -> empty, - markupProperty = \p _ -> quote $ verb $ text p, - markupExample = \e _ -> quote $ verb $ text $ unlines $ map exampleToString e, + markupProperty = \p _ -> blockElem $ quote $ verb $ text p, + markupExample = \e _ -> blockElem $ quote $ verb $ text $ unlines $ map exampleToString e, markupHeader = \(Header l h) p -> header l (h p), markupTable = \(Table h b) p -> table h b p } where + blockElem :: LaTeX -> LaTeX + blockElem = ($$ text "") + header 1 d = text "\\section*" <> braces d header 2 d = text "\\subsection*" <> braces d header l d diff --git a/haddock-api/src/Haddock/Backends/Xhtml.hs b/haddock-api/src/Haddock/Backends/Xhtml.hs index 9add4cae4c..b31530ca5d 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml.hs @@ -146,8 +146,7 @@ srcButton :: SourceURLs -> Maybe Interface -> Maybe Html srcButton (Just src_base_url, _, _, _) Nothing = Just (anchor ! [href src_base_url] << "Source") srcButton (_, Just src_module_url, _, _) (Just iface) = - let url = spliceURL (Just $ ifaceOrigFilename iface) - (Just $ ifaceMod iface) Nothing Nothing src_module_url + let url = spliceURL (Just $ ifaceMod iface) Nothing Nothing src_module_url in Just (anchor ! [href url] << "Source") srcButton _ _ = Nothing @@ -158,7 +157,7 @@ wikiButton (Just wiki_base_url, _, _) Nothing = Just (anchor ! [href wiki_base_url] << "User Comments") wikiButton (_, Just wiki_module_url, _) (Just mdl) = - let url = spliceURL Nothing (Just mdl) Nothing Nothing wiki_module_url + let url = spliceURL (Just mdl) Nothing Nothing wiki_module_url in Just (anchor ! [href url] << "User Comments") wikiButton _ _ = @@ -379,8 +378,7 @@ ppJsonIndex odir maybe_source_url maybe_wiki_url unicode pkg qual_opt ifaces = d goInterface iface = concatMap (goExport mdl qual) (ifaceRnExportItems iface) where - aliases = ifaceModuleAliases iface - qual = makeModuleQual qual_opt aliases mdl + qual = makeModuleQual qual_opt mdl mdl = ifaceMod iface goExport :: Module -> Qualification -> ExportItem DocNameI -> [Value] @@ -547,7 +545,6 @@ ppHtmlModule odir doctitle themes maybe_contents_url maybe_index_url unicode pkg qual debug iface = do let mdl = ifaceMod iface - aliases = ifaceModuleAliases iface mdl_str = moduleString mdl mdl_str_annot = mdl_str ++ if ifaceIsSig iface then " (signature)" @@ -559,7 +556,7 @@ ppHtmlModule odir doctitle themes ")" | otherwise = toHtml mdl_str - real_qual = makeModuleQual qual aliases mdl + real_qual = makeModuleQual qual mdl html = headHtml mdl_str_annot themes maybe_mathjax_url +++ bodyHtml doctitle (Just iface) diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs b/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs index 9952721cf8..cbdbfe81c9 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Decl.hs @@ -36,6 +36,7 @@ import Text.XHtml hiding ( name, title, p, quote ) import BasicTypes (PromotionFlag(..), isPromoted) import GHC hiding (LexicalFixity(..)) +import qualified GHC import GHC.Exts import Name import BooleanFormula @@ -75,14 +76,14 @@ ppLFunSig :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName -> [Located DocName] -> LHsType DocNameI -> [(DocName, Fixity)] -> Splice -> Unicode -> Maybe Package -> Qualification -> Html ppLFunSig summary links loc doc lnames lty fixities splice unicode pkg qual = - ppFunSig summary links loc doc (map unLoc lnames) lty fixities + ppFunSig summary links loc noHtml doc (map unLoc lnames) lty fixities splice unicode pkg qual -ppFunSig :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName -> +ppFunSig :: Bool -> LinksInfo -> SrcSpan -> Html -> DocForDecl DocName -> [DocName] -> LHsType DocNameI -> [(DocName, Fixity)] -> Splice -> Unicode -> Maybe Package -> Qualification -> Html -ppFunSig summary links loc doc docnames typ fixities splice unicode pkg qual = - ppSigLike summary links loc mempty doc docnames fixities (unLoc typ, pp_typ) +ppFunSig summary links loc leader doc docnames typ fixities splice unicode pkg qual = + ppSigLike summary links loc leader doc docnames fixities (unLoc typ, pp_typ) splice unicode pkg qual HideEmptyContexts where pp_typ = ppLType unicode qual HideEmptyContexts typ @@ -229,7 +230,7 @@ ppFor :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName -> Splice -> Unicode -> Maybe Package -> Qualification -> Html ppFor summary links loc doc (ForeignImport _ (L _ name) typ _) fixities splice unicode pkg qual - = ppFunSig summary links loc doc [name] (hsSigType typ) fixities splice unicode pkg qual + = ppFunSig summary links loc noHtml doc [name] (hsSigType typ) fixities splice unicode pkg qual ppFor _ _ _ _ _ _ _ _ _ _ = error "ppFor" @@ -511,7 +512,7 @@ ppShortClassDecl summary links (ClassDecl { tcdCtxt = lctxt, tcdLName = lname, t -- ToDo: add associated type defaults - [ ppFunSig summary links loc doc names (hsSigType typ) + [ ppFunSig summary links loc noHtml doc names (hsSigType typ) [] splice unicode pkg qual | L _ (ClassOpSig _ False lnames typ) <- sigs , let doc = lookupAnySubdoc (head names) subdocs @@ -532,8 +533,9 @@ ppClassDecl :: Bool -> LinksInfo -> [DocInstance DocNameI] -> [(DocName, Fixity) -> [(DocName, DocForDecl DocName)] -> TyClDecl DocNameI -> Splice -> Unicode -> Maybe Package -> Qualification -> Html ppClassDecl summary links instances fixities loc d subdocs - decl@(ClassDecl { tcdCtxt = lctxt, tcdLName = lname, tcdTyVars = ltyvars - , tcdFDs = lfds, tcdSigs = lsigs, tcdATs = ats }) + decl@(ClassDecl { tcdCtxt = lctxt, tcdLName = lname@(L _ nm) + , tcdTyVars = ltyvars, tcdFDs = lfds, tcdSigs = lsigs + , tcdATs = ats, tcdATDefs = atsDefs }) splice unicode pkg qual | summary = ppShortClassDecl summary links decl loc subdocs splice unicode pkg qual | otherwise = classheader +++ docSection curname pkg qual d @@ -550,28 +552,68 @@ ppClassDecl summary links instances fixities loc d subdocs -- Only the fixity relevant to the class header fixs = ppFixities [ f | f@(n,_) <- fixities, n == unLoc lname ] qual - nm = tcdName decl - hdr = ppClassHdr summary lctxt (unLoc lname) ltyvars lfds - -- ToDo: add assocatied typ defaults - atBit = subAssociatedTypes [ ppAssocType summary links doc at subfixs splice unicode pkg qual - | at <- ats - , let n = unL . fdLName $ unL at - doc = lookupAnySubdoc (unL $ fdLName $ unL at) subdocs - subfixs = [ f | f@(n',_) <- fixities, n == n' ] ] - - methodBit = subMethods [ ppFunSig summary links loc doc [name] (hsSigType typ) - subfixs splice unicode pkg qual - | L _ (ClassOpSig _ _ lnames typ) <- lsigs - , name <- map unLoc lnames - , let doc = lookupAnySubdoc name subdocs - subfixs = [ f | f@(n',_) <- fixities - , name == n' ] - ] - -- N.B. taking just the first name is ok. Signatures with multiple names - -- are expanded so that each name gets its own signature. + -- Associated types + atBit = subAssociatedTypes + [ ppAssocType summary links doc at subfixs splice unicode pkg qual + <+> + subDefaults (maybeToList defTys) + | at <- ats + , let name = unL . fdLName $ unL at + doc = lookupAnySubdoc name subdocs + subfixs = filter ((== name) . fst) fixities + defTys = ppDefaultAssocTy name <$> lookupDAT name + ] + + -- Default associated types + ppDefaultAssocTy n (vs,t,d') = ppTySyn summary links [] loc d' synDecl + splice unicode pkg qual + where + synDecl = SynDecl { tcdSExt = noExt + , tcdLName = noLoc n + , tcdTyVars = vs + , tcdFixity = GHC.Prefix + , tcdRhs = t } + + lookupDAT name = Map.lookup (getName name) defaultAssocTys + defaultAssocTys = Map.fromList + [ (getName name, (vs, typ, doc)) + | L _ (FamEqn { feqn_rhs = typ + , feqn_tycon = L _ name + , feqn_pats = vs }) <- atsDefs + , let doc = noDocForDecl -- TODO: get docs for associated type defaults + ] + + -- Methods + methodBit = subMethods + [ ppFunSig summary links loc noHtml doc [name] (hsSigType typ) + subfixs splice unicode pkg qual + <+> + subDefaults (maybeToList defSigs) + | ClassOpSig _ False lnames typ <- sigs + , name <- map unLoc lnames + , let doc = lookupAnySubdoc name subdocs + subfixs = filter ((== name) . fst) fixities + defSigs = ppDefaultFunSig name <$> lookupDM name + ] + -- N.B. taking just the first name is ok. Signatures with multiple names + -- are expanded so that each name gets its own signature. + + -- Default methods + ppDefaultFunSig n (t, d') = ppFunSig summary links loc (keyword "default") + d' [n] (hsSigType t) [] splice unicode pkg qual + + lookupDM name = Map.lookup (getOccString name) defaultMethods + defaultMethods = Map.fromList + [ (nameStr, (typ, doc)) + | ClassOpSig _ True lnames typ <- sigs + , name <- map unLoc lnames + , let doc = lookupAnySubdoc name subdocs + , '$':'d':'m':nameStr <- [getOccString name] + ] + -- Minimal complete definition minimalBit = case [ s | MinimalSig _ _ (L _ s) <- sigs ] of -- Miminal complete definition = every shown method And xs : _ | sort [getName n | L _ (Var (L _ n)) <- xs] == @@ -580,7 +622,7 @@ ppClassDecl summary links instances fixities loc d subdocs -- Minimal complete definition = the only shown method Var (L _ n) : _ | [getName n] == - [getName n' | L _ (ClassOpSig _ _ ns _) <- lsigs, L _ n' <- ns] + [getName n' | ClassOpSig _ _ ns _ <- sigs, L _ n' <- ns] -> noHtml -- Minimal complete definition = nothing @@ -595,6 +637,7 @@ ppClassDecl summary links instances fixities loc d subdocs where wrap | p = parens | otherwise = id ppMinimal p (Parens x) = ppMinimal p (unLoc x) + -- Instances instancesBit = ppInstances links (OriginClass nm) instances splice unicode pkg qual diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs b/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs index 25d8b07a30..6a54946cf4 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Layout.hs @@ -35,6 +35,7 @@ module Haddock.Backends.Xhtml.Layout ( subInstances, subOrphanInstances, subInstHead, subInstDetails, subFamInstDetails, subMethods, + subDefaults, subMinimal, topDeclElem, declElem, @@ -49,7 +50,6 @@ import qualified Data.Map as Map import Text.XHtml hiding ( name, title, quote ) import Data.Maybe (fromMaybe) -import FastString ( unpackFS ) import GHC import Name (nameOccName) @@ -259,6 +259,9 @@ instAnchorId iid = makeAnchorId $ "i:" ++ iid subMethods :: [Html] -> Html subMethods = divSubDecls "methods" "Methods" . subBlock +subDefaults :: [Html] -> Html +subDefaults = divSubDecls "default" "" . subBlock + subMinimal :: Html -> Html subMinimal = divSubDecls "minimal" "Minimal complete definition" . Just . declElem @@ -289,15 +292,14 @@ links ((_,_,sourceMap,lineMap), (_,_,maybe_wiki_url)) loc splice mdl' docName@(D | otherwise = maybe lineUrl Just nameUrl in case mUrl of Nothing -> noHtml - Just url -> let url' = spliceURL (Just fname) (Just origMod) - (Just n) (Just loc) url + Just url -> let url' = spliceURL (Just origMod) (Just n) (Just loc) + url in anchor ! [href url', theclass "link"] << "Source" wikiLink = case maybe_wiki_url of Nothing -> noHtml - Just url -> let url' = spliceURL (Just fname) (Just mdl) - (Just n) (Just loc) url + Just url -> let url' = spliceURL (Just mdl) (Just n) (Just loc) url in anchor ! [href url', theclass "link"] << "Comments" -- For source links, we want to point to the original module, @@ -307,8 +309,4 @@ links ((_,_,sourceMap,lineMap), (_,_,maybe_wiki_url)) loc splice mdl' docName@(D -- will point to the module defining the class/family, which is wrong. origMod = fromMaybe (nameModule n) mdl' origPkg = moduleUnitId origMod - - fname = case loc of - RealSrcSpan l -> unpackFS (srcSpanFile l) - UnhelpfulSpan _ -> error "links: UnhelpfulSpan" links _ _ _ _ _ = noHtml diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Names.hs b/haddock-api/src/Haddock/Backends/Xhtml/Names.hs index 574045e020..2d0499ef8a 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Names.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Names.hs @@ -23,7 +23,6 @@ import Haddock.Types import Haddock.Utils import Text.XHtml hiding ( name, p, quote ) -import qualified Data.Map as M import qualified Data.List as List import GHC hiding (LexicalFixity(..)) @@ -88,11 +87,6 @@ ppQualifyName qual notation name mdl = Just _ -> ppFullQualName notation mdl name -- some other module, D.x -> D.x Nothing -> ppFullQualName notation mdl name - AliasedQual aliases localmdl -> - case (moduleString mdl == moduleString localmdl, - M.lookup mdl aliases) of - (False, Just alias) -> ppQualName notation alias name - _ -> ppName notation name ppFullQualName :: Notation -> Module -> Name -> Html @@ -100,11 +94,6 @@ ppFullQualName notation mdl name = wrapInfix notation (getOccName name) qname where qname = toHtml $ moduleString mdl ++ '.' : getOccString name -ppQualName :: Notation -> ModuleName -> Name -> Html -ppQualName notation mdlName name = wrapInfix notation (getOccName name) qname - where - qname = toHtml $ moduleNameString mdlName ++ '.' : getOccString name - ppName :: Notation -> Name -> Html ppName notation name = wrapInfix notation (getOccName name) $ toHtml (getOccString name) @@ -131,14 +120,11 @@ ppBinder' notation n = wrapInfix notation n $ ppOccName n wrapInfix :: Notation -> OccName -> Html -> Html wrapInfix notation n = case notation of - Infix | is_star_kind -> id - | not is_sym -> quote - Prefix | is_star_kind -> id - | is_sym -> parens + Infix | not is_sym -> quote + Prefix | is_sym -> parens _ -> id where is_sym = isSymOcc n - is_star_kind = isTcOcc n && occNameString n == "*" linkId :: Module -> Maybe Name -> Html -> Html linkId mdl mbName = linkIdOcc mdl (fmap nameOccName mbName) True diff --git a/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs b/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs index c3acb6dfa3..a8718c8dbd 100644 --- a/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs +++ b/haddock-api/src/Haddock/Backends/Xhtml/Utils.hs @@ -33,8 +33,6 @@ module Haddock.Backends.Xhtml.Utils ( import Haddock.Utils -import Data.Maybe - import Text.XHtml hiding ( name, title, p, quote ) import qualified Text.XHtml as XHtml @@ -48,19 +46,18 @@ import Name ( getOccString, nameOccName, isValOcc ) -- Used to generate URL for customized external paths, usually provided with -- @--source-module@, @--source-entity@ and related command-line arguments. -- --- >>> spliceURL Nothing mmod mname Nothing "output/%{MODULE}.hs#%{NAME}" +-- >>> spliceURL mmod mname Nothing "output/%{MODULE}.hs#%{NAME}" -- "output/Foo.hs#foo" -spliceURL :: Maybe FilePath -> Maybe Module -> Maybe GHC.Name -> +spliceURL :: Maybe Module -> Maybe GHC.Name -> Maybe SrcSpan -> String -> String -spliceURL mfile mmod = spliceURL' mfile (moduleName <$> mmod) +spliceURL mmod = spliceURL' (moduleName <$> mmod) -- | Same as 'spliceURL' but takes 'ModuleName' instead of 'Module'. -spliceURL' :: Maybe FilePath -> Maybe ModuleName -> Maybe GHC.Name -> +spliceURL' :: Maybe ModuleName -> Maybe GHC.Name -> Maybe SrcSpan -> String -> String -spliceURL' maybe_file maybe_mod maybe_name maybe_loc = run +spliceURL' maybe_mod maybe_name maybe_loc = run where - file = fromMaybe "" maybe_file mdl = case maybe_mod of Nothing -> "" Just m -> moduleNameString m @@ -81,23 +78,18 @@ spliceURL' maybe_file maybe_mod maybe_name maybe_loc = run run "" = "" run ('%':'M':rest) = mdl ++ run rest - run ('%':'F':rest) = file ++ run rest run ('%':'N':rest) = name ++ run rest run ('%':'K':rest) = kind ++ run rest run ('%':'L':rest) = line ++ run rest run ('%':'%':rest) = '%' : run rest run ('%':'{':'M':'O':'D':'U':'L':'E':'}':rest) = mdl ++ run rest - run ('%':'{':'F':'I':'L':'E':'}':rest) = file ++ run rest run ('%':'{':'N':'A':'M':'E':'}':rest) = name ++ run rest run ('%':'{':'K':'I':'N':'D':'}':rest) = kind ++ run rest run ('%':'{':'M':'O':'D':'U':'L':'E':'/':'.':'/':c:'}':rest) = map (\x -> if x == '.' then c else x) mdl ++ run rest - run ('%':'{':'F':'I':'L':'E':'/':'/':'/':c:'}':rest) = - map (\x -> if x == '/' then c else x) file ++ run rest - run ('%':'{':'L':'I':'N':'E':'}':rest) = line ++ run rest run (c:rest) = c : run rest diff --git a/haddock-api/src/Haddock/Convert.hs b/haddock-api/src/Haddock/Convert.hs index 5312bfc75b..2e7cbfef79 100644 --- a/haddock-api/src/Haddock/Convert.hs +++ b/haddock-api/src/Haddock/Convert.hs @@ -12,13 +12,16 @@ -- Conversion between TyThing and HsDecl. This functionality may be moved into -- GHC at some point. ----------------------------------------------------------------------------- -module Haddock.Convert where --- Some other functions turned out to be useful for converting --- instance heads, which aren't TyThings, so just export everything. +module Haddock.Convert ( + tyThingToLHsDecl, + synifyInstHead, + synifyFamInst, + PrintRuntimeReps(..), +) where import Bag ( emptyBag ) import BasicTypes ( TupleSort(..), SourceText(..), LexicalFixity(..) - , PromotionFlag(..) ) + , PromotionFlag(..), DefMethSpec(..) ) import Class import CoAxiom import ConLike @@ -49,12 +52,22 @@ import VarSet import Haddock.Types import Haddock.Interface.Specialize +import Haddock.GhcUtils ( orderedFVs, defaultRuntimeRepVars ) +import Data.Maybe ( catMaybes, maybeToList ) +-- | Whether or not to default 'RuntimeRep' variables to 'LiftedRep'. Check +-- out Note [Defaulting RuntimeRep variables] in IfaceType.hs for the +-- motivation. +data PrintRuntimeReps = ShowRuntimeRep | HideRuntimeRep deriving Show + -- the main function here! yay! -tyThingToLHsDecl :: TyThing -> Either ErrMsg ([ErrMsg], (HsDecl GhcRn)) -tyThingToLHsDecl t = case t of +tyThingToLHsDecl + :: PrintRuntimeReps + -> TyThing + -> Either ErrMsg ([ErrMsg], (HsDecl GhcRn)) +tyThingToLHsDecl prr t = case t of -- ids (functions and zero-argument a.k.a. CAFs) get a type signature. -- Including built-in functions like seq. -- foreign-imported functions could be represented with ForD @@ -63,40 +76,60 @@ tyThingToLHsDecl t = case t of -- in a future code version we could turn idVarDetails = foreign-call -- into a ForD instead of a SigD if we wanted. Haddock doesn't -- need to care. - AnId i -> allOK $ SigD noExt (synifyIdSig ImplicitizeForAll i) + AnId i -> allOK $ SigD noExt (synifyIdSig prr ImplicitizeForAll [] i) -- type-constructors (e.g. Maybe) are complicated, put the definition -- later in the file (also it's used for class associated-types too.) ATyCon tc | Just cl <- tyConClass_maybe tc -- classes are just a little tedious - -> let extractFamilyDecl :: TyClDecl a -> Either ErrMsg (LFamilyDecl a) - extractFamilyDecl (FamDecl _ d) = return $ noLoc d + -> let extractFamilyDecl :: TyClDecl a -> Either ErrMsg (FamilyDecl a) + extractFamilyDecl (FamDecl _ d) = return d extractFamilyDecl _ = Left "tyThingToLHsDecl: impossible associated tycon" - atTyClDecls = [synifyTyCon Nothing at_tc | ATI at_tc _ <- classATItems cl] - atFamDecls = map extractFamilyDecl (rights atTyClDecls) - tyClErrors = lefts atTyClDecls - famDeclErrors = lefts atFamDecls - in withErrs (tyClErrors ++ famDeclErrors) . TyClD noExt $ ClassDecl + extractFamDefDecl :: FamilyDecl GhcRn -> Type -> TyFamDefltEqn GhcRn + extractFamDefDecl fd rhs = FamEqn + { feqn_ext = noExt + , feqn_tycon = fdLName fd + , feqn_bndrs = Nothing + -- TODO: this must change eventually + , feqn_pats = fdTyVars fd + , feqn_fixity = fdFixity fd + , feqn_rhs = synifyType WithinType [] rhs } + + extractAtItem + :: ClassATItem + -> Either ErrMsg (LFamilyDecl GhcRn, Maybe (LTyFamDefltEqn GhcRn)) + extractAtItem (ATI at_tc def) = do + tyDecl <- synifyTyCon prr Nothing at_tc + famDecl <- extractFamilyDecl tyDecl + let defEqnTy = fmap (noLoc . extractFamDefDecl famDecl . fst) def + pure (noLoc famDecl, defEqnTy) + + atTyClDecls = map extractAtItem (classATItems cl) + (atFamDecls, atDefFamDecls) = unzip (rights atTyClDecls) + vs = tyConVisibleTyVars (classTyCon cl) + + in withErrs (lefts atTyClDecls) . TyClD noExt $ ClassDecl { tcdCtxt = synifyCtx (classSCTheta cl) , tcdLName = synifyName cl - , tcdTyVars = synifyTyVars (tyConVisibleTyVars (classTyCon cl)) - , tcdFixity = Prefix + , tcdTyVars = synifyTyVars vs + , tcdFixity = synifyFixity cl , tcdFDs = map (\ (l,r) -> noLoc (map (noLoc . getName) l, map (noLoc . getName) r) ) $ snd $ classTvsFds cl , tcdSigs = noLoc (MinimalSig noExt NoSourceText . noLoc . fmap noLoc $ classMinimalDef cl) : - map (noLoc . synifyTcIdSig DeleteTopLevelQuantification) - (classMethods cl) + [ noLoc tcdSig + | clsOp <- classOpItems cl + , tcdSig <- synifyTcIdSig vs clsOp ] , tcdMeths = emptyBag --ignore default method definitions, they don't affect signature -- class associated-types are a subset of TyCon: - , tcdATs = rights atFamDecls - , tcdATDefs = [] --ignore associated type defaults + , tcdATs = atFamDecls + , tcdATDefs = catMaybes atDefFamDecls , tcdDocs = [] --we don't have any docs at this point , tcdCExt = placeHolderNamesTc } | otherwise - -> synifyTyCon Nothing tc >>= allOK . TyClD noExt + -> synifyTyCon prr Nothing tc >>= allOK . TyClD noExt -- type-constructors (e.g. Maybe) are complicated, put the definition -- later in the file (also it's used for class associated-types too.) @@ -104,7 +137,7 @@ tyThingToLHsDecl t = case t of -- a data-constructor alone just gets rendered as a function: AConLike (RealDataCon dc) -> allOK $ SigD noExt (TypeSig noExt [synifyName dc] - (synifySigWcType ImplicitizeForAll (dataConUserType dc))) + (synifySigWcType ImplicitizeForAll [] (dataConUserType dc))) AConLike (PatSynCon ps) -> allOK . SigD noExt $ PatSynSig noExt [synifyName ps] (synifyPatSynSigType ps) @@ -116,17 +149,17 @@ synifyAxBranch :: TyCon -> CoAxBranch -> TyFamInstEqn GhcRn synifyAxBranch tc (CoAxBranch { cab_tvs = tkvs, cab_lhs = args, cab_rhs = rhs }) = let name = synifyName tc args_types_only = filterOutInvisibleTypes tc args - typats = map (synifyType WithinType) args_types_only + typats = map (synifyType WithinType []) args_types_only annot_typats = zipWith3 annotHsType (mkIsPolyTvs fam_tvs) args_types_only typats - hs_rhs = synifyType WithinType rhs + hs_rhs = synifyType WithinType [] rhs in HsIB { hsib_ext = map tyVarName tkvs , hsib_body = FamEqn { feqn_ext = noExt , feqn_tycon = name , feqn_bndrs = Nothing - -- this must change eventually + -- TODO: this must change eventually , feqn_pats = map HsValArg annot_typats - , feqn_fixity = Prefix + , feqn_fixity = synifyFixity name , feqn_rhs = hs_rhs } } where fam_tvs = tyConVisibleTyVars tc @@ -141,42 +174,51 @@ synifyAxiom ax@(CoAxiom { co_ax_tc = tc }) | Just ax' <- isClosedSynFamilyTyConWithAxiom_maybe tc , getUnique ax' == getUnique ax -- without the getUniques, type error - = synifyTyCon (Just ax) tc >>= return . TyClD noExt + = synifyTyCon ShowRuntimeRep (Just ax) tc >>= return . TyClD noExt | otherwise = Left "synifyAxiom: closed/open family confusion" --- | Turn type constructors into type class declarations -synifyTyCon :: Maybe (CoAxiom br) -> TyCon -> Either ErrMsg (TyClDecl GhcRn) -synifyTyCon _coax tc +-- | Turn type constructors into data declarations, type families, or type synonyms +synifyTyCon + :: PrintRuntimeReps + -> Maybe (CoAxiom br) -- ^ RHS of type synonym + -> TyCon -- ^ type constructor to convert + -> Either ErrMsg (TyClDecl GhcRn) +synifyTyCon prr _coax tc | isFunTyCon tc || isPrimTyCon tc = return $ DataDecl { tcdLName = synifyName tc - , tcdTyVars = -- tyConTyVars doesn't work on fun/prim, but we can make them up: - let mk_hs_tv realKind fakeTyVar - = noLoc $ KindedTyVar noExt (noLoc (getName fakeTyVar)) - (synifyKindSig realKind) - in HsQTvs { hsq_ext = + , tcdTyVars = HsQTvs { hsq_ext = HsQTvsRn { hsq_implicit = [] -- No kind polymorphism , hsq_dependent = emptyNameSet } - , hsq_explicit = zipWith mk_hs_tv (fst (splitFunTys (tyConKind tc))) - alphaTyVars --a, b, c... which are unfortunately all kind * + , hsq_explicit = zipWith mk_hs_tv + tyVarKinds + alphaTyVars --a, b, c... which are unfortunately all kind * } - , tcdFixity = Prefix + , tcdFixity = synifyFixity tc , tcdDataDefn = HsDataDefn { dd_ext = noExt , dd_ND = DataType -- arbitrary lie, they are neither -- algebraic data nor newtype: , dd_ctxt = noLoc [] , dd_cType = Nothing - , dd_kindSig = Just (synifyKindSig (tyConKind tc)) + , dd_kindSig = synifyDataTyConReturnKind tc -- we have their kind accurately: , dd_cons = [] -- No constructors , dd_derivs = noLoc [] } , tcdDExt = DataDeclRn False placeHolderNamesTc } + where + -- tyConTyVars doesn't work on fun/prim, but we can make them up: + mk_hs_tv realKind fakeTyVar + | isLiftedTypeKind realKind = noLoc $ UserTyVar noExt (noLoc (getName fakeTyVar)) + | otherwise = noLoc $ KindedTyVar noExt (noLoc (getName fakeTyVar)) (synifyKindSig realKind) + + conKind = defaultType prr (tyConKind tc) + tyVarKinds = fst . splitFunTys . snd . splitPiTysInvisible $ conKind -synifyTyCon _coax tc +synifyTyCon _prr _coax tc | Just flav <- famTyConFlav_maybe tc = case flav of -- Type families @@ -200,7 +242,7 @@ synifyTyCon _coax tc , fdInfo = i , fdLName = synifyName tc , fdTyVars = synifyTyVars (tyConVisibleTyVars tc) - , fdFixity = Prefix + , fdFixity = synifyFixity tc , fdResultSig = synifyFamilyResultSig resultVar (tyConResKind tc) , fdInjectivityAnn = @@ -208,13 +250,13 @@ synifyTyCon _coax tc (tyConInjectivityInfo tc) } -synifyTyCon coax tc +synifyTyCon _prr coax tc | Just ty <- synTyConRhs_maybe tc = return $ SynDecl { tcdSExt = emptyNameSet , tcdLName = synifyName tc , tcdTyVars = synifyTyVars (tyConVisibleTyVars tc) - , tcdFixity = Prefix - , tcdRhs = synifyType WithinType ty } + , tcdFixity = synifyFixity tc + , tcdRhs = synifyType WithinType [] ty } | otherwise = -- (closed) newtype and data let @@ -242,7 +284,7 @@ synifyTyCon coax tc -- That seems like an acceptable compromise (they'll just be documented -- in prefix position), since, otherwise, the logic (at best) gets much more -- complicated. (would use dataConIsInfix.) - use_gadt_syntax = any (not . isVanillaDataCon) (tyConDataCons tc) + use_gadt_syntax = isGadtSyntaxTyCon tc consRaw = map (synifyDataCon use_gadt_syntax) (tyConDataCons tc) cons = rights consRaw -- "deriving" doesn't affect the signature, no need to specify any. @@ -256,31 +298,31 @@ synifyTyCon coax tc , dd_derivs = alg_deriv } in case lefts consRaw of [] -> return $ - DataDecl { tcdLName = name, tcdTyVars = tyvars, tcdFixity = Prefix + DataDecl { tcdLName = name, tcdTyVars = tyvars + , tcdFixity = synifyFixity name , tcdDataDefn = defn , tcdDExt = DataDeclRn False placeHolderNamesTc } dataConErrs -> Left $ unlines dataConErrs --- In this module, every TyCon being considered has come from an interface +-- | In this module, every TyCon being considered has come from an interface -- file. This means that when considering a data type constructor such as: -- --- data Foo (w :: *) (m :: * -> *) (a :: *) +-- > data Foo (w :: *) (m :: * -> *) (a :: *) -- -- Then its tyConKind will be (* -> (* -> *) -> * -> *). But beware! We are -- also rendering the type variables of Foo, so if we synify the tyConKind of -- Foo in full, we will end up displaying this in Haddock: -- --- data Foo (w :: *) (m :: * -> *) (a :: *) --- :: * -> (* -> *) -> * -> * +-- > data Foo (w :: *) (m :: * -> *) (a :: *) +-- > :: * -> (* -> *) -> * -> * -- --- Which is entirely wrong (#548). We only want to display the *return* kind, +-- Which is entirely wrong (#548). We only want to display the /return/ kind, -- which this function obtains. synifyDataTyConReturnKind :: TyCon -> Maybe (LHsKind GhcRn) synifyDataTyConReturnKind tc - = case splitFunTys (tyConKind tc) of - (_, ret_kind) - | isLiftedTypeKind ret_kind -> Nothing -- Don't bother displaying :: * - | otherwise -> Just (synifyKindSig ret_kind) + | isLiftedTypeKind ret_kind = Nothing -- Don't bother displaying :: * + | otherwise = Just (synifyKindSig ret_kind) + where ret_kind = tyConResKind tc synifyInjectivityAnn :: Maybe Name -> [TyVar] -> Injectivity -> Maybe (LInjectivityAnn GhcRn) @@ -291,8 +333,9 @@ synifyInjectivityAnn (Just lhs) tvs (Injective inj) = in Just $ noLoc $ InjectivityAnn (noLoc lhs) rhs synifyFamilyResultSig :: Maybe Name -> Kind -> LFamilyResultSig GhcRn -synifyFamilyResultSig Nothing kind = - noLoc $ KindSig noExt (synifyKindSig kind) +synifyFamilyResultSig Nothing kind + | isLiftedTypeKind kind = noLoc $ NoSig noExt + | otherwise = noLoc $ KindSig noExt (synifyKindSig kind) synifyFamilyResultSig (Just name) kind = noLoc $ TyVarSig noExt (noLoc $ KindedTyVar noExt (noLoc name) (synifyKindSig kind)) @@ -313,11 +356,12 @@ synifyDataCon use_gadt_syntax dc = (univ_tvs, ex_tvs, _eq_spec, theta, arg_tys, res_ty) = dataConFullSig dc -- skip any EqTheta, use 'orig'inal syntax - ctx = synifyCtx theta + ctx | null theta = Nothing + | otherwise = Just $ synifyCtx theta linear_tys = zipWith (\ty bang -> - let tySyn = synifyType WithinType ty + let tySyn = synifyType WithinType [] ty in case bang of (HsSrcBang _ NoSrcUnpack NoSrcStrict) -> tySyn bang' -> noLoc $ HsBangTy noExt bang' tySyn) @@ -341,33 +385,55 @@ synifyDataCon use_gadt_syntax dc = then return $ noLoc $ ConDeclGADT { con_g_ext = noExt , con_names = [name] - , con_forall = noLoc True + , con_forall = noLoc False , con_qvars = synifyTyVars (univ_tvs ++ ex_tvs) - , con_mb_cxt = Just ctx - , con_args = hat - , con_res_ty = synifyType WithinType res_ty - , con_doc = Nothing } + , con_mb_cxt = ctx + , con_args = hat + , con_res_ty = synifyType WithinType [] res_ty + , con_doc = Nothing } else return $ noLoc $ ConDeclH98 { con_ext = noExt , con_name = name - , con_forall = noLoc True + , con_forall = noLoc False , con_ex_tvs = map synifyTyVar ex_tvs - , con_mb_cxt = Just ctx + , con_mb_cxt = ctx , con_args = hat , con_doc = Nothing } synifyName :: NamedThing n => n -> Located Name synifyName n = L (srcLocSpan (getSrcLoc n)) (getName n) - -synifyIdSig :: SynifyTypeState -> Id -> Sig GhcRn -synifyIdSig s i = TypeSig noExt [synifyName i] (synifySigWcType s (varType i)) - -synifyTcIdSig :: SynifyTypeState -> Id -> Sig GhcRn -synifyTcIdSig s i = ClassOpSig noExt False [synifyName i] (synifySigType s (varType i)) +-- | Guess the fixity of a something with a name. This isn't quite right, since +-- a user can always declare an infix name in prefix form or a prefix name in +-- infix form. Unfortunately, that is not something we can usually reconstruct. +synifyFixity :: NamedThing n => n -> LexicalFixity +synifyFixity n | isSymOcc (getOccName n) = Infix + | otherwise = Prefix + +synifyIdSig + :: PrintRuntimeReps -- ^ are we printing tyvars of kind 'RuntimeRep'? + -> SynifyTypeState -- ^ what to do with a 'forall' + -> [TyVar] -- ^ free variables in the type to convert + -> Id -- ^ the 'Id' from which to get the type signature + -> Sig GhcRn +synifyIdSig prr s vs i = TypeSig noExt [synifyName i] (synifySigWcType s vs t) + where + t = defaultType prr (varType i) + +-- | Turn a 'ClassOpItem' into a list of signatures. The list returned is going +-- to contain the synified 'ClassOpSig' as well (when appropriate) a default +-- 'ClassOpSig'. +synifyTcIdSig :: [TyVar] -> ClassOpItem -> [Sig GhcRn] +synifyTcIdSig vs (i, dm) = + [ ClassOpSig noExt False [synifyName i] (mainSig (varType i)) ] ++ + [ ClassOpSig noExt True [noLoc dn] (defSig dt) + | Just (dn, GenericDM dt) <- [dm] ] + where + mainSig t = synifySigType DeleteTopLevelQuantification vs t + defSig t = synifySigType ImplicitizeForAll vs t synifyCtx :: [PredType] -> LHsContext GhcRn -synifyCtx = noLoc . map (synifyType WithinType) +synifyCtx = noLoc . map (synifyType WithinType []) synifyTyVars :: [TyVar] -> LHsQTyVars GhcRn @@ -376,13 +442,20 @@ synifyTyVars ktvs = HsQTvs { hsq_ext = HsQTvsRn { hsq_implicit = [] , hsq_explicit = map synifyTyVar ktvs } synifyTyVar :: TyVar -> LHsTyVarBndr GhcRn -synifyTyVar tv - | isLiftedTypeKind kind = noLoc (UserTyVar noExt (noLoc name)) - | otherwise = noLoc (KindedTyVar noExt (noLoc name) (synifyKindSig kind)) +synifyTyVar = synifyTyVar' emptyVarSet + +-- | Like 'synifyTyVar', but accepts a set of variables for which to omit kind +-- signatures (even if they don't have the lifted type kind). +synifyTyVar' :: VarSet -> TyVar -> LHsTyVarBndr GhcRn +synifyTyVar' no_kinds tv + | isLiftedTypeKind kind || tv `elemVarSet` no_kinds + = noLoc (UserTyVar noExt (noLoc name)) + | otherwise = noLoc (KindedTyVar noExt (noLoc name) (synifyKindSig kind)) where kind = tyVarKind tv name = getName tv + -- | Annotate (with HsKingSig) a type if the first parameter is True -- and if the type contains a free variable. -- This is used to synify type patterns for poly-kinded tyvars in @@ -394,7 +467,7 @@ annotHsType _ _ hs_ty@(L _ (HsKindSig {})) = hs_ty annotHsType True ty hs_ty | not $ isEmptyVarSet $ filterVarSet isTyVar $ tyCoVarsOfType ty = let ki = typeKind ty - hs_ki = synifyType WithinType ki + hs_ki = synifyType WithinType [] ki in noLoc (HsKindSig noExt hs_ty hs_ki) annotHsType _ _ hs_ty = hs_ty @@ -417,7 +490,8 @@ data SynifyTypeState -- quite understand what's going on. | ImplicitizeForAll -- ^ beginning of a function definition, in which, to make it look - -- less ugly, those rank-1 foralls are made implicit. + -- less ugly, those rank-1 foralls (without kind annotations) are made + -- implicit. | DeleteTopLevelQuantification -- ^ because in class methods the context is added to the type -- (e.g. adding @forall a. Num a =>@ to @(+) :: a -> a -> a@) @@ -426,22 +500,36 @@ data SynifyTypeState -- the defining class gets to quantify all its functions for free! -synifySigType :: SynifyTypeState -> Type -> LHsSigType GhcRn +synifySigType :: SynifyTypeState -> [TyVar] -> Type -> LHsSigType GhcRn -- The empty binders is a bit suspicious; -- what if the type has free variables? -synifySigType s ty = mkEmptyImplicitBndrs (synifyType s ty) +synifySigType s vs ty = mkEmptyImplicitBndrs (synifyType s vs ty) -synifySigWcType :: SynifyTypeState -> Type -> LHsSigWcType GhcRn +synifySigWcType :: SynifyTypeState -> [TyVar] -> Type -> LHsSigWcType GhcRn -- Ditto (see synifySigType) -synifySigWcType s ty = mkEmptyWildCardBndrs (mkEmptyImplicitBndrs (synifyType s ty)) +synifySigWcType s vs ty = mkEmptyWildCardBndrs (mkEmptyImplicitBndrs (synifyType s vs ty)) synifyPatSynSigType :: PatSyn -> LHsSigType GhcRn -- Ditto (see synifySigType) synifyPatSynSigType ps = mkEmptyImplicitBndrs (synifyPatSynType ps) -synifyType :: SynifyTypeState -> Type -> LHsType GhcRn -synifyType _ (TyVarTy tv) = noLoc $ HsTyVar noExt NotPromoted $ noLoc (getName tv) -synifyType _ (TyConApp tc tys) +-- | Depending on the first argument, try to default all type variables of kind +-- 'RuntimeRep' to 'LiftedType'. +defaultType :: PrintRuntimeReps -> Type -> Type +defaultType ShowRuntimeRep = id +defaultType HideRuntimeRep = defaultRuntimeRepVars + +-- | Convert a core type into an 'HsType'. +synifyType + :: SynifyTypeState -- ^ what to do with a 'forall' + -> [TyVar] -- ^ free variables in the type to convert + -> Type -- ^ the type to convert + -> LHsType GhcRn +synifyType _ _ (TyVarTy tv) + | mkTyVarOcc "_" == occName tv + = noLoc $ HsWildCardTy noExt -- TODO: Maybe test this?! + | otherwise = noLoc $ HsTyVar noExt NotPromoted $ noLoc (getName tv) +synifyType _ vs (TyConApp tc tys) = maybe_sig res_ty where res_ty :: LHsType GhcRn @@ -459,21 +547,21 @@ synifyType _ (TyConApp tc tys) BoxedTuple -> HsBoxedTuple ConstraintTuple -> HsConstraintTuple UnboxedTuple -> HsUnboxedTuple) - (map (synifyType WithinType) vis_tys) - | isUnboxedSumTyCon tc = noLoc $ HsSumTy noExt (map (synifyType WithinType) vis_tys) + (map (synifyType WithinType vs) vis_tys) + | isUnboxedSumTyCon tc = noLoc $ HsSumTy noExt (map (synifyType WithinType vs) vis_tys) | Just dc <- isPromotedDataCon_maybe tc , isTupleDataCon dc , dataConSourceArity dc == length vis_tys - = noLoc $ HsExplicitTupleTy noExt (map (synifyType WithinType) vis_tys) + = noLoc $ HsExplicitTupleTy noExt (map (synifyType WithinType vs) vis_tys) -- ditto for lists | getName tc == listTyConName, [ty] <- vis_tys = - noLoc $ HsListTy noExt (synifyType WithinType ty) + noLoc $ HsListTy noExt (synifyType WithinType vs ty) | tc == promotedNilDataCon, [] <- vis_tys = noLoc $ HsExplicitListTy noExt IsPromoted [] | tc == promotedConsDataCon , [ty1, ty2] <- vis_tys - = let hTy = synifyType WithinType ty1 - in case synifyType WithinType ty2 of + = let hTy = synifyType WithinType vs ty1 + in case synifyType WithinType vs ty2 of tTy | L _ (HsExplicitListTy _ IsPromoted tTy') <- stripKindSig tTy -> noLoc $ HsExplicitListTy noExt IsPromoted (hTy : tTy') | otherwise @@ -482,21 +570,21 @@ synifyType _ (TyConApp tc tys) | tc `hasKey` ipClassKey , [name, ty] <- tys , Just x <- isStrLitTy name - = noLoc $ HsIParamTy noExt (noLoc $ HsIPName x) (synifyType WithinType ty) + = noLoc $ HsIParamTy noExt (noLoc $ HsIPName x) (synifyType WithinType vs ty) -- and equalities | tc `hasKey` eqTyConKey , [ty1, ty2] <- tys = noLoc $ HsOpTy noExt - (synifyType WithinType ty1) + (synifyType WithinType vs ty1) (noLoc eqTyConName) - (synifyType WithinType ty2) + (synifyType WithinType vs ty2) -- and infix type operators | isSymOcc (nameOccName (getName tc)) , ty1:ty2:tys_rest <- vis_tys = mk_app_tys (HsOpTy noExt - (synifyType WithinType ty1) + (synifyType WithinType vs ty1) (noLoc $ getName tc) - (synifyType WithinType ty2)) + (synifyType WithinType vs ty2)) tys_rest -- Most TyCons: | otherwise @@ -507,7 +595,7 @@ synifyType _ (TyConApp tc tys) mk_app_tys ty_app ty_args = foldl (\t1 t2 -> noLoc $ HsAppTy noExt t1 t2) (noLoc ty_app) - (map (synifyType WithinType) $ + (map (synifyType WithinType vs) $ filterOut isCoercionTy ty_args) vis_tys = filterOutInvisibleTypes tc tys @@ -518,7 +606,7 @@ synifyType _ (TyConApp tc tys) maybe_sig ty' | needs_kind_sig = let full_kind = typeKind (mkTyConApp tc tys) - full_kind' = synifyType WithinType full_kind + full_kind' = synifyType WithinType vs full_kind in noLoc $ HsKindSig noExt ty' full_kind' | otherwise = ty' @@ -536,80 +624,174 @@ synifyType _ (TyConApp tc tys) in not (subVarSet result_vars dropped_vars) -synifyType s (AppTy t1 (CoercionTy {})) = synifyType s t1 -synifyType _ (AppTy t1 t2) = let - s1 = synifyType WithinType t1 - s2 = synifyType WithinType t2 +synifyType s vs (AppTy t1 (CoercionTy {})) = synifyType s vs t1 +synifyType _ vs (AppTy t1 t2) = let + s1 = synifyType WithinType vs t1 + s2 = synifyType WithinType vs t2 in noLoc $ HsAppTy noExt s1 s2 -synifyType _ (FunTy t1 t2) = let - s1 = synifyType WithinType t1 - s2 = synifyType WithinType t2 - in noLoc $ HsFunTy noExt s1 s2 -synifyType s forallty@(ForAllTy _tv _ty) = - let (tvs, ctx, tau) = tcSplitSigmaTyPreserveSynonyms forallty +synifyType s vs funty@(FunTy t1 t2) + | isPredTy t1 = synifyForAllType s vs funty + | otherwise = let s1 = synifyType WithinType vs t1 + s2 = synifyType WithinType vs t2 + in noLoc $ HsFunTy noExt s1 s2 +synifyType s vs forallty@(ForAllTy _tv _ty) = synifyForAllType s vs forallty + +synifyType _ _ (LitTy t) = noLoc $ HsTyLit noExt $ synifyTyLit t +synifyType s vs (CastTy t _) = synifyType s vs t +synifyType _ _ (CoercionTy {}) = error "synifyType:Coercion" + +-- | Process a 'Type' which starts with a forall or a constraint into +-- an 'HsType' +synifyForAllType + :: SynifyTypeState -- ^ what to do with the 'forall' + -> [TyVar] -- ^ free variables in the type to convert + -> Type -- ^ the forall type to convert + -> LHsType GhcRn +synifyForAllType s vs ty = + let (tvs, ctx, tau) = tcSplitSigmaTyPreserveSynonyms ty sPhi = HsQualTy { hst_ctxt = synifyCtx ctx - , hst_xqual = noExt - , hst_body = synifyType WithinType tau } + , hst_xqual = noExt + , hst_body = synifyType WithinType (tvs' ++ vs) tau } + + sTy = HsForAllTy { hst_bndrs = sTvs + , hst_xforall = noExt + , hst_body = noLoc sPhi } + + sTvs = map synifyTyVar tvs + + -- Figure out what the type variable order would be inferred in the + -- absence of an explicit forall + tvs' = orderedFVs (mkVarSet vs) (ctx ++ [tau]) + in case s of - DeleteTopLevelQuantification -> synifyType ImplicitizeForAll tau - WithinType -> noLoc $ HsForAllTy { hst_bndrs = map synifyTyVar tvs - , hst_xforall = noExt - , hst_body = noLoc sPhi } - ImplicitizeForAll -> noLoc sPhi + DeleteTopLevelQuantification -> synifyType ImplicitizeForAll (tvs' ++ vs) tau + + -- Put a forall in if there are any type variables + WithinType + | not (null tvs) -> noLoc sTy + | otherwise -> noLoc sPhi + + ImplicitizeForAll -> implicitForAll [] vs tvs ctx (synifyType WithinType) tau + + +-- | Put a forall in if there are any type variables which require +-- explicit kind annotations or if the inferred type variable order +-- would be different. +implicitForAll + :: [TyCon] -- ^ type constructors that determine their args kinds + -> [TyVar] -- ^ free variables in the type to convert + -> [TyVar] -- ^ type variable binders in the forall + -> ThetaType -- ^ constraints right after the forall + -> ([TyVar] -> Type -> LHsType GhcRn) -- ^ how to convert the inner type + -> Type -- ^ inner type + -> LHsType GhcRn +implicitForAll tycons vs tvs ctx synInner tau + | any (isHsKindedTyVar . unLoc) sTvs = noLoc sTy + | tvs' /= tvs = noLoc sTy + | otherwise = noLoc sPhi + where + sRho = synInner (tvs' ++ vs) tau + sPhi | null ctx = unLoc sRho + | otherwise + = HsQualTy { hst_ctxt = synifyCtx ctx + , hst_xqual = noExt + , hst_body = synInner (tvs' ++ vs) tau } + sTy = HsForAllTy { hst_bndrs = sTvs + , hst_xforall = noExt + , hst_body = noLoc sPhi } + + no_kinds_needed = noKindTyVars tycons tau + sTvs = map (synifyTyVar' no_kinds_needed) tvs + + -- Figure out what the type variable order would be inferred in the + -- absence of an explicit forall + tvs' = orderedFVs (mkVarSet vs) (ctx ++ [tau]) -synifyType _ (LitTy t) = noLoc $ HsTyLit noExt $ synifyTyLit t -synifyType s (CastTy t _) = synifyType s t -synifyType _ (CoercionTy {}) = error "synifyType:Coercion" + + +-- | Find the set of type variables whose kind signatures can be properly +-- inferred just from their uses in the type signature. This means the type +-- variable to has at least one fully applied use @f x1 x2 ... xn@ where: +-- +-- * @f@ has a function kind where the arguments have the same kinds +-- as @x1 x2 ... xn@. +-- +-- * @f@ has a function kind whose final return has lifted type kind +-- +noKindTyVars + :: [TyCon] -- ^ type constructors that determine their args kinds + -> Type -- ^ type to inspect + -> VarSet -- ^ set of variables whose kinds can be inferred from uses in the type +noKindTyVars _ (TyVarTy var) + | isLiftedTypeKind (tyVarKind var) = unitVarSet var +noKindTyVars ts ty + | (f, xs) <- splitAppTys ty + , not (null xs) + = let args = map (noKindTyVars ts) xs + func = case f of + TyVarTy var | (xsKinds, outKind) <- splitFunTys (tyVarKind var) + , xsKinds `eqTypes` map typeKind xs + , isLiftedTypeKind outKind + -> unitVarSet var + TyConApp t ks | t `elem` ts + , all noFreeVarsOfType ks + -> mkVarSet [ v | TyVarTy v <- xs ] + _ -> noKindTyVars ts f + in unionVarSets (func : args) +noKindTyVars ts (ForAllTy _ t) = noKindTyVars ts t +noKindTyVars ts (FunTy t1 t2) = noKindTyVars ts t1 `unionVarSet` noKindTyVars ts t2 +noKindTyVars ts (CastTy t _) = noKindTyVars ts t +noKindTyVars _ _ = emptyVarSet synifyPatSynType :: PatSyn -> LHsType GhcRn -synifyPatSynType ps = let - (univ_tvs, req_theta, ex_tvs, prov_theta, arg_tys, res_ty) = patSynSig ps - req_theta' | null req_theta && not (null prov_theta && null ex_tvs) = [unitTy] - -- HACK: a HsQualTy with theta = [unitTy] will be printed as "() =>", - -- i.e., an explicit empty context, which is what we need. This is not - -- possible by taking theta = [], as that will print no context at all - | otherwise = req_theta - sForAll [] s = s - sForAll tvs s = HsForAllTy { hst_bndrs = map synifyTyVar tvs - , hst_xforall = noExt - , hst_body = noLoc s } - sQual theta s = HsQualTy { hst_ctxt = synifyCtx theta - , hst_xqual = noExt - , hst_body = noLoc s } - sTau = unLoc $ synifyType WithinType $ mkFunTys arg_tys res_ty - in noLoc $ sForAll univ_tvs $ sQual req_theta' $ sForAll ex_tvs $ sQual prov_theta sTau +synifyPatSynType ps = + let (univ_tvs, req_theta, ex_tvs, prov_theta, arg_tys, res_ty) = patSynSig ps + ts = maybeToList (tyConAppTyCon_maybe res_ty) + + -- HACK: a HsQualTy with theta = [unitTy] will be printed as "() =>", + -- i.e., an explicit empty context, which is what we need. This is not + -- possible by taking theta = [], as that will print no context at all + req_theta' | null req_theta + , not (null prov_theta && null ex_tvs) + = [unitTy] + | otherwise = req_theta + + in implicitForAll ts [] (univ_tvs ++ ex_tvs) req_theta' + (\vs -> implicitForAll ts vs [] prov_theta (synifyType WithinType)) + (mkFunTys arg_tys res_ty) synifyTyLit :: TyLit -> HsTyLit synifyTyLit (NumTyLit n) = HsNumTy NoSourceText n synifyTyLit (StrTyLit s) = HsStrTy NoSourceText s synifyKindSig :: Kind -> LHsKind GhcRn -synifyKindSig k = synifyType WithinType k +synifyKindSig k = synifyType WithinType [] k stripKindSig :: LHsType GhcRn -> LHsType GhcRn stripKindSig (L _ (HsKindSig _ t _)) = t stripKindSig t = t synifyInstHead :: ([TyVar], [PredType], Class, [Type]) -> InstHead GhcRn -synifyInstHead (_, preds, cls, types) = specializeInstHead $ InstHead +synifyInstHead (vs, preds, cls, types) = specializeInstHead $ InstHead { ihdClsName = getName cls , ihdTypes = map unLoc annot_ts , ihdInstType = ClassInst - { clsiCtx = map (unLoc . synifyType WithinType) preds + { clsiCtx = map (unLoc . synifyType WithinType []) preds , clsiTyVars = synifyTyVars (tyConVisibleTyVars cls_tycon) , clsiSigs = map synifyClsIdSig $ classMethods cls , clsiAssocTys = do - (Right (FamDecl _ fam)) <- map (synifyTyCon Nothing) $ classATs cls + (Right (FamDecl _ fam)) <- map (synifyTyCon HideRuntimeRep Nothing) + (classATs cls) pure $ mkPseudoFamilyDecl fam } } where cls_tycon = classTyCon cls ts = filterOutInvisibleTypes cls_tycon types - ts' = map (synifyType WithinType) ts + ts' = map (synifyType WithinType vs) ts annot_ts = zipWith3 annotHsType is_poly_tvs ts ts' is_poly_tvs = mkIsPolyTvs (tyConVisibleTyVars cls_tycon) - synifyClsIdSig = synifyIdSig DeleteTopLevelQuantification + synifyClsIdSig = synifyIdSig ShowRuntimeRep DeleteTopLevelQuantification vs -- Convert a family instance, this could be a type family or data family synifyFamInst :: FamInst -> Bool -> Either ErrMsg (InstHead GhcRn) @@ -623,9 +805,9 @@ synifyFamInst fi opaque = do where ityp SynFamilyInst | opaque = return $ TypeInst Nothing ityp SynFamilyInst = - return . TypeInst . Just . unLoc $ synifyType WithinType fam_rhs + return . TypeInst . Just . unLoc $ synifyType WithinType [] fam_rhs ityp (DataFamilyInst c) = - DataInst <$> synifyTyCon (Just $ famInstAxiom fi) c + DataInst <$> synifyTyCon HideRuntimeRep (Just $ famInstAxiom fi) c fam_tc = famInstTyCon fi fam_flavor = fi_flavor fi fam_lhs = fi_tys fi @@ -645,7 +827,7 @@ synifyFamInst fi opaque = do = fam_lhs ts = filterOutInvisibleTypes fam_tc eta_expanded_lhs - synifyTypes = map (synifyType WithinType) + synifyTypes = map (synifyType WithinType []) ts' = synifyTypes ts annot_ts = zipWith3 annotHsType is_poly_tvs ts ts' is_poly_tvs = mkIsPolyTvs (tyConVisibleTyVars fam_tc) diff --git a/haddock-api/src/Haddock/GhcUtils.hs b/haddock-api/src/Haddock/GhcUtils.hs index a342de0068..24efc39f9f 100644 --- a/haddock-api/src/Haddock/GhcUtils.hs +++ b/haddock-api/src/Haddock/GhcUtils.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE BangPatterns, FlexibleInstances, ViewPatterns #-} +{-# LANGUAGE BangPatterns, StandaloneDeriving, FlexibleInstances, ViewPatterns #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleContexts #-} {-# OPTIONS_GHC -fno-warn-orphans #-} @@ -24,15 +24,24 @@ import Data.Char ( isSpace ) import Haddock.Types( DocNameI ) import Exception +import FastString ( fsLit ) +import FV import Outputable ( Outputable, panic, showPpr ) import Name import NameSet import Module +import PrelNames ( mkBaseModule ) import HscTypes import GHC import Class import DynFlags import SrcLoc ( advanceSrcLoc ) +import Var ( VarBndr(..), TyVarBinder, tyVarKind, updateTyVarKind, + isInvisibleArgFlag ) +import VarSet ( VarSet, emptyVarSet ) +import VarEnv ( TyVarEnv, extendVarEnv, elemVarEnv, emptyVarEnv ) +import TyCoRep ( Type(..), isRuntimeRepVar ) +import TysWiredIn( liftedRepDataConTyCon ) import StringBuffer ( StringBuffer ) import qualified StringBuffer as S @@ -156,6 +165,9 @@ nubByName f ns = go emptyNameSet ns where y = f x +dATA_LIST :: Module +dATA_LIST = mkBaseModule (fsLit "Data.List") + -- --------------------------------------------------------------------- -- This function is duplicated as getGADTConType and getGADTConTypeG, @@ -549,3 +561,104 @@ tryCppLine !loc !buf = spanSpace (S.prevChar buf '\n' == '\n') loc buf (c , b') -> spanCppLine (advanceSrcLoc l c) b' +------------------------------------------------------------------------------- +-- * Free variables of a 'Type' +------------------------------------------------------------------------------- + +-- | Get free type variables in a 'Type' in their order of appearance. +-- See [Ordering of implicit variables]. +orderedFVs + :: VarSet -- ^ free variables to ignore + -> [Type] -- ^ types to traverse (in order) looking for free variables + -> [TyVar] -- ^ free type variables, in the order they appear in +orderedFVs vs tys = + reverse . fst $ tyCoFVsOfTypes' tys (const True) vs ([], emptyVarSet) + + +-- See the "Free variables of types and coercions" section in 'TyCoRep', or +-- check out Note [Free variables of types]. The functions in this section +-- don't output type variables in the order they first appear in in the 'Type'. +-- +-- For example, 'tyCoVarsOfTypeList' reports an incorrect order for the type +-- of 'const :: a -> b -> a': +-- +-- >>> import Name +-- >>> import TyCoRep +-- >>> import TysPrim +-- >>> import Var +-- >>> a = TyVarTy alphaTyVar +-- >>> b = TyVarTy betaTyVar +-- >>> constTy = mkFunTys [a, b] a +-- >>> map (getOccString . tyVarName) (tyCoVarsOfTypeList constTy) +-- ["b","a"] +-- +-- However, we want to reuse the very optimized traversal machinery there, so +-- so we make our own `tyCoFVsOfType'`, `tyCoFVsBndr'`, and `tyCoVarsOfTypes'`. +-- All these do differently is traverse in a different order and ignore +-- coercion variables. + +-- | Just like 'tyCoFVsOfType', but traverses type variables in reverse order +-- of appearance. +tyCoFVsOfType' :: Type -> FV +tyCoFVsOfType' (TyVarTy v) a b c = (FV.unitFV v `unionFV` tyCoFVsOfType' (tyVarKind v)) a b c +tyCoFVsOfType' (TyConApp _ tys) a b c = tyCoFVsOfTypes' tys a b c +tyCoFVsOfType' (LitTy {}) a b c = emptyFV a b c +tyCoFVsOfType' (AppTy fun arg) a b c = (tyCoFVsOfType' arg `unionFV` tyCoFVsOfType' fun) a b c +tyCoFVsOfType' (FunTy arg res) a b c = (tyCoFVsOfType' res `unionFV` tyCoFVsOfType' arg) a b c +tyCoFVsOfType' (ForAllTy bndr ty) a b c = tyCoFVsBndr' bndr (tyCoFVsOfType' ty) a b c +tyCoFVsOfType' (CastTy ty _) a b c = (tyCoFVsOfType' ty) a b c +tyCoFVsOfType' (CoercionTy _ ) a b c = emptyFV a b c + +-- | Just like 'tyCoFVsOfTypes', but traverses type variables in reverse order +-- of appearance. +tyCoFVsOfTypes' :: [Type] -> FV +tyCoFVsOfTypes' (ty:tys) fv_cand in_scope acc = (tyCoFVsOfTypes' tys `unionFV` tyCoFVsOfType' ty) fv_cand in_scope acc +tyCoFVsOfTypes' [] fv_cand in_scope acc = emptyFV fv_cand in_scope acc + +-- | Just like 'tyCoFVsBndr', but traverses type variables in reverse order of +-- appearance. +tyCoFVsBndr' :: TyVarBinder -> FV -> FV +tyCoFVsBndr' (Bndr tv _) fvs = FV.delFV tv fvs `unionFV` tyCoFVsOfType' (tyVarKind tv) + + +------------------------------------------------------------------------------- +-- * Defaulting RuntimeRep variables +------------------------------------------------------------------------------- + +-- | Traverses the type, defaulting type variables of kind 'RuntimeRep' to +-- 'LiftedType'. See 'defaultRuntimeRepVars' in IfaceType.hs the original such +-- function working over `IfaceType`'s. +defaultRuntimeRepVars :: Type -> Type +defaultRuntimeRepVars = go emptyVarEnv + where + go :: TyVarEnv () -> Type -> Type + go subs (ForAllTy (Bndr var flg) ty) + | isRuntimeRepVar var + , isInvisibleArgFlag flg + = let subs' = extendVarEnv subs var () + in go subs' ty + | otherwise + = ForAllTy (Bndr (updateTyVarKind (go subs) var) flg) + (go subs ty) + + go subs (TyVarTy tv) + | tv `elemVarEnv` subs + = TyConApp liftedRepDataConTyCon [] + | otherwise + = TyVarTy (updateTyVarKind (go subs) tv) + + go subs (TyConApp tc tc_args) + = TyConApp tc (map (go subs) tc_args) + + go subs (FunTy arg res) + = FunTy (go subs arg) (go subs res) + + go subs (AppTy t u) + = AppTy (go subs t) (go subs u) + + go subs (CastTy x co) + = CastTy (go subs x) co + + go _ ty@(LitTy {}) = ty + go _ ty@(CoercionTy {}) = ty + diff --git a/haddock-api/src/Haddock/Interface.hs b/haddock-api/src/Haddock/Interface.hs index f1b2d45e89..133036566f 100644 --- a/haddock-api/src/Haddock/Interface.hs +++ b/haddock-api/src/Haddock/Interface.hs @@ -48,19 +48,20 @@ import Data.List import qualified Data.Map as Map import qualified Data.Set as Set import Distribution.Verbosity +import System.Exit import Text.Printf -import Module (mkModuleSet, emptyModuleSet, unionModuleSet, ModuleSet) import Digraph import DynFlags hiding (verbosity) import GHC hiding (verbosity) +import GhcMake import HscTypes import FastString (unpackFS) -import TcRnTypes (tcg_rdr_env) -import Name (nameIsFromExternalPackage, nameOccName) -import OccName (isTcOcc) -import RdrName (unQualOK, gre_name, globalRdrEnvElts) +import TcRnMonad import ErrUtils (withTiming) +import Outputable +import LoadIface +import GhcMonad #if defined(mingw32_HOST_OS) import System.IO @@ -88,7 +89,7 @@ processModules verbosity modules flags extIfaces = do out verbosity verbose "Creating interfaces..." let instIfaceMap = Map.fromList [ (instMod iface, iface) | ext <- extIfaces , iface <- ifInstalledIfaces ext ] - (interfaces, ms) <- createIfaces verbosity modules flags instIfaceMap + interfaces <- createIfaces verbosity modules flags instIfaceMap let exportedNames = Set.unions $ map (Set.fromList . ifaceExports) $ @@ -97,7 +98,7 @@ processModules verbosity modules flags extIfaces = do out verbosity verbose "Attaching instances..." interfaces' <- {-# SCC attachInstances #-} withTiming getDynFlags "attachInstances" (const ()) $ do - attachInstances (exportedNames, mods) interfaces instIfaceMap ms + attachInstances (exportedNames, mods) interfaces instIfaceMap out verbosity verbose "Building cross-linking environment..." -- Combine the link envs of the external packages into one @@ -121,56 +122,52 @@ processModules verbosity modules flags extIfaces = do -------------------------------------------------------------------------------- -createIfaces :: Verbosity -> [String] -> [Flag] -> InstIfaceMap -> Ghc ([Interface], ModuleSet) +createIfaces :: Verbosity -> [String] -> [Flag] -> InstIfaceMap -> Ghc [Interface] createIfaces verbosity modules flags instIfaceMap = do -- Ask GHC to tell us what the module graph is targets <- mapM (\filePath -> guessTarget filePath Nothing) modules setTargets targets modGraph <- depanal [] False + -- Create (if necessary) and load .hi-files. + success <- withTiming getDynFlags "load'" (const ()) $ do + load' LoadAllTargets Nothing modGraph + when (failed success) $ do + out verbosity normal "load' failed" + liftIO exitFailure + -- Visit modules in that order let sortedMods = flattenSCCs $ topSortModuleGraph False modGraph Nothing out verbosity normal "Haddock coverage:" - (ifaces, _, !ms) <- foldM f ([], Map.empty, emptyModuleSet) sortedMods - return (reverse ifaces, ms) + (ifaces, _) <- foldM f ([], Map.empty) sortedMods + return (reverse ifaces) where - f (ifaces, ifaceMap, !ms) modSummary = do + f (ifaces, ifaceMap) modSummary = do x <- {-# SCC processModule #-} withTiming getDynFlags "processModule" (const ()) $ do processModule verbosity modSummary flags ifaceMap instIfaceMap return $ case x of - Just (iface, ms') -> ( iface:ifaces - , Map.insert (ifaceMod iface) iface ifaceMap - , unionModuleSet ms ms' ) - Nothing -> ( ifaces - , ifaceMap - , ms ) -- Boot modules don't generate ifaces. + Just iface -> ( iface:ifaces + , Map.insert (ifaceMod iface) iface ifaceMap ) + Nothing -> ( ifaces + , ifaceMap ) -- Boot modules don't generate ifaces. -processModule :: Verbosity -> ModSummary -> [Flag] -> IfaceMap -> InstIfaceMap -> Ghc (Maybe (Interface, ModuleSet)) +processModule :: Verbosity -> ModSummary -> [Flag] -> IfaceMap -> InstIfaceMap -> Ghc (Maybe Interface) processModule verbosity modsum flags modMap instIfaceMap = do out verbosity verbose $ "Checking module " ++ moduleString (ms_mod modsum) ++ "..." - tm <- {-# SCC "parse/typecheck/load" #-} loadModule =<< typecheckModule =<< parseModule modsum + mod_iface <- withSession $ \hsc_env -> + liftIO $ initIfaceCheck (text "processModule 0") hsc_env $ + loadSysInterface (text "processModule 1") + (ms_mod modsum) + + let mod_loc = ms_location modsum if not $ isBootSummary modsum then do out verbosity verbose "Creating interface..." (interface, msgs) <- {-# SCC createIterface #-} - withTiming getDynFlags "createInterface" (const ()) $ do - runWriterGhc $ createInterface tm flags modMap instIfaceMap - - -- We need to keep track of which modules were somehow in scope so that when - -- Haddock later looks for instances, it also looks in these modules too. - -- - -- See https://github.com/haskell/haddock/issues/469. - hsc_env <- getSession - let new_rdr_env = tcg_rdr_env . fst . GHC.tm_internals_ $ tm - this_pkg = thisPackage (hsc_dflags hsc_env) - !mods = mkModuleSet [ nameModule name - | gre <- globalRdrEnvElts new_rdr_env - , let name = gre_name gre - , nameIsFromExternalPackage this_pkg name - , isTcOcc (nameOccName name) -- Types and classes only - , unQualOK gre ] -- In scope unqualified + withTiming getDynFlags "createInterface" (const ()) $ + runWriterGhc $ createInterface mod_iface mod_loc flags modMap instIfaceMap liftIO $ mapM_ putStrLn (nub msgs) dflags <- getDynFlags @@ -205,7 +202,7 @@ processModule verbosity modsum flags modMap instIfaceMap = do unless header $ out verbosity normal " Module header" mapM_ (out verbosity normal . (" " ++)) undocumentedExports interface' <- liftIO $ evaluate interface - return (Just (interface', mods)) + return (Just interface') else return Nothing diff --git a/haddock-api/src/Haddock/Interface/AttachInstances.hs b/haddock-api/src/Haddock/Interface/AttachInstances.hs index dd6c70a5f9..beb8df5172 100644 --- a/haddock-api/src/Haddock/Interface/AttachInstances.hs +++ b/haddock-api/src/Haddock/Interface/AttachInstances.hs @@ -34,11 +34,12 @@ import ErrUtils import FamInstEnv import GHC import InstEnv -import Module ( ModuleSet, moduleSetElts ) +import Module ( moduleSetElts, mkModuleSet ) import MonadUtils (liftIO) import Name import NameEnv import Outputable (text, sep, (<+>)) +import Packages ( ModuleOrigin(..), moduleToPkgConfAll ) import SrcLoc import TyCon import TyCoRep @@ -50,13 +51,30 @@ type Modules = Set.Set Module type ExportInfo = (ExportedNames, Modules) -- Also attaches fixities -attachInstances :: ExportInfo -> [Interface] -> InstIfaceMap -> ModuleSet -> Ghc [Interface] -attachInstances expInfo ifaces instIfaceMap mods = do +attachInstances :: ExportInfo -> [Interface] -> InstIfaceMap -> Ghc [Interface] +attachInstances expInfo ifaces instIfaceMap = do + + -- We need to keep load modules in which we will look for instances. We've + -- somewhat arbitrarily decided to load all modules which are available - + -- either directly or from a re-export. + -- + -- See https://github.com/haskell/haddock/issues/469. + dflags <- getDynFlags + let mod_to_pkg_conf = moduleToPkgConfAll (pkgState dflags) + mods = mkModuleSet [ m + | mod_map <- Map.elems mod_to_pkg_conf + , ( m + , ModOrigin { fromOrigPackage = fromOrig + , fromExposedReexport = reExp + } + ) <- Map.assocs mod_map + , fromOrig == Just True || not (null reExp) + ] + mods' = Just (moduleSetElts mods) + (_msgs, mb_index) <- getNameToInstancesIndex (map ifaceMod ifaces) mods' mapM (attach $ fromMaybe emptyNameEnv mb_index) ifaces where - mods' = Just (moduleSetElts mods) - -- TODO: take an IfaceMap as input ifaceMap = Map.fromList [ (ifaceMod i, i) | i <- ifaces ] diff --git a/haddock-api/src/Haddock/Interface/Create.hs b/haddock-api/src/Haddock/Interface/Create.hs index 36cfeaca91..f930e2b9a2 100644 --- a/haddock-api/src/Haddock/Interface/Create.hs +++ b/haddock-api/src/Haddock/Interface/Create.hs @@ -19,7 +19,6 @@ ----------------------------------------------------------------------------- module Haddock.Interface.Create (createInterface) where -import Documentation.Haddock.Doc (metaDocAppend) import Haddock.Types import Haddock.Options import Haddock.GhcUtils @@ -27,123 +26,134 @@ import Haddock.Utils import Haddock.Convert import Haddock.Interface.LexParseRn -import Data.Bifunctor -import Data.Bitraversable import qualified Data.Map as M import Data.Map (Map) import Data.List +import qualified Data.List.NonEmpty as NE import Data.Maybe -import Data.Ord -import Control.Applicative +import Control.Arrow ((&&&)) import Control.Monad import Data.Traversable import Avail hiding (avail) import qualified Avail -import qualified Module -import qualified SrcLoc import ConLike (ConLike(..)) import GHC +import GhcMonad import HscTypes import Name import NameSet -import NameEnv -import Packages ( lookupModuleInAllPackages, PackageName(..) ) -import Bag -import RdrName -import TcRnTypes -import FastString ( unpackFS, fastStringToByteString) -import BasicTypes ( StringLiteral(..), SourceText(..), PromotionFlag(..) ) +import qualified Outputable +import Packages ( PackageName(..) ) +import TcIface +import TcRnMonad +import FastString ( unpackFS ) +import BasicTypes ( WarningSort(..), warningTxtContents + , TupleSort(..), Boxity(..), PromotionFlag(..) ) import qualified Outputable as O +import DynFlags ( getDynFlags ) +import TysPrim ( funTyConName ) +import TysWiredIn ( listTyConName, nilDataConName, consDataConName, eqTyConName + , tupleDataCon, tupleTyConName) +import PrelNames ( dATA_TUPLE, pRELUDE, gHC_PRIM, gHC_TYPES ) - --- | Use a 'TypecheckedModule' to produce an 'Interface'. +-- | Use a 'ModIface' to produce an 'Interface'. -- To do this, we need access to already processed modules in the topological -- sort. That's what's in the 'IfaceMap'. -createInterface :: TypecheckedModule +createInterface :: ModIface + -> ModLocation -> [Flag] -- Boolean flags -> IfaceMap -- Locally processed modules -> InstIfaceMap -- External, already installed interfaces -> ErrMsgGhc Interface -createInterface tm flags modMap instIfaceMap = do - - let ms = pm_mod_summary . tm_parsed_module $ tm - mi = moduleInfo tm - L _ hsm = parsedSource tm - !safety = modInfoSafe mi - mdl = ms_mod ms - sem_mdl = tcg_semantic_mod (fst (tm_internals_ tm)) - is_sig = ms_hsc_src ms == HsigFile - dflags = ms_hspp_opts ms - !instances = modInfoInstances mi - !fam_instances = md_fam_insts md - !exportedNames = modInfoExportsWithSelectors mi +createInterface mod_iface mod_loc flags modMap instIfaceMap = do + dflags <- getDynFlags + + let mdl = mi_module mod_iface + sem_mdl = mi_semantic_module mod_iface + is_sig = isJust (mi_sig_of mod_iface) + safety = getSafeMode (mi_trust mod_iface) + + -- Not sure whether the relevant info is in these dflags (pkgNameFS, _) = modulePackageInfo dflags flags (Just mdl) pkgName = fmap (unpackFS . (\(PackageName n) -> n)) pkgNameFS + warnings = mi_warns mod_iface + + -- See Note [Exporting built-in items] + special_exports + | mdl == gHC_TYPES = listAvail <> eqAvail + | mdl == gHC_PRIM = funAvail + | mdl == pRELUDE = listAvail <> funAvail + | mdl == dATA_TUPLE = tupsAvail + | mdl == dATA_LIST = listAvail + | otherwise = [] + !exportedNames = concatMap availNamesWithSelectors + (special_exports <> mi_exports mod_iface) + + fixMap = mkFixMap exportedNames (mi_fixities mod_iface) + + mod_iface_docs <- case mi_docs mod_iface of + Just docs -> pure docs + Nothing -> do + liftErrMsg $ tell [O.showPpr dflags mdl ++ " has no docs in its .hi-file"] + pure emptyDocs - (TcGblEnv { tcg_rdr_env = gre - , tcg_warns = warnings - , tcg_exports = all_exports - }, md) = tm_internals_ tm - - -- The 'pkgName' is necessary to decide what package to mention in "@since" - -- annotations. Not having it is not fatal though. - -- - -- Cabal can be trusted to pass the right flags, so this warning should be - -- mostly encountered when running Haddock outside of Cabal. - when (isNothing pkgName) $ - liftErrMsg $ tell [ "Warning: Package name is not available." ] - - -- The renamed source should always be available to us, but it's best - -- to be on the safe side. - (group_, imports, mayExports, mayDocHeader) <- - case renamedSource tm of - Nothing -> do - liftErrMsg $ tell [ "Warning: Renamed source is not available." ] - return (emptyRnGroup, [], Nothing, Nothing) - Just x -> return x - - opts <- liftErrMsg $ mkDocOpts (haddockOptions dflags) flags mdl + opts <- liftErrMsg $ mkDocOpts (docs_haddock_opts mod_iface_docs) flags mdl + let prr | OptPrintRuntimeRep `elem` opts = ShowRuntimeRep + | otherwise = HideRuntimeRep -- Process the top-level module header documentation. - (!info, mbDoc) <- liftErrMsg $ processModuleHeader dflags pkgName gre safety mayDocHeader + (!info, mbDoc) <- processModuleHeader pkgName safety + (docs_language mod_iface_docs) + (docs_extensions mod_iface_docs) + (docs_mod_hdr mod_iface_docs) - let declsWithDocs = topDecls group_ + modWarn <- moduleWarning warnings - exports0 = fmap (map (first unLoc)) mayExports - exports - | OptIgnoreExports `elem` opts = Nothing - | otherwise = exports0 + let process = processDocStringParas pkgName + docMap <- traverse process (docs_decls mod_iface_docs) + argMap <- traverse (traverse process) (docs_args mod_iface_docs) - unrestrictedImportedMods - -- module re-exports are only possible with - -- explicit export list - | Just{} <- exports - = unrestrictedModuleImports (map unLoc imports) - | otherwise = M.empty + warningMap <- mkWarningMap warnings exportedNames - fixMap = mkFixMap group_ - (decls, _) = unzip declsWithDocs - localInsts = filter (nameIsLocalOrFrom sem_mdl) + -- Are these all the (fam_)instances that we need? + (instances, fam_instances) <- liftGhcToErrMsgGhc $ withSession $ \hsc_env -> liftIO $ + (md_insts &&& md_fam_insts) + <$> initIfaceCheck (Outputable.text "createInterface'") hsc_env + (typecheckIface mod_iface) + let localInsts = filter (nameIsLocalOrFrom sem_mdl) $ map getName instances ++ map getName fam_instances - -- Locations of all TH splices - splices = [ l | L l (SpliceD _ _) <- hsmodDecls hsm ] - - warningMap <- liftErrMsg (mkWarningMap dflags warnings gre exportedNames) - - maps@(!docMap, !argMap, !declMap, _) <- - liftErrMsg (mkMaps dflags pkgName gre localInsts declsWithDocs) + instanceMap = M.fromList (map (getSrcSpan &&& id) localInsts) let allWarnings = M.unions (warningMap : map ifaceWarningMap (M.elems modMap)) + -- Locations of all TH splices + -- TODO: We use the splice info in 'Haddock.Backends.Xhtml.Layout.links' to + -- determine what kind of link we want to generate. Since we depend on + -- declaration locations there, it makes sense to get the splice locations + -- together with the other locations from the extended .hie files. + splices = [] + + -- See Note [Exporting built-in items] + let builtinTys = DsiSectionHeading 1 (HsDoc (mkHsDocString "Builtin syntax") []) + bonus_ds mods + | mdl == gHC_TYPES = [ DsiExports (listAvail <> eqAvail) ] <> mods + | mdl == gHC_PRIM = [ builtinTys, DsiExports funAvail ] <> mods + | mdl == pRELUDE = let (hs, rest) = splitAt 2 mods + in hs <> [ DsiExports (listAvail <> funAvail) ] <> rest + | mdl == dATA_TUPLE = mods <> [ DsiExports tupsAvail ] + | mdl == dATA_LIST = [ DsiExports listAvail ] <> mods + | otherwise = mods + -- The MAIN functionality: compute the export items which will -- each be the actual documentation of this module. - exportItems <- mkExportItems is_sig modMap pkgName mdl sem_mdl allWarnings gre - exportedNames decls maps fixMap unrestrictedImportedMods - splices exports all_exports instIfaceMap dflags + exportItems <- mkExportItems prr modMap pkgName mdl allWarnings + docMap argMap fixMap splices + (docs_named_chunks mod_iface_docs) + (bonus_ds $ docs_structure mod_iface_docs) instIfaceMap - let !visibleNames = mkVisibleNames maps exportItems opts + let !visibleNames = mkVisibleNames instanceMap exportItems opts -- Measure haddock documentation coverage. let prunedExportItems0 = pruneExportItems exportItems @@ -158,15 +168,9 @@ createInterface tm flags modMap instIfaceMap = do | otherwise = exportItems !prunedExportItems = seqList prunedExportItems' `seq` prunedExportItems' - let !aliases = - mkAliasMap dflags $ tm_renamed_source tm - - modWarn <- liftErrMsg (moduleWarning dflags gre warnings) - return $! Interface { ifaceMod = mdl , ifaceIsSig = is_sig - , ifaceOrigFilename = msHsFilePath ms , ifaceInfo = info , ifaceDoc = Documentation mbDoc modWarn , ifaceRnDoc = Documentation Nothing Nothing @@ -179,128 +183,130 @@ createInterface tm flags modMap instIfaceMap = do , ifaceRnExportItems = [] , ifaceExports = exportedNames , ifaceVisibleExports = visibleNames - , ifaceDeclMap = declMap , ifaceFixMap = fixMap - , ifaceModuleAliases = aliases , ifaceInstances = instances , ifaceFamInstances = fam_instances - , ifaceOrphanInstances = [] -- Filled in `attachInstances` - , ifaceRnOrphanInstances = [] -- Filled in `renameInterface` + , ifaceOrphanInstances = [] + , ifaceRnOrphanInstances = [] , ifaceHaddockCoverage = coverage , ifaceWarningMap = warningMap - , ifaceHieFile = Just $ ml_hie_file $ ms_location ms + , ifaceHieFile = Just $ ml_hie_file mod_loc , ifaceDynFlags = dflags } + where + -- Note [Exporting built-in items] + -- + -- Some items do not show up in their modules exports simply because Haskell + -- lacks the concrete syntax to represent such an export. We'd still like + -- these to show up in docs, so we manually patch on some extra exports for a + -- small number of modules: + -- + -- * "GHC.Prim" should export @(->)@ + -- * "GHC.Types" should export @[]([], (:))@ and @(~)@ + -- * "Prelude" should export @(->)@ and @[]([], (:))@ + -- * "Data.Tuple" should export tuples up to arity 15 (that is the number + -- that Haskell98 guarantees exist and that it also the point at which + -- GHC stops providing instances) + -- + listAvail = [ AvailTC listTyConName + [listTyConName, nilDataConName, consDataConName] + [] ] + funAvail = [ AvailTC funTyConName [funTyConName] [] ] + eqAvail = [ AvailTC eqTyConName [eqTyConName] [] ] + tupsAvail = [ AvailTC tyName [tyName, datName] [] + | i<-[0..15] + , let tyName = tupleTyConName BoxedTuple i + , let datName = getName $ tupleDataCon Boxed i + ] --- | Given all of the @import M as N@ declarations in a package, --- create a mapping from the module identity of M, to an alias N --- (if there are multiple aliases, we pick the last one.) This --- will go in 'ifaceModuleAliases'. -mkAliasMap :: DynFlags -> Maybe RenamedSource -> M.Map Module ModuleName -mkAliasMap dflags mRenamedSource = - case mRenamedSource of - Nothing -> M.empty - Just (_,impDecls,_,_) -> - M.fromList $ - mapMaybe (\(SrcLoc.L _ impDecl) -> do - SrcLoc.L _ alias <- ideclAs impDecl - return $ - (lookupModuleDyn dflags - -- TODO: This is supremely dodgy, because in general the - -- UnitId isn't going to look anything like the package - -- qualifier (even with old versions of GHC, the - -- IPID would be p-0.1, but a package qualifier never - -- has a version number it. (Is it possible that in - -- Haddock-land, the UnitIds never have version numbers? - -- I, ezyang, have not quite understand Haddock's package - -- identifier model.) - -- - -- Additionally, this is simulating some logic GHC already - -- has for deciding how to qualify names when it outputs - -- them to the user. We should reuse that information; - -- or at least reuse the renamed imports, which know what - -- they import! - (fmap Module.fsToUnitId $ - fmap sl_fs $ ideclPkgQual impDecl) - (case ideclName impDecl of SrcLoc.L _ name -> name), - alias)) - impDecls - --- We want to know which modules are imported without any qualification. This --- way we can display module reexports more compactly. This mapping also looks --- through aliases: +-- | Given the information that comes out of a 'DsiModExport', decide which of +-- the re-exported modules can be linked directly and which modules need to have +-- their avails inlined. We can link directly to a module when: -- --- module M (module X) where --- import M1 as X --- import M2 as X +-- * all of the stuff avail from that module is also available here +-- * that module is not marked as hidden -- --- With our mapping we know that we can display exported modules M1 and M2. --- -unrestrictedModuleImports :: [ImportDecl name] -> M.Map ModuleName [ModuleName] -unrestrictedModuleImports idecls = - M.map (map (unLoc . ideclName)) - $ M.filter (all isInteresting) impModMap +-- TODO: Do we need a special case for the current module? +unrestrictedModExports + :: IfaceMap + -> Avails + -> [ModuleName] + -> ErrMsgGhc ([Module], Avails) + -- ^ ( modules exported without restriction + -- , remaining exports not included in any + -- of these modules + -- ) +unrestrictedModExports ifaceMap avails mod_names = do + mods_and_exports <- fmap catMaybes $ for mod_names $ \mod_name -> do + mdl <- liftGhcToErrMsgGhc $ findModule mod_name Nothing + mb_modinfo <- liftGhcToErrMsgGhc $ getModuleInfo mdl + case mb_modinfo of + Nothing -> do + dflags <- getDynFlags + liftErrMsg $ tell [ "Bug: unrestrictedModExports: " ++ pretty dflags mdl] + pure Nothing + Just modinfo -> + pure (Just (mdl, mkNameSet (modInfoExportsWithSelectors modinfo))) + let unrestricted = filter everythingVisible mods_and_exports + mod_exps = unionNameSets (map snd unrestricted) + remaining = nubAvails (filterAvails (\n -> not (n `elemNameSet` mod_exps)) avails) + pure (map fst unrestricted, remaining) where - impModMap = - M.fromListWith (++) (concatMap moduleMapping idecls) - - moduleMapping idecl = - concat [ [ (unLoc (ideclName idecl), [idecl]) ] - , [ (unLoc mod_name, [idecl]) - | Just mod_name <- [ideclAs idecl] - ] - ] - - isInteresting idecl = - case ideclHiding idecl of - -- i) no subset selected - Nothing -> True - -- ii) an import with a hiding clause - -- without any names - Just (True, L _ []) -> True - -- iii) any other case of qualification - _ -> False - --- Similar to GHC.lookupModule --- ezyang: Not really... -lookupModuleDyn :: - DynFlags -> Maybe UnitId -> ModuleName -> Module -lookupModuleDyn _ (Just pkgId) mdlName = - Module.mkModule pkgId mdlName -lookupModuleDyn dflags Nothing mdlName = - case lookupModuleInAllPackages dflags mdlName of - (m,_):_ -> m - [] -> Module.mkModule Module.mainUnitId mdlName + all_names = availsToNameSetWithSelectors avails + + -- Is everything in this (supposedly re-exported) module visible? + everythingVisible :: (Module, NameSet) -> Bool + everythingVisible (mdl, exps) + | not (exps `isSubsetOf` all_names) = False + | Just iface <- M.lookup mdl ifaceMap = OptHide `notElem` ifaceOptions iface + | otherwise = True + + -- TODO: Add a utility based on IntMap.isSubmapOfBy + isSubsetOf :: NameSet -> NameSet -> Bool + isSubsetOf a b = nameSetAll (`elemNameSet` b) a ------------------------------------------------------------------------------- -- Warnings ------------------------------------------------------------------------------- -mkWarningMap :: DynFlags -> Warnings -> GlobalRdrEnv -> [Name] -> ErrMsgM WarningMap -mkWarningMap dflags warnings gre exps = case warnings of +-- TODO: Either find a different way of looking up the OccNames or change the Warnings or +-- WarningMap type. +mkWarningMap :: Warnings (HsDoc Name) -> [Name] -> ErrMsgGhc WarningMap +mkWarningMap warnings exps = case warnings of NoWarnings -> pure M.empty WarnAll _ -> pure M.empty WarnSome ws -> + -- Not sure if this is equivalent to the original code below. + let expsOccEnv = mkOccEnv [(nameOccName n, n) | n <- exps] + ws' = flip mapMaybe ws $ \(occ, w) -> + (,w) <$> lookupOccEnv expsOccEnv occ + {- let ws' = [ (n, w) | (occ, w) <- ws , elt <- lookupGlobalRdrEnv gre occ , let n = gre_name elt, n `elem` exps ] - in M.fromList <$> traverse (bitraverse pure (parseWarning dflags gre)) ws' - -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 -> ErrMsgM (Doc Name) -parseWarning dflags gre w = case w of - DeprecatedTxt _ msg -> format "Deprecated: " (foldMap (fastStringToByteString . sl_fs . unLoc) msg) - WarningTxt _ msg -> format "Warning: " (foldMap (fastStringToByteString . sl_fs . unLoc) msg) + -} + in M.fromList <$> traverse (traverse parseWarning) ws' + +moduleWarning :: Warnings (HsDoc Name) -> ErrMsgGhc (Maybe (Doc Name)) +moduleWarning = \case + NoWarnings -> pure Nothing + WarnSome _ -> pure Nothing + WarnAll w -> Just <$> parseWarning w + +parseWarning :: WarningTxt (HsDoc Name) -> ErrMsgGhc (Doc Name) +parseWarning w = + -- TODO: Find something more efficient than (foldl' appendHsDoc) + format heading (foldl' appendHsDoc emptyHsDoc msgs) where - format x bs = DocWarning . DocParagraph . DocAppend (DocString x) - <$> processDocString dflags gre (mkHsDocStringUtf8ByteString bs) + format x msg = DocWarning . DocParagraph . DocAppend (DocString x) + <$> processDocString msg + heading = case sort_ of + WsWarning -> "Warning: " + WsDeprecated -> "Deprecated: " + (sort_, msgs) = warningTxtContents w ------------------------------------------------------------------------------- @@ -325,447 +331,121 @@ mkDocOpts mbOpts flags mdl = do go os m | m == Flag_HideModule mdlStr = OptHide : os | m == Flag_ShowModule mdlStr = filter (/= OptHide) os | m == Flag_ShowAllModules = filter (/= OptHide) os - | m == Flag_IgnoreAllExports = OptIgnoreExports : os - | m == Flag_ShowExtensions mdlStr = OptIgnoreExports : os + | m == Flag_ShowExtensions mdlStr = OptShowExtensions : os | otherwise = os parseOption :: String -> ErrMsgM (Maybe DocOption) parseOption "hide" = return (Just OptHide) parseOption "prune" = return (Just OptPrune) -parseOption "ignore-exports" = return (Just OptIgnoreExports) parseOption "not-home" = return (Just OptNotHome) parseOption "show-extensions" = return (Just OptShowExtensions) +parseOption "print-explicit-runtime-reps" = return (Just OptPrintRuntimeRep) parseOption other = tell ["Unrecognised option: " ++ other] >> return Nothing - --------------------------------------------------------------------------------- --- Maps --------------------------------------------------------------------------------- - - -type Maps = (DocMap Name, ArgMap Name, DeclMap, InstMap) - --- | Create 'Maps' by looping through the declarations. For each declaration, --- find its names, its subordinates, and its doc strings. Process doc strings --- into 'Doc's. -mkMaps :: DynFlags - -> Maybe Package -- this package - -> GlobalRdrEnv - -> [Name] - -> [(LHsDecl GhcRn, [HsDocString])] - -> ErrMsgM Maps -mkMaps dflags pkgName gre instances decls = do - (a, b, c) <- unzip3 <$> traverse mappings decls - pure ( f' (map (nubByName fst) a) - , f (filterMapping (not . M.null) b) - , f (filterMapping (not . null) c) - , instanceMap - ) - where - f :: (Ord a, Monoid b) => [[(a, b)]] -> Map a b - f = M.fromListWith (<>) . concat - - 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]) - -> ErrMsgM ( [(Name, MDoc Name)] - , [(Name, Map Int (MDoc Name))] - , [(Name, [LHsDecl GhcRn])] - ) - mappings (ldecl, docStrs) = do - let L l decl = ldecl - declDoc :: [HsDocString] -> Map Int HsDocString - -> ErrMsgM (Maybe (MDoc Name), Map Int (MDoc Name)) - declDoc strs m = do - doc' <- processDocStrings dflags pkgName gre strs - m' <- traverse (processDocStringParas dflags pkgName gre) m - pure (doc', m') - - (doc, args) <- declDoc docStrs (declTypeDocs decl) - - let - subs :: [(Name, [HsDocString], Map Int HsDocString)] - subs = subordinates instanceMap decl - - (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 - cm = [ (n, [ldecl]) | n <- ns ++ subNs ] - - seqList ns `seq` - seqList subNs `seq` - doc `seq` - seqList subDocs `seq` - seqList subArgs `seq` - pure (dm, am, cm) - - instanceMap :: Map SrcSpan Name - instanceMap = M.fromList [ (getSrcSpan n, n) | n <- instances ] - - names :: SrcSpan -> HsDecl GhcRn -> [Name] - names _ (InstD _ d) = maybeToList (M.lookup loc instanceMap) -- See note [2]. - where loc = case d of - -- The CoAx's loc is the whole line, but only for TFs. The - -- workaround is to dig into the family instance declaration and - -- get the identifier with the right location. - TyFamInstD _ (TyFamInstDecl d') -> getLoc (feqn_tycon (hsib_body d')) - _ -> getInstLoc d - names l (DerivD {}) = maybeToList (M.lookup l instanceMap) -- See note [2]. - names _ decl = getMainDeclBinder decl - --- Note [2]: ------------- --- We relate ClsInsts to InstDecls and DerivDecls using the SrcSpans buried --- inside them. That should work for normal user-written instances (from --- looking at GHC sources). We can assume that commented instances are --- user-written. This lets us relate Names (from ClsInsts) to comments --- (associated with InstDecls and DerivDecls). - --------------------------------------------------------------------------------- --- Declarations --------------------------------------------------------------------------------- - - --- | 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 decl = case decl of - InstD _ (ClsInstD _ d) -> do - DataFamInstDecl { dfid_eqn = HsIB { hsib_body = - FamEqn { feqn_tycon = L l _ - , feqn_rhs = defn }}} <- unLoc <$> cid_datafam_insts d - [ (n, [], M.empty) | Just n <- [M.lookup l instMap] ] ++ dataSubs defn - - InstD _ (DataFamInstD _ (DataFamInstDecl (HsIB { hsib_body = d }))) - -> dataSubs (feqn_rhs d) - TyClD _ d | isClassDecl d -> classSubs d - | isDataDecl d -> dataSubs (tcdDataDefn d) - _ -> [] - where - classSubs dd = [ (name, doc, declTypeDocs d) | (L _ d, doc) <- classDecls dd - , name <- getMainDeclBinder d, not (isValD d) - ] - dataSubs :: HsDataDefn GhcRn -> [(Name, [HsDocString], Map Int HsDocString)] - dataSubs dd = constrs ++ fields ++ derivs - where - cons = map unL $ (dd_cons dd) - constrs = [ (unL cname, maybeToList $ fmap unL $ con_doc c, conArgDocs c) - | c <- cons, cname <- getConNames c ] - fields = [ (extFieldOcc n, maybeToList $ fmap unL doc, M.empty) - | RecCon flds <- map getConArgs cons - , L _ (ConDeclField _ ns _ doc) <- (unLoc flds) - , L _ n <- ns ] - derivs = [ (instName, [unL doc], M.empty) - | HsIB { hsib_body = L l (HsDocTy _ _ doc) } - <- concatMap (unLoc . deriv_clause_tys . unLoc) $ - unLoc $ dd_derivs dd - , Just instName <- [M.lookup l instMap] ] - --- | Extract constructor argument docs from inside constructor decls. -conArgDocs :: ConDecl GhcRn -> Map Int HsDocString -conArgDocs con = case getConArgs con of - PrefixCon args -> go 0 (map unLoc args ++ ret) - InfixCon arg1 arg2 -> go 0 ([unLoc arg1, unLoc arg2] ++ ret) - RecCon _ -> go 1 ret - where - go n (HsDocTy _ _ (L _ ds) : tys) = M.insert n ds $ go (n+1) tys - go n (HsBangTy _ _ (L _ (HsDocTy _ _ (L _ ds))) : tys) = M.insert n ds $ go (n+1) tys - go n (_ : tys) = go (n+1) tys - go _ [] = M.empty - - ret = case con of - ConDeclGADT { con_res_ty = res_ty } -> [ unLoc res_ty ] - _ -> [] - --- | Extract function argument docs from inside top-level decls. -declTypeDocs :: HsDecl GhcRn -> Map Int HsDocString -declTypeDocs (SigD _ (TypeSig _ _ ty)) = typeDocs (unLoc (hsSigWcType ty)) -declTypeDocs (SigD _ (ClassOpSig _ _ _ ty)) = typeDocs (unLoc (hsSigType ty)) -declTypeDocs (SigD _ (PatSynSig _ _ ty)) = typeDocs (unLoc (hsSigType ty)) -declTypeDocs (ForD _ (ForeignImport _ _ ty _)) = typeDocs (unLoc (hsSigType ty)) -declTypeDocs (TyClD _ (SynDecl { tcdRhs = ty })) = typeDocs (unLoc ty) -declTypeDocs _ = M.empty - --- | Extract function argument docs from inside types. -typeDocs :: HsType GhcRn -> Map Int HsDocString -typeDocs = go 0 - where - 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 - go _ _ = M.empty - --- | All the sub declarations of a class (that we handle), ordered by --- source location, with documentation attached if it exists. -classDecls :: TyClDecl GhcRn -> [(LHsDecl GhcRn, [HsDocString])] -classDecls class_ = filterDecls . collectDocs . sortByLoc $ decls - where - decls = docs ++ defs ++ sigs ++ ats - docs = mkDecls tcdDocs (DocD noExt) class_ - defs = mkDecls (bagToList . tcdMeths) (ValD noExt) class_ - sigs = mkDecls tcdSigs (SigD noExt) class_ - ats = mkDecls tcdATs (TyClD noExt . FamDecl noExt) class_ - - --- | The top-level declarations of a module that we care about, --- ordered by source location, with documentation attached if it exists. -topDecls :: HsGroup GhcRn -> [(LHsDecl GhcRn, [HsDocString])] -topDecls = - filterClasses . filterDecls . collectDocs . sortByLoc . ungroup - -- | Extract a map of fixity declarations only -mkFixMap :: HsGroup GhcRn -> FixMap -mkFixMap group_ = M.fromList [ (n,f) - | L _ (FixitySig _ ns f) <- hs_fixds group_, - L _ n <- ns ] - - --- | Take all declarations except pragmas, infix decls, rules from an 'HsGroup'. -ungroup :: HsGroup GhcRn -> [LHsDecl GhcRn] -ungroup group_ = - mkDecls (tyClGroupTyClDecls . hs_tyclds) (TyClD noExt) group_ ++ - mkDecls hs_derivds (DerivD noExt) group_ ++ - mkDecls hs_defds (DefD noExt) group_ ++ - mkDecls hs_fords (ForD noExt) group_ ++ - mkDecls hs_docs (DocD noExt) group_ ++ - mkDecls (tyClGroupInstDecls . hs_tyclds) (InstD noExt) group_ ++ - mkDecls (typesigs . hs_valds) (SigD noExt) group_ ++ - mkDecls (valbinds . hs_valds) (ValD noExt) group_ +mkFixMap :: [Name] -> [(OccName, Fixity)] -> FixMap +mkFixMap exps occFixs = + M.fromList $ flip mapMaybe occFixs $ \(occ, fix_) -> + (,fix_) <$> lookupOccEnv expsOccEnv occ where - typesigs (XValBindsLR (NValBinds _ sigs)) = filter isUserLSig sigs - typesigs _ = error "expected ValBindsOut" - - valbinds (XValBindsLR (NValBinds binds _)) = concatMap bagToList . snd . unzip $ binds - valbinds _ = error "expected ValBindsOut" - - --- | Take a field of declarations from a data structure and create HsDecls --- using the given constructor -mkDecls :: (a -> [Located b]) -> (b -> c) -> a -> [Located c] -mkDecls field con struct = [ L loc (con decl) | L loc decl <- field struct ] - - --- | Sort by source location -sortByLoc :: [Located a] -> [Located a] -sortByLoc = sortBy (comparing getLoc) - - --------------------------------------------------------------------------------- --- Filtering of declarations --- --- We filter out declarations that we don't intend to handle later. --------------------------------------------------------------------------------- - + expsOccEnv = mkOccEnv (map (nameOccName &&& id) exps) --- | Filter out declarations that we don't handle in Haddock -filterDecls :: [(LHsDecl a, doc)] -> [(LHsDecl a, doc)] -filterDecls = filter (isHandled . unL . fst) - where - isHandled (ForD _ (ForeignImport {})) = True - isHandled (TyClD {}) = True - isHandled (InstD {}) = True - isHandled (DerivD {}) = True - isHandled (SigD _ d) = isUserLSig (reL d) - isHandled (ValD {}) = True - -- we keep doc declarations to be able to get at named docs - isHandled (DocD {}) = True - isHandled _ = False - --- | Go through all class declarations and filter their sub-declarations -filterClasses :: [(LHsDecl a, doc)] -> [(LHsDecl a, doc)] -filterClasses decls = [ if isClassD d then (L loc (filterClass d), doc) else x - | x@(L loc d, doc) <- decls ] - where - filterClass (TyClD x c) = - TyClD x $ c { tcdSigs = filter (liftA2 (||) isUserLSig isMinimalLSig) $ tcdSigs c } - filterClass _ = error "expected TyClD" - - --------------------------------------------------------------------------------- --- Collect docs --- --- To be able to attach the right Haddock comment to the right declaration, --- we sort the declarations by their SrcLoc and "collect" the docs for each --- declaration. --------------------------------------------------------------------------------- - - --- | Collect docs and attach them to the right declarations. -collectDocs :: [LHsDecl a] -> [(LHsDecl a, [HsDocString])] -collectDocs = go Nothing [] - where - go Nothing _ [] = [] - go (Just prev) docs [] = finished prev docs [] - go prev docs (L _ (DocD _ (DocCommentNext str)) : ds) - | Nothing <- prev = go Nothing (str:docs) ds - | Just decl <- prev = finished decl docs (go Nothing [str] ds) - go prev docs (L _ (DocD _ (DocCommentPrev str)) : ds) = go prev (str:docs) ds - go Nothing docs (d:ds) = go (Just d) docs ds - go (Just prev) docs (d:ds) = finished prev docs (go (Just d) [] ds) - - finished decl docs rest = (decl, reverse docs) : rest - - --- | Build the list of items that will become the documentation, from the --- export list. At this point, the list of ExportItems is in terms of --- original names. --- --- We create the export items even if the module is hidden, since they --- might be useful when creating the export items for other modules. mkExportItems - :: Bool -- is it a signature + :: PrintRuntimeReps -> IfaceMap -> Maybe Package -- this package -> Module -- this module - -> Module -- semantic module -> WarningMap - -> GlobalRdrEnv - -> [Name] -- exported names (orig) - -> [LHsDecl GhcRn] -- renamed source declarations - -> Maps + -> DocMap Name -- docs (keyed by 'Name's) + -> ArgMap Name -- docs for arguments (keyed by 'Name's) -> FixMap - -> M.Map ModuleName [ModuleName] -> [SrcSpan] -- splice locations - -> Maybe [(IE GhcRn, Avails)] - -> Avails -- exported stuff from this module + -> Map String (HsDoc Name) -- named chunks + -> DocStructure -> InstIfaceMap - -> DynFlags -> ErrMsgGhc [ExportItem GhcRn] mkExportItems - is_sig modMap pkgName thisMod semMod warnings gre exportedNames decls - maps fixMap unrestricted_imp_mods splices exportList allExports - instIfaceMap dflags = - case exportList of - Nothing -> - fullModuleContents is_sig modMap pkgName thisMod semMod warnings gre - exportedNames decls maps fixMap splices instIfaceMap dflags - allExports - Just exports -> liftM concat $ mapM lookupExport exports + prr modMap mbPkgName thisMod warnings + docMap argMap fixMap splices namedChunks dsItems instIfaceMap = + concat <$> traverse lookupExport dsItems where - lookupExport (IEGroup _ lev docStr, _) = liftErrMsg $ do - doc <- processDocString dflags gre docStr - return [ExportGroup lev "" doc] - - lookupExport (IEDoc _ docStr, _) = liftErrMsg $ do - doc <- processDocStringParas dflags pkgName gre docStr - return [ExportDoc doc] - - lookupExport (IEDocNamed _ str, _) = liftErrMsg $ - findNamedDoc str [ unL d | d <- decls ] >>= \case - Nothing -> return [] - Just docStr -> do - doc <- processDocStringParas dflags pkgName gre docStr - return [ExportDoc doc] - - lookupExport (IEModuleContents _ (L _ mod_name), _) - -- only consider exporting a module if we are sure we - -- are really exporting the whole module and not some - -- subset. We also look through module aliases here. - | Just mods <- M.lookup mod_name unrestricted_imp_mods - , not (null mods) - = concat <$> traverse (moduleExport thisMod dflags modMap instIfaceMap) mods - - lookupExport (_, avails) = - concat <$> traverse availExport (nubAvails avails) + lookupExport :: DocStructureItem -> ErrMsgGhc [ExportItem GhcRn] + lookupExport = \case + DsiSectionHeading lev hsDoc -> do + doc <- processDocString hsDoc + pure [ExportGroup lev "" doc] + DsiDocChunk hsDoc -> do + doc <- processDocStringParas mbPkgName hsDoc + pure [ExportDoc doc] + DsiNamedChunkRef ref -> do + case M.lookup ref namedChunks of + Nothing -> do + liftErrMsg $ tell ["Cannot find documentation for: $" ++ ref] + pure [] + Just hsDoc -> do + doc <- processDocStringParas mbPkgName hsDoc + pure [ExportDoc doc] + DsiExports avails -> + -- TODO: We probably don't need nubAvails here. + -- mkDocStructureFromExportList already uses it. + concat <$> traverse availExport (nubAvails avails) + DsiModExport mod_names avails -> do + -- only consider exporting a module if we are sure we are really + -- exporting the whole module and not some subset. + (unrestricted_mods, remaining_avails) <- unrestrictedModExports modMap avails (NE.toList mod_names) + avail_exps <- concat <$> traverse availExport remaining_avails + pure (map ExportModule unrestricted_mods ++ avail_exps) availExport avail = - availExportItem is_sig modMap thisMod semMod warnings exportedNames - maps fixMap splices instIfaceMap dflags avail + availExportItem prr modMap thisMod warnings + docMap argMap fixMap splices instIfaceMap avail -availExportItem :: Bool -- is it a signature +availExportItem :: PrintRuntimeReps -> IfaceMap -> Module -- this module - -> Module -- semantic module -> WarningMap - -> [Name] -- exported names (orig) - -> Maps + -> DocMap Name -- docs (keyed by 'Name's) + -> ArgMap Name -- docs for arguments (keyed by 'Name's) -> FixMap -> [SrcSpan] -- splice locations -> InstIfaceMap - -> DynFlags -> AvailInfo -> ErrMsgGhc [ExportItem GhcRn] -availExportItem is_sig modMap thisMod semMod warnings exportedNames - (docMap, argMap, declMap, _) fixMap splices instIfaceMap - dflags availInfo = declWith availInfo +availExportItem prr modMap thisMod warnings + docMap argMap fixMap _splices instIfaceMap + availInfo = declWith availInfo where declWith :: AvailInfo -> ErrMsgGhc [ ExportItem GhcRn ] declWith avail = do - let t = availName avail - r <- findDecl avail - case r of - ([L l (ValD _ _)], (doc, _)) -> do - -- Top-level binding without type signature - 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) - in case () of - _ - -- We should not show a subordinate by itself if any of its - -- parents is also exported. See note [1]. - | t `notElem` declNames, - Just p <- find isExported (parents t $ unL decl) -> - do liftErrMsg $ tell [ - "Warning: " ++ moduleString thisMod ++ ": " ++ - pretty dflags (nameOccName t) ++ " is exported separately but " ++ - "will be documented under " ++ pretty dflags (nameOccName p) ++ - ". Consider exporting it together with its parent(s)" ++ - " for code clarity." ] - return [] - - -- normal case - | otherwise -> case decl of - -- A single signature might refer to many names, but we - -- create an export item for a single name only. So we - -- modify the signature to contain only that single name. - L loc (SigD _ sig) -> - -- fromJust is safe since we already checked in guards - -- that 't' is a name declared in this declaration. - let newDecl = L loc . SigD noExt . fromJust $ filterSigNames (== t) sig - in availExportDecl avail newDecl docs_ - - L loc (TyClD _ cl@ClassDecl{}) -> do - mdef <- liftGhcToErrMsgGhc $ minimalDef t - let sig = maybeToList $ fmap (noLoc . MinimalSig noExt NoSourceText . noLoc . fmap noLoc) mdef - availExportDecl avail - (L loc $ TyClD noExt cl { tcdSigs = sig ++ tcdSigs cl }) docs_ - - _ -> availExportDecl avail decl docs_ - - -- Declaration from another package - ([], _) -> do - mayDecl <- hiDecl dflags t - case mayDecl of - Nothing -> return [ ExportNoDecl t [] ] - Just decl -> - -- We try to get the subs and docs - -- from the installed .haddock file for that package. - -- TODO: This needs to be more sophisticated to deal - -- with signature inheritance - case M.lookup (nameModule t) instIfaceMap of - Nothing -> do - liftErrMsg $ tell - ["Warning: Couldn't find .haddock for export " ++ pretty dflags t] - let subs_ = availNoDocs avail - availExportDecl avail decl (noDocForDecl, subs_) + dflags <- getDynFlags + let t = availName avail -- NB: 't' might not be in the scope of 'avail'. + -- Example: @data C = D@, where C isn't exported. + mayDecl <- hiDecl prr t + case mayDecl of + Nothing -> return [ ExportNoDecl t [] ] + Just decl -> do + docs_ <- do + let tmod = nameModule t + if tmod == thisMod + then pure (lookupDocs avail warnings docMap argMap) + else case M.lookup tmod modMap of Just iface -> - availExportDecl avail decl (lookupDocs avail warnings (instDocMap iface) (instArgMap iface)) - - _ -> return [] + pure (lookupDocs avail warnings (ifaceDocMap iface) (ifaceArgMap iface)) + Nothing -> + -- We try to get the subs and docs + -- from the installed .haddock file for that package. + -- TODO: This needs to be more sophisticated to deal + -- with signature inheritance + case M.lookup (nameModule t) instIfaceMap of + Nothing -> do + liftErrMsg $ tell + ["Warning: " ++ pretty dflags thisMod ++ + ": Couldn't find .haddock for export " ++ pretty dflags t] + let subs_ = availNoDocs avail + pure (noDocForDecl, subs_) + Just instIface -> + pure (lookupDocs avail warnings (instDocMap instIface) (instArgMap instIface)) + availExportDecl avail decl docs_ availExportDecl :: AvailInfo -> LHsDecl GhcRn -> (DocForDecl Name, [(Name, DocForDecl Name)]) @@ -786,9 +466,10 @@ availExportItem is_sig modMap thisMod semMod warnings exportedNames , Just f <- [M.lookup n fixMap] ] + extracted <- extractDecl prr (availName avail) decl + return [ ExportDecl { - expItemDecl = restrictTo (fmap fst subs) - (extractDecl declMap (availName avail) decl) + expItemDecl = restrictTo (fmap fst subs) extracted , expItemPats = bundledPatSyns , expItemMbDoc = doc , expItemSubDocs = subs @@ -799,49 +480,18 @@ availExportItem is_sig modMap thisMod semMod warnings exportedNames ] | otherwise = - return [ ExportDecl { - expItemDecl = extractDecl declMap sub decl - , expItemPats = [] - , expItemMbDoc = sub_doc - , expItemSubDocs = [] - , expItemInstances = [] - , expItemFixities = [ (sub, f) | Just f <- [M.lookup sub fixMap] ] - , expItemSpliced = False - } - | (sub, sub_doc) <- subs - ] - - exportedNameSet = mkNameSet exportedNames - isExported n = elemNameSet n exportedNameSet - - findDecl :: AvailInfo -> ErrMsgGhc ([LHsDecl GhcRn], (DocForDecl Name, [(Name, DocForDecl Name)])) - findDecl avail - | m == semMod = - case M.lookup n declMap of - Just ds -> return (ds, lookupDocs avail warnings docMap argMap) - Nothing - | is_sig -> do - -- OK, so it wasn't in the local declaration map. It could - -- have been inherited from a signature. Reconstitute it - -- from the type. - mb_r <- hiDecl dflags n - case mb_r of - Nothing -> return ([], (noDocForDecl, availNoDocs avail)) - -- TODO: If we try harder, we might be able to find - -- a Haddock! Look in the Haddocks for each thing in - -- requirementContext (pkgState) - Just decl -> return ([decl], (noDocForDecl, availNoDocs avail)) - | otherwise -> - return ([], (noDocForDecl, availNoDocs avail)) - | Just iface <- M.lookup (semToIdMod (moduleUnitId thisMod) m) modMap - , Just ds <- M.lookup n (ifaceDeclMap iface) = - return (ds, lookupDocs avail warnings - (ifaceDocMap iface) - (ifaceArgMap iface)) - | otherwise = return ([], (noDocForDecl, availNoDocs avail)) - where - n = availName avail - m = nameModule n + let extractSub (sub, sub_doc) = do + extracted <- extractDecl prr sub decl + pure (ExportDecl { + expItemDecl = extracted + , expItemPats = [] + , expItemMbDoc = sub_doc + , expItemSubDocs = [] + , expItemInstances = [] + , expItemFixities = [ (sub, f) | Just f <- [M.lookup sub fixMap] ] + , expItemSpliced = False + }) + in traverse extractSub subs findBundledPatterns :: AvailInfo -> ErrMsgGhc [(HsDecl GhcRn, DocForDecl Name)] findBundledPatterns avail = do @@ -877,21 +527,16 @@ availNoDocs :: AvailInfo -> [(Name, DocForDecl Name)] availNoDocs avail = zip (availSubordinates avail) (repeat noDocForDecl) --- | Given a 'Module' from a 'Name', convert it into a 'Module' that --- we can actually find in the 'IfaceMap'. -semToIdMod :: UnitId -> Module -> Module -semToIdMod this_uid m - | Module.isHoleModule m = mkModule this_uid (moduleName m) - | otherwise = m - -hiDecl :: DynFlags -> Name -> ErrMsgGhc (Maybe (LHsDecl GhcRn)) -hiDecl dflags t = do +hiDecl :: PrintRuntimeReps -> Name -> ErrMsgGhc (Maybe (LHsDecl GhcRn)) +hiDecl prr t = do + dflags <- getDynFlags mayTyThing <- liftGhcToErrMsgGhc $ lookupName t + let bugWarn = O.showSDoc dflags . warnLine case mayTyThing of Nothing -> do liftErrMsg $ tell ["Warning: Not found in environment: " ++ pretty dflags t] return Nothing - Just x -> case tyThingToLHsDecl x of + Just x -> case tyThingToLHsDecl prr x of Left m -> liftErrMsg (tell [bugWarn m]) >> return Nothing Right (m, t') -> liftErrMsg (tell $ map bugWarn m) >> return (Just $ noLoc t') @@ -899,141 +544,31 @@ hiDecl dflags t = do warnLine x = O.text "haddock-bug:" O.<+> O.text x O.<> O.comma O.<+> O.quotes (O.ppr t) O.<+> O.text "-- Please report this on Haddock issue tracker!" - bugWarn = O.showSDoc dflags . warnLine - --- | 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 GhcRn) -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) - where - fixSpan (L l t) = L (SrcLoc.combineSrcSpans l nLoc) t - fixities = case fixity of - Just f -> [(name, f)] - Nothing -> [] - -- | Lookup docs for a declaration from maps. lookupDocs :: AvailInfo -> WarningMap -> DocMap Name -> ArgMap Name -> (DocForDecl Name, [(Name, DocForDecl Name)]) lookupDocs avail warnings docMap argMap = - let n = availName avail in - let lookupArgDoc x = M.findWithDefault M.empty x argMap in - let doc = (lookupDoc n, lookupArgDoc n) in - let subDocs = [ (s, (lookupDoc s, lookupArgDoc s)) - | s <- availSubordinates avail - ] in - (doc, subDocs) - where - lookupDoc name = Documentation (M.lookup name docMap) (M.lookup name warnings) - - --- | Export the given module as `ExportModule`. We are not concerned with the --- single export items of the given module. -moduleExport :: Module -- ^ Module A (identity, NOT semantic) - -> DynFlags -- ^ The flags used when typechecking A - -> IfaceMap -- ^ Already created interfaces - -> InstIfaceMap -- ^ Interfaces in other packages - -> ModuleName -- ^ The exported module - -> ErrMsgGhc [ExportItem GhcRn] -- ^ Resulting export items -moduleExport thisMod dflags ifaceMap instIfaceMap expMod = - -- NB: we constructed the identity module when looking up in - -- the IfaceMap. - case M.lookup m ifaceMap of - Just iface - | OptHide `elem` ifaceOptions iface -> return (ifaceExportItems iface) - | otherwise -> return [ ExportModule m ] - - Nothing -> -- We have to try to find it in the installed interfaces - -- (external packages). - case M.lookup expMod (M.mapKeys moduleName instIfaceMap) of - Just iface -> return [ ExportModule (instMod iface) ] - Nothing -> do - liftErrMsg $ - tell ["Warning: " ++ pretty dflags thisMod ++ ": Could not find " ++ - "documentation for exported module: " ++ pretty dflags expMod] - return [] + ( lookupDocForDecl (availName avail) + , [ (s, lookupDocForDecl s) | s <- availSubordinates avail ] + ) where - m = mkModule unitId expMod -- Identity module! - unitId = moduleUnitId thisMod - --- Note [1]: ------------- --- It is unnecessary to document a subordinate by itself at the top level if --- any of its parents is also documented. Furthermore, if the subordinate is a --- record field or a class method, documenting it under its parent --- indicates its special status. --- --- A user might expect that it should show up separately, so we issue a --- warning. It's a fine opportunity to also tell the user she might want to --- export the subordinate through the parent export item for clarity. --- --- The code removes top-level subordinates also when the parent is exported --- through a 'module' export. I think that is fine. --- --- (For more information, see Trac #69) - - --- | Simplified variant of 'mkExportItems', where we can assume that --- every locally defined declaration is exported; thus, we just --- zip through the renamed declarations. - -fullModuleContents :: Bool -- is it a signature - -> IfaceMap - -> Maybe Package -- this package - -> Module -- this module - -> Module -- semantic module - -> WarningMap - -> GlobalRdrEnv -- ^ The renaming environment - -> [Name] -- exported names (orig) - -> [LHsDecl GhcRn] -- renamed source declarations - -> Maps - -> FixMap - -> [SrcSpan] -- splice locations - -> InstIfaceMap - -> DynFlags - -> Avails - -> ErrMsgGhc [ExportItem GhcRn] -fullModuleContents is_sig modMap pkgName thisMod semMod warnings gre exportedNames - decls maps@(_, _, declMap, _) fixMap splices instIfaceMap dflags avails = do - let availEnv = availsToNameEnv (nubAvails avails) - (concat . concat) `fmap` (for decls $ \decl -> do - case decl of - (L _ (DocD _ (DocGroup lev docStr))) -> do - doc <- liftErrMsg (processDocString dflags gre docStr) - return [[ExportGroup lev "" doc]] - (L _ (DocD _ (DocCommentNamed _ docStr))) -> do - doc <- liftErrMsg (processDocStringParas dflags pkgName gre docStr) - return [[ExportDoc doc]] - (L _ (ValD _ valDecl)) - | name:_ <- collectHsBindBinders valDecl - , Just (L _ SigD{}:_) <- filter isSigD <$> M.lookup name declMap - -> return [] - _ -> - for (getMainDeclBinder (unLoc decl)) $ \nm -> do - case lookupNameEnv availEnv nm of - Just avail -> - availExportItem is_sig modMap thisMod - semMod warnings exportedNames maps fixMap - splices instIfaceMap dflags avail - Nothing -> pure []) - where - isSigD (L _ SigD{}) = True - isSigD _ = False + lookupDoc x = Documentation (M.lookup x docMap) (M.lookup x warnings) + lookupArgDoc x = M.findWithDefault M.empty x argMap + lookupDocForDecl x = (lookupDoc x, lookupArgDoc x) + -- | Sometimes the declaration we want to export is not the "main" declaration: -- it might be an individual record selector or a class method. In these -- cases we have to extract the required declaration (and somehow cobble -- together a type signature for it...). -extractDecl :: DeclMap -> Name -> LHsDecl GhcRn -> LHsDecl GhcRn -extractDecl declMap name decl - | name `elem` getMainDeclBinder (unLoc decl) = decl +extractDecl + :: PrintRuntimeReps -- ^ should we print 'RuntimeRep' tyvars? + -> Name -- ^ name of subdecl to extract + -> LHsDecl GhcRn -- ^ parent decl + -> ErrMsgGhc (LHsDecl GhcRn) -- ^ extracted subdecl +extractDecl prr name decl + | name `elem` getMainDeclBinder (unLoc decl) = pure decl | otherwise = case unLoc decl of TyClD _ d@ClassDecl {} -> @@ -1056,29 +591,34 @@ extractDecl declMap name decl in case (matchesMethod, matchesAssociatedType) of ([s0], _) -> let (n, tyvar_names) = (tcdName d, tyClDeclTyVars d) L pos sig = addClassContext n tyvar_names s0 - in L pos (SigD noExt sig) - (_, [L pos fam_decl]) -> L pos (TyClD noExt (FamDecl noExt fam_decl)) - - ([], []) - | Just (famInstDecl:_) <- M.lookup name declMap - -> extractDecl declMap name famInstDecl + in pure (L pos (SigD noExt sig)) + (_, [L pos fam_decl]) -> pure (L pos (TyClD noExt (FamDecl noExt fam_decl))) + + ([], []) -> do + famInstDeclOpt <- hiDecl prr name + case famInstDeclOpt of + Nothing -> O.pprPanic "extractDecl" (O.text "Failed to find decl for" O.<+> O.ppr name) + Just famInstDecl -> extractDecl prr name famInstDecl _ -> O.pprPanic "extractDecl" (O.text "Ambiguous decl for" O.<+> O.ppr name O.<+> O.text "in class:" O.$$ O.nest 4 (O.ppr d) O.$$ O.text "Matches:" O.$$ O.nest 4 (O.ppr matchesMethod O.<+> O.ppr matchesAssociatedType)) - TyClD _ d@DataDecl {} -> + TyClD _ d@DataDecl {} -> pure $ let (n, tyvar_tys) = (tcdName d, lHsQTyVarsToTypes (tyClDeclTyVars d)) in if isDataConName name then SigD noExt <$> extractPatternSyn name n (map HsValArg tyvar_tys) (dd_cons (tcdDataDefn d)) else SigD noExt <$> extractRecSel name n (map HsValArg tyvar_tys) (dd_cons (tcdDataDefn d)) TyClD _ FamDecl {} | isValName name - , Just (famInst:_) <- M.lookup name declMap - -> extractDecl declMap name famInst + -> do + famInstOpt <- hiDecl prr name + case famInstOpt of + Nothing -> O.pprPanic "extractDecl" (O.text "Failed to find decl for" O.<+> O.ppr name) + Just famInst -> extractDecl prr name famInst InstD _ (DataFamInstD _ (DataFamInstDecl (HsIB { hsib_body = FamEqn { feqn_tycon = L _ n , feqn_pats = tys - , feqn_rhs = defn }}))) -> + , feqn_rhs = defn }}))) -> pure $ if isDataConName name then SigD noExt <$> extractPatternSyn name n tys (dd_cons defn) else SigD noExt <$> extractRecSel name n tys (dd_cons defn) @@ -1091,7 +631,7 @@ extractDecl declMap name decl , name `elem` map unLoc (concatMap (getConNames . unLoc) (dd_cons dd)) ] in case matches of - [d0] -> extractDecl declMap name (noLoc (InstD noExt (DataFamInstD noExt d0))) + [d0] -> extractDecl prr name (noLoc (InstD noExt (DataFamInstD noExt d0))) _ -> error "internal: extractDecl (ClsInstD)" | otherwise -> let matches = [ d' | L _ d'@(DataFamInstDecl (HsIB { hsib_body = d })) @@ -1103,7 +643,7 @@ extractDecl declMap name decl , extFieldOcc n == name ] in case matches of - [d0] -> extractDecl declMap name (noLoc . InstD noExt $ DataFamInstD noExt d0) + [d0] -> extractDecl prr name (noLoc . InstD noExt $ DataFamInstD noExt d0) _ -> error "internal: extractDecl (ClsInstD)" _ -> O.pprPanic "extractDecl" $ O.text "Unhandled decl for" O.<+> O.ppr name O.<> O.text ":" @@ -1173,8 +713,8 @@ pruneExportItems = filter hasDoc hasDoc _ = True -mkVisibleNames :: Maps -> [ExportItem GhcRn] -> [DocOption] -> [Name] -mkVisibleNames (_, _, _, instMap) exports opts +mkVisibleNames :: InstMap -> [ExportItem GhcRn] -> [DocOption] -> [Name] +mkVisibleNames instMap exports opts | OptHide `elem` opts = [] | otherwise = let ns = concatMap exportName exports in seqList ns `seq` ns @@ -1192,15 +732,3 @@ mkVisibleNames (_, _, _, instMap) exports opts seqList :: [a] -> () seqList [] = () seqList (x : xs) = x `seq` seqList xs - --- | Find a stand-alone documentation comment by its name. -findNamedDoc :: String -> [HsDecl GhcRn] -> ErrMsgM (Maybe HsDocString) -findNamedDoc name = search - where - search [] = do - tell ["Cannot find documentation for: $" ++ name] - return Nothing - search (DocD _ (DocCommentNamed name' doc) : rest) - | name == name' = return (Just doc) - | otherwise = search rest - search (_other_decl : rest) = search rest diff --git a/haddock-api/src/Haddock/Interface/LexParseRn.hs b/haddock-api/src/Haddock/Interface/LexParseRn.hs index 59ad4fdfdb..365ac98fee 100644 --- a/haddock-api/src/Haddock/Interface/LexParseRn.hs +++ b/haddock-api/src/Haddock/Interface/LexParseRn.hs @@ -15,7 +15,6 @@ module Haddock.Interface.LexParseRn ( processDocString , processDocStringParas - , processDocStrings , processModuleHeader ) where @@ -24,8 +23,9 @@ import Control.Arrow import Control.Monad import Data.List import Data.Ord -import Documentation.Haddock.Doc (metaDocConcat) -import DynFlags (languageExtensions) +import qualified Data.Map as Map +import qualified Documentation.Haddock.Parser as LibParser +import DynFlags (getDynFlags, languageExtensions, Language) import qualified GHC.LanguageExtensions as LangExt import GHC import Haddock.Interface.ParseModuleHeader @@ -35,48 +35,46 @@ import Name import Outputable ( showPpr, showSDoc ) import RdrName import EnumSet -import RnEnv (dataTcOccs) - -processDocStrings :: DynFlags -> Maybe Package -> GlobalRdrEnv -> [HsDocString] - -> ErrMsgM (Maybe (MDoc Name)) -processDocStrings dflags pkg gre strs = do - mdoc <- metaDocConcat <$> traverse (processDocStringParas dflags pkg 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 Nothing Nothing, _doc = DocEmpty } -> pure Nothing - x -> pure (Just x) - -processDocStringParas :: DynFlags -> Maybe Package -> GlobalRdrEnv -> HsDocString -> ErrMsgM (MDoc Name) -processDocStringParas dflags pkg gre hds = - overDocF (rename dflags gre) $ parseParas dflags pkg (unpackHDS hds) - -processDocString :: DynFlags -> GlobalRdrEnv -> HsDocString -> ErrMsgM (Doc Name) -processDocString dflags gre hds = - rename dflags gre $ parseString dflags (unpackHDS hds) - -processModuleHeader :: DynFlags -> Maybe Package -> GlobalRdrEnv -> SafeHaskellMode -> Maybe LHsDocString - -> ErrMsgM (HaddockModInfo Name, Maybe (MDoc Name)) -processModuleHeader dflags pkgName gre safety mayStr = do + +processDocStringParas :: Maybe Package -> (HsDoc Name) -> ErrMsgGhc (MDoc Name) +processDocStringParas pkg hsDoc = do + let mdoc = LibParser.parseParas pkg (unpackHDS (hsDocString hsDoc)) + overDocF (rename (hsDocRenamer hsDoc)) mdoc + +processDocString :: HsDoc Name -> ErrMsgGhc (Doc Name) +processDocString hsDoc = do + let doc = LibParser.parseString (unpackHDS (hsDocString hsDoc)) + rename (hsDocRenamer hsDoc) doc + +processModuleHeader :: Maybe Package -> SafeHaskellMode + -> Maybe Language -> EnumSet LangExt.Extension + -> Maybe (HsDoc Name) + -> ErrMsgGhc (HaddockModInfo Name, Maybe (MDoc Name)) +processModuleHeader pkgName safety mayLang extSet mayStr = do (hmi, doc) <- case mayStr of Nothing -> return failure - Just (L _ hds) -> do - let str = unpackHDS hds - (hmi, doc) = parseModuleHeader dflags pkgName str + Just hsDoc -> do + let str = unpackHDS (hsDocString hsDoc) + (hmi, doc) = parseModuleHeader pkgName str + renamer = hsDocRenamer hsDoc !descr <- case hmi_description hmi of - Just hmi_descr -> Just <$> rename dflags gre hmi_descr + Just hmi_descr -> Just <$> rename renamer hmi_descr Nothing -> pure Nothing let hmi' = hmi { hmi_description = descr } - doc' <- overDocF (rename dflags gre) doc + doc' <- overDocF (rename renamer) doc return (hmi', Just doc') + let flags :: [LangExt.Extension] - -- We remove the flags implied by the language setting and we display the language instead - flags = EnumSet.toList (extensionFlags dflags) \\ languageExtensions (language dflags) + -- We remove the flags implied by the language setting and we display the + -- language instead. + -- NB: 'hmi_extensions' cannot reflect that some extensions included in + -- 'mayLang' may have been disabled. + flags = EnumSet.toList extSet \\ languageExtensions mayLang + dflags <- getDynFlags return (hmi { hmi_safety = Just $ showPpr dflags safety - , hmi_language = language dflags + , hmi_language = mayLang , hmi_extensions = flags } , doc) where @@ -89,41 +87,32 @@ processModuleHeader dflags pkgName 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 -> ErrMsgM (Doc Name) -rename dflags gre = rn +rename :: Renamer -> Doc Identifier -> ErrMsgGhc (Doc Name) +rename renamer = rn where rn d = case d of 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. - let choices = dataTcOccs x - - -- Lookup any GlobalRdrElts that match the choices. - case concatMap (\c -> lookupGRE_RdrName c gre) choices of - -- We found no names in the env so we start guessing. - [] -> - case choices of - -- This shouldn't happen as 'dataTcOccs' always returns at least its input. - [] -> 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 - -- 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 + DocIdentifier id_@(_, x, _) -> do + case renamer x of + Nothing -> invalid id_ + + -- 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. + Just [] -> outOfScope x -- There is only one name in the environment that matches so -- use it. - [a] -> pure (DocIdentifier (gre_name a)) + Just [a] -> pure (DocIdentifier a) -- There are multiple names available. - gres -> ambiguous dflags x gres + Just names -> ambiguous id_ names DocWarning doc -> DocWarning <$> rn doc DocEmphasis doc -> DocEmphasis <$> rn doc @@ -147,6 +136,10 @@ rename dflags gre = rn DocHeader (Header l t) -> DocHeader . Header l <$> rn t DocTable t -> DocTable <$> traverse rn t +-- | TODO: We could emit a warning here. +invalid :: Identifier -> ErrMsgGhc (Doc a) +invalid (o, x, e) = pure (DocString $ o : x ++ [e]) + -- | 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 @@ -155,46 +148,54 @@ rename dflags gre = rn -- 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 -> ErrMsgM (Doc a) -outOfScope dflags x = - case x of - Unqual occ -> warnAndMonospace occ - Qual mdl occ -> pure (DocIdentifierUnchecked (mdl, occ)) - Orig _ occ -> warnAndMonospace occ - Exact name -> warnAndMonospace name -- Shouldn't happen since x is out of scope - where - warnAndMonospace a = do - tell ["Warning: '" ++ showPpr dflags a ++ "' is out of scope.\n" ++ - " If you qualify the identifier, haddock can try to link it anyway."] - pure (monospaced a) - monospaced a = DocMonospaced (DocString (showPpr dflags a)) +outOfScope :: String -> ErrMsgGhc (Doc a) +outOfScope x = do + dflags <- getDynFlags + let warnAndMonospace a = do + liftErrMsg $ + tell ["Warning: '" ++ showPpr dflags a ++ "' is out of scope.\n" ++ + " If you qualify the identifier, haddock can try to link it anyway."] + pure (monospaced a) + monospaced a = DocMonospaced (DocString (showPpr dflags a)) + + -- Using our local dflags isn't quite correct – ideally we'd use those GHC used when + -- compiling the module + case parseIdent dflags x of + Nothing -> invalid ('\'', x, '\'') -- Shouldn't happen + Just (rdr_name) -> case rdr_name of + Unqual occ -> warnAndMonospace occ + Qual mdl occ -> pure (DocIdentifierUnchecked (mdl, occ)) + Orig _ occ -> warnAndMonospace occ + Exact name -> warnAndMonospace name -- Shouldn't happen since x is out of scope -- | Handle ambiguous identifiers. -- -- Prefers local names primarily and type constructors or class names secondarily. -- -- Emits a warning if the 'GlobalRdrElts's don't belong to the same type or class. -ambiguous :: DynFlags - -> RdrName - -> [GlobalRdrElt] -- ^ More than one @gre@s sharing the same `RdrName` above. - -> ErrMsgM (Doc Name) -ambiguous dflags x gres = do - let noChildren = map availName (gresToAvailInfo gres) +ambiguous :: Identifier + -> [Name] -- ^ More than one 'Name's that the 'Identifier' may be intended + -- to reference. + -> ErrMsgGhc (Doc Name) +ambiguous (o, x, e) names = do + dflags <- getDynFlags + let noChildren = map availName (nubAvails (map avail names)) dflt = maximumBy (comparing (isLocalName &&& isTyConName)) noChildren - msg = "Warning: " ++ x_str ++ " is ambiguous. It is defined\n" ++ - concatMap (\n -> " * " ++ defnLoc n ++ "\n") (map gre_name gres) ++ + dflt_str = '\'' : showPpr dflags dflt ++ "'" + id_str = o : x ++ (e : []) + defnLoc = showSDoc dflags . pprNameDefnLoc + msg = "Warning: " ++ id_str ++ " is ambiguous. It is defined\n" ++ + concatMap (\n -> " * " ++ defnLoc n ++ "\n") names ++ " You may be able to disambiguate the identifier by qualifying it or\n" ++ " by hiding some imports.\n" ++ - " Defaulting to " ++ x_str ++ " defined " ++ defnLoc dflt - -- TODO: Once we have a syntax for namespace qualification (#667) we may also - -- want to emit a warning when an identifier is a data constructor for a type - -- of the same name, but not the only constructor. - -- For example, for @data D = C | D@, someone may want to reference the @D@ - -- constructor. - when (length noChildren > 1) $ tell [msg] + " Defaulting to " ++ dflt_str ++ " defined " ++ defnLoc dflt + when (length noChildren > 1) $ liftErrMsg $ tell [msg] pure (DocIdentifier dflt) where isLocalName (nameSrcLoc -> RealSrcLoc {}) = True isLocalName _ = False - x_str = '\'' : showPpr dflags x ++ "'" - defnLoc = showSDoc dflags . pprNameDefnLoc + +hsDocRenamer :: HsDoc Name -> Renamer +hsDocRenamer hsDoc = \s -> Map.lookup s env + where + env = Map.mapKeysMonotonic unpackHDS (hsDocIdEnv hsDoc) diff --git a/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs b/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs index 050901b6e3..8ef8780eb3 100644 --- a/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs +++ b/haddock-api/src/Haddock/Interface/ParseModuleHeader.hs @@ -11,12 +11,10 @@ ----------------------------------------------------------------------------- module Haddock.Interface.ParseModuleHeader (parseModuleHeader) where +import qualified Documentation.Haddock.Parser as P import Control.Monad (mplus) import Data.Char -import DynFlags -import Haddock.Parser import Haddock.Types -import RdrName -- ----------------------------------------------------------------------------- -- Parsing module headers @@ -24,8 +22,8 @@ import RdrName -- NB. The headers must be given in the order Module, Description, -- Copyright, License, Maintainer, Stability, Portability, except that -- any or all may be omitted. -parseModuleHeader :: DynFlags -> Maybe Package -> String -> (HaddockModInfo RdrName, MDoc RdrName) -parseModuleHeader dflags pkgName str0 = +parseModuleHeader :: Maybe Package -> String -> (HaddockModInfo Identifier, MDoc Identifier) +parseModuleHeader pkgName str0 = let getKey :: String -> String -> (Maybe String,String) getKey key str = case parseKey key str of @@ -43,7 +41,7 @@ parseModuleHeader dflags pkgName str0 = (portabilityOpt,str9) = getKey "Portability" str8 in (HaddockModInfo { - hmi_description = parseString dflags <$> descriptionOpt, + hmi_description = P.parseString <$> descriptionOpt, hmi_copyright = copyrightOpt, hmi_license = spdxLicenceOpt `mplus` licenseOpt `mplus` licenceOpt, hmi_maintainer = maintainerOpt, @@ -52,7 +50,7 @@ parseModuleHeader dflags pkgName str0 = hmi_safety = Nothing, hmi_language = Nothing, -- set in LexParseRn hmi_extensions = [] -- also set in LexParseRn - }, parseParas dflags pkgName str9) + }, P.parseParas pkgName str9) -- | This function is how we read keys. -- diff --git a/haddock-api/src/Haddock/Interface/Rename.hs b/haddock-api/src/Haddock/Interface/Rename.hs index 57e6d69946..b052d3a530 100644 --- a/haddock-api/src/Haddock/Interface/Rename.hs +++ b/haddock-api/src/Haddock/Interface/Rename.hs @@ -14,8 +14,6 @@ module Haddock.Interface.Rename (renameInterface) where -import Data.Traversable (mapM) - import Haddock.GhcUtils import Haddock.Types @@ -23,12 +21,13 @@ import Bag (emptyBag) import GHC hiding (NoLink) import Name import Outputable ( panic ) -import RdrName (RdrName(Exact)) -import TysWiredIn (eqTyCon_RDR) +import RdrName ( RdrName(Exact) ) +import TysPrim ( eqPrimTyCon ) +import TysWiredIn ( eqTyCon_RDR ) import Control.Applicative import Control.Arrow ( first ) -import Control.Monad hiding (mapM) +import Control.Monad import Data.List import qualified Data.Map as Map hiding ( Map ) import Prelude hiding (mapM) @@ -73,7 +72,8 @@ renameInterface dflags renamingEnv warnings iface = | n <- missingNames , not (isSystemName n) , not (isBuiltInSyntax n) - , Exact n /= eqTyCon_RDR + , Exact n /= eqTyCon_RDR -- (~) + , n /= getName eqPrimTyCon -- (~#) ] in do @@ -168,10 +168,8 @@ renameDocumentation :: Documentation Name -> RnM (Documentation DocName) renameDocumentation (Documentation mDoc mWarning) = Documentation <$> mapM renameDoc mDoc <*> mapM renameDoc mWarning - -renameLDocHsSyn :: LHsDocString -> RnM LHsDocString -renameLDocHsSyn = return - +renameLDocHsSyn :: LHsDoc Name -> RnM (LHsDoc DocName) +renameLDocHsSyn = traverse renameDoc renameDoc :: Traversable t => t Name -> RnM (t DocName) renameDoc = traverse rename diff --git a/haddock-api/src/Haddock/InterfaceFile.hs b/haddock-api/src/Haddock/InterfaceFile.hs index e1d8dbe19e..ac2f71b2a7 100644 --- a/haddock-api/src/Haddock/InterfaceFile.hs +++ b/haddock-api/src/Haddock/InterfaceFile.hs @@ -27,8 +27,6 @@ import Control.Monad import Data.Array import Data.IORef import Data.List -import qualified Data.Map as Map -import Data.Map (Map) import Data.Word import BinIface (getSymtabName, getDictFastString) @@ -356,12 +354,6 @@ serialiseName bh name _ = do -- * GhcBinary instances ------------------------------------------------------------------------------- - -instance (Ord k, Binary k, Binary v) => Binary (Map k v) where - put_ bh m = put_ bh (Map.toList m) - get bh = fmap (Map.fromList) (get bh) - - instance Binary InterfaceFile where put_ bh (InterfaceFile env ifaces) = do put_ bh env @@ -394,8 +386,8 @@ instance Binary InstalledInterface where visExps <- get bh opts <- get bh fixMap <- get bh - return (InstalledInterface modu is_sig info docMap argMap - exps visExps opts fixMap) + return (InstalledInterface modu is_sig info + docMap argMap exps visExps opts fixMap) instance Binary DocOption where @@ -403,11 +395,11 @@ instance Binary DocOption where putByte bh 0 put_ bh OptPrune = do putByte bh 1 - put_ bh OptIgnoreExports = do - putByte bh 2 put_ bh OptNotHome = do - putByte bh 3 + putByte bh 2 put_ bh OptShowExtensions = do + putByte bh 3 + put_ bh OptPrintRuntimeRep = do putByte bh 4 get bh = do h <- getByte bh @@ -417,11 +409,11 @@ instance Binary DocOption where 1 -> do return OptPrune 2 -> do - return OptIgnoreExports - 3 -> do return OptNotHome - 4 -> do + 3 -> do return OptShowExtensions + 4 -> do + return OptPrintRuntimeRep _ -> fail "invalid binary data found" diff --git a/haddock-api/src/Haddock/Options.hs b/haddock-api/src/Haddock/Options.hs index e314bbd05a..4b156469fb 100644 --- a/haddock-api/src/Haddock/Options.hs +++ b/haddock-api/src/Haddock/Options.hs @@ -89,7 +89,6 @@ data Flag | Flag_GenContents | Flag_UseIndex String | Flag_GenIndex - | Flag_IgnoreAllExports | Flag_HideModule String | Flag_ShowModule String | Flag_ShowAllModules @@ -147,9 +146,9 @@ options backwardsCompat = "URL for a source code link on the contents\nand index pages", Option ['s'] (if backwardsCompat then ["source", "source-module"] else ["source-module"]) (ReqArg Flag_SourceModuleURL "URL") - "URL for a source code link for each module\n(using the %{FILE} or %{MODULE} vars)", + "URL for a source code link for each module\n(using the %{MODULE} var)", Option [] ["source-entity"] (ReqArg Flag_SourceEntityURL "URL") - "URL for a source code link for each entity\n(using the %{FILE}, %{MODULE}, %{NAME},\n%{KIND} or %{LINE} vars)", + "URL for a source code link for each entity\n(using the %{MODULE}, %{NAME},\n%{KIND} or %{LINE} vars)", Option [] ["source-entity-line"] (ReqArg Flag_SourceLEntityURL "URL") "URL for a source code link for each entity.\nUsed if name links are unavailable, eg. for TH splices.", Option [] ["comments-base"] (ReqArg Flag_WikiBaseURL "URL") @@ -157,7 +156,7 @@ options backwardsCompat = Option [] ["comments-module"] (ReqArg Flag_WikiModuleURL "URL") "URL for a comments link for each module\n(using the %{MODULE} var)", Option [] ["comments-entity"] (ReqArg Flag_WikiEntityURL "URL") - "URL for a comments link for each entity\n(using the %{FILE}, %{MODULE}, %{NAME},\n%{KIND} or %{LINE} vars)", + "URL for a comments link for each entity\n(using the %{MODULE}, %{NAME},\n%{KIND} or %{LINE} vars)", Option ['c'] ["css", "theme"] (ReqArg Flag_CSS "PATH") "the CSS file or theme directory to use for HTML output", Option [] ["built-in-themes"] (NoArg Flag_BuiltInThemes) @@ -167,7 +166,7 @@ options backwardsCompat = Option ['t'] ["title"] (ReqArg Flag_Heading "TITLE") "page heading", Option ['q'] ["qual"] (ReqArg Flag_Qualification "QUAL") - "qualification of names, one of \n'none' (default), 'full', 'local'\n'relative' or 'aliased'", + "qualification of names, one of \n'none' (default), 'full', 'local'\nor 'relative'", Option ['?'] ["help"] (NoArg Flag_Help) "display this help and exit", Option ['V'] ["version"] (NoArg Flag_Version) @@ -188,8 +187,6 @@ options backwardsCompat = "use a separately-generated HTML index", Option [] ["gen-index"] (NoArg Flag_GenIndex) "generate an HTML index from specified\ninterfaces", - Option [] ["ignore-all-exports"] (NoArg Flag_IgnoreAllExports) - "behave as if all modules have the\nignore-exports attribute", Option [] ["hide"] (ReqArg Flag_HideModule "MODULE") "behave as if MODULE has the hide attribute", Option [] ["show"] (ReqArg Flag_ShowModule "MODULE") @@ -316,7 +313,6 @@ qualification flags = ["full"] -> Right OptFullQual ["local"] -> Right OptLocalQual ["relative"] -> Right OptRelativeQual - ["aliased"] -> Right OptAliasedQual [arg] -> Left $ "unknown qualification type " ++ show arg _:_ -> Left "qualification option given multiple times" diff --git a/haddock-api/src/Haddock/Types.hs b/haddock-api/src/Haddock/Types.hs index a4ef5f8203..c329af1021 100644 --- a/haddock-api/src/Haddock/Types.hs +++ b/haddock-api/src/Haddock/Types.hs @@ -24,6 +24,7 @@ module Haddock.Types ( module Haddock.Types , HsDocString, LHsDocString , Fixity(..) + , Identifier , module Documentation.Haddock.Types ) where @@ -35,15 +36,17 @@ import Control.Monad.IO.Class (MonadIO(..)) import Data.Typeable (Typeable) import Data.Map (Map) import Data.Data (Data) -import Documentation.Haddock.Types import BasicTypes (Fixity(..), PromotionFlag(..)) import GHC -import DynFlags (Language) +import DynFlags (Language, HasDynFlags(..)) import qualified GHC.LanguageExtensions as LangExt import OccName import Outputable +import Documentation.Haddock.Types +import Documentation.Haddock.Parser + ----------------------------------------------------------------------------- -- * Convenient synonyms ----------------------------------------------------------------------------- @@ -54,7 +57,6 @@ type InstIfaceMap = Map Module InstalledInterface -- TODO: rename type DocMap a = Map Name (MDoc a) type ArgMap a = Map Name (Map Int (MDoc a)) type SubMap = Map Name [Name] -type DeclMap = Map Name [LHsDecl GhcRn] type InstMap = Map SrcSpan Name type FixMap = Map Name Fixity type DocPaths = (FilePath, Maybe FilePath) -- paths to HTML and sources @@ -78,9 +80,6 @@ data Interface = Interface -- | Is this a signature? , ifaceIsSig :: !Bool - -- | Original file name of the module. - , ifaceOrigFilename :: !FilePath - -- | Textual information about the module. , ifaceInfo :: !(HaddockModInfo Name) @@ -90,14 +89,9 @@ data Interface = Interface -- | Documentation header with cross-reference information. , ifaceRnDoc :: !(Documentation DocName) - -- | Haddock options for this module (prune, ignore-exports, etc). + -- | Haddock options for this module (prune, not-home, etc). , ifaceOptions :: ![DocOption] - -- | Declarations originating from the module. Excludes declarations without - -- names (instances and stand-alone documentation comments). Includes - -- names of subordinate declarations mapped to their parent declarations. - , ifaceDeclMap :: !(Map Name [LHsDecl GhcRn]) - -- | Documentation of declarations originating from the module (including -- subordinates). , ifaceDocMap :: !(DocMap Name) @@ -119,11 +113,10 @@ data Interface = Interface -- | All \"visible\" names exported by the module. -- A visible name is a name that will show up in the documentation of the -- module. + -- + -- Names from modules that are entirely re-exported don't count as visible. , ifaceVisibleExports :: ![Name] - -- | Aliases of module imports as in @import A.B.C as C@. - , ifaceModuleAliases :: !AliasMap - -- | Instances exported by the module. , ifaceInstances :: ![ClsInst] , ifaceFamInstances :: ![FamInst] @@ -175,7 +168,7 @@ data InstalledInterface = InstalledInterface -- module. , instVisibleExports :: [Name] - -- | Haddock options for this module (prune, ignore-exports, etc). + -- | Haddock options for this module (prune, not-home, etc). , instOptions :: [DocOption] , instFixMap :: Map Name Fixity @@ -329,6 +322,9 @@ instance SetName DocName where setName name' (Undocumented _) = Undocumented name' +instance HasOccName DocName where + + occName = occName . getName ----------------------------------------------------------------------------- -- * Instances @@ -524,10 +520,11 @@ emptyHaddockModInfo = HaddockModInfo data DocOption = OptHide -- ^ This module should not appear in the docs. | OptPrune - | OptIgnoreExports -- ^ Pretend everything is exported. | OptNotHome -- ^ Not the best place to get docs for things -- exported by this module. | OptShowExtensions -- ^ Render enabled extensions for this module. + | OptPrintRuntimeRep -- ^ Render runtime reps for this module (see + -- the GHC @-fprint-explicit-runtime-reps@ flag) deriving (Eq, Show) @@ -538,23 +535,12 @@ data QualOption | OptLocalQual -- ^ Qualify all imported names fully. | OptRelativeQual -- ^ Like local, but strip module prefix -- from modules in the same hierarchy. - | OptAliasedQual -- ^ Uses aliases of module names - -- as suggested by module import renamings. - -- However, we are unfortunately not able - -- to maintain the original qualifications. - -- Image a re-export of a whole module, - -- how could the re-exported identifiers be qualified? - -type AliasMap = Map Module ModuleName data Qualification = NoQual | FullQual | LocalQual Module | RelativeQual Module - | AliasedQual AliasMap Module - -- ^ @Module@ contains the current module. - -- This way we can distinguish imported and local identifiers. makeContentsQual :: QualOption -> Qualification makeContentsQual qual = @@ -562,12 +548,11 @@ makeContentsQual qual = OptNoQual -> NoQual _ -> FullQual -makeModuleQual :: QualOption -> AliasMap -> Module -> Qualification -makeModuleQual qual aliases mdl = +makeModuleQual :: QualOption -> Module -> Qualification +makeModuleQual qual mdl = case qual of OptLocalQual -> LocalQual mdl OptRelativeQual -> RelativeQual mdl - OptAliasedQual -> AliasedQual aliases mdl OptFullQual -> FullQual OptNoQual -> NoQual @@ -584,6 +569,17 @@ data SinceQual | External -- ^ only qualify when the thing being annotated is from -- an external package +----------------------------------------------------------------------------- +-- * Renaming +----------------------------------------------------------------------------- + +-- | Validates and renames an identifier. +-- +-- [@Nothing@]: The input is not a valid identifier. +-- +-- [@Just []@]: The input is a valid identifier but it's not in scope. +type Renamer = String -> Maybe [Name] + ----------------------------------------------------------------------------- -- * Error handling ----------------------------------------------------------------------------- @@ -662,7 +658,10 @@ instance Monad ErrMsgGhc where fmap (second (msgs1 ++)) (runWriterGhc (k a)) instance MonadIO ErrMsgGhc where - liftIO m = WriterGhc (fmap (\x -> (x, [])) (liftIO m)) + liftIO = liftGhcToErrMsgGhc . liftIO + +instance HasDynFlags ErrMsgGhc where + getDynFlags = liftGhcToErrMsgGhc getDynFlags ----------------------------------------------------------------------------- -- * Pass sensitive types diff --git a/haddock-api/src/Haddock/Utils.hs b/haddock-api/src/Haddock/Utils.hs index dda42cea8d..69d8034089 100644 --- a/haddock-api/src/Haddock/Utils.hs +++ b/haddock-api/src/Haddock/Utils.hs @@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-} +{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- -- | -- Module : Haddock.Utils @@ -168,8 +169,8 @@ restrictTo names (L loc decl) = L loc $ case decl of TyClD x d | isDataDecl d -> TyClD x (d { tcdDataDefn = restrictDataDefn names (tcdDataDefn d) }) TyClD x d | isClassDecl d -> - TyClD x (d { tcdSigs = restrictDecls names (tcdSigs d), - tcdATs = restrictATs names (tcdATs d) }) + TyClD x (d { tcdSigs = restrictDecls names (tcdSigs d) + , tcdATs = restrictATs names (tcdATs d) }) _ -> decl restrictDataDefn :: [Name] -> HsDataDefn GhcRn -> HsDataDefn GhcRn @@ -207,7 +208,13 @@ restrictCons names decls = [ L p d | L p (Just d) <- map (fmap keep) decls ] keep _ = Nothing restrictDecls :: [Name] -> [LSig GhcRn] -> [LSig GhcRn] -restrictDecls names = mapMaybe (filterLSigNames (`elem` names)) +restrictDecls names = mapMaybe (filterLSigNames func) + where func n | n `elem` names = True + + -- let through default method iff method is let through + | '$':'d':'m':strN <- getOccString n + , strN `elem` map getOccString names = True + | otherwise = False restrictATs :: [Name] -> [LFamilyDecl GhcRn] -> [LFamilyDecl GhcRn] diff --git a/haddock-library/src/Documentation/Haddock/Doc.hs b/haddock-library/src/Documentation/Haddock/Doc.hs index 297d30d61d..7184dc32b7 100644 --- a/haddock-library/src/Documentation/Haddock/Doc.hs +++ b/haddock-library/src/Documentation/Haddock/Doc.hs @@ -1,6 +1,6 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} module Documentation.Haddock.Doc (docParagraph, docAppend, - docConcat, metaDocConcat, + docConcat, metaDocAppend, emptyMetaDoc, metaAppend, metaConcat) where @@ -15,10 +15,6 @@ docConcat = foldr docAppend DocEmpty metaConcat :: [Meta] -> Meta metaConcat = foldr metaAppend emptyMeta --- | Like 'docConcat' but also joins the 'Meta' info. -metaDocConcat :: [MetaDoc mod id] -> MetaDoc mod id -metaDocConcat = foldr metaDocAppend emptyMetaDoc - -- | We do something perhaps unexpected here and join the meta info -- in ‘reverse’: this results in the metadata from the ‘latest’ -- paragraphs taking precedence. diff --git a/hoogle-test/ref/Bug873/test.txt b/hoogle-test/ref/Bug873/test.txt index 3c0e187066..6887331746 100644 --- a/hoogle-test/ref/Bug873/test.txt +++ b/hoogle-test/ref/Bug873/test.txt @@ -21,7 +21,7 @@ module Bug873 -- Note that ($) is levity-polymorphic in its result -- type, so that foo $ True where foo :: Bool -> -- Int# is well-typed. -($) :: () => (a -> b) -> a -> b +($) :: forall (r :: RuntimeRep) a (b :: TYPE r). (a -> b) -> a -> b infixr 0 $ ($$) :: (a -> b) -> a -> b infixr 0 $$ diff --git a/html-test/Main.hs b/html-test/Main.hs index d65a508708..1de2a9c74e 100755 --- a/html-test/Main.hs +++ b/html-test/Main.hs @@ -54,12 +54,6 @@ ingoredTests = -- we need a reliable way to deduplicate here. -- Happens since PR #688. "B" - - -- ignore-exports flag broke with PR #688. We use - -- the Avails calculated by GHC now. Probably - -- requires a change to GHC to "ignore" a modules - -- export list reliably. - , "IgnoreExports" ] checkIgnore :: FilePath -> Bool diff --git a/html-test/ref/Bug548.html b/html-test/ref/Bug548.html index cff64ca2d0..e040e6031a 100644 --- a/html-test/ref/Bug548.html +++ b/html-test/ref/Bug548.html @@ -148,7 +148,9 @@ >

from1 :: :: forall (a0 :: k). WrappedArrow a b a0 -> Rep1

to1 :: :: forall (a0 :: k). Rep1 (WrappedArrowDefaultAssociatedTypes

Safe HaskellSafe

DefaultAssociatedTypes

Synopsis

Documentation

class Foo a where #

Documentation for Foo.

Associated Types

type Qux a #

Doc for Qux

type Qux a = [a] #

Methods

bar :: a -> String #

Documentation for bar and baz.

baz :: a -> String #

Documentation for bar and baz.

\ No newline at end of file diff --git a/html-test/ref/DefaultSignatures.html b/html-test/ref/DefaultSignatures.html new file mode 100644 index 0000000000..061876b4d8 --- /dev/null +++ b/html-test/ref/DefaultSignatures.html @@ -0,0 +1,182 @@ +DefaultSignatures

Safe HaskellSafe

DefaultSignatures

Synopsis

Documentation

class Foo a where #

Documentation for Foo.

Minimal complete definition

baz

Methods

bar :: a -> String #

Documentation for bar and baz.

default bar :: Show a => a -> String #

baz :: a -> String #

Documentation for bar and baz.

baz' :: String -> a #

Documentation for baz'.

default baz' :: Read a => String -> a #

\ No newline at end of file diff --git a/html-test/ref/HideRuntimeReps.html b/html-test/ref/HideRuntimeReps.html new file mode 100644 index 0000000000..ecab70382f --- /dev/null +++ b/html-test/ref/HideRuntimeReps.html @@ -0,0 +1,152 @@ +HideRuntimeReps

Safe HaskellSafe

HideRuntimeReps

Synopsis

Documentation

($) :: (a -> b) -> a -> b infixr 0 #

Application operator. This operator is redundant, since ordinary + application (f x) means the same as (f $ x). However, $ has + low, right-associative binding precedence, so it sometimes allows + parentheses to be omitted; for example:

f $ g $ h x  =  f (g (h x))

It is also useful in higher-order situations, such as map ($ 0) xs, + or zipWith ($) fs xs.

Note that ($) is levity-polymorphic in its result type, so that + foo $ True where foo :: Bool -> Int# + is well-typed

error :: HasCallStack => [Char] -> a #

error stops execution and displays an error message.

\ No newline at end of file diff --git a/html-test/ref/Instances.html b/html-test/ref/Instances.html index 4f51f0492d..0cf0fc92ef 100644 --- a/html-test/ref/Instances.html +++ b/html-test/ref/Instances.html @@ -2038,8 +2038,6 @@ >Int c Bool :: Type #

Thud Int c :: Type c #

type Plugh [a] c [b] :: Type [a] c [b] #

data Thud [a] c :: Type [a] c #

pattern (:+) :: forall a. a -> a -> [a] :: a -> a -> [a]
  • datapattern (:+) :: forall a. a -> a -> [a] :: a -> a -> [a] infixr 3 +> \ No newline at end of file diff --git a/html-test/ref/PatternSyns.html b/html-test/ref/PatternSyns.html index af6d0210b1..6b4f8fda5d 100644 --- a/html-test/ref/PatternSyns.html +++ b/html-test/ref/PatternSyns.html @@ -68,9 +68,7 @@ >pattern Foo :: forall x. x -> :: x -> FooType x
  • pattern Bar :: forall x. x -> :: x -> FooType (FooTypepattern (:<->) :: forall x x1. x -> x1 -> ( :: x -> x1 -> (FooType x, FooTypepattern Blub :: () => forall x. :: () => Show x => x -> BlubTypepattern E :: forall k a (b :: k). a :: a >< b
  • pattern Foo :: forall x. x -> :: x -> FooType x #pattern Bar :: forall x. x -> :: x -> FooType (FooTypepattern (:<->) :: forall x x1. x -> x1 -> ( :: x -> x1 -> (FooType x, FooTypepattern Blub :: () => forall x. :: () => Show x => x -> BlubTypepattern E :: forall k a (b :: k). a :: a >< b # +> \ No newline at end of file diff --git a/html-test/ref/IgnoreExports.html b/html-test/ref/PrefixStarOperator.html similarity index 59% rename from html-test/ref/IgnoreExports.html rename to html-test/ref/PrefixStarOperator.html index eed12c0067..5de211ac1f 100644 --- a/html-test/ref/IgnoreExports.html +++ b/html-test/ref/PrefixStarOperator.html @@ -3,7 +3,7 @@ >IgnoreExportsPrefixStarOperator

    IgnoreExports

    Synopsis
    PrefixStarOperator

    Documentation

    foo :: Int #

    documentation for foo

    bar :: Int type (*) a = (,) a #

    documentation for bar

    PrintRuntimeReps
    Safe HaskellSafe

    PrintRuntimeReps

    Synopsis

    Documentation

    ($) :: forall (r :: RuntimeRep) a (b :: TYPE r). (a -> b) -> a -> b infixr 0 #

    Application operator. This operator is redundant, since ordinary + application (f x) means the same as (f $ x). However, $ has + low, right-associative binding precedence, so it sometimes allows + parentheses to be omitted; for example:

    f $ g $ h x  =  f (g (h x))

    It is also useful in higher-order situations, such as map ($ 0) xs, + or zipWith ($) fs xs.

    Note that ($) is levity-polymorphic in its result type, so that + foo $ True where foo :: Bool -> Int# + is well-typed

    error :: forall (r :: RuntimeRep) (a :: TYPE r). HasCallStack => [Char] -> a #

    error stops execution and displays an error message.

    \ No newline at end of file diff --git a/html-test/ref/TypeFamilies.html b/html-test/ref/TypeFamilies.html index 492b7ec1d7..8e1e736414 100644 --- a/html-test/ref/TypeFamilies.html +++ b/html-test/ref/TypeFamilies.html @@ -286,8 +286,6 @@ >AssocD X :: Type #

    AssocT X :: Type #

    AssocD Y :: Type #

    AssocT Y :: Type #

  • BatZ1 :: forall (z :: Z). :: Z -> Bat
  • BatZ2 :: forall (z :: Z). {..} -> :: {..} -> Bat 'ZB
  • BatZ1 :: forall (z :: Z). :: Z -> Bat
  • BatZ2 :: forall (z :: Z). {..} -> :: {..} -> Bat 'ZBAssocD Y :: Type #

    AssocT Y :: Type #

    AssocD X :: Type #

    AssocT X :: Type #

    -IgnoreExports

    IgnoreExports

    diff --git a/html-test/src/DefaultAssociatedTypes.hs b/html-test/src/DefaultAssociatedTypes.hs new file mode 100644 index 0000000000..6ad197d399 --- /dev/null +++ b/html-test/src/DefaultAssociatedTypes.hs @@ -0,0 +1,14 @@ +{-# LANGUAGE DefaultSignatures, TypeFamilies #-} + +module DefaultAssociatedTypes where + +-- | Documentation for Foo. +class Foo a where + -- | Documentation for bar and baz. + bar, baz :: a -> String + + -- | Doc for Qux + type Qux a :: * + + -- | Doc for default Qux + type Qux a = [a] diff --git a/html-test/src/DefaultSignatures.hs b/html-test/src/DefaultSignatures.hs new file mode 100644 index 0000000000..52d68a9609 --- /dev/null +++ b/html-test/src/DefaultSignatures.hs @@ -0,0 +1,19 @@ +{-# LANGUAGE DefaultSignatures #-} + +module DefaultSignatures where + +-- | Documentation for Foo. +class Foo a where + -- | Documentation for bar and baz. + bar, baz :: a -> String + + -- | Documentation for the default signature of bar. + default bar :: Show a => a -> String + bar = show + + -- | Documentation for baz'. + baz' :: String -> a + + -- | Documentation for the default signature of baz'. + default baz' :: Read a => String -> a + baz' = read diff --git a/html-test/src/HideRuntimeReps.hs b/html-test/src/HideRuntimeReps.hs new file mode 100644 index 0000000000..9fa035f78d --- /dev/null +++ b/html-test/src/HideRuntimeReps.hs @@ -0,0 +1,2 @@ +module HideRuntimeReps (($), error) where +-- Type variables of kind 'RuntimeRep' are hidden by default. diff --git a/html-test/src/IgnoreExports.hs b/html-test/src/IgnoreExports.hs deleted file mode 100644 index 0321ad0272..0000000000 --- a/html-test/src/IgnoreExports.hs +++ /dev/null @@ -1,10 +0,0 @@ -{-# OPTIONS_HADDOCK ignore-exports #-} -module IgnoreExports (foo) where - --- | documentation for foo -foo :: Int -foo = 23 - --- | documentation for bar -bar :: Int -bar = 23 diff --git a/html-test/src/PrefixStarOperator.hs b/html-test/src/PrefixStarOperator.hs new file mode 100644 index 0000000000..2532099153 --- /dev/null +++ b/html-test/src/PrefixStarOperator.hs @@ -0,0 +1,3 @@ +{-# LANGUAGE TypeOperators, NoStarIsType #-} +module PrefixStarOperator where +type (*) a = (,) a diff --git a/html-test/src/PrintRuntimeReps.hs b/html-test/src/PrintRuntimeReps.hs new file mode 100644 index 0000000000..6dce82a77b --- /dev/null +++ b/html-test/src/PrintRuntimeReps.hs @@ -0,0 +1,2 @@ +{-# OPTIONS_HADDOCK print-explicit-runtime-reps #-} +module PrintRuntimeReps (($), error) where diff --git a/latex-test/ref/DefaultSignatures/DefaultSignatures.tex b/latex-test/ref/DefaultSignatures/DefaultSignatures.tex new file mode 100644 index 0000000000..63ec7beb16 --- /dev/null +++ b/latex-test/ref/DefaultSignatures/DefaultSignatures.tex @@ -0,0 +1,48 @@ +\haddockmoduleheading{DefaultSignatures} +\label{module:DefaultSignatures} +\haddockbeginheader +{\haddockverb\begin{verbatim} +module DefaultSignatures ( + Foo(baz', baz, bar) + ) where\end{verbatim}} +\haddockendheader + +\begin{haddockdesc} +\item[\begin{tabular}{@{}l} +class\ Foo\ a\ where +\end{tabular}]\haddockbegindoc +Documentation for Foo.\par + +\haddockpremethods{}\emph{Methods} +\begin{haddockdesc} +\item[\begin{tabular}{@{}l} +bar\ ::\ a\ ->\ String +\end{tabular}]\haddockbegindoc +Documentation for bar and baz.\par + +\end{haddockdesc} +\begin{haddockdesc} +\item[\begin{tabular}{@{}l} +default\ bar\ ::\ Show\ a\ =>\ a\ ->\ String +\end{tabular}] +\end{haddockdesc} +\begin{haddockdesc} +\item[\begin{tabular}{@{}l} +baz\ ::\ a\ ->\ String +\end{tabular}]\haddockbegindoc +Documentation for bar and baz.\par + +\end{haddockdesc} +\begin{haddockdesc} +\item[\begin{tabular}{@{}l} +baz'\ ::\ String\ ->\ a +\end{tabular}]\haddockbegindoc +Documentation for baz'.\par + +\end{haddockdesc} +\begin{haddockdesc} +\item[\begin{tabular}{@{}l} +default\ baz'\ ::\ Read\ a\ =>\ String\ ->\ a +\end{tabular}] +\end{haddockdesc} +\end{haddockdesc} \ No newline at end of file diff --git a/latex-test/ref/DefaultSignatures/haddock.sty b/latex-test/ref/DefaultSignatures/haddock.sty new file mode 100644 index 0000000000..6e031a98b6 --- /dev/null +++ b/latex-test/ref/DefaultSignatures/haddock.sty @@ -0,0 +1,57 @@ +% Default Haddock style definitions. To use your own style, invoke +% Haddock with the option --latex-style=mystyle. + +\usepackage{tabulary} % see below + +% make hyperlinks in the PDF, and add an expandabale index +\usepackage[pdftex,bookmarks=true]{hyperref} + +\newenvironment{haddocktitle} + {\begin{center}\bgroup\large\bfseries} + {\egroup\end{center}} +\newenvironment{haddockprologue}{\vspace{1in}}{} + +\newcommand{\haddockmoduleheading}[1]{\chapter{\texttt{#1}}} + +\newcommand{\haddockbeginheader}{\hrulefill} +\newcommand{\haddockendheader}{\noindent\hrulefill} + +% a little gap before the ``Methods'' header +\newcommand{\haddockpremethods}{\vspace{2ex}} + +% inserted before \\begin{verbatim} +\newcommand{\haddockverb}{\small} + +% an identifier: add an index entry +\newcommand{\haddockid}[1]{\haddocktt{#1}\index{#1@\texttt{#1}}} + +% The tabulary environment lets us have a column that takes up ``the +% rest of the space''. Unfortunately it doesn't allow +% the \end{tabulary} to be in the expansion of a macro, it must appear +% literally in the document text, so Haddock inserts +% the \end{tabulary} itself. +\newcommand{\haddockbeginconstrs}{\begin{tabulary}{\linewidth}{@{}llJ@{}}} +\newcommand{\haddockbeginargs}{\begin{tabulary}{\linewidth}{@{}llJ@{}}} + +\newcommand{\haddocktt}[1]{{\small \texttt{#1}}} +\newcommand{\haddockdecltt}[1]{{\small\bfseries \texttt{#1}}} + +\makeatletter +\newenvironment{haddockdesc} + {\list{}{\labelwidth\z@ \itemindent-\leftmargin + \let\makelabel\haddocklabel}} + {\endlist} +\newcommand*\haddocklabel[1]{\hspace\labelsep\haddockdecltt{#1}} +\makeatother + +% after a declaration, start a new line for the documentation. +% Otherwise, the documentation starts right after the declaration, +% because we're using the list environment and the declaration is the +% ``label''. I tried making this newline part of the label, but +% couldn't get that to work reliably (the space seemed to stretch +% sometimes). +\newcommand{\haddockbegindoc}{\hfill\\[1ex]} + +% spacing between paragraphs and no \parindent looks better +\parskip=10pt plus2pt minus2pt +\setlength{\parindent}{0cm} diff --git a/latex-test/ref/DefaultSignatures/main.tex b/latex-test/ref/DefaultSignatures/main.tex new file mode 100644 index 0000000000..d30eb00840 --- /dev/null +++ b/latex-test/ref/DefaultSignatures/main.tex @@ -0,0 +1,11 @@ +\documentclass{book} +\usepackage{haddock} +\begin{document} +\begin{titlepage} +\begin{haddocktitle} + +\end{haddocktitle} +\end{titlepage} +\tableofcontents +\input{DefaultSignatures} +\end{document} \ No newline at end of file diff --git a/latex-test/ref/Deprecated/Deprecated.tex b/latex-test/ref/Deprecated/Deprecated.tex new file mode 100644 index 0000000000..fa8fc20ac2 --- /dev/null +++ b/latex-test/ref/Deprecated/Deprecated.tex @@ -0,0 +1,17 @@ +\haddockmoduleheading{Deprecated} +\label{module:Deprecated} +\haddockbeginheader +{\haddockverb\begin{verbatim} +module Deprecated ( + deprecated + ) where\end{verbatim}} +\haddockendheader + +\begin{haddockdesc} +\item[\begin{tabular}{@{}l} +deprecated\ ::\ Int +\end{tabular}]\haddockbegindoc +Deprecated: Don't use this\par +Docs for something deprecated\par + +\end{haddockdesc} \ No newline at end of file diff --git a/latex-test/ref/Deprecated/haddock.sty b/latex-test/ref/Deprecated/haddock.sty new file mode 100644 index 0000000000..6e031a98b6 --- /dev/null +++ b/latex-test/ref/Deprecated/haddock.sty @@ -0,0 +1,57 @@ +% Default Haddock style definitions. To use your own style, invoke +% Haddock with the option --latex-style=mystyle. + +\usepackage{tabulary} % see below + +% make hyperlinks in the PDF, and add an expandabale index +\usepackage[pdftex,bookmarks=true]{hyperref} + +\newenvironment{haddocktitle} + {\begin{center}\bgroup\large\bfseries} + {\egroup\end{center}} +\newenvironment{haddockprologue}{\vspace{1in}}{} + +\newcommand{\haddockmoduleheading}[1]{\chapter{\texttt{#1}}} + +\newcommand{\haddockbeginheader}{\hrulefill} +\newcommand{\haddockendheader}{\noindent\hrulefill} + +% a little gap before the ``Methods'' header +\newcommand{\haddockpremethods}{\vspace{2ex}} + +% inserted before \\begin{verbatim} +\newcommand{\haddockverb}{\small} + +% an identifier: add an index entry +\newcommand{\haddockid}[1]{\haddocktt{#1}\index{#1@\texttt{#1}}} + +% The tabulary environment lets us have a column that takes up ``the +% rest of the space''. Unfortunately it doesn't allow +% the \end{tabulary} to be in the expansion of a macro, it must appear +% literally in the document text, so Haddock inserts +% the \end{tabulary} itself. +\newcommand{\haddockbeginconstrs}{\begin{tabulary}{\linewidth}{@{}llJ@{}}} +\newcommand{\haddockbeginargs}{\begin{tabulary}{\linewidth}{@{}llJ@{}}} + +\newcommand{\haddocktt}[1]{{\small \texttt{#1}}} +\newcommand{\haddockdecltt}[1]{{\small\bfseries \texttt{#1}}} + +\makeatletter +\newenvironment{haddockdesc} + {\list{}{\labelwidth\z@ \itemindent-\leftmargin + \let\makelabel\haddocklabel}} + {\endlist} +\newcommand*\haddocklabel[1]{\hspace\labelsep\haddockdecltt{#1}} +\makeatother + +% after a declaration, start a new line for the documentation. +% Otherwise, the documentation starts right after the declaration, +% because we're using the list environment and the declaration is the +% ``label''. I tried making this newline part of the label, but +% couldn't get that to work reliably (the space seemed to stretch +% sometimes). +\newcommand{\haddockbegindoc}{\hfill\\[1ex]} + +% spacing between paragraphs and no \parindent looks better +\parskip=10pt plus2pt minus2pt +\setlength{\parindent}{0cm} diff --git a/latex-test/ref/Deprecated/main.tex b/latex-test/ref/Deprecated/main.tex new file mode 100644 index 0000000000..76def1cddf --- /dev/null +++ b/latex-test/ref/Deprecated/main.tex @@ -0,0 +1,11 @@ +\documentclass{book} +\usepackage{haddock} +\begin{document} +\begin{titlepage} +\begin{haddocktitle} + +\end{haddocktitle} +\end{titlepage} +\tableofcontents +\input{Deprecated} +\end{document} \ No newline at end of file diff --git a/latex-test/ref/Example/Example.tex b/latex-test/ref/Example/Example.tex new file mode 100644 index 0000000000..0a4f057342 --- /dev/null +++ b/latex-test/ref/Example/Example.tex @@ -0,0 +1,30 @@ +\haddockmoduleheading{Example} +\label{module:Example} +\haddockbeginheader +{\haddockverb\begin{verbatim} +module Example ( + split + ) where\end{verbatim}} +\haddockendheader + +\begin{haddockdesc} +\item[\begin{tabular}{@{}l} +split\ ::\ Int\ ->\ () +\end{tabular}]\haddockbegindoc +Example use.\par +\begin{quote} +{\haddockverb\begin{verbatim} +>>> split 1 +() + +\end{verbatim}} +\end{quote} +\begin{quote} +{\haddockverb\begin{verbatim} +>>> split 2 +() + +\end{verbatim}} +\end{quote} + +\end{haddockdesc} \ No newline at end of file diff --git a/latex-test/ref/Example/haddock.sty b/latex-test/ref/Example/haddock.sty new file mode 100644 index 0000000000..6e031a98b6 --- /dev/null +++ b/latex-test/ref/Example/haddock.sty @@ -0,0 +1,57 @@ +% Default Haddock style definitions. To use your own style, invoke +% Haddock with the option --latex-style=mystyle. + +\usepackage{tabulary} % see below + +% make hyperlinks in the PDF, and add an expandabale index +\usepackage[pdftex,bookmarks=true]{hyperref} + +\newenvironment{haddocktitle} + {\begin{center}\bgroup\large\bfseries} + {\egroup\end{center}} +\newenvironment{haddockprologue}{\vspace{1in}}{} + +\newcommand{\haddockmoduleheading}[1]{\chapter{\texttt{#1}}} + +\newcommand{\haddockbeginheader}{\hrulefill} +\newcommand{\haddockendheader}{\noindent\hrulefill} + +% a little gap before the ``Methods'' header +\newcommand{\haddockpremethods}{\vspace{2ex}} + +% inserted before \\begin{verbatim} +\newcommand{\haddockverb}{\small} + +% an identifier: add an index entry +\newcommand{\haddockid}[1]{\haddocktt{#1}\index{#1@\texttt{#1}}} + +% The tabulary environment lets us have a column that takes up ``the +% rest of the space''. Unfortunately it doesn't allow +% the \end{tabulary} to be in the expansion of a macro, it must appear +% literally in the document text, so Haddock inserts +% the \end{tabulary} itself. +\newcommand{\haddockbeginconstrs}{\begin{tabulary}{\linewidth}{@{}llJ@{}}} +\newcommand{\haddockbeginargs}{\begin{tabulary}{\linewidth}{@{}llJ@{}}} + +\newcommand{\haddocktt}[1]{{\small \texttt{#1}}} +\newcommand{\haddockdecltt}[1]{{\small\bfseries \texttt{#1}}} + +\makeatletter +\newenvironment{haddockdesc} + {\list{}{\labelwidth\z@ \itemindent-\leftmargin + \let\makelabel\haddocklabel}} + {\endlist} +\newcommand*\haddocklabel[1]{\hspace\labelsep\haddockdecltt{#1}} +\makeatother + +% after a declaration, start a new line for the documentation. +% Otherwise, the documentation starts right after the declaration, +% because we're using the list environment and the declaration is the +% ``label''. I tried making this newline part of the label, but +% couldn't get that to work reliably (the space seemed to stretch +% sometimes). +\newcommand{\haddockbegindoc}{\hfill\\[1ex]} + +% spacing between paragraphs and no \parindent looks better +\parskip=10pt plus2pt minus2pt +\setlength{\parindent}{0cm} diff --git a/latex-test/ref/Example/main.tex b/latex-test/ref/Example/main.tex new file mode 100644 index 0000000000..66459115f1 --- /dev/null +++ b/latex-test/ref/Example/main.tex @@ -0,0 +1,11 @@ +\documentclass{book} +\usepackage{haddock} +\begin{document} +\begin{titlepage} +\begin{haddocktitle} + +\end{haddocktitle} +\end{titlepage} +\tableofcontents +\input{Example} +\end{document} \ No newline at end of file diff --git a/latex-test/src/DefaultSignatures/DefaultSignatures.hs b/latex-test/src/DefaultSignatures/DefaultSignatures.hs new file mode 100644 index 0000000000..52d68a9609 --- /dev/null +++ b/latex-test/src/DefaultSignatures/DefaultSignatures.hs @@ -0,0 +1,19 @@ +{-# LANGUAGE DefaultSignatures #-} + +module DefaultSignatures where + +-- | Documentation for Foo. +class Foo a where + -- | Documentation for bar and baz. + bar, baz :: a -> String + + -- | Documentation for the default signature of bar. + default bar :: Show a => a -> String + bar = show + + -- | Documentation for baz'. + baz' :: String -> a + + -- | Documentation for the default signature of baz'. + default baz' :: Read a => String -> a + baz' = read diff --git a/latex-test/src/Deprecated/Deprecated.hs b/latex-test/src/Deprecated/Deprecated.hs new file mode 100644 index 0000000000..aecec94e9b --- /dev/null +++ b/latex-test/src/Deprecated/Deprecated.hs @@ -0,0 +1,7 @@ +module Deprecated where + +-- | Docs for something deprecated +deprecated :: Int +deprecated = 1 + +{-# DEPRECATED deprecated "Don't use this" #-} diff --git a/latex-test/src/Example/Example.hs b/latex-test/src/Example/Example.hs new file mode 100644 index 0000000000..42ff1646ef --- /dev/null +++ b/latex-test/src/Example/Example.hs @@ -0,0 +1,11 @@ +module Example where + +-- | Example use. +-- +-- >>> split 1 +-- () +-- +-- >>> split 2 +-- () +split :: Int -> () +split _ = ()