Skip to content

Commit

Permalink
WIP: very bare-bones NamedTuple type
Browse files Browse the repository at this point in the history
Based on #16580
  • Loading branch information
JeffBezanson committed Jun 4, 2017
1 parent ab771ef commit 11a1021
Show file tree
Hide file tree
Showing 11 changed files with 99 additions and 27 deletions.
2 changes: 1 addition & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export
# key types
Any, DataType, Vararg, ANY, NTuple,
Tuple, Type, UnionAll, TypeName, TypeVar, Union, Void,
SimpleVector, AbstractArray, DenseArray,
SimpleVector, AbstractArray, DenseArray, NamedTuple,
# special objects
Function, CodeInfo, Method, MethodTable, TypeMapEntry, TypeMapLevel,
Module, Symbol, Task, Array, WeakRef, VecElement,
Expand Down
9 changes: 9 additions & 0 deletions base/essentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,12 @@ call obsolete versions of a function `f`.
`f` directly, and the type of the result cannot be inferred by the compiler.)
"""
invokelatest(f, args...) = Core._apply_latest(f, args)

@generated function namedtuple(::Type{NamedTuple{names,T} where T}, args...) where names
N = length(names)
if length(args) != N
:(throw(ArgumentError("wrong number of arguments to named tuple constructor")))
else
Expr(:new, :(NamedTuple{names,$(Tuple{args...})}), [ :(args[$i]) for i in 1:N ]...)
end
end
2 changes: 1 addition & 1 deletion base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ julia> fieldname(SparseMatrixCSC,5)
:nzval
```
"""
fieldname(t::DataType, i::Integer) = t.name.names[i]::Symbol
fieldname(t::DataType, i::Integer) = (isdefined(t,:names) ? t.names[i] : t.name.names[i])::Symbol
fieldname(t::UnionAll, i::Integer) = fieldname(unwrap_unionall(t), i)
fieldname(t::Type{<:Tuple}, i::Integer) = i < 1 || i > nfields(t) ? throw(BoundsError(t, i)) : Int(i)

Expand Down
3 changes: 2 additions & 1 deletion src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ JL_CALLABLE(jl_f_sizeof)
if (dx->name == jl_array_typename || dx == jl_symbol_type || dx == jl_simplevector_type ||
dx == jl_string_type)
jl_error("type does not have a canonical binary representation");
if (!(dx->name->names == jl_emptysvec && jl_datatype_size(dx) > 0)) {
if (!(jl_field_names(dx) == jl_emptysvec && jl_datatype_size(dx) > 0)) {
// names===() and size > 0 => bitstype, size always known
if (dx->abstract || !jl_is_leaf_type(x))
jl_error("argument is an abstract type; size is indeterminate");
Expand Down Expand Up @@ -1150,6 +1150,7 @@ void jl_init_primitives(void)
add_builtin("QuoteNode", (jl_value_t*)jl_quotenode_type);
add_builtin("NewvarNode", (jl_value_t*)jl_newvarnode_type);
add_builtin("GlobalRef", (jl_value_t*)jl_globalref_type);
add_builtin("NamedTuple", (jl_value_t*)jl_namedtuple_type);

#ifdef _P64
add_builtin("Int", (jl_value_t*)jl_int64_type);
Expand Down
2 changes: 1 addition & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3149,7 +3149,7 @@ static bool emit_builtin_call(jl_cgval_t *ret, jl_value_t *f, jl_value_t **args,
// this is issue #8798
sty != (jl_value_t*)jl_datatype_type) {
if (jl_is_leaf_type(sty) ||
(((jl_datatype_t*)sty)->name->names == jl_emptysvec && jl_datatype_size(sty) > 0)) {
(jl_field_names((jl_datatype_t*)sty) == jl_emptysvec && jl_datatype_size(sty) > 0)) {
*ret = mark_julia_type(ConstantInt::get(T_size, jl_datatype_size(sty)), false, jl_long_type, ctx);
JL_GC_POP();
return true;
Expand Down
5 changes: 3 additions & 2 deletions src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ jl_datatype_t *jl_new_uninitialized_datatype(void)
t->hasfreetypevars = 0;
t->isleaftype = 1;
t->layout = NULL;
t->names = NULL;
return t;
}

Expand Down Expand Up @@ -230,7 +231,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
uint64_t max_offset = (((uint64_t)1) << 32) - 1;
uint64_t max_size = max_offset >> 1;

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

JL_DLLEXPORT int jl_field_index(jl_datatype_t *t, jl_sym_t *fld, int err)
{
jl_svec_t *fn = t->name->names;
jl_svec_t *fn = jl_field_names(t);
for(size_t i=0; i < jl_svec_len(fn); i++) {
if (jl_svecref(fn,i) == (jl_value_t*)fld) {
return (int)i;
Expand Down
9 changes: 6 additions & 3 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ static void jl_serialize_datatype(jl_serializer_state *s, jl_datatype_t *dt)
if (has_instance)
jl_serialize_value(s, dt->instance);
jl_serialize_value(s, dt->name);
jl_serialize_value(s, dt->names);
jl_serialize_value(s, dt->parameters);
jl_serialize_value(s, dt->super);
jl_serialize_value(s, dt->types);
Expand Down Expand Up @@ -1534,6 +1535,8 @@ static jl_value_t *jl_deserialize_datatype(jl_serializer_state *s, int pos, jl_v
}
dt->name = (jl_typename_t*)jl_deserialize_value(s, (jl_value_t**)&dt->name);
jl_gc_wb(dt, dt->name);
dt->names = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&dt->names);
jl_gc_wb(dt, dt->names);
dt->parameters = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&dt->parameters);
jl_gc_wb(dt, dt->parameters);
dt->super = (jl_datatype_t*)jl_deserialize_value(s, (jl_value_t**)&dt->super);
Expand Down Expand Up @@ -3365,7 +3368,6 @@ void jl_init_serializer(void)
jl_box_int32(30), jl_box_int32(31), jl_box_int32(32),
#ifndef _P64
jl_box_int32(33), jl_box_int32(34), jl_box_int32(35),
jl_box_int32(36), jl_box_int32(37),
#endif
jl_box_int64(0), jl_box_int64(1), jl_box_int64(2),
jl_box_int64(3), jl_box_int64(4), jl_box_int64(5),
Expand All @@ -3380,7 +3382,6 @@ void jl_init_serializer(void)
jl_box_int64(30), jl_box_int64(31), jl_box_int64(32),
#ifdef _P64
jl_box_int64(33), jl_box_int64(34), jl_box_int64(35),
jl_box_int64(36), jl_box_int64(37),
#endif
jl_labelnode_type, jl_linenumbernode_type, jl_gotonode_type,
jl_quotenode_type, jl_type_type, jl_bottom_type, jl_ref_type,
Expand All @@ -3406,7 +3407,8 @@ void jl_init_serializer(void)
jl_intrinsic_type->name, jl_task_type->name, jl_labelnode_type->name,
jl_linenumbernode_type->name, jl_builtin_type->name, jl_gotonode_type->name,
jl_quotenode_type->name, jl_globalref_type->name, jl_typeofbottom_type->name,
jl_string_type->name, jl_abstractstring_type->name,
jl_string_type->name, jl_abstractstring_type->name, jl_namedtuple_type,
jl_namedtuple_typename,

ptls->root_task,

Expand Down Expand Up @@ -3450,6 +3452,7 @@ void jl_init_serializer(void)
arraylist_push(&builtin_typenames, ((jl_datatype_t*)jl_unwrap_unionall((jl_value_t*)jl_densearray_type))->name);
arraylist_push(&builtin_typenames, jl_tuple_typename);
arraylist_push(&builtin_typenames, jl_vararg_typename);
arraylist_push(&builtin_typenames, jl_namedtuple_typename);
}

#ifdef __cplusplus
Expand Down
2 changes: 1 addition & 1 deletion src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super)
if (!jl_is_datatype(super) || !jl_is_abstracttype(super) ||
tt->name == ((jl_datatype_t*)super)->name ||
jl_subtype(super,(jl_value_t*)jl_vararg_type) ||
jl_is_tuple_type(super) ||
jl_is_tuple_type(super) || jl_is_namedtuple_type(super) ||
jl_subtype(super,(jl_value_t*)jl_type_type) ||
super == (jl_value_t*)jl_builtin_type) {
jl_errorf("invalid subtyping in definition of %s",
Expand Down
69 changes: 54 additions & 15 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ jl_unionall_t *jl_pointer_type;
jl_typename_t *jl_pointer_typename;
jl_datatype_t *jl_void_type;
jl_datatype_t *jl_voidpointer_type;
jl_typename_t *jl_namedtuple_typename;
jl_unionall_t *jl_namedtuple_type;
jl_value_t *jl_an_empty_vec_any=NULL;
jl_value_t *jl_stackovf_exception;
#ifdef SEGV_EXCEPTION
Expand Down Expand Up @@ -1006,6 +1008,7 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
jl_typestack_t top;
jl_typename_t *tn = dt->name;
int istuple = (tn == jl_tuple_typename);
int isnamedtuple = (tn == jl_namedtuple_typename);
// check type cache
if (cacheable) {
JL_LOCK(&typecache_lock); // Might GC
Expand Down Expand Up @@ -1126,7 +1129,32 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
ndt->super = NULL;
ndt->parameters = p;
jl_gc_wb(ndt, ndt->parameters);
ndt->types = istuple ? p : NULL; // to be filled in below
ndt->types = NULL; // to be filled in below
if (istuple) {
ndt->types = p;
}
else if (isnamedtuple) {
jl_value_t *names_tup = jl_svecref(p, 0);
jl_value_t *values_tt = jl_svecref(p, 1);
if (!jl_has_free_typevars(names_tup) && !jl_has_free_typevars(values_tt)) {
if (!jl_is_tuple(names_tup))
jl_type_error_rt("NamedTuple", "names", jl_anytuple_type, names_tup);
size_t nf = jl_nfields(names_tup);
jl_svec_t *names = jl_alloc_svec_uninit(nf);
for(size_t i = 0; i < nf; i++) {
jl_value_t *ni = jl_fieldref(names_tup, i);
if (!jl_is_symbol(ni))
jl_type_error_rt("NamedTuple", "name", jl_symbol_type, ni);
jl_svecset(names, i, ni);
}
if (jl_is_va_tuple(values_tt) || jl_nparams(values_tt) != nf)
jl_error("NamedTuple names and field types must have matching lengths");
ndt->names = names;
jl_gc_wb(ndt, ndt->names);
ndt->types = ((jl_datatype_t*)values_tt)->parameters;
jl_gc_wb(ndt, ndt->types);
}
}
ndt->mutabl = dt->mutabl;
ndt->abstract = dt->abstract;
ndt->instance = NULL;
Expand All @@ -1140,15 +1168,15 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
if (cacheable && !ndt->abstract)
ndt->uid = jl_assign_type_uid();

if (istuple) {
if (istuple || isnamedtuple) {
ndt->super = jl_any_type;
}
else if (dt->super) {
ndt->super = (jl_datatype_t*)inst_type_w_((jl_value_t*)dt->super, env, stack, 1);
jl_gc_wb(ndt, ndt->super);
}
jl_svec_t *ftypes = dt->types;
if (!istuple && ndt->name->names == jl_emptysvec) {
if (!istuple && jl_field_names(ndt) == jl_emptysvec) {
assert(ftypes == NULL || ftypes == jl_emptysvec);
ndt->size = dt->size;
ndt->layout = dt->layout;
Expand All @@ -1161,13 +1189,13 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
if (ftypes == NULL || dt->super == NULL) {
// in the process of creating this type definition:
// need to instantiate the super and types fields later
assert(inside_typedef && !istuple);
assert(inside_typedef && !istuple && !isnamedtuple);
arraylist_push(&partial_inst, ndt);
}
else {
if (ftypes != jl_emptysvec) {
if (ftypes != jl_emptysvec || isnamedtuple) {
assert(!ndt->abstract);
if (!istuple) {
if (!istuple && !isnamedtuple) {
// recursively instantiate the types of the fields
ndt->types = inst_all(ftypes, env, stack, 1);
jl_gc_wb(ndt, ndt->types);
Expand All @@ -1186,6 +1214,8 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
}
if (istuple)
ndt->ninitialized = ntp;
else if (isnamedtuple)
ndt->ninitialized = jl_svec_len(ndt->types);
else
ndt->ninitialized = dt->ninitialized;

Expand Down Expand Up @@ -1565,11 +1595,12 @@ void jl_init_types(void)
jl_datatype_type->name->wrapper = (jl_value_t*)jl_datatype_type;
jl_datatype_type->super = (jl_datatype_t*)jl_type_type;
jl_datatype_type->parameters = jl_emptysvec;
jl_datatype_type->name->names = jl_perm_symsvec(16,
jl_datatype_type->name->names = jl_perm_symsvec(17,
"name",
"super",
"parameters",
"types",
"names",
"instance",
"layout",
"size",
Expand All @@ -1582,11 +1613,11 @@ void jl_init_types(void)
"depth",
"hasfreetypevars",
"isleaftype");
jl_datatype_type->types = jl_svec(16,
jl_datatype_type->types = jl_svec(17,
jl_typename_type,
jl_datatype_type,
jl_simplevector_type,
jl_simplevector_type,
jl_simplevector_type, jl_simplevector_type,
jl_any_type, // instance
jl_any_type, jl_any_type, jl_any_type, jl_any_type,
jl_any_type, jl_any_type, jl_any_type, jl_any_type,
Expand Down Expand Up @@ -2028,20 +2059,28 @@ void jl_init_types(void)
jl_perm_symsvec(1, "len"), jl_svec1(jl_long_type),
0, 1, 1);

jl_tvar_t *ntval_var = jl_new_typevar(jl_symbol("T"), (jl_value_t*)jl_bottom_type,
(jl_value_t*)jl_anytuple_type);
tv = jl_svec2(tvar("names"), ntval_var);
jl_datatype_t *ntt = jl_new_datatype(jl_symbol("NamedTuple"), jl_any_type, tv,
jl_emptysvec, jl_emptysvec, 0, 0, 0);
jl_namedtuple_type = (jl_unionall_t*)ntt->name->wrapper;
jl_namedtuple_typename = ntt->name;

// complete builtin type metadata
jl_value_t *pointer_void = jl_apply_type1((jl_value_t*)jl_pointer_type, (jl_value_t*)jl_void_type);
jl_voidpointer_type = (jl_datatype_t*)pointer_void;
jl_svecset(jl_datatype_type->types, 5, jl_voidpointer_type);
jl_svecset(jl_datatype_type->types, 6, jl_int32_type);
jl_svecset(jl_datatype_type->types, 6, jl_voidpointer_type);
jl_svecset(jl_datatype_type->types, 7, jl_int32_type);
jl_svecset(jl_datatype_type->types, 8, jl_int32_type);
jl_svecset(jl_datatype_type->types, 9, jl_bool_type);
jl_svecset(jl_datatype_type->types, 9, jl_int32_type);
jl_svecset(jl_datatype_type->types, 10, jl_bool_type);
jl_svecset(jl_datatype_type->types, 11, jl_voidpointer_type);
jl_svecset(jl_datatype_type->types, 11, jl_bool_type);
jl_svecset(jl_datatype_type->types, 12, jl_voidpointer_type);
jl_svecset(jl_datatype_type->types, 13, jl_int32_type);
jl_svecset(jl_datatype_type->types, 14, jl_bool_type);
jl_svecset(jl_datatype_type->types, 13, jl_voidpointer_type);
jl_svecset(jl_datatype_type->types, 14, jl_int32_type);
jl_svecset(jl_datatype_type->types, 15, jl_bool_type);
jl_svecset(jl_datatype_type->types, 16, jl_bool_type);
jl_svecset(jl_simplevector_type->types, 0, jl_long_type);
jl_svecset(jl_typename_type->types, 1, jl_module_type);
jl_svecset(jl_typename_type->types, 6, jl_long_type);
Expand Down
21 changes: 20 additions & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ typedef struct _jl_datatype_t {
struct _jl_datatype_t *super;
jl_svec_t *parameters;
jl_svec_t *types;
jl_svec_t *names;
jl_value_t *instance; // for singletons
const jl_datatype_layout_t *layout;
int32_t size; // TODO: move to _jl_datatype_layout_t
Expand Down Expand Up @@ -551,6 +552,8 @@ extern JL_DLLEXPORT jl_datatype_t *jl_voidpointer_type;
extern JL_DLLEXPORT jl_unionall_t *jl_pointer_type;
extern JL_DLLEXPORT jl_unionall_t *jl_ref_type;
extern JL_DLLEXPORT jl_typename_t *jl_pointer_typename;
extern JL_DLLEXPORT jl_typename_t *jl_namedtuple_typename;
extern JL_DLLEXPORT jl_unionall_t *jl_namedtuple_type;

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

// struct type info
#define jl_field_name(st,i) (jl_sym_t*)jl_svecref(((jl_datatype_t*)st)->name->names, (i))
STATIC_INLINE jl_svec_t *jl_field_names(jl_datatype_t *st)
{
jl_svec_t *names = st->names;
if (!names)
names = st->name->names;
return names;
}
STATIC_INLINE jl_sym_t *jl_field_name(jl_datatype_t *st, size_t i)
{
return (jl_sym_t*)jl_svecref(jl_field_names(st), i);
}
#define jl_field_type(st,i) jl_svecref(((jl_datatype_t*)st)->types, (i))
#define jl_field_count(st) jl_svec_len(((jl_datatype_t*)st)->types)
#define jl_datatype_size(t) (((jl_datatype_t*)t)->size)
Expand Down Expand Up @@ -953,6 +966,12 @@ STATIC_INLINE int jl_is_tuple_type(void *t)
((jl_datatype_t*)(t))->name == jl_tuple_typename);
}

STATIC_INLINE int jl_is_namedtuple_type(void *t)
{
return (jl_is_datatype(t) &&
((jl_datatype_t*)(t))->name == jl_namedtuple_typename);
}

STATIC_INLINE int jl_is_vecelement_type(jl_value_t* t)
{
return (jl_is_datatype(t) &&
Expand Down
2 changes: 1 addition & 1 deletion src/rtutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt
i = 1;
for (; i < tlen; i++) {
if (!istuple) {
n += jl_printf(out, "%s", jl_symbol_name((jl_sym_t*)jl_svecref(vt->name->names, i)));
n += jl_printf(out, "%s", jl_symbol_name((jl_sym_t*)jl_svecref(jl_field_names(vt), i)));
n += jl_printf(out, "=");
}
size_t offs = jl_field_offset(vt, i);
Expand Down

0 comments on commit 11a1021

Please sign in to comment.