Skip to content

Commit

Permalink
Various inferrability improvements (#41917)
Browse files Browse the repository at this point in the history
- two functions affected by `Core.Box` (#15276) were ameliorated
- type info added to the `stack` field of `ExceptionStack`
- avoid unknown dispatch from de-specialized code

Co-authored-by: Jameson Nash <vtjnash@gmail.com>
  • Loading branch information
timholy and vtjnash authored Aug 25, 2021
1 parent e2aeefb commit e2377f1
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 51 deletions.
33 changes: 18 additions & 15 deletions base/arrayshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ column going across the screen.
"""
function alignment(io::IO, @nospecialize(X::AbstractVecOrMat),
rows::AbstractVector{T}, cols::AbstractVector{V},
cols_if_complete::Integer, cols_otherwise::Integer, sep::Integer) where {T,V}
cols_if_complete::Integer, cols_otherwise::Integer, sep::Integer,
#= `size(X) may not infer, set this in caller =# ncols::Integer=size(X, 2)) where {T,V}
a = Tuple{T, V}[]
for j in cols # need to go down each column one at a time
l = r = 0
Expand All @@ -78,7 +79,7 @@ function alignment(io::IO, @nospecialize(X::AbstractVecOrMat),
break
end
end
if 1 < length(a) < length(axes(X,2))
if 1 < length(a) < ncols
while sum(map(sum,a)) + sep*length(a) >= cols_otherwise
pop!(a)
end
Expand All @@ -95,7 +96,8 @@ is specified as string sep.
"""
function print_matrix_row(io::IO,
@nospecialize(X::AbstractVecOrMat), A::Vector,
i::Integer, cols::AbstractVector, sep::AbstractString)
i::Integer, cols::AbstractVector, sep::AbstractString,
#= `axes(X)` may not infer, set this in caller =# idxlast::Integer=last(axes(X, 2)))
for (k, j) = enumerate(cols)
k > length(A) && break
if isassigned(X,Int(i),Int(j)) # isassigned accepts only `Int` indices
Expand All @@ -114,7 +116,7 @@ function print_matrix_row(io::IO,
sx = undef_ref_str
end
l = repeat(" ", A[k][1]-a[1]) # pad on left and right as needed
r = j == axes(X, 2)[end] ? "" : repeat(" ", A[k][2]-a[2])
r = j == idxlast ? "" : repeat(" ", A[k][2]-a[2])
prettysx = replace_in_print_matrix(X,i,j,sx)
print(io, l, prettysx, r)
if k < length(A); print(io, sep); end
Expand Down Expand Up @@ -171,6 +173,7 @@ end

function _print_matrix(io, @nospecialize(X::AbstractVecOrMat), pre, sep, post, hdots, vdots, ddots, hmod, vmod, rowsA, colsA)
hmod, vmod = Int(hmod)::Int, Int(vmod)::Int
ncols, idxlast = length(colsA), last(colsA)
if !(get(io, :limit, false)::Bool)
screenheight = screenwidth = typemax(Int)
else
Expand Down Expand Up @@ -201,26 +204,26 @@ function _print_matrix(io, @nospecialize(X::AbstractVecOrMat), pre, sep, post, h
else
colsA = [colsA;]
end
A = alignment(io, X, rowsA, colsA, screenwidth, screenwidth, sepsize)
A = alignment(io, X, rowsA, colsA, screenwidth, screenwidth, sepsize, ncols)
# Nine-slicing is accomplished using print_matrix_row repeatedly
if m <= screenheight # rows fit vertically on screen
if n <= length(A) # rows and cols fit so just print whole matrix in one piece
for i in rowsA
print(io, i == first(rowsA) ? pre : presp)
print_matrix_row(io, X,A,i,colsA,sep)
print_matrix_row(io, X,A,i,colsA,sep,idxlast)
print(io, i == last(rowsA) ? post : postsp)
if i != last(rowsA); println(io); end
end
else # rows fit down screen but cols don't, so need horizontal ellipsis
c = div(screenwidth-length(hdots)::Int+1,2)+1 # what goes to right of ellipsis
Ralign = reverse(alignment(io, X, rowsA, reverse(colsA), c, c, sepsize)) # alignments for right
Ralign = reverse(alignment(io, X, rowsA, reverse(colsA), c, c, sepsize, ncols)) # alignments for right
c = screenwidth - sum(map(sum,Ralign)) - (length(Ralign)-1)*sepsize - length(hdots)::Int
Lalign = alignment(io, X, rowsA, colsA, c, c, sepsize) # alignments for left of ellipsis
Lalign = alignment(io, X, rowsA, colsA, c, c, sepsize, ncols) # alignments for left of ellipsis
for i in rowsA
print(io, i == first(rowsA) ? pre : presp)
print_matrix_row(io, X,Lalign,i,colsA[1:length(Lalign)],sep)
print_matrix_row(io, X,Lalign,i,colsA[1:length(Lalign)],sep,idxlast)
print(io, (i - first(rowsA)) % hmod == 0 ? hdots : repeat(" ", length(hdots)::Int))
print_matrix_row(io, X, Ralign, i, (n - length(Ralign)) .+ colsA, sep)
print_matrix_row(io, X, Ralign, i, (n - length(Ralign)) .+ colsA, sep, idxlast)
print(io, i == last(rowsA) ? post : postsp)
if i != last(rowsA); println(io); end
end
Expand All @@ -229,7 +232,7 @@ function _print_matrix(io, @nospecialize(X::AbstractVecOrMat), pre, sep, post, h
if n <= length(A) # rows don't fit, cols do, so only vertical ellipsis
for i in rowsA
print(io, i == first(rowsA) ? pre : presp)
print_matrix_row(io, X,A,i,colsA,sep)
print_matrix_row(io, X,A,i,colsA,sep,idxlast)
print(io, i == last(rowsA) ? post : postsp)
if i != rowsA[end] || i == rowsA[halfheight]; println(io); end
if i == rowsA[halfheight]
Expand All @@ -240,15 +243,15 @@ function _print_matrix(io, @nospecialize(X::AbstractVecOrMat), pre, sep, post, h
end
else # neither rows nor cols fit, so use all 3 kinds of dots
c = div(screenwidth-length(hdots)::Int+1,2)+1
Ralign = reverse(alignment(io, X, rowsA, reverse(colsA), c, c, sepsize))
Ralign = reverse(alignment(io, X, rowsA, reverse(colsA), c, c, sepsize, ncols))
c = screenwidth - sum(map(sum,Ralign)) - (length(Ralign)-1)*sepsize - length(hdots)::Int
Lalign = alignment(io, X, rowsA, colsA, c, c, sepsize)
Lalign = alignment(io, X, rowsA, colsA, c, c, sepsize, ncols)
r = mod((length(Ralign)-n+1),vmod) # where to put dots on right half
for i in rowsA
print(io, i == first(rowsA) ? pre : presp)
print_matrix_row(io, X,Lalign,i,colsA[1:length(Lalign)],sep)
print_matrix_row(io, X,Lalign,i,colsA[1:length(Lalign)],sep,idxlast)
print(io, (i - first(rowsA)) % hmod == 0 ? hdots : repeat(" ", length(hdots)::Int))
print_matrix_row(io, X,Ralign,i,(n-length(Ralign)).+colsA,sep)
print_matrix_row(io, X,Ralign,i,(n-length(Ralign)).+colsA,sep,idxlast)
print(io, i == last(rowsA) ? post : postsp)
if i != rowsA[end] || i == rowsA[halfheight]; println(io); end
if i == rowsA[halfheight]
Expand Down
2 changes: 1 addition & 1 deletion base/error.jl
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ function catch_backtrace()
end

struct ExceptionStack <: AbstractArray{Any,1}
stack
stack::Array{Any,1}
end

"""
Expand Down
13 changes: 7 additions & 6 deletions base/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -615,22 +615,23 @@ function print_range(io::IO, r::AbstractRange,
maxpossiblecols = div(screenwidth, 1+sepsize) # assume each element is at least 1 char + 1 separator
colsr = n <= maxpossiblecols ? (1:n) : [1:div(maxpossiblecols,2)+1; (n-div(maxpossiblecols,2)):n]
rowmatrix = reshape(r[colsr], 1, length(colsr)) # treat the range as a one-row matrix for print_matrix_row
A = alignment(io, rowmatrix, 1:m, 1:length(rowmatrix), screenwidth, screenwidth, sepsize) # how much space range takes
nrow, idxlast = size(rowmatrix, 2), last(axes(rowmatrix, 2))
A = alignment(io, rowmatrix, 1:m, 1:length(rowmatrix), screenwidth, screenwidth, sepsize, nrow) # how much space range takes
if n <= length(A) # cols fit screen, so print out all elements
print(io, pre) # put in pre chars
print_matrix_row(io,rowmatrix,A,1,1:n,sep) # the entire range
print_matrix_row(io,rowmatrix,A,1,1:n,sep,idxlast) # the entire range
print(io, post) # add the post characters
else # cols don't fit so put horiz ellipsis in the middle
# how many chars left after dividing width of screen in half
# and accounting for the horiz ellipsis
c = div(screenwidth-length(hdots)+1,2)+1 # chars remaining for each side of rowmatrix
alignR = reverse(alignment(io, rowmatrix, 1:m, length(rowmatrix):-1:1, c, c, sepsize)) # which cols of rowmatrix to put on the right
alignR = reverse(alignment(io, rowmatrix, 1:m, length(rowmatrix):-1:1, c, c, sepsize, nrow)) # which cols of rowmatrix to put on the right
c = screenwidth - sum(map(sum,alignR)) - (length(alignR)-1)*sepsize - length(hdots)
alignL = alignment(io, rowmatrix, 1:m, 1:length(rowmatrix), c, c, sepsize) # which cols of rowmatrix to put on the left
alignL = alignment(io, rowmatrix, 1:m, 1:length(rowmatrix), c, c, sepsize, nrow) # which cols of rowmatrix to put on the left
print(io, pre) # put in pre chars
print_matrix_row(io, rowmatrix,alignL,1,1:length(alignL),sep) # left part of range
print_matrix_row(io, rowmatrix,alignL,1,1:length(alignL),sep,idxlast) # left part of range
print(io, hdots) # horizontal ellipsis
print_matrix_row(io, rowmatrix,alignR,1,length(rowmatrix)-length(alignR)+1:length(rowmatrix),sep) # right part of range
print_matrix_row(io, rowmatrix,alignR,1,length(rowmatrix)-length(alignR)+1:length(rowmatrix),sep,idxlast) # right part of range
print(io, post) # post chars
end
end
Expand Down
2 changes: 1 addition & 1 deletion contrib/generate_precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ function generate_precompile_statements()
# XXX: precompile doesn't currently handle overloaded Vararg arguments very well.
# Replacing N with a large number works around it.
l = l.args[end]
if isexpr(l, :curly) && length(l.args) == 2 && l.args[1] == :Vararg # Vararg{T}
if isexpr(l, :curly) && length(l.args) == 2 && l.args[1] === :Vararg # Vararg{T}
push!(l.args, 100) # form Vararg{T, 100} instead
end
end
Expand Down
2 changes: 1 addition & 1 deletion stdlib/Logging/src/ConsoleLogger.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function default_metafmt(level::LogLevel, _module, group, id, file, line)
prefix = string(level == Warn ? "Warning" : string(level), ':')
suffix::String = ""
Info <= level < Warn && return color, prefix, suffix
_module !== nothing && (suffix *= "$(_module)")
_module !== nothing && (suffix *= string(_module)::String)
if file !== nothing
_module !== nothing && (suffix *= " ")
suffix *= Base.contractuser(file)::String
Expand Down
10 changes: 7 additions & 3 deletions stdlib/REPL/src/docview.jl
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,12 @@ function symbol_latex(s::String)

return get(symbols_latex, s, "")
end
function repl_latex(io::IO, s::String)
latex = symbol_latex(s)
function repl_latex(io::IO, s0::String)
# This has rampant `Core.Box` problems (#15276). Use the tricks of
# https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured
# We're changing some of the values so the `let` trick isn't applicable.
s::String = s0
latex::String = symbol_latex(s)
if isempty(latex)
# Decompose NFC-normalized identifier to match tab-completion
# input if the first search came up empty.
Expand All @@ -420,7 +424,7 @@ function repl_latex(io::IO, s::String)
print(io, "\"")
printstyled(io, s, color=:cyan)
print(io, "\" can be typed by ")
state = '\0'
state::Char = '\0'
with_output_color(:cyan, io) do io
for c in s
cstr = string(c)
Expand Down
50 changes: 26 additions & 24 deletions stdlib/Test/src/Test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1580,30 +1580,32 @@ function _inferred(ex, mod, allow = :(Union{}))
ex = Expr(:call, GlobalRef(Test, :_materialize_broadcasted),
farg, ex.args[2:end]...)
end
Base.remove_linenums!(quote
let
allow = $(esc(allow))
allow isa Type || throw(ArgumentError("@inferred requires a type as second argument"))
$(if any(a->(Meta.isexpr(a, :kw) || Meta.isexpr(a, :parameters)), ex.args)
# Has keywords
args = gensym()
kwargs = gensym()
quote
$(esc(args)), $(esc(kwargs)), result = $(esc(Expr(:call, _args_and_call, ex.args[2:end]..., ex.args[1])))
inftypes = $(gen_call_with_extracted_types(mod, Base.return_types, :($(ex.args[1])($(args)...; $(kwargs)...))))
end
else
# No keywords
quote
args = ($([esc(ex.args[i]) for i = 2:length(ex.args)]...),)
result = $(esc(ex.args[1]))(args...)
inftypes = Base.return_types($(esc(ex.args[1])), Base.typesof(args...))
end
end)
@assert length(inftypes) == 1
rettype = result isa Type ? Type{result} : typeof(result)
rettype <: allow || rettype == typesplit(inftypes[1], allow) || error("return type $rettype does not match inferred return type $(inftypes[1])")
result
Base.remove_linenums!(let ex = ex;
quote
let
allow = $(esc(allow))
allow isa Type || throw(ArgumentError("@inferred requires a type as second argument"))
$(if any(a->(Meta.isexpr(a, :kw) || Meta.isexpr(a, :parameters)), ex.args)
# Has keywords
args = gensym()
kwargs = gensym()
quote
$(esc(args)), $(esc(kwargs)), result = $(esc(Expr(:call, _args_and_call, ex.args[2:end]..., ex.args[1])))
inftypes = $(gen_call_with_extracted_types(mod, Base.return_types, :($(ex.args[1])($(args)...; $(kwargs)...))))
end
else
# No keywords
quote
args = ($([esc(ex.args[i]) for i = 2:length(ex.args)]...),)
result = $(esc(ex.args[1]))(args...)
inftypes = Base.return_types($(esc(ex.args[1])), Base.typesof(args...))
end
end)
@assert length(inftypes) == 1
rettype = result isa Type ? Type{result} : typeof(result)
rettype <: allow || rettype == typesplit(inftypes[1], allow) || error("return type $rettype does not match inferred return type $(inftypes[1])")
result
end
end
end)
end
Expand Down

0 comments on commit e2377f1

Please sign in to comment.