From 2c5ebe67ba0506f3706c3380462fa76d37d9bfd8 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Thu, 30 Jun 2022 16:05:10 +0900 Subject: [PATCH] improve type stability of `Base.active_module()` (#45838) Now this method is called from many `show`-related utilities, so it would be better to make it robust against invalidations. --- base/Base.jl | 4 ++++ base/client.jl | 20 +++++++++----------- base/show.jl | 8 +++++--- stdlib/REPL/src/REPL.jl | 13 ++++++++++--- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/base/Base.jl b/base/Base.jl index 6fb7a7b8973175..843d5e6087b2c6 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -124,6 +124,10 @@ include("operators.jl") include("pointer.jl") include("refvalue.jl") include("refpointer.jl") + +# The REPL stdlib hooks into Base using this Ref +const REPL_MODULE_REF = Ref{Module}() + include("checked.jl") using .Checked diff --git a/base/client.jl b/base/client.jl index 66d7ffc3d21354..eba3c210ab68f2 100644 --- a/base/client.jl +++ b/base/client.jl @@ -370,9 +370,6 @@ function __atreplinit(repl) end _atreplinit(repl) = invokelatest(__atreplinit, repl) -# The REPL stdlib hooks into Base using this Ref -const REPL_MODULE_REF = Ref{Module}() - function load_InteractiveUtils(mod::Module=Main) # load interactive-only libraries if !isdefined(mod, :InteractiveUtils) @@ -390,10 +387,10 @@ function load_InteractiveUtils(mod::Module=Main) return getfield(mod, :InteractiveUtils) end +global active_repl + # run the requested sort of evaluation loop on stdio function run_main_repl(interactive::Bool, quiet::Bool, banner::Bool, history_file::Bool, color_set::Bool) - global active_repl - load_InteractiveUtils() if interactive && isassigned(REPL_MODULE_REF) @@ -402,17 +399,18 @@ function run_main_repl(interactive::Bool, quiet::Bool, banner::Bool, history_fil term = REPL.Terminals.TTYTerminal(term_env, stdin, stdout, stderr) banner && Base.banner(term) if term.term_type == "dumb" - active_repl = REPL.BasicREPL(term) + repl = REPL.BasicREPL(term) quiet || @warn "Terminal not fully functional" else - active_repl = REPL.LineEditREPL(term, get(stdout, :color, false), true) - active_repl.history_file = history_file + repl = REPL.LineEditREPL(term, get(stdout, :color, false), true) + repl.history_file = history_file end + global active_repl = repl # Make sure any displays pushed in .julia/config/startup.jl ends up above the # REPLDisplay - pushdisplay(REPL.REPLDisplay(active_repl)) - _atreplinit(active_repl) - REPL.run_repl(active_repl, backend->(global active_repl_backend = backend)) + pushdisplay(REPL.REPLDisplay(repl)) + _atreplinit(repl) + REPL.run_repl(repl, backend->(global active_repl_backend = backend)) end else # otherwise provide a simple fallback diff --git a/base/show.jl b/base/show.jl index cfcf634582e717..9841d34efe88bf 100644 --- a/base/show.jl +++ b/base/show.jl @@ -482,9 +482,11 @@ function _show_default(io::IO, @nospecialize(x)) print(io,')') end -active_module()::Module = isdefined(Base, :active_repl) && isdefined(Base.active_repl, :mistate) && Base.active_repl.mistate !== nothing ? - Base.active_repl.mistate.active_module : - Main +function active_module() + isassigned(REPL_MODULE_REF) || return Main + REPL = REPL_MODULE_REF[] + return REPL.active_module()::Module +end # Check if a particular symbol is exported from a standard library module function is_exported_from_stdlib(name::Symbol, mod::Module) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 4a5246301cf43a..d3d0c9bc985823 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -491,11 +491,16 @@ REPLCompletionProvider() = REPLCompletionProvider(LineEdit.Modifiers()) mutable struct ShellCompletionProvider <: CompletionProvider end struct LatexCompletions <: CompletionProvider end -active_module(repl::LineEditREPL) = repl.mistate === nothing ? Main : repl.mistate.active_module +function active_module() # this method is also called from Base + isdefined(Base, :active_repl) || return Main + return active_module(Base.active_repl::AbstractREPL) +end +active_module((; mistate)::LineEditREPL) = mistate === nothing ? Main : mistate.active_module active_module(::AbstractREPL) = Main active_module(d::REPLDisplay) = active_module(d.repl) setmodifiers!(c::REPLCompletionProvider, m::LineEdit.Modifiers) = c.modifiers = m + """ activate(mod::Module=Main) @@ -503,9 +508,11 @@ Set `mod` as the default contextual module in the REPL, both for evaluating expressions and printing them. """ function activate(mod::Module=Main) - Base.active_repl.mistate.active_module = mod + mistate = (Base.active_repl::LineEditREPL).mistate + mistate === nothing && return nothing + mistate.active_module = mod Base.load_InteractiveUtils(mod) - nothing + return nothing end beforecursor(buf::IOBuffer) = String(buf.data[1:buf.ptr-1])