diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 773415d70d0d3a..d409eea9a6ca8f 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -254,179 +254,6 @@ function getdoc end getdoc(@nospecialize(x), @nospecialize(sig)) = getdoc(x) getdoc(@nospecialize(x)) = nothing -""" - Docs.doc(binding, sig) - -Return all documentation that matches both `binding` and `sig`. - -If `getdoc` returns a non-`nothing` result on the value of the binding, then a -dynamic docstring is returned instead of one based on the binding itself. -""" -function doc(binding::Binding, sig::Type = Union{}) - if defined(binding) - result = getdoc(resolve(binding), sig) - result === nothing || return result - end - results, groups, sigs = DocStr[], MultiDoc[], Any[] - # Lookup `binding` and `sig` for matches in all modules of the docsystem. - for mod in modules - dict = meta(mod) - if haskey(dict, binding) - multidoc = dict[binding] - push!(groups, multidoc) - for msig in multidoc.order - if (isconcrete(sig) && sig <: msig) || (!isconcrete(sig) && msig <: sig) || sig == Union{} - push!(sigs, msig) - push!(results, multidoc.docs[msig]) - end - end - end - end - if isempty(groups) - # When no `MultiDoc`s are found that match `binding` then we check whether `binding` - # is an alias of some other `Binding`. When it is we then re-run `doc` with that - # `Binding`, otherwise if it's not an alias then we generate a summary for the - # `binding` and display that to the user instead. - alias = aliasof(binding) - alias == binding ? summarize(alias, sig) : doc(alias, sig) - else - # There was at least one match for `binding` while searching. If there weren't any - # matches for `sig` then we concatenate *all* the docs from the matching `Binding`s. - if isempty(results) - for group in groups, each in group.order - push!(results, group.docs[each]) - end - elseif sig != Union{} - # If the signature is abstract, only show more specific methods - morespec = [x <: sig && x != Union{} for x in sigs] - if !any(morespec) - # If not any method is more specific that sig, show the most specific one - results = DocStr[results[first(sortperm(sigs, lt = (a,b) -> a <: b))]] - else - results = results[morespec] - end - end - # Get parsed docs and concatenate them. - md = catdoc(map(parsedoc, results)...) - # Save metadata in the generated markdown. - if isa(md, Markdown.MD) - md.meta[:results] = results - md.meta[:binding] = binding - md.meta[:typesig] = sig - end - return md - end -end - -# Some additional convenience `doc` methods that take objects rather than `Binding`s. -doc(obj::UnionAll) = doc(Base.unwrap_unionall(obj)) -doc(object, sig::Type = Union{}) = doc(aliasof(object, typeof(object)), sig) -doc(object, sig...) = doc(object, Tuple{sig...}) - -""" - Docs.fielddoc(binding, field) - -Return documentation for a particular `field` of a type if it exists. -""" -function fielddoc(binding::Binding, field::Symbol) - for mod in modules - dict = meta(mod) - if haskey(dict, binding) - multidoc = dict[binding] - if haskey(multidoc.docs, Union{}) - fields = multidoc.docs[Union{}].data[:fields] - if haskey(fields, field) - doc = fields[field] - return isa(doc, Markdown.MD) ? doc : Markdown.parse(doc) - end - end - end - end - fields = join(["`$f`" for f in fieldnames(resolve(binding))], ", ", ", and ") - fields = isempty(fields) ? "no fields" : "fields $fields" - Markdown.parse("`$(resolve(binding))` has $fields.") -end - -# As with the additional `doc` methods, this converts an object to a `Binding` first. -fielddoc(object, field::Symbol) = fielddoc(aliasof(object, typeof(object)), field) - -# Object Summaries. -# ================= - -function summarize(binding::Binding, sig) - io = IOBuffer() - println(io, "No documentation found.\n") - if defined(binding) - summarize(io, resolve(binding), binding) - else - println(io, "Binding `", binding, "` does not exist.") - end - md = Markdown.parse(seekstart(io)) - # Save metadata in the generated markdown. - md.meta[:results] = DocStr[] - md.meta[:binding] = binding - md.meta[:typesig] = sig - return md -end - -function summarize(io::IO, λ::Function, binding) - kind = startswith(string(binding.var), '@') ? "macro" : "`Function`" - println(io, "`", binding, "` is a ", kind, ".") - println(io, "```\n", methods(λ), "\n```") -end - -function summarize(io::IO, T::DataType, binding) - println(io, "# Summary") - println(io, "```") - println(io, - T.abstract ? "abstract type" : - T.mutable ? "mutable struct" : - Base.isstructtype(T) ? "struct" : "primitive type", - " ", T, " <: ", supertype(T) - ) - println(io, "```") - if !T.abstract && T.name !== Tuple.name && !isempty(fieldnames(T)) - println(io, "# Fields") - println(io, "```") - pad = maximum(length(string(f)) for f in fieldnames(T)) - for (f, t) in zip(fieldnames(T), T.types) - println(io, rpad(f, pad), " :: ", t) - end - println(io, "```") - end - if !isempty(subtypes(T)) - println(io, "# Subtypes") - println(io, "```") - for t in subtypes(T) - println(io, t) - end - println(io, "```") - end - if supertype(T) != Any - println(io, "# Supertype Hierarchy") - println(io, "```") - Base.show_supertypes(io, T) - println(io) - println(io, "```") - end -end - -function summarize(io::IO, m::Module, binding) - readme = Pkg.dir(string(m), "README.md") - if isfile(readme) - println(io, "Displaying the `README.md` for the module instead.\n") - println(io, "---\n") - println(io, read(readme, String)) - else - println(io, "No docstring or `README.md` found for module `", m, "`.\n") - end -end - -function summarize(io::IO, ::T, binding) where T - println(io, "`", binding, "` is of type `", T, "`.\n") - summarize(io, T, binding) -end - # Utilities. # ========== diff --git a/stdlib/REPL/src/docview.jl b/stdlib/REPL/src/docview.jl index ebb2dcbd70d0dd..114e2ad37ce625 100644 --- a/stdlib/REPL/src/docview.jl +++ b/stdlib/REPL/src/docview.jl @@ -86,7 +86,7 @@ function doc(binding::Binding, sig::Type = Union{}) result = getdoc(resolve(binding), sig) result === nothing || return result end - results, groups = DocStr[], MultiDoc[] + results, groups, sigs = DocStr[], MultiDoc[], Any[] # Lookup `binding` and `sig` for matches in all modules of the docsystem. for mod in modules dict = meta(mod) @@ -94,7 +94,11 @@ function doc(binding::Binding, sig::Type = Union{}) multidoc = dict[binding] push!(groups, multidoc) for msig in multidoc.order - sig <: msig && push!(results, multidoc.docs[msig]) + if typeintersect(msig, sig) != Union{} + #if (isconcretetype(sig) && sig <: msig) || (!isconcretetype(sig) && msig <: sig) || sig == Union{} + push!(sigs, msig) + push!(results, multidoc.docs[msig]) + end end end end @@ -112,6 +116,15 @@ function doc(binding::Binding, sig::Type = Union{}) for group in groups, each in group.order push!(results, group.docs[each]) end + elseif sig != Union{} + # If the signature is abstract, only show more specific methods + morespec = [x <: sig && x != Union{} for x in sigs] + if !any(morespec) + # If not any method is more specific that sig, show the most specific one + results = DocStr[results[first(sortperm(sigs, lt = (a,b) -> a <: b))]] + else + results = results[morespec] + end end # Get parsed docs and concatenate them. md = catdoc(map(parsedoc, results)...) diff --git a/test/docs.jl b/test/docs.jl index c6cbb3847ae28d..19dba237e17574 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -1145,3 +1145,57 @@ end end @test M27832.xs == ":(\$(Expr(:\$, :fn)))" Core.atdoc!(_last_atdoc) + +# issue #20064 + +""" +f_20064 +""" +function f_20064 end + +""" +Number +""" +f_20064(x::Number) = x + +""" +Real +""" +f_20064(x::Real) = x + +""" +Int +""" +f_20064(x::Int) = x + +""" +Real, Int +""" +f_20064(x::Real, y::Int) = x + +@test docstrings_equal(Docs.doc(f_20064, Tuple{Int}), + doc""" + Int + """) + +@test docstrings_equal(Docs.doc(f_20064, Tuple{Float64}), + doc""" + Real + """) + +@test docstrings_equal(Docs.doc(f_20064, Tuple{Float64, Int}), + doc""" + Real, Int + """) + +@test docstrings_equal(Docs.doc(f_20064, Tuple{Real}), + doc""" + Real + + Int + """) + +@test docstrings_equal(Docs.doc(f_20064, Tuple{Real, Real}), + doc""" + Real, Int + """)