Skip to content

Commit 53beb34

Browse files
authored
fix some issues with abstract named tuple types (#32725)
fixes #32697, fixes #32698
1 parent 997ce45 commit 53beb34

File tree

5 files changed

+92
-36
lines changed

5 files changed

+92
-36
lines changed

base/compiler/tfuncs.jl

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -745,8 +745,24 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name))
745745
return Any
746746
end
747747
if s.name === _NAMEDTUPLE_NAME && !isconcretetype(s)
748-
# TODO: better approximate inference
749-
return Any
748+
if isa(name, Const) && isa(name.val, Symbol)
749+
if isa(s.parameters[1], Tuple)
750+
name = Const(Int(ccall(:jl_field_index, Cint, (Any, Any, Cint), s, name.val, false)+1))
751+
else
752+
name = Int
753+
end
754+
elseif Symbol name
755+
name = Int
756+
end
757+
_ts = s.parameters[2]
758+
while isa(_ts, TypeVar)
759+
_ts = _ts.ub
760+
end
761+
_ts = rewrap_unionall(_ts, s00)
762+
if !(_ts <: Tuple)
763+
return Any
764+
end
765+
return getfield_tfunc(_ts, name)
750766
end
751767
ftypes = datatype_fieldtypes(s)
752768
if isempty(ftypes)

src/builtins.c

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -799,44 +799,49 @@ static jl_value_t *get_fieldtype(jl_value_t *t, jl_value_t *f, int dothrow)
799799
int field_index;
800800
if (jl_is_long(f)) {
801801
field_index = jl_unbox_long(f) - 1;
802-
if (st->name == jl_namedtuple_typename) {
803-
jl_value_t *nm = jl_tparam0(st);
804-
if (jl_is_tuple(nm)) {
805-
int nf = jl_nfields(nm);
806-
if (field_index < 0 || field_index >= nf) {
807-
if (dothrow)
808-
jl_bounds_error(t, f);
809-
else
810-
return jl_bottom_type;
811-
}
812-
}
813-
jl_value_t *tt = jl_tparam1(st);
814-
while (jl_is_typevar(tt))
815-
tt = ((jl_tvar_t*)tt)->ub;
816-
if (tt == (jl_value_t*)jl_any_type)
817-
return (jl_value_t*)jl_any_type;
818-
return get_fieldtype(tt, f, dothrow);
819-
}
820-
jl_svec_t *types = jl_get_fieldtypes(st);
821-
int nf = jl_svec_len(types);
822-
if (nf > 0 && field_index >= nf-1 && st->name == jl_tuple_typename) {
823-
jl_value_t *ft = jl_field_type(st, nf-1);
824-
if (jl_is_vararg_type(ft))
825-
return jl_unwrap_vararg(ft);
826-
}
827-
if (field_index < 0 || field_index >= nf) {
828-
if (dothrow)
829-
jl_bounds_error(t, f);
830-
else
831-
return jl_bottom_type;
832-
}
833802
}
834803
else {
835804
JL_TYPECHK(fieldtype, symbol, f);
836805
field_index = jl_field_index(st, (jl_sym_t*)f, dothrow);
837806
if (field_index == -1)
838807
return jl_bottom_type;
839808
}
809+
if (st->name == jl_namedtuple_typename) {
810+
jl_value_t *nm = jl_tparam0(st);
811+
if (jl_is_tuple(nm)) {
812+
int nf = jl_nfields(nm);
813+
if (field_index < 0 || field_index >= nf) {
814+
if (dothrow)
815+
jl_bounds_error(t, f);
816+
else
817+
return jl_bottom_type;
818+
}
819+
}
820+
jl_value_t *tt = jl_tparam1(st);
821+
while (jl_is_typevar(tt))
822+
tt = ((jl_tvar_t*)tt)->ub;
823+
if (tt == (jl_value_t*)jl_any_type)
824+
return (jl_value_t*)jl_any_type;
825+
JL_GC_PUSH1(&f);
826+
if (jl_is_symbol(f))
827+
f = jl_box_long(field_index+1);
828+
jl_value_t *ft = get_fieldtype(tt, f, dothrow);
829+
JL_GC_POP();
830+
return ft;
831+
}
832+
jl_svec_t *types = jl_get_fieldtypes(st);
833+
int nf = jl_svec_len(types);
834+
if (nf > 0 && field_index >= nf-1 && st->name == jl_tuple_typename) {
835+
jl_value_t *ft = jl_field_type(st, nf-1);
836+
if (jl_is_vararg_type(ft))
837+
return jl_unwrap_vararg(ft);
838+
}
839+
if (field_index < 0 || field_index >= nf) {
840+
if (dothrow)
841+
jl_bounds_error(t, f);
842+
else
843+
return jl_bottom_type;
844+
}
840845
return jl_field_type(st, field_index);
841846
}
842847

src/datatype.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -905,9 +905,25 @@ JL_DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type)
905905
JL_DLLEXPORT int jl_field_index(jl_datatype_t *t, jl_sym_t *fld, int err)
906906
{
907907
jl_svec_t *fn = jl_field_names(t);
908-
for(size_t i=0; i < jl_svec_len(fn); i++) {
909-
if (jl_svecref(fn,i) == (jl_value_t*)fld) {
910-
return (int)i;
908+
size_t n = jl_svec_len(fn);
909+
if (n == 0) {
910+
if (jl_is_namedtuple_type(t)) {
911+
jl_value_t *ns = jl_tparam0(t);
912+
if (jl_is_tuple(ns)) {
913+
n = jl_nfields(ns);
914+
for(size_t i=0; i < n; i++) {
915+
if (jl_get_nth_field(ns, i) == (jl_value_t*)fld) {
916+
return (int)i;
917+
}
918+
}
919+
}
920+
}
921+
}
922+
else {
923+
for(size_t i=0; i < n; i++) {
924+
if (jl_svecref(fn,i) == (jl_value_t*)fld) {
925+
return (int)i;
926+
}
911927
}
912928
}
913929
if (err)

test/compiler/inference.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,6 +1460,21 @@ f_pure_add() = (1 + 1 == 2) ? true : "FAIL"
14601460
@test Core.Compiler.getfield_tfunc(Const(Vector{Int}), Const(:mutable)) == Const(true)
14611461
@test Core.Compiler.getfield_tfunc(DataType, Const(:mutable)) == Bool
14621462

1463+
# getfield on abstract named tuples. issue #32698
1464+
import Core.Compiler.getfield_tfunc
1465+
@test getfield_tfunc(NamedTuple{(:id, :y), T} where {T <: Tuple{Int, Union{Float64, Missing}}},
1466+
Const(:y)) == Union{Missing, Float64}
1467+
@test getfield_tfunc(NamedTuple{(:id, :y), T} where {T <: Tuple{Int, Union{Float64, Missing}}},
1468+
Const(2)) == Union{Missing, Float64}
1469+
@test getfield_tfunc(NamedTuple{(:id, :y), T} where {T <: Tuple{Int, Union{Float64, Missing}}},
1470+
Symbol) == Union{Missing, Float64, Int}
1471+
@test getfield_tfunc(NamedTuple{<:Any, T} where {T <: Tuple{Int, Union{Float64, Missing}}},
1472+
Symbol) == Union{Missing, Float64, Int}
1473+
@test getfield_tfunc(NamedTuple{<:Any, T} where {T <: Tuple{Int, Union{Float64, Missing}}},
1474+
Int) == Union{Missing, Float64, Int}
1475+
@test getfield_tfunc(NamedTuple{<:Any, T} where {T <: Tuple{Int, Union{Float64, Missing}}},
1476+
Const(:x)) == Union{Missing, Float64, Int}
1477+
14631478
struct Foo_22708
14641479
x::Ptr{Foo_22708}
14651480
end

test/reflection.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,10 @@ tlayout = TLayout(5,7,11)
271271
@test fieldtype((NamedTuple{(:a,:b),T} where T<:Tuple{Vararg{Integer}}), 2) === Integer
272272
@test_throws BoundsError fieldtype(NamedTuple{(:a,:b)}, 3)
273273

274+
# issue #32697
275+
@test fieldtype(NamedTuple{(:x,:y), T} where T <: Tuple{Int, Union{Float64, Missing}}, :x) == Int
276+
@test fieldtype(NamedTuple{(:x,:y), T} where T <: Tuple{Int, Union{Float64, Missing}}, :y) == Union{Float64, Missing}
277+
274278
@test fieldtypes(NamedTuple{(:a,:b)}) == (Any, Any)
275279
@test fieldtypes((NamedTuple{T,Tuple{Int,String}} where T)) === (Int, String)
276280
@test fieldtypes(TLayout) === (Int8, Int16, Int32)

0 commit comments

Comments
 (0)