Skip to content

Conversation

fingolfin
Copy link
Member

Encountered while looking through JET report for GAP.jl

invalid builtin function call: getfield(x::RawFD, f::Symbol)

Clearly the code itself really is fine, but the annotation silences this warning.

Full context:

┌ _spawn_primitive(file::String, cmd::Cmd, stdio::Memory{Union{RawFD, Base.SyncCloseFD, IO}}) @ Base ./process.jl:113
│┌ collect(::Type{Task}, itr::Base.Generator{Base.Iterators.Filter{…}, Base.var"#_spawn_primitive##0#_spawn_primitive##1"}) @ Base ./array.jl:641
││┌ _collect(::Type{…}, itr::Base.Generator{…}, isz::Base.SizeUnknown) @ Base ./array.jl:647
│││┌ iterate(::Base.Generator{Base.Iterators.Filter{…}, Base.var"#_spawn_primitive##0#_spawn_primitive##1"}) @ Base ./generator.jl:48
││││┌ (::Base.var"#_spawn_primitive##0#_spawn_primitive##1")(io::Union{RawFD, Base.SyncCloseFD, IO}) @ Base ./none:0
│││││┌ getproperty(x::RawFD, f::Symbol) @ Base ./Base_compiler.jl:54
││││││ invalid builtin function call: getfield(x::RawFD, f::Symbol)
│││││└────────────────────

invalid builtin function call: getfield(x::RawFD, f::Symbol)
@fingolfin fingolfin added the backport 1.12 Change should be backported to release-1.12 label Jul 27, 2025
@Keno
Copy link
Member

Keno commented Jul 29, 2025

I'm ok with it, but also does point to missing inference quality in guarded generators.

@fingolfin
Copy link
Member Author

Yes I agree this is kinda papering over a problem (or opportunity for improvement).

I am seeing more (all against the Julia release-1.12 branch right now):

│││││┌ complete_path_string(path::String, hint::Bool; shell_escape::Bool, cmd_escape::Bool, string_escape::Bool, dirsep::Char, kws::@Kwargs{…}) @ REPL.REPLCompletions /Users/mhorn/Projekte/Julia/julia.release-1.12/usr/share/julia/stdlib/v1.12/REPL/src/REPLCompletions.jl:1353
││││││┌ kwcall(::@NamedTuple{dirsep::Char, use_envpath::Bool}, ::typeof(REPL.REPLCompletions.complete_path), path::String) @ REPL.REPLCompletions /Users/mhorn/Projekte/Julia/julia.release-1.12/usr/share/julia/stdlib/v1.12/REPL/src/REPLCompletions.jl:426
│││││││┌  @ REPL.REPLCompletions /Users/mhorn/Projekte/Julia/julia.release-1.12/usr/share/julia/stdlib/v1.12/REPL/src/REPLCompletions.jl:468
││││││││┌ maybe_spawn_cache_PATH() @ REPL.REPLCompletions /Users/mhorn/Projekte/Julia/julia.release-1.12/usr/share/julia/stdlib/v1.12/REPL/src/REPLCompletions.jl:338
│││││││││ no matching method found `istaskdone(::Nothing)` (1/2 union split): REPL.REPLCompletions.istaskdone(REPL.REPLCompletions.PATH_cache_task)
││││││││└────────────────────
││││││││┌ maybe_spawn_cache_PATH() @ REPL.REPLCompletions /Users/mhorn/Projekte/Julia/julia.release-1.12/usr/share/julia/stdlib/v1.12/REPL/src/REPLCompletions.jl:338
│││││││││┌ (::REPL.REPLCompletions.var"#maybe_spawn_cache_PATH##0#maybe_spawn_cache_PATH##1")() @ REPL.REPLCompletions /Users/mhorn/Projekte/Julia/julia.release-1.12/usr/share/julia/stdlib/v1.12/REPL/src/REPLCompletions.jl:343
││││││││││ no matching method found `notify(::Nothing)` (1/2 union split): @_6 = REPL.REPLCompletions.notify(REPL.REPLCompletions.PATH_cache_condition)
│││││││││└────────────────────
││││││││┌ maybe_spawn_cache_PATH() @ REPL.REPLCompletions /Users/mhorn/Projekte/Julia/julia.release-1.12/usr/share/julia/stdlib/v1.12/REPL/src/REPLCompletions.jl:338
│││││││││ no matching method found `errormonitor(::Nothing)` (1/2 union split): (REPL.REPLCompletions.Base).errormonitor::typeof(errormonitor)(REPL.REPLCompletions.PATH_cache_task)
││││││││└────────────────────

Yet the code in question seems like it should require no union splitting at all, at least in two of the tree places, since either a concrete type is checked, or a !== nothing check is there. Alas I am not sure if this is an issue in Julia, in JET, both, neither... (CC @aviatesk)

function maybe_spawn_cache_PATH()
    global PATH_cache_task, next_cache_update
    @lock PATH_cache_lock begin
        PATH_cache_task isa Task && !istaskdone(PATH_cache_task) && return  # <- JET warning 1
        time() < next_cache_update && return
        PATH_cache_task = Threads.@spawn begin
            REPLCompletions.cache_PATH()
            @lock PATH_cache_lock begin
                next_cache_update = time() + 10 # earliest next update can run is 10s after
                PATH_cache_task = nothing # release memory when done
                PATH_cache_condition !== nothing && notify(PATH_cache_condition)  # <- JET warning 2
            end
        end
        Base.errormonitor(PATH_cache_task)  # <- JET warning 3
    end
end

aviatesk added a commit that referenced this pull request Jul 29, 2025
This addresses type inference issues with filtered list comprehensions
reported in #59111. The root cause is the compiler's
inability to perform type refinement in cases like:

```julia let t::Tuple{Any,Any} x, y = t if x isa Int return t # still
`::Tuple{Any,Any}` end nothing end ```

Fixing this fundamentally would require extensive improvements to
abstract interpretation. As a workaround, I improved the iterators.jl
implementation to avoid this pattern.

One implementation consideration: if `iterate(f.itr, state...)` always
returns `Union{Nothing,Tuple{Any,Any}}`, the `if y isa Tuple{Any,Any}`
branch should be unnecessary. However, it's unclear whether we can
safely assume this for the iterate interface, so I kept the branch for
now.
@aviatesk
Copy link
Member

I'm ok with it, but also does point to missing inference quality in guarded generators.

Will be fixed by #59142.

aviatesk added a commit that referenced this pull request Jul 29, 2025
This addresses type inference issues with filtered list comprehensions
reported in #59111. The root cause is the compiler's
inability to perform type refinement in cases like:

```julia
let t::Tuple{Any,Any}
    x, y = t
    if x isa Int
        return t # still `::Tuple{Any,Any}`
    end
    nothing
end
```

Fixing this fundamentally would require extensive improvements to
abstract interpretation. As a workaround, I improved the iterators.jl
implementation to avoid this pattern.

One implementation consideration: if `iterate(f.itr, state...)` always
returns `Union{Nothing,Tuple{Any,Any}}`, the `if y isa Tuple{Any,Any}`
branch should be unnecessary. However, it's unclear whether we can
safely assume this for the iterate interface, so I kept the branch for
now.
@aviatesk
Copy link
Member

Yet the code in question seems like it should require no union splitting at all, at least in two of the tree places, since either a concrete type is checked, or a !== nothing check is there. Alas I am not sure if this is an issue in Julia, in JET, both, neither... (CC @aviatesk)

#59144

aviatesk added a commit that referenced this pull request Jul 29, 2025
This addresses type inference issues with filtered list comprehensions
reported in #59111. The root cause is the compiler's
inability to perform type refinement in cases like:

```julia
let t::Tuple{Any,Any}
    x, y = t
    if x isa Int
        return t # still `::Tuple{Any,Any}`
    end
    nothing
end
```

Fixing this fundamentally would require extensive improvements to
abstract interpretation. As a workaround, I improved the iterators.jl
implementation to avoid this pattern.

One implementation consideration: if `iterate(f.itr, state...)` always
returns `Union{Nothing,Tuple{Any,Any}}`, the `if y isa Tuple{Any,Any}`
branch should be unnecessary. However, it's unclear whether we can
safely assume this for the iterate interface, so I kept the branch for
now.
@aviatesk
Copy link
Member

With these linked PRs merged, now I think this PR can be closed.

@lgoettgens
Copy link
Contributor

With these linked PRs merged, now I think this PR can be closed.

Since the issues brought up here were observed in julia 1.12, could we backport #59142 and #59144?

@aviatesk
Copy link
Member

Backported.

@KristofferC KristofferC mentioned this pull request Aug 6, 2025
38 tasks
@KristofferC KristofferC mentioned this pull request Aug 19, 2025
27 tasks
@aviatesk aviatesk closed this Aug 21, 2025
@aviatesk
Copy link
Member

Closed as this particular JET issue has been resolved by the improvements on the Filter implementation.

@aviatesk aviatesk deleted the mh/fix-JET branch August 21, 2025 04:34
@fingolfin
Copy link
Member Author

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport 1.12 Change should be backported to release-1.12

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants