Skip to content

Commit 81038d3

Browse files
committed
Improve type inference for @something
`@something` eagerly unwraps any `Some` given to it, while keeping the variable between its arguments the same. This can be an issue if a previously unpacked value is used as input to `@something`, leading to a type instability on more than two arguments (e.g. because of a fallback to `Some(nothing)`). By using different variables for each argument, type inference has an easier time handling these cases that are isolated to single branches anyway.
1 parent 0c46852 commit 81038d3

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

base/some.jl

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,31 @@ true
138138
This macro is available as of Julia 1.7.
139139
"""
140140
macro something(args...)
141-
expr = :(nothing)
141+
noth = GlobalRef(Base, :nothing)
142+
something = GlobalRef(Base, :something)
143+
144+
# This preserves existing semantics of throwing on `nothing`
145+
expr = :($something($noth))
146+
147+
#=
148+
We go through the arguments in reverse
149+
because we're building a nested if/else
150+
expression from the inside out.
151+
The innermost thing to check is the last argument,
152+
which is why we need the last argument first
153+
when building the final expression.
154+
=#
142155
for arg in reverse(args)
143-
expr = :(val = $(esc(arg)); val !== nothing ? val : ($expr))
156+
val = gensym()
157+
expr = quote
158+
$val = $(esc(arg))
159+
if !isnothing($val)
160+
# unwrap eagerly to help type inference
161+
$something($val)
162+
else
163+
$expr
164+
end
165+
end
144166
end
145-
something = GlobalRef(Base, :something)
146-
return :($something($expr))
167+
return expr
147168
end

0 commit comments

Comments
 (0)