# This file is a part of Julia. License is MIT: http://julialang.org/license # fallback text/plain representation of any type: show(io::IO, ::MIME"text/plain", x) = show(io, x) # multiline show functions for types defined before multimedia.jl: function show(io::IO, ::MIME"text/plain", iter::Union{KeyIterator,ValueIterator}) print(io, summary(iter)) isempty(iter) && return print(io, ". ", isa(iter,KeyIterator) ? "Keys" : "Values", ":") limit::Bool = get(io, :limit, false) if limit sz = displaysize(io) rows, cols = sz[1] - 3, sz[2] rows < 2 && (print(io, " …"); return) cols < 4 && (cols = 4) cols -= 2 # For prefix " " rows -= 2 # For summary and final ⋮ continuation lines else rows = cols = 0 end for (i, v) in enumerate(iter) print(io, "\n ") limit && i >= rows && (print(io, "⋮"); break) if limit str = sprint(0, show, v, env=io) str = _truncate_at_width_or_chars(str, cols, "\r\n") print(io, str) else show(io, v) end end end function show{K,V}(io::IO, ::MIME"text/plain", t::Associative{K,V}) # show more descriptively, with one line per key/value pair recur_io = IOContext(io, :SHOWN_SET => t) limit::Bool = get(io, :limit, false) if !haskey(io, :compact) recur_io = IOContext(recur_io, :compact => true) end print(io, summary(t)) isempty(t) && return print(io, ":\n ") show_circular(io, t) && return if limit sz = displaysize(io) rows, cols = sz[1] - 3, sz[2] rows < 2 && (print(io, " …"); return) cols < 12 && (cols = 12) # Minimum widths of 2 for key, 4 for value cols -= 6 # Subtract the widths of prefix " " separator " => " rows -= 2 # Subtract the summary and final ⋮ continuation lines # determine max key width to align the output, caching the strings ks = Array{AbstractString}(min(rows, length(t))) vs = Array{AbstractString}(min(rows, length(t))) keylen = 0 vallen = 0 for (i, (k, v)) in enumerate(t) i > rows && break ks[i] = sprint(0, show, k, env=recur_io) vs[i] = sprint(0, show, v, env=recur_io) keylen = clamp(length(ks[i]), keylen, cols) vallen = clamp(length(vs[i]), vallen, cols) end if keylen > max(div(cols, 2), cols - vallen) keylen = max(cld(cols, 3), cols - vallen) end else rows = cols = 0 end first = true for (i, (k, v)) in enumerate(t) first || print(io, "\n ") first = false limit && i > rows && (print(io, rpad("⋮", keylen), " => ⋮"); break) if limit key = rpad(_truncate_at_width_or_chars(ks[i], keylen, "\r\n"), keylen) else key = sprint(0, show, k, env=recur_io) end print(recur_io, key) print(io, " => ") if limit val = _truncate_at_width_or_chars(vs[i], cols - keylen, "\r\n") print(io, val) else show(recur_io, v) end end end function show(io::IO, ::MIME"text/plain", f::Function) ft = typeof(f) mt = ft.name.mt if isa(f, Core.IntrinsicFunction) show(io, f) id = Core.Intrinsics.bitcast(Int32, f) print(io, " (intrinsic function #$id)") elseif isa(f, Core.Builtin) print(io, mt.name, " (built-in function)") else name = mt.name isself = isdefined(ft.name.module, name) && ft == typeof(getfield(ft.name.module, name)) n = length(methods(f)) m = n==1 ? "method" : "methods" ns = isself ? string(name) : string("(::", name, ")") what = startswith(ns, '@') ? "macro" : "generic function" print(io, ns, " (", what, " with $n $m)") end end function show(io::IO, ::MIME"text/plain", r::LinSpace) # show for linspace, e.g. # linspace(1,3,7) # 7-element LinSpace{Float64}: # 1.0,1.33333,1.66667,2.0,2.33333,2.66667,3.0 print(io, summary(r)) if !isempty(r) println(io, ":") print_range(io, r) end end function show(io::IO, ::MIME"text/plain", t::Task) show(io, t) if t.state == :failed println(io) showerror(io, CapturedException(t.result, t.backtrace)) end end show(io::IO, ::MIME"text/plain", X::AbstractArray) = showarray(io, X, false) show(io::IO, ::MIME"text/plain", r::Range) = show(io, r) # always use the compact form for printing ranges # display something useful even for strings containing arbitrary # (non-UTF8) binary data: function show(io::IO, ::MIME"text/plain", s::String) if isvalid(s) show(io, s) else println(io, sizeof(s), "-byte String of invalid UTF-8 data:") showarray(io, Vector{UInt8}(s), false; header=false) end end # showing exception objects as descriptive error messages showerror(io::IO, ex) = show(io, ex) function showerror(io::IO, ex::BoundsError) print(io, "BoundsError") if isdefined(ex, :a) print(io, ": attempt to access ") if isa(ex.a, AbstractArray) print(io, summary(ex.a)) else show(io, MIME"text/plain"(), ex.a) end if isdefined(ex, :i) !isa(ex.a, AbstractArray) && print(io, "\n ") print(io, " at index [") if isa(ex.i, Range) print(io, ex.i) else join(io, ex.i, ", ") end print(io, ']') end end end function showerror(io::IO, ex::TypeError) print(io, "TypeError: ") ctx = isempty(ex.context) ? "" : "in $(ex.context), " if ex.expected === Bool print(io, "non-boolean ($(typeof(ex.got))) used in boolean context") else if isa(ex.got, Type) tstr = "Type{$(ex.got)}" else tstr = string(typeof(ex.got)) end print(io, "$(ex.func): $(ctx)expected $(ex.expected), got $tstr") end end function showerror(io::IO, ex, bt; backtrace=true) try with_output_color(have_color ? error_color() : :nothing, io) do io showerror(io, ex) end finally backtrace && show_backtrace(io, bt) end end function showerror(io::IO, ex::LoadError, bt; backtrace=true) print(io, "LoadError: ") showerror(io, ex.error, bt, backtrace=backtrace) print(io, "\nwhile loading $(ex.file), in expression starting on line $(ex.line)") end showerror(io::IO, ex::LoadError) = showerror(io, ex, []) function showerror(io::IO, ex::InitError, bt; backtrace=true) print(io, "InitError: ") showerror(io, ex.error, bt, backtrace=backtrace) print(io, "\nduring initialization of module $(ex.mod)") end showerror(io::IO, ex::InitError) = showerror(io, ex, []) function showerror(io::IO, ex::DomainError, bt; backtrace=true) print(io, "DomainError:") for b in bt for code in StackTraces.lookup(b) if code.from_c continue elseif code.func === :nan_dom_err continue elseif code.func in (:log, :log2, :log10, :sqrt) print(io, "\n$(code.func) will only return a complex result if called ", "with a complex argument. Try $(string(code.func))(complex(x)).") elseif (code.func === :^ && (code.file === Symbol("intfuncs.jl") || code.file === Symbol(joinpath(".", "intfuncs.jl")))) || code.func === :power_by_squaring #3024 print(io, "\nCannot raise an integer x to a negative power -n. ", "\nMake x a float by adding a zero decimal (e.g. 2.0^-n instead ", "of 2^-n), or write 1/x^n, float(x)^-n, or (x//1)^-n.") elseif code.func === :^ && (code.file === Symbol("math.jl") || code.file === Symbol(joinpath(".", "math.jl"))) print(io, "\nExponentiation yielding a complex result requires a complex ", "argument.\nReplace x^y with (x+0im)^y, Complex(x)^y, or similar.") end @goto showbacktrace end end @label showbacktrace backtrace && show_backtrace(io, bt) nothing end function showerror(io::IO, ex::SystemError) if ex.extrainfo === nothing print(io, "SystemError: $(ex.prefix): $(Libc.strerror(ex.errnum))") else print(io, "SystemError (with $(ex.extrainfo)): $(ex.prefix): $(Libc.strerror(ex.errnum))") end end showerror(io::IO, ::DivideError) = print(io, "DivideError: integer division error") showerror(io::IO, ::StackOverflowError) = print(io, "StackOverflowError:") showerror(io::IO, ::UndefRefError) = print(io, "UndefRefError: access to undefined reference") showerror(io::IO, ::EOFError) = print(io, "EOFError: read end of file") function showerror(io::IO, ex::ErrorException) print(io, ex.msg) if ex.msg == "type String has no field data" println(io) print(io, "Use `Vector{UInt8}(str)` instead.") end end showerror(io::IO, ex::KeyError) = print(io, "KeyError: key $(repr(ex.key)) not found") showerror(io::IO, ex::InterruptException) = print(io, "InterruptException:") showerror(io::IO, ex::ArgumentError) = print(io, "ArgumentError: $(ex.msg)") showerror(io::IO, ex::AssertionError) = print(io, "AssertionError: $(ex.msg)") function showerror(io::IO, ex::UndefVarError) if ex.var in [:UTF16String, :UTF32String, :WString, :utf16, :utf32, :wstring, :RepString] return showerror(io, ErrorException(""" `$(ex.var)` has been moved to the package LegacyStrings.jl: Run Pkg.add("LegacyStrings") to install LegacyStrings on Julia v0.5-; Then do `using LegacyStrings` to get `$(ex.var)`. """)) end print(io, "UndefVarError: $(ex.var) not defined") end function showerror(io::IO, ex::MethodError) # ex.args is a tuple type if it was thrown from `invoke` and is # a tuple of the arguments otherwise. is_arg_types = isa(ex.args, DataType) arg_types = is_arg_types ? ex.args : typesof(ex.args...) f = ex.f meth = methods_including_ambiguous(f, arg_types) if length(meth) > 1 return showerror_ambiguous(io, meth, f, arg_types) end arg_types_param::SimpleVector = arg_types.parameters print(io, "MethodError: ") ft = typeof(f) name = ft.name.mt.name f_is_function = false kwargs = Any[] if startswith(string(ft.name.name), "#kw#") f = ex.args[2] ft = typeof(f) name = ft.name.mt.name arg_types_param = arg_types_param[3:end] temp = ex.args[1] kwargs = Any[(temp[i*2-1], temp[i*2]) for i in 1:(length(temp) ÷ 2)] ex = MethodError(f, ex.args[3:end]) end if f == Base.convert && length(arg_types_param) == 2 && !is_arg_types f_is_function = true # See #13033 T = striptype(ex.args[1]) if T === nothing print(io, "First argument to `convert` must be a Type, got ", ex.args[1]) else print(io, "Cannot `convert` an object of type ", arg_types_param[2], " to an object of type ", T) end elseif isempty(methods(f)) && !isa(f, Function) print(io, "objects of type $ft are not callable") else if ft <: Function && isempty(ft.parameters) && isdefined(ft.name.module, name) && ft == typeof(getfield(ft.name.module, name)) f_is_function = true print(io, "no method matching ", name) elseif isa(f, Type) if isa(f, DataType) && f.abstract # Print a more appropriate message if the only method # on the type is the default one from sysimg.jl. ms = methods(f) if length(ms) == 1 m = first(ms) if Base.is_default_method(m) print(io, "no constructors have been defined for $f") return end end end print(io, "no method matching ", f) else print(io, "no method matching (::", ft, ")") end print(io, "(") for (i, typ) in enumerate(arg_types_param) print(io, "::$typ") i == length(arg_types_param) || print(io, ", ") end if !isempty(kwargs) print(io, "; ") for (i, (k, v)) in enumerate(kwargs) print(io, k, "=") show(IOContext(io, :limit=>true), v) i == length(kwargs) || print(io, ", ") end end print(io, ")") end if ft <: AbstractArray print(io, "\nUse square brackets [] for indexing an Array.") end # Check for local functions that shadow methods in Base if f_is_function && isdefined(Base, name) basef = getfield(Base, name) if basef !== ex.f && method_exists(basef, arg_types) println(io) print(io, "You may have intended to import Base.", name) end end if (ex.world != typemax(UInt) && method_exists(ex.f, arg_types) && !method_exists(ex.f, arg_types, ex.world)) curworld = ccall(:jl_get_world_counter, UInt, ()) println(io) print(io, "The applicable method may be too new: running in world age $(ex.world), while current world is $(curworld).") end if !is_arg_types # Check for row vectors used where a column vector is intended. vec_args = [] hasrows = false for arg in ex.args isrow = isa(arg,Array) && ndims(arg)==2 && size(arg,1)==1 hasrows |= isrow push!(vec_args, isrow ? vec(arg) : arg) end if hasrows && applicable(f, vec_args...) print(io, "\n\nYou might have used a 2d row vector where a 1d column vector was required.", "\nNote the difference between 1d column vector [1,2,3] and 2d row vector [1 2 3].", "\nYou can convert to a column vector with the vec() function.") end end # Give a helpful error message if the user likely called a type constructor # and sees a no method error for convert if (f === Base.convert && !isempty(arg_types_param) && !is_arg_types && isa(arg_types_param[1], DataType) && arg_types_param[1].name === Type.body.name) construct_type = arg_types_param[1].parameters[1] println(io) print(io, "This may have arisen from a call to the constructor $construct_type(...),", "\nsince type constructors fall back to convert methods.") end try show_method_candidates(io, ex, kwargs) catch warn(io, "Error showing method candidates, aborted") end end striptype{T}(::Type{T}) = T striptype(::Any) = nothing function showerror_ambiguous(io::IO, meth, f, args) print(io, "MethodError: ", f, "(") p = args.parameters for (i,a) in enumerate(p) print(io, "::", a) i < length(p) && print(io, ", ") end print(io, ") is ambiguous. Candidates:") for m in meth print(io, "\n ", m) end nothing end #Show an error by directly calling jl_printf. #Useful in Base submodule __init__ functions where STDERR isn't defined yet. function showerror_nostdio(err, msg::AbstractString) stderr_stream = ccall(:jl_stderr_stream, Ptr{Void}, ()) ccall(:jl_printf, Cint, (Ptr{Void},Cstring), stderr_stream, msg) ccall(:jl_printf, Cint, (Ptr{Void},Cstring), stderr_stream, ":\n") ccall(:jl_static_show, Csize_t, (Ptr{Void},Any), stderr_stream, err) ccall(:jl_printf, Cint, (Ptr{Void},Cstring), stderr_stream, "\n") end function show_method_candidates(io::IO, ex::MethodError, kwargs::Vector=Any[]) is_arg_types = isa(ex.args, DataType) arg_types = is_arg_types ? ex.args : typesof(ex.args...) arg_types_param = Any[arg_types.parameters...] # Displays the closest candidates of the given function by looping over the # functions methods and counting the number of matching arguments. f = ex.f ft = typeof(f) lines = [] # These functions are special cased to only show if first argument is matched. special = f in [convert, getindex, setindex!] funcs = Any[(f, arg_types_param)] # An incorrect call method produces a MethodError for convert. # It also happens that users type convert when they mean call. So # pool MethodErrors for these two functions. if f === convert && !isempty(arg_types_param) at1 = arg_types_param[1] if isa(at1,DataType) && (at1::DataType).name === Type.body.name && isleaftype(at1) push!(funcs, (at1.parameters[1], arg_types_param[2:end])) end end for (func,arg_types_param) in funcs for method in methods(func) buf = IOBuffer() tv = Any[] sig0 = method.sig if Base.is_default_method(method) continue end while isa(sig0, UnionAll) push!(tv, sig0.var) sig0 = sig0.body end s1 = sig0.parameters[1] sig = sig0.parameters[2:end] print(buf, " ") if !isa(func, s1) # function itself doesn't match return else # TODO: use the methodshow logic here use_constructor_syntax = isa(func, Type) print(buf, use_constructor_syntax ? func : typeof(func).name.mt.name) end print(buf, "(") t_i = copy(arg_types_param) right_matches = 0 for i = 1 : min(length(t_i), length(sig)) i > 1 && print(buf, ", ") # If isvarargtype then it checks whether the rest of the input arguments matches # the varargtype if Base.isvarargtype(sig[i]) sigstr = string(unwrap_unionall(sig[i]).parameters[1], "...") j = length(t_i) else sigstr = string(sig[i]) j = i end # Checks if the type of arg 1:i of the input intersects with the current method t_in = typeintersect(rewrap_unionall(Tuple{sig[1:i]...}, method.sig), rewrap_unionall(Tuple{t_i[1:j]...}, method.sig)) # If the function is one of the special cased then it should break the loop if # the type of the first argument is not matched. t_in === Union{} && special && i == 1 && break if t_in === Union{} if Base.have_color Base.with_output_color(Base.error_color(), buf) do buf print(buf, "::$sigstr") end else print(buf, "!Matched::$sigstr") end # If there is no typeintersect then the type signature from the method is # inserted in t_i this ensures if the type at the next i matches the type # signature then there will be a type intersect t_i[i] = sig[i] else right_matches += j==i ? 1 : 0 print(buf, "::$sigstr") end end special && right_matches==0 && return # continue the do-block if length(t_i) > length(sig) && !isempty(sig) && Base.isvarargtype(sig[end]) # It ensures that methods like f(a::AbstractString...) gets the correct # number of right_matches for t in arg_types_param[length(sig):end] if t <: rewrap_unionall(unwrap_unionall(sig[end]).parameters[1], method.sig) right_matches += 1 end end end if right_matches > 0 || length(ex.args) < 2 if length(t_i) < length(sig) # If the methods args is longer than input then the method # arguments is printed as not a match for (k, sigtype) in enumerate(sig[length(t_i)+1:end]) sigtype = isvarargtype(sigtype) ? unwrap_unionall(sigtype) : sigtype if Base.isvarargtype(sigtype) sigstr = string(sigtype.parameters[1], "...") else sigstr = string(sigtype) end if !((min(length(t_i), length(sig)) == 0) && k==1) print(buf, ", ") end if Base.have_color Base.with_output_color(Base.error_color(), buf) do buf print(buf, "::$sigstr") end else print(buf, "!Matched::$sigstr") end end end kwords = Symbol[] if isdefined(ft.name.mt, :kwsorter) kwsorter_t = typeof(ft.name.mt.kwsorter) kwords = kwarg_decl(method, kwsorter_t) length(kwords) > 0 && print(buf, "; ", join(kwords, ", ")) end print(buf, ")") show_method_params(buf, tv) print(buf, " at ", method.file, ":", method.line) if !isempty(kwargs) unexpected = Symbol[] if isempty(kwords) || !(any(endswith(string(kword), "...") for kword in kwords)) for (k, v) in kwargs if !(k in kwords) push!(unexpected, k) end end end if !isempty(unexpected) Base.with_output_color(Base.error_color(), buf) do buf plur = length(unexpected) > 1 ? "s" : "" print(buf, " got unsupported keyword argument$plur \"", join(unexpected, "\", \""), "\"") end end end if ex.world < min_world(method) print(buf, " (method too new to be called from this world context.)") end if ex.world > max_world(method) print(buf, " (method deleted before this world age.)") end # TODO: indicate if it's in the wrong world push!(lines, (buf, right_matches)) end end end if !isempty(lines) # Display up to three closest candidates Base.with_output_color(:normal, io) do io println(io) print(io, "Closest candidates are:") sort!(lines, by = x -> -x[2]) i = 0 for line in lines println(io) if i >= 3 print(io, " ...") break end i += 1 print(io, String(take!(line[1]))) end end end end function show_trace_entry(io, frame, n; prefix = "") print(io, "\n", prefix) show(io, frame, full_path=true) n > 1 && print(io, " (repeats ", n, " times)") end # Contains file name and file number. Gets set when a backtrace # is shown. Used by the REPL to make it possible to open # the location of a stackframe in the edítor. global LAST_BACKTRACE_LINE_INFOS = Tuple{String, Int}[] function show_backtrace(io::IO, t::Vector) n_frames = 0 frame_counter = 0 resize!(LAST_BACKTRACE_LINE_INFOS, 0) process_backtrace((a,b) -> n_frames += 1, t) n_frames != 0 && print(io, "\nStacktrace:") process_entry = (last_frame, n) -> begin frame_counter += 1 show_trace_entry(IOContext(io, :backtrace => true), last_frame, n, prefix = string(" [", frame_counter, "] ")) push!(LAST_BACKTRACE_LINE_INFOS, (string(last_frame.file), last_frame.line)) end process_backtrace(process_entry, t) end function show_backtrace(io::IO, t::Vector{Any}) for entry in t show_trace_entry(io, entry...) end end # call process_func on each frame in a backtrace function process_backtrace(process_func::Function, t::Vector, limit::Int=typemax(Int); skipC = true) n = 0 last_frame = StackTraces.UNKNOWN count = 0 for i = eachindex(t) lkups = StackTraces.lookup(t[i]) for lkup in lkups if lkup === StackTraces.UNKNOWN continue end if lkup.from_c && skipC; continue; end if i == 1 && lkup.func == :error; continue; end count += 1 if count > limit; break; end if lkup.file != last_frame.file || lkup.line != last_frame.line || lkup.func != last_frame.func if n > 0 process_func(last_frame, n) end n = 1 last_frame = lkup else n += 1 end end end if n > 0 process_func(last_frame, n) end end """ Determines whether a method is the default method which is provided to all types from sysimg.jl. Such a method is usually undesirable to be displayed to the user in the REPL. """ function is_default_method(m::Method) return m.module == Base && m.file == Symbol("sysimg.jl") && m.sig == Tuple{Type{T},Any} where T end