Skip to content

Commit 58eaa6b

Browse files
committed
WIP: very bare-bones NamedTuple type
Based on #16580
1 parent 2d8c0f9 commit 58eaa6b

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
@@ -359,3 +359,12 @@ call obsolete versions of a function `f`.
359359
`f` directly, and the type of the result cannot be inferred by the compiler.)
360360
"""
361361
invokelatest(f, args...) = Core._apply_latest(f, args)
362+
363+
@generated function namedtuple(::Type{NamedTuple{names,T} where T}, args...) where names
364+
N = length(names)
365+
if length(args) != N
366+
:(throw(ArgumentError("wrong number of arguments to named tuple constructor")))
367+
else
368+
Expr(:new, :(NamedTuple{names,$(Tuple{args...})}), [ :(args[$i]) for i in 1:N ]...)
369+
end
370+
end

base/reflection.jl

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

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");
@@ -1154,6 +1154,7 @@ void jl_init_primitives(void)
11541154
add_builtin("QuoteNode", (jl_value_t*)jl_quotenode_type);
11551155
add_builtin("NewvarNode", (jl_value_t*)jl_newvarnode_type);
11561156
add_builtin("GlobalRef", (jl_value_t*)jl_globalref_type);
1157+
add_builtin("NamedTuple", (jl_value_t*)jl_namedtuple_type);
11571158

11581159
#ifdef _P64
11591160
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
@@ -3154,7 +3154,7 @@ static bool emit_builtin_call(jl_cgval_t *ret, jl_value_t *f, jl_value_t **args,
31543154
// this is issue #8798
31553155
sty != (jl_value_t*)jl_datatype_type) {
31563156
if (jl_is_leaf_type(sty) ||
3157-
(((jl_datatype_t*)sty)->name->names == jl_emptysvec && jl_datatype_size(sty) > 0)) {
3157+
(jl_field_names((jl_datatype_t*)sty) == jl_emptysvec && jl_datatype_size(sty) > 0)) {
31583158
*ret = mark_julia_type(ConstantInt::get(T_size, jl_datatype_size(sty)), false, jl_long_type, ctx);
31593159
JL_GC_POP();
31603160
return true;

src/datatype.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ jl_datatype_t *jl_new_uninitialized_datatype(void)
8181
t->hasfreetypevars = 0;
8282
t->isleaftype = 1;
8383
t->layout = NULL;
84+
t->names = NULL;
8485
return t;
8586
}
8687

@@ -224,7 +225,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
224225
uint64_t max_offset = (((uint64_t)1) << 32) - 1;
225226
uint64_t max_size = max_offset >> 1;
226227

227-
if (st->name->wrapper) {
228+
if (st->name->wrapper && !jl_is_namedtuple_type(st)) {
228229
// If layout doesn't depend on type parameters, it's stored in st->name->wrapper
229230
// and reused by all subtypes.
230231
jl_datatype_t *w = (jl_datatype_t*)jl_unwrap_unionall(st->name->wrapper);
@@ -689,7 +690,7 @@ JL_DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type)
689690

690691
JL_DLLEXPORT int jl_field_index(jl_datatype_t *t, jl_sym_t *fld, int err)
691692
{
692-
jl_svec_t *fn = t->name->names;
693+
jl_svec_t *fn = jl_field_names(t);
693694
for(size_t i=0; i < jl_svec_len(fn); i++) {
694695
if (jl_svecref(fn,i) == (jl_value_t*)fld) {
695696
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
@@ -168,7 +168,7 @@ void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super)
168168
if (!jl_is_datatype(super) || !jl_is_abstracttype(super) ||
169169
tt->name == ((jl_datatype_t*)super)->name ||
170170
jl_subtype(super,(jl_value_t*)jl_vararg_type) ||
171-
jl_is_tuple_type(super) ||
171+
jl_is_tuple_type(super) || jl_is_namedtuple_type(super) ||
172172
jl_subtype(super,(jl_value_t*)jl_type_type) ||
173173
super == (jl_value_t*)jl_builtin_type) {
174174
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

@@ -1566,11 +1596,12 @@ void jl_init_types(void)
15661596
jl_datatype_type->name->wrapper = (jl_value_t*)jl_datatype_type;
15671597
jl_datatype_type->super = (jl_datatype_t*)jl_type_type;
15681598
jl_datatype_type->parameters = jl_emptysvec;
1569-
jl_datatype_type->name->names = jl_perm_symsvec(16,
1599+
jl_datatype_type->name->names = jl_perm_symsvec(17,
15701600
"name",
15711601
"super",
15721602
"parameters",
15731603
"types",
1604+
"names",
15741605
"instance",
15751606
"layout",
15761607
"size",
@@ -1583,11 +1614,11 @@ void jl_init_types(void)
15831614
"depth",
15841615
"hasfreetypevars",
15851616
"isleaftype");
1586-
jl_datatype_type->types = jl_svec(16,
1617+
jl_datatype_type->types = jl_svec(17,
15871618
jl_typename_type,
15881619
jl_datatype_type,
15891620
jl_simplevector_type,
1590-
jl_simplevector_type,
1621+
jl_simplevector_type, jl_simplevector_type,
15911622
jl_any_type, // instance
15921623
jl_any_type, jl_any_type, jl_any_type, jl_any_type,
15931624
jl_any_type, jl_any_type, jl_any_type, jl_any_type,
@@ -2029,20 +2060,28 @@ void jl_init_types(void)
20292060
jl_perm_symsvec(1, "len"), jl_svec1(jl_long_type),
20302061
0, 1, 1);
20312062

2063+
jl_tvar_t *ntval_var = jl_new_typevar(jl_symbol("T"), (jl_value_t*)jl_bottom_type,
2064+
(jl_value_t*)jl_anytuple_type);
2065+
tv = jl_svec2(tvar("names"), ntval_var);
2066+
jl_datatype_t *ntt = jl_new_datatype(jl_symbol("NamedTuple"), jl_any_type, tv,
2067+
jl_emptysvec, jl_emptysvec, 0, 0, 0);
2068+
jl_namedtuple_type = (jl_unionall_t*)ntt->name->wrapper;
2069+
jl_namedtuple_typename = ntt->name;
2070+
20322071
// complete builtin type metadata
20332072
jl_value_t *pointer_void = jl_apply_type1((jl_value_t*)jl_pointer_type, (jl_value_t*)jl_void_type);
20342073
jl_voidpointer_type = (jl_datatype_t*)pointer_void;
2035-
jl_svecset(jl_datatype_type->types, 5, jl_voidpointer_type);
2036-
jl_svecset(jl_datatype_type->types, 6, jl_int32_type);
2074+
jl_svecset(jl_datatype_type->types, 6, jl_voidpointer_type);
20372075
jl_svecset(jl_datatype_type->types, 7, jl_int32_type);
20382076
jl_svecset(jl_datatype_type->types, 8, jl_int32_type);
2039-
jl_svecset(jl_datatype_type->types, 9, jl_bool_type);
2077+
jl_svecset(jl_datatype_type->types, 9, jl_int32_type);
20402078
jl_svecset(jl_datatype_type->types, 10, jl_bool_type);
2041-
jl_svecset(jl_datatype_type->types, 11, jl_voidpointer_type);
2079+
jl_svecset(jl_datatype_type->types, 11, jl_bool_type);
20422080
jl_svecset(jl_datatype_type->types, 12, jl_voidpointer_type);
2043-
jl_svecset(jl_datatype_type->types, 13, jl_int32_type);
2044-
jl_svecset(jl_datatype_type->types, 14, jl_bool_type);
2081+
jl_svecset(jl_datatype_type->types, 13, jl_voidpointer_type);
2082+
jl_svecset(jl_datatype_type->types, 14, jl_int32_type);
20452083
jl_svecset(jl_datatype_type->types, 15, jl_bool_type);
2084+
jl_svecset(jl_datatype_type->types, 16, jl_bool_type);
20462085
jl_svecset(jl_simplevector_type->types, 0, jl_long_type);
20472086
jl_svecset(jl_typename_type->types, 1, jl_module_type);
20482087
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
@@ -372,6 +372,7 @@ typedef struct _jl_datatype_t {
372372
struct _jl_datatype_t *super;
373373
jl_svec_t *parameters;
374374
jl_svec_t *types;
375+
jl_svec_t *names;
375376
jl_value_t *instance; // for singletons
376377
const jl_datatype_layout_t *layout;
377378
int32_t size; // TODO: move to _jl_datatype_layout_t
@@ -558,6 +559,8 @@ extern JL_DLLEXPORT jl_datatype_t *jl_voidpointer_type;
558559
extern JL_DLLEXPORT jl_unionall_t *jl_pointer_type;
559560
extern JL_DLLEXPORT jl_unionall_t *jl_ref_type;
560561
extern JL_DLLEXPORT jl_typename_t *jl_pointer_typename;
562+
extern JL_DLLEXPORT jl_typename_t *jl_namedtuple_typename;
563+
extern JL_DLLEXPORT jl_unionall_t *jl_namedtuple_type;
561564

562565
extern JL_DLLEXPORT jl_value_t *jl_array_uint8_type;
563566
extern JL_DLLEXPORT jl_value_t *jl_array_any_type;
@@ -777,7 +780,17 @@ STATIC_INLINE void jl_array_uint8_set(void *a, size_t i, uint8_t x)
777780
#define jl_gf_name(f) (jl_gf_mtable(f)->name)
778781

779782
// struct type info
780-
#define jl_field_name(st,i) (jl_sym_t*)jl_svecref(((jl_datatype_t*)st)->name->names, (i))
783+
STATIC_INLINE jl_svec_t *jl_field_names(jl_datatype_t *st)
784+
{
785+
jl_svec_t *names = st->names;
786+
if (!names)
787+
names = st->name->names;
788+
return names;
789+
}
790+
STATIC_INLINE jl_sym_t *jl_field_name(jl_datatype_t *st, size_t i)
791+
{
792+
return (jl_sym_t*)jl_svecref(jl_field_names(st), i);
793+
}
781794
#define jl_field_type(st,i) jl_svecref(((jl_datatype_t*)st)->types, (i))
782795
#define jl_field_count(st) jl_svec_len(((jl_datatype_t*)st)->types)
783796
#define jl_datatype_size(t) (((jl_datatype_t*)t)->size)
@@ -960,6 +973,12 @@ STATIC_INLINE int jl_is_tuple_type(void *t)
960973
((jl_datatype_t*)(t))->name == jl_tuple_typename);
961974
}
962975

976+
STATIC_INLINE int jl_is_namedtuple_type(void *t)
977+
{
978+
return (jl_is_datatype(t) &&
979+
((jl_datatype_t*)(t))->name == jl_namedtuple_typename);
980+
}
981+
963982
STATIC_INLINE int jl_is_vecelement_type(jl_value_t* t)
964983
{
965984
return (jl_is_datatype(t) &&

0 commit comments

Comments
 (0)