/
githubmirror
/
julia
Обзор
Документация
Войти
/
githubmirror
/
julia
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
test/scopedvalues.jl
287 строк
7 KB
Keno Fischer
cancellation: Add basic CancellationToken[Source] APIs (#62429)
24 июл 2026, 23:23
Не верифицирован
24 июл 2026, 23:23
7afe4ed
Код
Авторство
О чём код?
# This file is a part of Julia. License is MIT: https://julialang.org/license using Base.ScopedValues include(joinpath(@__DIR__,"../Compiler/test/irutils.jl")) @testset "errors" begin @test ScopedValue{Float64}(1)[] == 1.0 @test_throws InexactError ScopedValue{Int}(1.5) let val = ScopedValue(1) @test_throws MethodError val[] = 2 with() do @test_throws MethodError val[] = 2 end end let val = ScopedValue{String}() @test_throws KeyError val[] end let val = ScopedValue{Int}() @test_throws KeyError val[] end @test_throws MethodError ScopedValue() end const sval = ScopedValue(1) @testset "inheritance" begin @test sval[] == 1 with() do @test sval[] == 1 with() do @test sval[] == 1 end with(sval => 2) do @test sval[] == 2 end @test sval[] == 1 end @test sval[] == 1 end const sval_float = ScopedValue(1.0) @testset "multiple scoped values" begin with(sval => 2, sval_float => 2.0) do @test sval[] == 2 @test sval_float[] == 2.0 end with(sval => 2, sval => 3) do @test sval[] == 3 end end emptyf() = nothing @testset "conversion" begin with(emptyf, sval_float=>2) @test_throws MethodError with(emptyf, sval_float=>"hello") a = ScopedValue(1) with(a => 2.0) do @test a[] == 2 @test a[] isa Int end a = ScopedValue(1.0) with(a => 2) do @test a[] == 2.0 @test a[] isa Float64 end end import Base.Threads: @spawn @testset "tasks" begin @test fetch(@spawn begin sval[] end) == 1 with(sval => 2) do @test fetch(@spawn begin sval[] end) == 2 end end @testset "show" begin @test sprint(show, ScopedValue{Int}(), context=(:module=>Core,)) == "Base.ScopedValues.ScopedValue{$Int}()" @test sprint(show, sval, context=(:module=>Core,)) == "Base.ScopedValues.ScopedValue{$Int}(1)" with(sval => 2.0) do @test sprint(show, sval, context=(:module=>Core,)) == "Base.ScopedValues.ScopedValue{$Int}(2)" objid = sprint(show, Base.objectid(sval)) let str = sprint(show, Core.current_scope(), context=(:module=>Core,)) @test startswith(str, "Base.Scope") @test contains(str, "Base.ScopedValues.ScopedValue{$Int}@$objid => 2") end end end const depth = ScopedValue(0) function nth_with(f, n) if n <= 0 f() else with(depth => n) do nth_with(f, n-1) end end end @testset "nested with" begin @testset for depth in 1:16 nth_with(depth) do @test sval_float[] == 1.0 end with(sval_float=>2.0) do nth_with(depth) do @test sval_float[] == 2.0 end end nth_with(depth) do with(sval_float=>2.0) do @test sval_float[] == 2.0 end end end with(sval_float=>2.0) do nth_with(15) do @test sval_float[] == 2.0 with(sval_float => 3.0) do @test sval_float[] == 3.0 end end end end @testset "macro" begin @with sval=>2 sval_float=>2.0 begin @test sval[] == 2 @test sval_float[] == 2.0 end # Doesn't do much... @with begin @test sval[] == 1 @test sval_float[] == 1.0 end @with sval=>2 sval_float=>2.0 begin @with begin @test sval[] == 2 @test sval_float[] == 2.0 end end end @testset "isassigned" begin sv = ScopedValue(1) @test isassigned(sv) sv = ScopedValue{Int}() @test !isassigned(sv) with(sv => 2) do @test isassigned(sv) end end # Test that the `@with` macro doesn't introduce unnecessary PhiC nodes # (which can be hard for the optimizer to remove). function with_macro_slot_cross() a = 1 @with sval=>1 begin a = sval_float[] end return a end let code = code_typed(with_macro_slot_cross)[1][1].code @test !any(x->isa(x, Core.PhiCNode), code) end # inline constant scoped values const inlineable_const_sv = ScopedValue(1) @test fully_eliminated(; retval=(inlineable_const_sv => 1)) do inlineable_const_sv => 1 end # Handle nothrow scope bodies correctly (#56609) @eval @noinline function nothrow_scope(@nospecialize(scope_at_entry)) $(Expr(:tryfinally, :(), nothing, 1)) @test Core.current_scope() === scope_at_entry end nothrow_scope(Core.current_scope()) # https://github.com/JuliaLang/julia/issues/56062 @testset "issue #56062" begin ts = Int[] try @with begin return end catch err finally push!(ts, 2) end end # LazyScopedValue global lsv_ncalled = 0 const lsv = LazyScopedValue{Int}(OncePerProcess(() -> (global lsv_ncalled; lsv_ncalled += 1; 1))) @testset "LazyScopedValue" begin @test (@with lsv=>2 lsv[]) == 2 @test lsv_ncalled == 0 @test lsv[] == 1 @test lsv_ncalled == 1 @test lsv[] == 1 @test lsv_ncalled == 1 end @testset "ScopedThunk" begin function check_svals() @test sval[] == 8 @test sval_float[] == 8.0 end sf = nothing @with sval=>8 sval_float=>8.0 begin sf = ScopedThunk(check_svals) end sf() @with sval=>8 sval_float=>8.0 begin sf2 = ScopedThunk{Function}(check_svals) end sf2() end using Base.ScopedValues: ScopedValue, with @noinline function test_59483() sv = ScopedValue([]) ch = Channel{Bool}() # Spawn a child task, which inherits the parent's Scope @noinline function inner_function() # Block until the parent task has left the scope. take!(ch) # Now, per issue 59483, this task's scope is not rooted, except by the task itself. # Now switch to an inner scope, leaving the current scope possibly unrooted. val = with(sv=>Any[2]) do # Inside this new scope, when we perform GC, the parent scope can be freed. # The fix for this issue made sure that the first scope in this task remains # rooted. GC.gc() GC.gc() sv[] end @test val == Any[2] # Finally, we've returned to the original scope, but that could be a dangling # pointer if the scope itself was freed by the above GCs. So these GCs could crash: GC.gc() GC.gc() end @noinline function spawn_inner() # Set a new Scope in the parent task - this is the scope that could be freed. with(sv=>Any[1]) do return @async inner_function() end end # RUN THE TEST: t = spawn_inner() # Exit the scope, and let the child task proceed put!(ch, true) wait(t) end @testset "issue 59483" begin test_59483() end # issue #53584 - ScopedValue should not allocate when accessed const sv_53584 = ScopedValue([0]) @noinline function access_scoped_53584() v = sv_53584[] v[1] += 1 return nothing end function run_53584() @with sv_53584=>[0] for _ in 1:100_000 access_scoped_53584() end end @testset "issue #53584" begin run_53584() # warmup @test (@allocated run_53584()) < 10_000 end