Skip to content

Commit 680e3b3

Browse files
authored
REPLCompletions: unswitch Union of same UnionAll results (JuliaLang#50483)
With this commit the inference-base REPL completion algorithm converts `Union` result of same `UnionAll` instances to `UnionAll` of `Union`s so that it can use the field information of the `UnionAll`. This allows us to get completions for cases like: ```julia julia> union_somes() = rand() < 0.5 ? Some(1) : Some(2.); julia> union_somes().| # completes to `value` ```
1 parent 25eeba4 commit 680e3b3

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

base/compiler/typeutils.jl

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -318,21 +318,32 @@ function unionall_depth(@nospecialize ua) # aka subtype_env_size
318318
end
319319

320320
# convert a Union of Tuple types to a Tuple of Unions
321-
function unswitchtupleunion(u::Union)
321+
unswitchtupleunion(u::Union) = unswitchtypeunion(u, Tuple.name)
322+
323+
function unswitchtypeunion(u::Union, typename::Union{Nothing,Core.TypeName}=nothing)
322324
ts = uniontypes(u)
323325
n = -1
324326
for t in ts
325-
if t isa DataType && t.name === Tuple.name && length(t.parameters) != 0 && !isvarargtype(t.parameters[end])
326-
if n == -1
327-
n = length(t.parameters)
328-
elseif n != length(t.parameters)
327+
if t isa DataType
328+
if typename === nothing
329+
typename = t.name
330+
elseif typename !== t.name
329331
return u
330332
end
333+
if length(t.parameters) != 0 && !isvarargtype(t.parameters[end])
334+
if n == -1
335+
n = length(t.parameters)
336+
elseif n != length(t.parameters)
337+
return u
338+
end
339+
end
331340
else
332341
return u
333342
end
334343
end
335-
Tuple{Any[ Union{Any[(t::DataType).parameters[i] for t in ts]...} for i in 1:n ]...}
344+
Head = (typename::Core.TypeName).wrapper
345+
unionparams = Any[ Union{Any[(t::DataType).parameters[i] for t in ts]...} for i in 1:n ]
346+
return Head{unionparams...}
336347
end
337348

338349
function unwraptv_ub(@nospecialize t)

stdlib/REPL/src/REPLCompletions.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,11 @@ function repl_eval_ex(@nospecialize(ex), context_module::Module)
580580

581581
result = frame.result.result
582582
result === Union{} && return nothing # for whatever reason, callers expect this as the Bottom and/or Top type instead
583+
if isa(result, Union)
584+
# unswitch `Union` of same `UnionAll` instances to `UnionAll` of `Union`s
585+
# so that we can use the field information of the `UnionAll`
586+
return CC.unswitchtypeunion(result)
587+
end
583588
return result
584589
end
585590

stdlib/REPL/test/replcompletions.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1873,3 +1873,13 @@ let s = "`abc`.e"
18731873
# (completions for the fields of `Cmd`)
18741874
@test c == Any["env", "exec"]
18751875
end
1876+
1877+
# Test completion for a case when type inference returned `Union` of the same types
1878+
function union_somes()
1879+
return rand() < 0.5 ? Some(1) : Some(2.)
1880+
end
1881+
let s = "union_somes()."
1882+
c, r, res = test_complete_context(s, @__MODULE__)
1883+
@test res
1884+
@test "value" in c
1885+
end

0 commit comments

Comments
 (0)