From 9223088faefd9680d8217b44d0bf82e478a311c1 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Tue, 15 Oct 2024 03:07:19 -0400 Subject: [PATCH] Add invalidation barriers for `displaysize` and `implicit_typeinfo` (#56159) These are invalidated by our own stdlibs (Dates and REPL) unfortunately so we need to put this barrier in. This fix is _very_ un-satisfying, because it doesn't do anything to solve this problem for downstream libraries that use e.g. `displaysize`. To fix that, I think we need a way to make sure callers get these invalidation barriers by default... --- base/arrayshow.jl | 16 +++++++++++----- base/logging/ConsoleLogger.jl | 2 +- base/precompilation.jl | 4 ++-- base/show.jl | 4 ++-- base/stream.jl | 7 +++++++ 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/base/arrayshow.jl b/base/arrayshow.jl index 164a9257d8412..3bc69e563a967 100644 --- a/base/arrayshow.jl +++ b/base/arrayshow.jl @@ -545,6 +545,12 @@ typeinfo_eltype(typeinfo::Type{<:AbstractArray{T}}) where {T} = eltype(typeinfo) typeinfo_eltype(typeinfo::Type{<:AbstractDict{K,V}}) where {K,V} = eltype(typeinfo) typeinfo_eltype(typeinfo::Type{<:AbstractSet{T}}) where {T} = eltype(typeinfo) +# This is a fancy way to make de-specialize a call to `typeinfo_implicit(T)` +# which is unfortunately invalidated by Dates +# (https://github.com/JuliaLang/julia/issues/56080) +# +# This makes the call less efficient, but avoids being invalidated by Dates. +_typeinfo_implicit(@nospecialize(T)) = Base.invoke_in_world(Base.tls_world_age(), typeinfo_implicit, T)::Bool # types that can be parsed back accurately from their un-decorated representations function typeinfo_implicit(@nospecialize(T)) @@ -553,9 +559,9 @@ function typeinfo_implicit(@nospecialize(T)) return true end return isconcretetype(T) && - ((T <: Array && typeinfo_implicit(eltype(T))) || - ((T <: Tuple || T <: NamedTuple || T <: Pair) && all(typeinfo_implicit, fieldtypes(T))) || - (T <: AbstractDict && typeinfo_implicit(keytype(T)) && typeinfo_implicit(valtype(T)))) + ((T <: Array && _typeinfo_implicit(eltype(T))) || + ((T <: Tuple || T <: NamedTuple || T <: Pair) && all(_typeinfo_implicit, fieldtypes(T))) || + (T <: AbstractDict && _typeinfo_implicit(keytype(T)) && _typeinfo_implicit(valtype(T)))) end # X not constrained, can be any iterable (cf. show_vector) @@ -573,7 +579,7 @@ function typeinfo_prefix(io::IO, X) if X isa AbstractDict if eltype_X == eltype_ctx sprint(show_type_name, typeof(X).name; context=io), false - elseif !isempty(X) && typeinfo_implicit(keytype(X)) && typeinfo_implicit(valtype(X)) + elseif !isempty(X) && _typeinfo_implicit(keytype(X)) && _typeinfo_implicit(valtype(X)) sprint(show_type_name, typeof(X).name; context=io), true else sprint(print, typeof(X); context=io), false @@ -582,7 +588,7 @@ function typeinfo_prefix(io::IO, X) # Types hard-coded here are those which are created by default for a given syntax if eltype_X == eltype_ctx "", false - elseif !isempty(X) && typeinfo_implicit(eltype_X) + elseif !isempty(X) && _typeinfo_implicit(eltype_X) "", true elseif print_without_params(eltype_X) sprint(show_type_name, unwrap_unionall(eltype_X).name; context=io), false # Print "Array" rather than "Array{T,N}" diff --git a/base/logging/ConsoleLogger.jl b/base/logging/ConsoleLogger.jl index c4596dd86c3f5..818b2272b773c 100644 --- a/base/logging/ConsoleLogger.jl +++ b/base/logging/ConsoleLogger.jl @@ -130,7 +130,7 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module if !(isopen(stream)::Bool) stream = stderr end - dsize = displaysize(stream)::Tuple{Int,Int} + dsize = Base.displaysize_(stream)::Tuple{Int,Int} nkwargs = length(kwargs)::Int if nkwargs > hasmaxlog valbuf = IOBuffer() diff --git a/base/precompilation.jl b/base/precompilation.jl index 7a821222c52d1..4b7da84a17d55 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -672,7 +672,7 @@ function precompilepkgs(pkgs::Vector{String}=String[]; n_print_rows = 0 while !printloop_should_exit lock(print_lock) do - term_size = Base.displaysize(io)::Tuple{Int,Int} + term_size = Base.displaysize_(io) num_deps_show = max(term_size[1] - 3, 2) # show at least 2 deps pkg_queue_show = if !interrupted_or_done.set && length(pkg_queue) > num_deps_show last(pkg_queue, num_deps_show) @@ -687,7 +687,7 @@ function precompilepkgs(pkgs::Vector{String}=String[]; bar.max = n_total - n_already_precomp # when sizing to the terminal width subtract a little to give some tolerance to resizing the # window between print cycles - termwidth = displaysize(io)[2] - 4 + termwidth = Base.displaysize_(io)[2] - 4 if !final_loop str = sprint(io -> show_progress(io, bar; termwidth, carriagereturn=false); context=io) print(iostr, Base._truncate_at_width_or_chars(true, str, termwidth), "\n") diff --git a/base/show.jl b/base/show.jl index 66560265e3b42..a147c2037d70e 100644 --- a/base/show.jl +++ b/base/show.jl @@ -427,7 +427,7 @@ get(io::IO, key, default) = default keys(io::IOContext) = keys(io.dict) keys(io::IO) = keys(ImmutableDict{Symbol,Any}()) -displaysize(io::IOContext) = haskey(io, :displaysize) ? io[:displaysize]::Tuple{Int,Int} : displaysize(io.io) +displaysize(io::IOContext) = haskey(io, :displaysize) ? io[:displaysize]::Tuple{Int,Int} : Base.displaysize_(io.io) show_circular(io::IO, @nospecialize(x)) = false function show_circular(io::IOContext, @nospecialize(x)) @@ -2622,7 +2622,7 @@ end function type_limited_string_from_context(out::IO, str::String) typelimitflag = get(out, :stacktrace_types_limited, nothing) if typelimitflag isa RefValue{Bool} - sz = get(out, :displaysize, displaysize(out))::Tuple{Int, Int} + sz = get(out, :displaysize, Base.displaysize_(out))::Tuple{Int, Int} str_lim = type_depth_limit(str, max(sz[2], 120)) if sizeof(str_lim) < sizeof(str) typelimitflag[] = true diff --git a/base/stream.jl b/base/stream.jl index 93aeead79eb9c..3ca5717be29db 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -569,6 +569,13 @@ displaysize(io::IO) = displaysize() displaysize() = (parse(Int, get(ENV, "LINES", "24")), parse(Int, get(ENV, "COLUMNS", "80")))::Tuple{Int, Int} +# This is a fancy way to make de-specialize a call to `displaysize(io::IO)` +# which is unfortunately invalidated by REPL +# (https://github.com/JuliaLang/julia/issues/56080) +# +# This makes the call less efficient, but avoids being invalidated by REPL. +displaysize_(io::IO) = Base.invoke_in_world(Base.tls_world_age(), displaysize, io)::Tuple{Int,Int} + function displaysize(io::TTY) check_open(io)