Skip to content

Commit 11a1021

Browse files
committed
WIP: very bare-bones NamedTuple type
Based on #16580
1 parent ab771ef commit 11a1021

File tree

11 files changed

+99
-27
lines changed

11 files changed

+99
-27
lines changed

base/boot.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export
120120
# key types
121121
Any, DataType, Vararg, ANY, NTuple,
122122
Tuple, Type, UnionAll, TypeName, TypeVar, Union, Void,
123-
SimpleVector, AbstractArray, DenseArray,
123+
SimpleVector, AbstractArray, DenseArray, NamedTuple,
124124
# special objects
125125
Function, CodeInfo, Method, MethodTable, TypeMapEntry, TypeMapLevel,
126126
Module, Symbol, Task, Array, WeakRef, VecElement,

base/essentials.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,3 +377,12 @@ call obsolete versions of a function `f`.
377377
`f` directly, and the type of the result cannot be inferred by the compiler.)
378378
"""
379379
invokelatest(f, args...) = Core._apply_latest(f, args)
380+
381+
@generated function namedtuple(::Type{NamedTuple{names,T} where T}, args...) where names
382+
N = length(names)
383+
if length(args) != N
384+
:(throw(ArgumentError("wrong number of arguments to named tuple constructor")))
385+
else
386+
Expr(:new, :(NamedTuple{names,$(Tuple{args...})}), [ :(args[$i]) for i in 1:N ]...)
387+
end
388+
end

base/reflection.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ julia> fieldname(SparseMatrixCSC,5)
117117
:nzval
118118
```
119119
"""
120-
fieldname(t::DataType, i::Integer) = t.name.names[i]::Symbol
120+
fieldname(t::DataType, i::Integer) = (isdefined(t,:names) ? t.names[i] : t.name.names[i])::Symbol
121121
fieldname(t::UnionAll, i::Integer) = fieldname(unwrap_unionall(t), i)
122122
fieldname(t::Type{<:Tuple}, i::Integer) = i < 1 || i > nfields(t) ? throw(BoundsError(t, i)) : Int(i)
123123

src/builtins.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ JL_CALLABLE(jl_f_sizeof)
254254
if (dx->name == jl_array_typename || dx == jl_symbol_type || dx == jl_simplevector_type ||
255255
dx == jl_string_type)
256256
jl_error("type does not have a canonical binary representation");
257-
if (!(dx->name->names == jl_emptysvec && jl_datatype_size(dx) > 0)) {
257+
if (!(jl_field_names(dx) == jl_emptysvec && jl_datatype_size(dx) > 0)) {
258258
// names===() and size > 0 => bitstype, size always known
259259
if (dx->abstract || !jl_is_leaf_type(x))
260260
jl_error("argument is an abstract type; size is indeterminate");
@@ -1150,6 +1150,7 @@ void jl_init_primitives(void)
11501150
add_builtin("QuoteNode", (jl_value_t*)jl_quotenode_type);
11511151
add_builtin("NewvarNode", (jl_value_t*)jl_newvarnode_type);
11521152
add_builtin("GlobalRef", (jl_value_t*)jl_globalref_type);
1153+
add_builtin("NamedTuple", (jl_value_t*)jl_namedtuple_type);
11531154

11541155
#ifdef _P64
11551156
add_builtin("Int", (jl_value_t*)jl_int64_type);

src/codegen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3149,7 +3149,7 @@ static bool emit_builtin_call(jl_cgval_t *ret, jl_value_t *f, jl_value_t **args,
31493149
// this is issue #8798
31503150
sty != (jl_value_t*)jl_datatype_type) {
31513151
if (jl_is_leaf_type(sty) ||
3152-
(((jl_datatype_t*)sty)->name->names == jl_emptysvec && jl_datatype_size(sty) > 0)) {
3152+
(jl_field_names((jl_datatype_t*)sty) == jl_emptysvec && jl_datatype_size(sty) > 0)) {
31533153
*ret = mark_julia_type(ConstantInt::get(T_size, jl_datatype_size(sty)), false, jl_long_type, ctx);
31543154
JL_GC_POP();
31553155
return true;

src/datatype.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ jl_datatype_t *jl_new_uninitialized_datatype(void)
8787
t->hasfreetypevars = 0;
8888
t->isleaftype = 1;
8989
t->layout = NULL;
90+
t->names = NULL;
9091
return t;
9192
}
9293

@@ -230,7 +231,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
230231
uint64_t max_offset = (((uint64_t)1) << 32) - 1;
231232
uint64_t max_size = max_offset >> 1;
232233

233-
if (st->name->wrapper) {
234+
if (st->name->wrapper && !jl_is_namedtuple_type(st)) {
234235
// If layout doesn't depend on type parameters, it's stored in st->name->wrapper
235236
// and reused by all subtypes.
236237
jl_datatype_t *w = (jl_datatype_t*)jl_unwrap_unionall(st->name->wrapper);
@@ -691,7 +692,7 @@ JL_DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type)
691692

692693
JL_DLLEXPORT int jl_field_index(jl_datatype_t *t, jl_sym_t *fld, int err)
693694
{
694-
jl_svec_t *fn = t->name->names;
695+
jl_svec_t *fn = jl_field_names(t);
695696
for(size_t i=0; i < jl_svec_len(fn); i++) {
696697
if (jl_svecref(fn,i) == (jl_value_t*)fld) {
697698
return (int)i;

src/dump.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,7 @@ static void jl_serialize_datatype(jl_serializer_state *s, jl_datatype_t *dt)
652652
if (has_instance)
653653
jl_serialize_value(s, dt->instance);
654654
jl_serialize_value(s, dt->name);
655+
jl_serialize_value(s, dt->names);
655656
jl_serialize_value(s, dt->parameters);
656657
jl_serialize_value(s, dt->super);
657658
jl_serialize_value(s, dt->types);
@@ -1534,6 +1535,8 @@ static jl_value_t *jl_deserialize_datatype(jl_serializer_state *s, int pos, jl_v
15341535
}
15351536
dt->name = (jl_typename_t*)jl_deserialize_value(s, (jl_value_t**)&dt->name);
15361537
jl_gc_wb(dt, dt->name);
1538+
dt->names = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&dt->names);
1539+
jl_gc_wb(dt, dt->names);
15371540
dt->parameters = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&dt->parameters);
15381541
jl_gc_wb(dt, dt->parameters);
15391542
dt->super = (jl_datatype_t*)jl_deserialize_value(s, (jl_value_t**)&dt->super);
@@ -3365,7 +3368,6 @@ void jl_init_serializer(void)
33653368
jl_box_int32(30), jl_box_int32(31), jl_box_int32(32),
33663369
#ifndef _P64
33673370
jl_box_int32(33), jl_box_int32(34), jl_box_int32(35),
3368-
jl_box_int32(36), jl_box_int32(37),
33693371
#endif
33703372
jl_box_int64(0), jl_box_int64(1), jl_box_int64(2),
33713373
jl_box_int64(3), jl_box_int64(4), jl_box_int64(5),
@@ -3380,7 +3382,6 @@ void jl_init_serializer(void)
33803382
jl_box_int64(30), jl_box_int64(31), jl_box_int64(32),
33813383
#ifdef _P64
33823384
jl_box_int64(33), jl_box_int64(34), jl_box_int64(35),
3383-
jl_box_int64(36), jl_box_int64(37),
33843385
#endif
33853386
jl_labelnode_type, jl_linenumbernode_type, jl_gotonode_type,
33863387
jl_quotenode_type, jl_type_type, jl_bottom_type, jl_ref_type,
@@ -3406,7 +3407,8 @@ void jl_init_serializer(void)
34063407
jl_intrinsic_type->name, jl_task_type->name, jl_labelnode_type->name,
34073408
jl_linenumbernode_type->name, jl_builtin_type->name, jl_gotonode_type->name,
34083409
jl_quotenode_type->name, jl_globalref_type->name, jl_typeofbottom_type->name,
3409-
jl_string_type->name, jl_abstractstring_type->name,
3410+
jl_string_type->name, jl_abstractstring_type->name, jl_namedtuple_type,
3411+
jl_namedtuple_typename,
34103412

34113413
ptls->root_task,
34123414

@@ -3450,6 +3452,7 @@ void jl_init_serializer(void)
34503452
arraylist_push(&builtin_typenames, ((jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)jl_densearray_type))->name);
34513453
arraylist_push(&builtin_typenames, jl_tuple_typename);
34523454
arraylist_push(&builtin_typenames, jl_vararg_typename);
3455+
arraylist_push(&builtin_typenames, jl_namedtuple_typename);
34533456
}
34543457

34553458
#ifdef __cplusplus

src/interpreter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super)
177177
if (!jl_is_datatype(super) || !jl_is_abstracttype(super) ||
178178
tt->name == ((jl_datatype_t*)super)->name ||
179179
jl_subtype(super,(jl_value_t*)jl_vararg_type) ||
180-
jl_is_tuple_type(super) ||
180+
jl_is_tuple_type(super) || jl_is_namedtuple_type(super) ||
181181
jl_subtype(super,(jl_value_t*)jl_type_type) ||
182182
super == (jl_value_t*)jl_builtin_type) {
183183
jl_errorf("invalid subtyping in definition of %s",

src/jltypes.c

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ jl_unionall_t *jl_pointer_type;
113113
jl_typename_t *jl_pointer_typename;
114114
jl_datatype_t *jl_void_type;
115115
jl_datatype_t *jl_voidpointer_type;
116+
jl_typename_t *jl_namedtuple_typename;
117+
jl_unionall_t *jl_namedtuple_type;
116118
jl_value_t *jl_an_empty_vec_any=NULL;
117119
jl_value_t *jl_stackovf_exception;
118120
#ifdef SEGV_EXCEPTION
@@ -1006,6 +1008,7 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
10061008
jl_typestack_t top;
10071009
jl_typename_t *tn = dt->name;
10081010
int istuple = (tn == jl_tuple_typename);
1011+
int isnamedtuple = (tn == jl_namedtuple_typename);
10091012
// check type cache
10101013
if (cacheable) {
10111014
JL_LOCK(&typecache_lock); // Might GC
@@ -1126,7 +1129,32 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
11261129
ndt->super = NULL;
11271130
ndt->parameters = p;
11281131
jl_gc_wb(ndt, ndt->parameters);
1129-
ndt->types = istuple ? p : NULL; // to be filled in below
1132+
ndt->types = NULL; // to be filled in below
1133+
if (istuple) {
1134+
ndt->types = p;
1135+
}
1136+
else if (isnamedtuple) {
1137+
jl_value_t *names_tup = jl_svecref(p, 0);
1138+
jl_value_t *values_tt = jl_svecref(p, 1);
1139+
if (!jl_has_free_typevars(names_tup) && !jl_has_free_typevars(values_tt)) {
1140+
if (!jl_is_tuple(names_tup))
1141+
jl_type_error_rt("NamedTuple", "names", jl_anytuple_type, names_tup);
1142+
size_t nf = jl_nfields(names_tup);
1143+
jl_svec_t *names = jl_alloc_svec_uninit(nf);
1144+
for(size_t i = 0; i < nf; i++) {
1145+
jl_value_t *ni = jl_fieldref(names_tup, i);
1146+
if (!jl_is_symbol(ni))
1147+
jl_type_error_rt("NamedTuple", "name", jl_symbol_type, ni);
1148+
jl_svecset(names, i, ni);
1149+
}
1150+
if (jl_is_va_tuple(values_tt) || jl_nparams(values_tt) != nf)
1151+
jl_error("NamedTuple names and field types must have matching lengths");
1152+
ndt->names = names;
1153+
jl_gc_wb(ndt, ndt->names);
1154+
ndt->types = ((jl_datatype_t*)values_tt)->parameters;
1155+
jl_gc_wb(ndt, ndt->types);
1156+
}
1157+
}
11301158
ndt->mutabl = dt->mutabl;
11311159
ndt->abstract = dt->abstract;
11321160
ndt->instance = NULL;
@@ -1140,15 +1168,15 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
11401168
if (cacheable && !ndt->abstract)
11411169
ndt->uid = jl_assign_type_uid();
11421170

1143-
if (istuple) {
1171+
if (istuple || isnamedtuple) {
11441172
ndt->super = jl_any_type;
11451173
}
11461174
else if (dt->super) {
11471175
ndt->super = (jl_datatype_t*)inst_type_w_((jl_value_t*)dt->super, env, stack, 1);
11481176
jl_gc_wb(ndt, ndt->super);
11491177
}
11501178
jl_svec_t *ftypes = dt->types;
1151-
if (!istuple && ndt->name->names == jl_emptysvec) {
1179+
if (!istuple && jl_field_names(ndt) == jl_emptysvec) {
11521180
assert(ftypes == NULL || ftypes == jl_emptysvec);
11531181
ndt->size = dt->size;
11541182
ndt->layout = dt->layout;
@@ -1161,13 +1189,13 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
11611189
if (ftypes == NULL || dt->super == NULL) {
11621190
// in the process of creating this type definition:
11631191
// need to instantiate the super and types fields later
1164-
assert(inside_typedef && !istuple);
1192+
assert(inside_typedef && !istuple && !isnamedtuple);
11651193
arraylist_push(&partial_inst, ndt);
11661194
}
11671195
else {
1168-
if (ftypes != jl_emptysvec) {
1196+
if (ftypes != jl_emptysvec || isnamedtuple) {
11691197
assert(!ndt->abstract);
1170-
if (!istuple) {
1198+
if (!istuple && !isnamedtuple) {
11711199
// recursively instantiate the types of the fields
11721200
ndt->types = inst_all(ftypes, env, stack, 1);
11731201
jl_gc_wb(ndt, ndt->types);
@@ -1186,6 +1214,8 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
11861214
}
11871215
if (istuple)
11881216
ndt->ninitialized = ntp;
1217+
else if (isnamedtuple)
1218+
ndt->ninitialized = jl_svec_len(ndt->types);
11891219
else
11901220
ndt->ninitialized = dt->ninitialized;
11911221

@@ -1565,11 +1595,12 @@ void jl_init_types(void)
15651595
jl_datatype_type->name->wrapper = (jl_value_t*)jl_datatype_type;
15661596
jl_datatype_type->super = (jl_datatype_t*)jl_type_type;
15671597
jl_datatype_type->parameters = jl_emptysvec;
1568-
jl_datatype_type->name->names = jl_perm_symsvec(16,
1598+
jl_datatype_type->name->names = jl_perm_symsvec(17,
15691599
"name",
15701600
"super",
15711601
"parameters",
15721602
"types",
1603+
"names",
15731604
"instance",
15741605
"layout",
15751606
"size",
@@ -1582,11 +1613,11 @@ void jl_init_types(void)
15821613
"depth",
15831614
"hasfreetypevars",
15841615
"isleaftype");
1585-
jl_datatype_type->types = jl_svec(16,
1616+
jl_datatype_type->types = jl_svec(17,
15861617
jl_typename_type,
15871618
jl_datatype_type,
15881619
jl_simplevector_type,
1589-
jl_simplevector_type,
1620+
jl_simplevector_type, jl_simplevector_type,
15901621
jl_any_type, // instance
15911622
jl_any_type, jl_any_type, jl_any_type, jl_any_type,
15921623
jl_any_type, jl_any_type, jl_any_type, jl_any_type,
@@ -2028,20 +2059,28 @@ void jl_init_types(void)
20282059
jl_perm_symsvec(1, "len"), jl_svec1(jl_long_type),
20292060
0, 1, 1);
20302061

2062+
jl_tvar_t *ntval_var = jl_new_typevar(jl_symbol("T"), (jl_value_t*)jl_bottom_type,
2063+
(jl_value_t*)jl_anytuple_type);
2064+
tv = jl_svec2(tvar("names"), ntval_var);
2065+
jl_datatype_t *ntt = jl_new_datatype(jl_symbol("NamedTuple"), jl_any_type, tv,
2066+
jl_emptysvec, jl_emptysvec, 0, 0, 0);
2067+
jl_namedtuple_type = (jl_unionall_t*)ntt->name->wrapper;
2068+
jl_namedtuple_typename = ntt->name;
2069+
20312070
// complete builtin type metadata
20322071
jl_value_t *pointer_void = jl_apply_type1((jl_value_t*)jl_pointer_type, (jl_value_t*)jl_void_type);
20332072
jl_voidpointer_type = (jl_datatype_t*)pointer_void;
2034-
jl_svecset(jl_datatype_type->types, 5, jl_voidpointer_type);
2035-
jl_svecset(jl_datatype_type->types, 6, jl_int32_type);
2073+
jl_svecset(jl_datatype_type->types, 6, jl_voidpointer_type);
20362074
jl_svecset(jl_datatype_type->types, 7, jl_int32_type);
20372075
jl_svecset(jl_datatype_type->types, 8, jl_int32_type);
2038-
jl_svecset(jl_datatype_type->types, 9, jl_bool_type);
2076+
jl_svecset(jl_datatype_type->types, 9, jl_int32_type);
20392077
jl_svecset(jl_datatype_type->types, 10, jl_bool_type);
2040-
jl_svecset(jl_datatype_type->types, 11, jl_voidpointer_type);
2078+
jl_svecset(jl_datatype_type->types, 11, jl_bool_type);
20412079
jl_svecset(jl_datatype_type->types, 12, jl_voidpointer_type);
2042-
jl_svecset(jl_datatype_type->types, 13, jl_int32_type);
2043-
jl_svecset(jl_datatype_type->types, 14, jl_bool_type);
2080+
jl_svecset(jl_datatype_type->types, 13, jl_voidpointer_type);
2081+
jl_svecset(jl_datatype_type->types, 14, jl_int32_type);
20442082
jl_svecset(jl_datatype_type->types, 15, jl_bool_type);
2083+
jl_svecset(jl_datatype_type->types, 16, jl_bool_type);
20452084
jl_svecset(jl_simplevector_type->types, 0, jl_long_type);
20462085
jl_svecset(jl_typename_type->types, 1, jl_module_type);
20472086
jl_svecset(jl_typename_type->types, 6, jl_long_type);

src/julia.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ typedef struct _jl_datatype_t {
365365
struct _jl_datatype_t *super;
366366
jl_svec_t *parameters;
367367
jl_svec_t *types;
368+
jl_svec_t *names;
368369
jl_value_t *instance; // for singletons
369370
const jl_datatype_layout_t *layout;
370371
int32_t size; // TODO: move to _jl_datatype_layout_t
@@ -551,6 +552,8 @@ extern JL_DLLEXPORT jl_datatype_t *jl_voidpointer_type;
551552
extern JL_DLLEXPORT jl_unionall_t *jl_pointer_type;
552553
extern JL_DLLEXPORT jl_unionall_t *jl_ref_type;
553554
extern JL_DLLEXPORT jl_typename_t *jl_pointer_typename;
555+
extern JL_DLLEXPORT jl_typename_t *jl_namedtuple_typename;
556+
extern JL_DLLEXPORT jl_unionall_t *jl_namedtuple_type;
554557

555558
extern JL_DLLEXPORT jl_value_t *jl_array_uint8_type;
556559
extern JL_DLLEXPORT jl_value_t *jl_array_any_type;
@@ -770,7 +773,17 @@ STATIC_INLINE void jl_array_uint8_set(void *a, size_t i, uint8_t x)
770773
#define jl_gf_name(f) (jl_gf_mtable(f)->name)
771774

772775
// struct type info
773-
#define jl_field_name(st,i) (jl_sym_t*)jl_svecref(((jl_datatype_t*)st)->name->names, (i))
776+
STATIC_INLINE jl_svec_t *jl_field_names(jl_datatype_t *st)
777+
{
778+
jl_svec_t *names = st->names;
779+
if (!names)
780+
names = st->name->names;
781+
return names;
782+
}
783+
STATIC_INLINE jl_sym_t *jl_field_name(jl_datatype_t *st, size_t i)
784+
{
785+
return (jl_sym_t*)jl_svecref(jl_field_names(st), i);
786+
}
774787
#define jl_field_type(st,i) jl_svecref(((jl_datatype_t*)st)->types, (i))
775788
#define jl_field_count(st) jl_svec_len(((jl_datatype_t*)st)->types)
776789
#define jl_datatype_size(t) (((jl_datatype_t*)t)->size)
@@ -953,6 +966,12 @@ STATIC_INLINE int jl_is_tuple_type(void *t)
953966
((jl_datatype_t*)(t))->name == jl_tuple_typename);
954967
}
955968

969+
STATIC_INLINE int jl_is_namedtuple_type(void *t)
970+
{
971+
return (jl_is_datatype(t) &&
972+
((jl_datatype_t*)(t))->name == jl_namedtuple_typename);
973+
}
974+
956975
STATIC_INLINE int jl_is_vecelement_type(jl_value_t* t)
957976
{
958977
return (jl_is_datatype(t) &&

0 commit comments

Comments
 (0)