diff --git a/HISTORY.md b/HISTORY.md index 6c2ca03662233..b8076b1c2753f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -133,6 +133,8 @@ New library features * `Timer` now has readable `timeout` and `interval` properties, and a more descriptive `show` method ([#57081]). * `sort` now supports `NTuple`s ([#54494]). * `map!(f, A)` now stores the results in `A`, like `map!(f, A, A)` or `A .= f.(A)` ([#40632]). +* `setprecision` with a function argument (typically a `do` block) is now thread safe. Other forms + should be avoided, and types should switch to an implementation using `ScopedValue` ([#51362]). Standard library changes ------------------------ diff --git a/base/mpfr.jl b/base/mpfr.jl index 25b7f0abe4b98..ee1e4eac39145 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -1183,9 +1183,29 @@ Often used as `setprecision(T, precision) do ... end` Note: `nextfloat()`, `prevfloat()` do not use the precision mentioned by `setprecision`. +!!! warning + There is a fallback implementation of this method that calls `precision` + and `setprecision`, but it should no longer be relied on. Instead, you + should define the 3-argument form directly in a way that uses `ScopedValue`, + or recommend that callers use `ScopedValue` and `@with` themselves. + !!! compat "Julia 1.8" The `base` keyword requires at least Julia 1.8. """ +function setprecision(f::Function, ::Type{T}, prec::Integer; kws...) where T + depwarn(""" + The fallback `setprecision(::Function, ...)` method is deprecated. Packages overloading this method should + implement their own specialization using `ScopedValue` instead. + """, :setprecision) + old_prec = precision(T) + setprecision(T, prec; kws...) + try + return f() + finally + setprecision(T, old_prec) + end +end + function setprecision(f::Function, ::Type{BigFloat}, prec::Integer; base::Integer=2) Base.ScopedValues.@with(CURRENT_PRECISION => _convert_precision_from_base(prec, base), f()) end