Skip to content

Commit b898d22

Browse files
authored
Merge branch 'master' into eliminate_some_Array-specific_methods_of_size
2 parents f3bfee3 + cdd4ac5 commit b898d22

File tree

23 files changed

+179
-61
lines changed

23 files changed

+179
-61
lines changed

.github/workflows/Typos.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
timeout-minutes: 5
1212
steps:
1313
- name: Checkout the JuliaLang/julia repository
14-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
14+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
1515
with:
1616
persist-credentials: false
1717
- name: Check spelling with typos

.github/workflows/Whitespace.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
timeout-minutes: 2
1616
steps:
1717
- name: Checkout the JuliaLang/julia repository
18-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
18+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
1919
with:
2020
persist-credentials: false
2121
- uses: julia-actions/setup-julia@5c9647d97b78a5debe5164e9eec09d653d29bd71 # v2.6.1

.github/workflows/cffconvert.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
runs-on: ubuntu-latest
2424
steps:
2525
- name: Check out a copy of the repository
26-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
26+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
2727
with:
2828
persist-credentials: false
2929

Compiler/src/ssair/show.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ function compute_ir_line_annotations(code::Union{IRCode,CodeInfo})
301301
x = min(length(last_stack), length(stack))
302302
depth = length(stack) - 1
303303
# Compute the last depth that was in common
304-
first_mismatch = let last_stack=last_stack
304+
first_mismatch = let last_stack=last_stack, stack=stack
305305
findfirst(i->last_stack[i] != stack[i], 1:x)
306306
end
307307
# If the first mismatch is the last stack frame, that might just

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ New library features
6767
migrate now by calling `legacyscope=false` or using `macroexpand!`. This may often require
6868
fixes to the code calling `macroexpand` with `Meta.unescape` and `Meta.reescape` or by
6969
updating tests to expect `hygienic-scope` or `escape` markers might appear in the result.
70+
* `Base.ScopedValues.LazyScopedValue{T}` is introduced for scoped values that compute their default using a
71+
`OncePerProcess{T}` callback, allowing for lazy initialization of the default value. `AbstractScopedValue` is
72+
now the abstract base type for both `ScopedValue` and `LazyScopedValue`. ([#59372])
7073

7174
Standard library changes
7275
------------------------

base/abstractset.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ intersect!(s::AbstractSet, itr) =
201201
setdiff(s, itrs...)
202202
203203
Construct the set of elements in `s` but not in any of the iterables in `itrs`.
204-
Maintain order with arrays.
204+
Maintain order with arrays. The result will have the same element type as `s`.
205205
206206
See also [`setdiff!`](@ref), [`union`](@ref) and [`intersect`](@ref).
207207
@@ -211,6 +211,10 @@ julia> setdiff([1,2,3], [3,4,5])
211211
2-element Vector{Int64}:
212212
1
213213
2
214+
215+
julia> setdiff([1,2,3], [1.0, 2.0])
216+
1-element Vector{Int64}:
217+
3
214218
```
215219
"""
216220
setdiff(s::AbstractSet, itrs...) = setdiff!(copymutable(s), itrs...)

base/array.jl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3126,14 +3126,17 @@ setdiff!( v::AbstractVector, itrs...) = _shrink!(setdiff!, v, itrs)
31263126

31273127
vectorfilter(T::Type, f, v) = T[x for x in v if f(x)]
31283128

3129-
function _shrink(shrinker!::F, itr, itrs) where F
3129+
function intersect(itr, itrs...)
31303130
T = promote_eltype(itr, itrs...)
3131-
keep = shrinker!(Set{T}(itr), itrs...)
3131+
keep = intersect!(Set{T}(itr), itrs...)
31323132
vectorfilter(T, _shrink_filter!(keep), itr)
31333133
end
31343134

3135-
intersect(itr, itrs...) = _shrink(intersect!, itr, itrs)
3136-
setdiff( itr, itrs...) = _shrink(setdiff!, itr, itrs)
3135+
function setdiff(itr, itrs...)
3136+
T = eltype(itr)
3137+
keep = setdiff!(Set{T}(itr), itrs...)
3138+
vectorfilter(T, _shrink_filter!(keep), itr)
3139+
end
31373140

31383141
function intersect(v::AbstractVector, r::AbstractRange)
31393142
T = promote_eltype(v, r)

base/indices.jl

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -385,10 +385,9 @@ end
385385
Slice(S::Slice) = S
386386
Slice{T}(S::Slice) where {T<:AbstractUnitRange} = Slice{T}(T(S.indices))
387387

388-
axes(S::Slice) = (IdentityUnitRange(S.indices),)
388+
axes(S::Slice) = (axes1(S),)
389389
axes1(S::Slice) = IdentityUnitRange(S.indices)
390-
axes(S::Slice{<:OneTo}) = (S.indices,)
391-
axes1(S::Slice{<:OneTo}) = S.indices
390+
axes1(S::Slice{<:AbstractOneTo{<:Integer}}) = S.indices
392391

393392
first(S::Slice) = first(S.indices)
394393
last(S::Slice) = last(S.indices)
@@ -414,10 +413,9 @@ IdentityUnitRange(S::IdentityUnitRange) = S
414413
IdentityUnitRange{T}(S::IdentityUnitRange) where {T<:AbstractUnitRange} = IdentityUnitRange{T}(T(S.indices))
415414

416415
# IdentityUnitRanges are offset and thus have offset axes, so they are their own axes
417-
axes(S::IdentityUnitRange) = (S,)
416+
axes(S::IdentityUnitRange) = (axes1(S),)
418417
axes1(S::IdentityUnitRange) = S
419-
axes(S::IdentityUnitRange{<:OneTo}) = (S.indices,)
420-
axes1(S::IdentityUnitRange{<:OneTo}) = S.indices
418+
axes1(S::IdentityUnitRange{<:AbstractOneTo{<:Integer}}) = S.indices
421419

422420
first(S::IdentityUnitRange) = first(S.indices)
423421
last(S::IdentityUnitRange) = last(S.indices)
@@ -465,11 +463,11 @@ end
465463
show(io::IO, r::IdentityUnitRange) = print(io, "Base.IdentityUnitRange(", r.indices, ")")
466464
iterate(S::IdentityUnitRange, s...) = iterate(S.indices, s...)
467465

468-
# For OneTo, the values and indices of the values are identical, so this may be defined in Base.
466+
# For AbstractOneTo, the values and indices of the values are identical, so this may be defined in Base.
469467
# In general such an indexing operation would produce offset ranges
470468
# This should also ideally return an AbstractUnitRange{eltype(S)}, but currently
471469
# we're restricted to eltype(::IdentityUnitRange) == Int by definition
472-
function getindex(S::OneTo, I::IdentityUnitRange{<:AbstractUnitRange{<:Integer}})
470+
function getindex(S::AbstractOneTo{<:Integer}, I::IdentityUnitRange{<:AbstractUnitRange{<:Integer}})
473471
@inline
474472
@boundscheck checkbounds(S, I)
475473
return I

base/scopedvalues.jl

Lines changed: 84 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,57 @@
22

33
module ScopedValues
44

5-
export ScopedValue, with, @with
5+
export ScopedValue, LazyScopedValue, with, @with
66
public get
77

8+
"""
9+
AbstractScopedValue{T}
10+
11+
Abstract base type for scoped values that propagate values across
12+
dynamic scopes. All scoped value types must extend this abstract type.
13+
14+
See also: [`ScopedValue`](@ref), [`LazyScopedValue`](@ref)
15+
16+
!!! compat "Julia 1.13"
17+
AbstractScopedValue requires Julia 1.13+.
18+
"""
19+
abstract type AbstractScopedValue{T} end
20+
21+
22+
"""
23+
LazyScopedValue{T}(f::OncePerProcess{T})
24+
25+
A scoped value that uses an `OncePerProcess{T}` to lazily compute its default value
26+
when none has been set in the current scope. Unlike `ScopedValue`, the default is
27+
not evaluated at construction time but only when first accessed.
28+
29+
# Examples
30+
31+
```julia-repl
32+
julia> using Base.ScopedValues;
33+
34+
julia> const editor = LazyScopedValue(OncePerProcess(() -> ENV["JULIA_EDITOR"]));
35+
36+
julia> editor[]
37+
"vim"
38+
39+
julia> with(editor => "emacs") do
40+
sval[]
41+
end
42+
"emacs"
43+
44+
julia> editor[]
45+
"vim"
46+
```
47+
48+
!!! compat "Julia 1.13"
49+
LazyScopedValue requires Julia 1.13+.
50+
"""
51+
mutable struct LazyScopedValue{T} <: AbstractScopedValue{T}
52+
const getdefault::OncePerProcess{T}
53+
end
54+
55+
856
"""
957
ScopedValue(x)
1058
@@ -40,17 +88,23 @@ julia> sval[]
4088
Scoped values were introduced in Julia 1.11. In Julia 1.8+ a compatible
4189
implementation is available from the package ScopedValues.jl.
4290
"""
43-
mutable struct ScopedValue{T}
91+
mutable struct ScopedValue{T} <: AbstractScopedValue{T}
4492
# NOTE this struct must be defined as mutable one since it's used as a key of
4593
# `ScopeStorage` dictionary and thus needs object identity
46-
const has_default::Bool # this field is necessary since isbitstype `default` field may be initialized with undefined value
94+
const hasdefault::Bool # this field is necessary since isbitstype `default` field may be initialized with undefined value
4795
const default::T
48-
ScopedValue{T}() where T = new(false)
96+
ScopedValue{T}() where T = new{T}(false)
4997
ScopedValue{T}(val) where T = new{T}(true, val)
5098
ScopedValue(val::T) where T = new{T}(true, val)
5199
end
52100

53-
Base.eltype(::ScopedValue{T}) where {T} = T
101+
Base.eltype(::AbstractScopedValue{T}) where {T} = T
102+
103+
hasdefault(val::ScopedValue) = val.hasdefault
104+
hasdefault(val::LazyScopedValue) = true
105+
106+
getdefault(val::ScopedValue) = val.hasdefault ? val.default : throw(KeyError(val))
107+
getdefault(val::LazyScopedValue) = val.getdefault()
54108

55109
"""
56110
isassigned(val::ScopedValue)
@@ -72,34 +126,34 @@ julia> isassigned(b)
72126
false
73127
```
74128
"""
75-
function Base.isassigned(val::ScopedValue)
76-
val.has_default && return true
129+
function Base.isassigned(val::AbstractScopedValue)
130+
hasdefault(val) && return true
77131
scope = Core.current_scope()::Union{Scope, Nothing}
78132
scope === nothing && return false
79133
return haskey((scope::Scope).values, val)
80134
end
81135

82-
const ScopeStorage = Base.PersistentDict{ScopedValue, Any}
136+
const ScopeStorage = Base.PersistentDict{AbstractScopedValue, Any}
83137

84138
struct Scope
85139
values::ScopeStorage
86140
end
87141

88142
Scope(scope::Scope) = scope
89143

90-
function Scope(parent::Union{Nothing, Scope}, key::ScopedValue{T}, value) where T
144+
function Scope(parent::Union{Nothing, Scope}, key::AbstractScopedValue{T}, value) where T
91145
val = convert(T, value)
92146
if parent === nothing
93147
return Scope(ScopeStorage(key=>val))
94148
end
95149
return Scope(ScopeStorage(parent.values, key=>val))
96150
end
97151

98-
function Scope(scope, pair::Pair{<:ScopedValue})
152+
function Scope(scope, pair::Pair{<:AbstractScopedValue})
99153
return Scope(scope, pair...)
100154
end
101155

102-
function Scope(scope, pair1::Pair{<:ScopedValue}, pair2::Pair{<:ScopedValue}, pairs::Pair{<:ScopedValue}...)
156+
function Scope(scope, pair1::Pair{<:AbstractScopedValue}, pair2::Pair{<:AbstractScopedValue}, pairs::Pair{<:AbstractScopedValue}...)
103157
# Unroll this loop through recursion to make sure that
104158
# our compiler optimization support works
105159
return Scope(Scope(scope, pair1...), pair2, pairs...)
@@ -115,19 +169,17 @@ function Base.show(io::IO, scope::Scope)
115169
else
116170
print(io, ", ")
117171
end
118-
print(io, typeof(key), "@")
172+
print(io, isa(key, ScopedValue) ? ScopedValue{eltype(key)} : typeof(key), "@")
119173
show(io, Base.objectid(key))
120174
print(io, " => ")
121175
show(IOContext(io, :typeinfo => eltype(key)), value)
122176
end
123177
print(io, ")")
124178
end
125179

126-
struct NoValue end
127-
const novalue = NoValue()
128-
129180
"""
130181
get(val::ScopedValue{T})::Union{Nothing, Some{T}}
182+
get(val::LazyScopedValue{T})::Union{Nothing, Some{T}}
131183
132184
If the scoped value isn't set and doesn't have a default value,
133185
return `nothing`. Otherwise returns `Some{T}` with the current
@@ -148,31 +200,36 @@ julia> isnothing(ScopedValues.get(b))
148200
true
149201
```
150202
"""
151-
function get(val::ScopedValue{T}) where {T}
203+
function get(val::AbstractScopedValue{T}) where {T}
152204
scope = Core.current_scope()::Union{Scope, Nothing}
153205
if scope === nothing
154-
val.has_default && return Some{T}(val.default)
155-
return nothing
206+
!hasdefault(val) && return nothing
207+
return Some{T}(getdefault(val))
156208
end
157209
scope = scope::Scope
158-
if val.has_default
159-
return Some{T}(Base.get(scope.values, val, val.default)::T)
210+
if hasdefault(val)
211+
return Some{T}(Base.get(Base.Fix1(getdefault, val), scope.values, val)::T)
160212
else
161-
v = Base.get(scope.values, val, novalue)
162-
v === novalue || return Some{T}(v::T)
213+
v = Base.KeyValue.get(scope.values, val)
214+
v === nothing && return nothing
215+
return Some{T}(only(v)::T)
163216
end
164217
return nothing
165218
end
166219

167-
function Base.getindex(val::ScopedValue{T})::T where T
220+
function Base.getindex(val::AbstractScopedValue{T})::T where T
168221
maybe = get(val)
169222
maybe === nothing && throw(KeyError(val))
170223
return something(maybe)::T
171224
end
172225

173-
function Base.show(io::IO, val::ScopedValue)
174-
print(io, ScopedValue)
175-
print(io, '{', eltype(val), '}')
226+
function Base.show(io::IO, val::AbstractScopedValue)
227+
if isa(val, ScopedValue)
228+
print(io, ScopedValue)
229+
print(io, '{', eltype(val), '}')
230+
else
231+
print(io, typeof(val))
232+
end
176233
print(io, '(')
177234
v = get(val)
178235
if v === nothing
@@ -265,7 +322,7 @@ julia> with(() -> a[] * b[], a=>3, b=>4)
265322
12
266323
```
267324
"""
268-
function with(f, pair::Pair{<:ScopedValue}, rest::Pair{<:ScopedValue}...)
325+
function with(f, pair::Pair{<:AbstractScopedValue}, rest::Pair{<:AbstractScopedValue}...)
269326
@with(pair, rest..., f())
270327
end
271328
with(@nospecialize(f)) = f()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
4ca411efb3c84aa309965fbc749d12aa

0 commit comments

Comments
 (0)