diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 00dce1b6a3ddd..1c56916cbaec6 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -338,7 +338,7 @@ function nfields_tfunc(@nospecialize(x)) x = widenconst(x) if isa(x, DataType) && !x.abstract && !(x.name === Tuple.name && isvatuple(x)) if !(x.name === _NAMEDTUPLE_NAME && !isconcretetype(x)) - return Const(length(x.types)) + return Const(isdefined(x, :types) ? length(x.types) : length(x.name.names)) end end return Int @@ -588,7 +588,7 @@ function fieldcount_noerror(@nospecialize t) if abstr return nothing end - return length(t.types) + return isdefined(t, :types) ? length(t.types) : length(t.name.names) end @@ -744,7 +744,8 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name)) # TODO: better approximate inference return Any end - if isempty(s.types) + ftypes = datatype_fieldtypes(s) + if isempty(ftypes) return Bottom end if isa(name, Conditional) @@ -754,27 +755,27 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name)) if !(Int <: name || Symbol <: name) return Bottom end - if length(s.types) == 1 - return rewrap_unionall(unwrapva(s.types[1]), s00) + if length(ftypes) == 1 + return rewrap_unionall(unwrapva(ftypes[1]), s00) end # union together types of all fields t = Bottom - for _ft in s.types + for _ft in ftypes t = tmerge(t, rewrap_unionall(unwrapva(_ft), s00)) t === Any && break end return t end fld = name.val - if isa(fld,Symbol) + if isa(fld, Symbol) fld = fieldindex(s, fld, false) end - if !isa(fld,Int) + if !isa(fld, Int) return Bottom end - nf = length(s.types) - if s <: Tuple && fld >= nf && isvarargtype(s.types[nf]) - return rewrap_unionall(unwrapva(s.types[nf]), s00) + nf = length(ftypes) + if s <: Tuple && fld >= nf && isvarargtype(ftypes[nf]) + return rewrap_unionall(unwrapva(ftypes[nf]), s00) end if fld < 1 || fld > nf return Bottom @@ -790,7 +791,7 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name)) t = const_datatype_getfield_tfunc(sp, fld) t !== nothing && return t end - R = s.types[fld] + R = ftypes[fld] if isempty(s.parameters) return R end @@ -843,7 +844,7 @@ function _fieldtype_nothrow(@nospecialize(s), exact::Bool, name::Const) fld = fieldindex(u, fld, false) end isa(fld, Int) || return false - ftypes = u.types + ftypes = datatype_fieldtypes(u) nf = length(ftypes) (fld >= 1 && fld <= nf) || return false if u.name === Tuple.name && fld >= nf && isvarargtype(ftypes[nf]) @@ -893,7 +894,7 @@ function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name)) # TODO: better approximate inference return Type end - ftypes = u.types + ftypes = datatype_fieldtypes(u) if isempty(ftypes) return Bottom end diff --git a/base/reflection.jl b/base/reflection.jl index abf5268922933..acc24dba51dbc 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -313,6 +313,8 @@ objectid(@nospecialize(x)) = ccall(:jl_object_id, UInt, (Any,), x) # concrete datatype predicates +datatype_fieldtypes(x::DataType) = ccall(:jl_get_fieldtypes, Any, (Any,), x) + struct DataTypeLayout nfields::UInt32 alignment::UInt32 @@ -407,7 +409,8 @@ function isstructtype(@nospecialize(t::Type)) t = unwrap_unionall(t) # TODO: what to do for `Union`? isa(t, DataType) || return false - return length(t.types) != 0 || (t.size == 0 && !t.abstract) + hasfield = !isdefined(t, :types) || !isempty(t.types) + return hasfield || (t.size == 0 && !t.abstract) end """ @@ -421,7 +424,8 @@ function isprimitivetype(@nospecialize(t::Type)) t = unwrap_unionall(t) # TODO: what to do for `Union`? isa(t, DataType) || return false - return length(t.types) == 0 && t.size != 0 && !t.abstract + hasfield = !isdefined(t, :types) || !isempty(t.types) + return !hasfield && t.size != 0 && !t.abstract end """ @@ -674,7 +678,10 @@ function fieldcount(@nospecialize t) if abstr throw(ArgumentError("type does not have a definite number of fields")) end - return length(t.types) + if isdefined(t, :types) + return length(t.types) + end + return length(t.name.names) end """ diff --git a/base/show.jl b/base/show.jl index 29320479f7534..69ac6b2bb8d76 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1729,7 +1729,7 @@ function dump(io::IOContext, x::DataType, n::Int, indent) end end fields = fieldnames(x) - fieldtypes = x.types + fieldtypes = datatype_fieldtypes(x) for idx in 1:length(fields) println(io) print(io, indent, " ", fields[idx], "::") diff --git a/base/summarysize.jl b/base/summarysize.jl index c6cac492b88c4..3ae3ee135d531 100644 --- a/base/summarysize.jl +++ b/base/summarysize.jl @@ -89,7 +89,9 @@ function (ss::SummarySize)(obj::DataType) size::Int = 7 * Core.sizeof(Int) + 6 * Core.sizeof(Int32) size += 4 * nfields(obj) + ifelse(Sys.WORD_SIZE == 64, 4, 0) size += ss(obj.parameters)::Int - size += ss(obj.types)::Int + if isdefined(obj, :types) + size += ss(obj.types)::Int + end return size end diff --git a/src/array.c b/src/array.c index 2744eafeab958..1afceb7054a56 100644 --- a/src/array.c +++ b/src/array.c @@ -171,9 +171,10 @@ static inline int is_ntuple_long(jl_value_t *v) { if (!jl_is_tuple(v)) return 0; - size_t nfields = jl_nfields(v); - for (size_t i = 0; i < nfields; i++) { - if (jl_field_type(jl_typeof(v), i) != (jl_value_t*)jl_long_type) { + jl_value_t *tt = jl_typeof(v); + size_t i, nfields = jl_nparams(tt); + for (i = 0; i < nfields; i++) { + if (jl_tparam(tt, i) != (jl_value_t*)jl_long_type) { return 0; } } diff --git a/src/builtins.c b/src/builtins.c index ba8eee130288e..a14167567ee3d 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -752,7 +752,8 @@ static jl_value_t *get_fieldtype(jl_value_t *t, jl_value_t *f, int dothrow) return (jl_value_t*)jl_any_type; return get_fieldtype(tt, f, dothrow); } - int nf = jl_field_count(st); + jl_svec_t *types = jl_get_fieldtypes(st); + int nf = jl_svec_len(types); if (nf > 0 && field_index >= nf-1 && st->name == jl_tuple_typename) { jl_value_t *ft = jl_field_type(st, nf-1); if (jl_is_vararg_type(ft)) @@ -790,8 +791,8 @@ JL_CALLABLE(jl_f_fieldtype) JL_CALLABLE(jl_f_nfields) { JL_NARGS(nfields, 1, 1); - jl_value_t *x = args[0]; - return jl_box_long(jl_field_count(jl_typeof(x))); + jl_datatype_t *xt = (jl_datatype_t*)jl_typeof(args[0]); + return jl_box_long(jl_datatype_nfields(xt)); } JL_CALLABLE(jl_f_isdefined) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index ec1cb73da2ff8..9a2f452a30197 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -569,9 +569,10 @@ static bool julia_struct_has_layout(jl_datatype_t *dt, jl_unionall_t *ua) if (dt->layout || dt->struct_decl || jl_justbits((jl_value_t*)dt)) return true; if (ua) { - size_t i, ntypes = jl_svec_len(dt->types); + jl_svec_t *types = jl_get_fieldtypes(dt); + size_t i, ntypes = jl_svec_len(types); for (i = 0; i < ntypes; i++) { - jl_value_t *ty = jl_svecref(dt->types, i); + jl_value_t *ty = jl_svecref(types, i); if (jl_has_typevar_from_unionall(ty, ua)) return false; } @@ -603,7 +604,8 @@ static Type *julia_struct_to_llvm(jl_value_t *jt, jl_unionall_t *ua, bool *isbox if (jst->struct_decl != NULL) return (Type*)jst->struct_decl; if (jl_is_structtype(jt) && !(jst->layout && jl_is_layout_opaque(jst->layout))) { - size_t i, ntypes = jl_svec_len(jst->types); + jl_svec_t *ftypes = jl_get_fieldtypes(jst); + size_t i, ntypes = jl_svec_len(ftypes); if (ntypes == 0 || (jst->layout && jl_datatype_nbits(jst) == 0)) return T_void; if (!julia_struct_has_layout(jst, ua)) @@ -615,7 +617,7 @@ static Type *julia_struct_to_llvm(jl_value_t *jt, jl_unionall_t *ua, bool *isbox Type *lasttype = NULL; bool allghost = true; for (i = 0; i < ntypes; i++) { - jl_value_t *ty = jl_svecref(jst->types, i); + jl_value_t *ty = jl_svecref(ftypes, i); if (jlasttype != NULL && ty != jlasttype) isvector = false; jlasttype = ty; @@ -1496,7 +1498,7 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx, } else if (is_tupletype_homogeneous(stt->types)) { assert(nfields > 0); // nf == 0 trapped by all_pointers case - jl_value_t *jt = jl_field_type(stt, 0); + jl_value_t *jt = jl_svecref(stt->types, 0); idx = emit_bounds_check(ctx, strct, (jl_value_t*)stt, idx, ConstantInt::get(T_size, nfields), inbounds); Value *ptr = maybe_decay_tracked(data_pointer(ctx, strct)); if (!stt->mutabl && !(maybe_null && jt == (jl_value_t*)jl_bool_type)) { @@ -1526,7 +1528,7 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx, return true; } assert(!jl_field_isptr(stt, 0)); - jl_value_t *jt = jl_field_type(stt, 0); + jl_value_t *jt = jl_svecref(stt->types, 0); Value *idx0 = emit_bounds_check(ctx, strct, (jl_value_t*)stt, idx, ConstantInt::get(T_size, nfields), inbounds); if (strct.isghost) { *ret = ghostValue(jt); diff --git a/src/datatype.c b/src/datatype.c index dceba56f8ea92..dd2f60769a6de 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -202,7 +202,7 @@ unsigned jl_special_vector_alignment(size_t nfields, jl_value_t *t) if (mask) return 0; // nfields has more than two 1s assert(jl_datatype_nfields(t)==1); - jl_value_t *ty = jl_field_type(t, 0); + jl_value_t *ty = jl_field_type((jl_datatype_t*)t, 0); if (!jl_is_primitivetype(ty)) // LLVM requires that a vector element be a primitive type. // LLVM allows pointer types as vector elements, but until a @@ -301,9 +301,9 @@ void jl_compute_field_offsets(jl_datatype_t *st) // based on whether its definition is self-referential if (w->types != NULL) { st->isbitstype = st->isconcretetype && !st->mutabl; - size_t i, nf = jl_field_count(st); + size_t i, nf = jl_svec_len(st->types); for (i = 0; i < nf; i++) { - jl_value_t *fld = jl_field_type(st, i); + jl_value_t *fld = jl_svecref(st->types, i); if (st->isbitstype) st->isbitstype = jl_is_datatype(fld) && ((jl_datatype_t*)fld)->isbitstype; if (!st->zeroinit) @@ -311,9 +311,9 @@ void jl_compute_field_offsets(jl_datatype_t *st) } if (st->isbitstype) { st->isinlinealloc = 1; - size_t i, nf = jl_field_count(w); + size_t i, nf = jl_svec_len(w->types); for (i = 0; i < nf; i++) { - jl_value_t *fld = jl_field_type(w, i); + jl_value_t *fld = jl_svecref(w->types, i); if (references_name(fld, w->name)) { st->isinlinealloc = 0; st->isbitstype = 0; diff --git a/src/dump.c b/src/dump.c index 27c8524a2c0b4..3702f29c16613 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1458,7 +1458,7 @@ static jl_value_t *jl_deserialize_datatype(jl_serializer_state *s, int pos, jl_v dt->super = (jl_datatype_t*)jl_deserialize_value(s, (jl_value_t**)&dt->super); jl_gc_wb(dt, dt->super); dt->types = (jl_svec_t*)jl_deserialize_value(s, (jl_value_t**)&dt->types); - jl_gc_wb(dt, dt->types); + if (dt->types) jl_gc_wb(dt, dt->types); return (jl_value_t*)dt; } diff --git a/src/gf.c b/src/gf.c index a50f9a29d9643..1620b5c7a455e 100644 --- a/src/gf.c +++ b/src/gf.c @@ -421,13 +421,13 @@ static int very_general_type(jl_value_t *t) jl_value_t *jl_nth_slot_type(jl_value_t *sig, size_t i) { sig = jl_unwrap_unionall(sig); - size_t len = jl_field_count(sig); + size_t len = jl_nparams(sig); if (len == 0) return NULL; if (i < len-1) return jl_tparam(sig, i); - if (jl_is_vararg_type(jl_tparam(sig,len-1))) - return jl_unwrap_vararg(jl_tparam(sig,len-1)); + if (jl_is_vararg_type(jl_tparam(sig, len-1))) + return jl_unwrap_vararg(jl_tparam(sig, len-1)); if (i == len-1) return jl_tparam(sig, i); return NULL; @@ -473,7 +473,7 @@ static void jl_compilation_sig( jl_value_t *decl = definition->sig; assert(jl_is_tuple_type(tt)); size_t i, np = jl_nparams(tt); - size_t nargs = definition->nargs; // == jl_field_count(jl_unwrap_unionall(decl)); + size_t nargs = definition->nargs; // == jl_nparams(jl_unwrap_unionall(decl)); for (i = 0; i < np; i++) { jl_value_t *elt = jl_tparam(tt, i); jl_value_t *decl_i = jl_nth_slot_type(decl, i); @@ -678,7 +678,7 @@ JL_DLLEXPORT int jl_isa_compileable_sig( return 0; size_t i, np = jl_nparams(type); - size_t nargs = definition->nargs; // == jl_field_count(jl_unwrap_unionall(decl)); + size_t nargs = definition->nargs; // == jl_nparams(jl_unwrap_unionall(decl)); if (np == 0) return nargs == 0; @@ -2565,7 +2565,7 @@ int jl_has_concrete_subtype(jl_value_t *typ) return 1; if (((jl_datatype_t*)typ)->name == jl_namedtuple_typename) return jl_has_concrete_subtype(jl_tparam1(typ)); - jl_svec_t *fields = ((jl_datatype_t*)typ)->types; + jl_svec_t *fields = jl_get_fieldtypes((jl_datatype_t*)typ); size_t i, l = jl_svec_len(fields); if (l != ((jl_datatype_t*)typ)->ninitialized) if (((jl_datatype_t*)typ)->name != jl_tuple_typename) diff --git a/src/interpreter.c b/src/interpreter.c index f4b93fe3ffa39..478527a98ee3d 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -47,11 +47,11 @@ SECT_INTERP static int equiv_type(jl_datatype_t *dta, jl_datatype_t *dtb) dta->ninitialized == dtb->ninitialized && jl_egal((jl_value_t*)jl_field_names(dta), (jl_value_t*)jl_field_names(dtb)) && jl_nparams(dta) == jl_nparams(dtb) && - jl_field_count(dta) == jl_field_count(dtb))) + jl_svec_len(dta->types) == jl_svec_len(dtb->types))) return 0; jl_value_t *a=NULL, *b=NULL; int ok = 1; - size_t i, nf = jl_field_count(dta); + size_t i, nf = jl_svec_len(dta->types); JL_GC_PUSH2(&a, &b); a = jl_rewrap_unionall((jl_value_t*)dta->super, dta->name->wrapper); b = jl_rewrap_unionall((jl_value_t*)dtb->super, dtb->name->wrapper); @@ -63,7 +63,8 @@ SECT_INTERP static int equiv_type(jl_datatype_t *dta, jl_datatype_t *dtb) JL_CATCH { ok = 0; } - if (!ok) goto no; + if (!ok) + goto no; assert(jl_is_datatype(a)); a = dta->name->wrapper; b = dtb->name->wrapper; @@ -77,9 +78,11 @@ SECT_INTERP static int equiv_type(jl_datatype_t *dta, jl_datatype_t *dtb) b = ub->body; } assert(jl_is_datatype(a) && jl_is_datatype(b)); - for (i=0; i < nf; i++) { - jl_value_t *ta = jl_svecref(((jl_datatype_t*)a)->types, i); - jl_value_t *tb = jl_svecref(((jl_datatype_t*)b)->types, i); + a = (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)a); + b = (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)b); + for (i = 0; i < nf; i++) { + jl_value_t *ta = jl_svecref(a, i); + jl_value_t *tb = jl_svecref(b, i); if (jl_has_free_typevars(ta)) { if (!jl_has_free_typevars(tb) || !jl_egal(ta, tb)) goto no; diff --git a/src/jlapi.c b/src/jlapi.c index 4bdb86e319919..c28fb9cf5aa27 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -394,6 +394,12 @@ JL_DLLEXPORT jl_value_t *(jl_typeof)(jl_value_t *v) return jl_typeof(v); } +JL_DLLEXPORT jl_value_t *(jl_get_fieldtypes)(jl_value_t *v) +{ + return (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)v); +} + + #ifndef __clang_analyzer__ JL_DLLEXPORT int8_t (jl_gc_unsafe_enter)(void) { diff --git a/src/jltypes.c b/src/jltypes.c index 0d59bdc3e659e..2e6e193480626 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -921,7 +921,7 @@ JL_EXTENSION struct _jl_typestack_t { }; static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check); -static jl_svec_t *inst_all(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *stack, int check); +static jl_svec_t *inst_ftypes(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *stack); JL_DLLEXPORT jl_value_t *jl_instantiate_unionall(jl_unionall_t *u, jl_value_t *p) { @@ -1251,6 +1251,9 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value ndt->super = (jl_datatype_t*)inst_type_w_((jl_value_t*)dt->super, env, stack, 1); jl_gc_wb(ndt, ndt->super); } + if (cacheable) { + jl_cache_type_(ndt); + } jl_svec_t *ftypes = dt->types; if (ftypes == NULL || dt->super == NULL) { // in the process of creating this type definition: @@ -1258,12 +1261,15 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value assert(inside_typedef && !istuple && !isnamedtuple); arraylist_push(&partial_inst, ndt); } - else { - assert(ftypes != jl_emptysvec || jl_field_names(ndt) == jl_emptysvec || isnamedtuple); + else if (!isnamedtuple && !istuple) { + assert(ftypes != jl_emptysvec || jl_field_names(ndt) == jl_emptysvec); assert(ftypes == jl_emptysvec || !ndt->abstract); - if (!istuple && !isnamedtuple) { + if (ftypes == jl_emptysvec) { + ndt->types = ftypes; + } + else if (cacheable) { // recursively instantiate the types of the fields - ndt->types = inst_all(ftypes, env, stack, 1); + ndt->types = inst_ftypes(ftypes, env, stack); jl_gc_wb(ndt, ndt->types); } } @@ -1284,7 +1290,6 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value ndt->ninitialized = dt->ninitialized; if (cacheable) { - jl_cache_type_(ndt); JL_UNLOCK(&typecache_lock); // Might GC } @@ -1344,14 +1349,21 @@ jl_datatype_t *jl_inst_concrete_tupletype_v(jl_value_t **p, size_t np) return (jl_datatype_t*)inst_datatype(jl_anytuple_type, NULL, p, np, 1, NULL); } -static jl_svec_t *inst_all(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *stack, int check) +static jl_svec_t *inst_ftypes(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *stack) { size_t i; size_t lp = jl_svec_len(p); jl_svec_t *np = jl_alloc_svec(lp); JL_GC_PUSH1(&np); - for(i=0; i < lp; i++) { - jl_svecset(np, i, (jl_value_t*)inst_type_w_(jl_svecref(p,i), env, stack, check)); + for (i = 0; i < lp; i++) { + jl_value_t *pi = jl_svecref(p, i); + JL_TRY { + pi = inst_type_w_(pi, env, stack, 1); + } + JL_CATCH { + pi = jl_bottom_type; + } + jl_svecset(np, i, pi); } JL_GC_POP(); return np; @@ -1401,7 +1413,7 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_ int i; for (i = 0; i < ntp; i++) { jl_value_t *elt = jl_svecref(tp, i); - jl_value_t *pi = (jl_value_t*)inst_type_w_(elt, env, stack, 0); + jl_value_t *pi = inst_type_w_(elt, env, stack, 0); iparams[i] = pi; if (ip_heap) jl_gc_wb(ip_heap, pi); @@ -1492,7 +1504,7 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t int cacheable = 1, bound = 0; for(i=0; i < ntp; i++) { jl_value_t *elt = jl_svecref(tp, i); - iparams[i] = (jl_value_t*)inst_type_w_(elt, env, stack, check); + iparams[i] = inst_type_w_(elt, env, stack, check); bound |= (iparams[i] != elt); if (cacheable && jl_has_free_typevars(iparams[i])) cacheable = 0; @@ -1505,18 +1517,18 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t return result; } -jl_value_t *instantiate_with(jl_value_t *t, jl_value_t **env, size_t n, jl_typeenv_t *te, jl_typestack_t *stack) +static jl_value_t *instantiate_with(jl_value_t *t, jl_value_t **env, size_t n, jl_typeenv_t *te) { if (n > 0) { jl_typeenv_t en = { (jl_tvar_t*)env[0], env[1], te }; - return instantiate_with(t, &env[2], n-1, &en, stack); + return instantiate_with(t, &env[2], n-1, &en ); } - return inst_type_w_(t, te, stack, 1); + return inst_type_w_(t, te, NULL, 1); } jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n) { - return instantiate_with(t, env, n, NULL, NULL); + return instantiate_with(t, env, n, NULL); } static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals, jl_typeenv_t *prev) @@ -1562,6 +1574,30 @@ jl_value_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n) return vn; } +JL_DLLEXPORT jl_svec_t *jl_compute_fieldtypes(jl_datatype_t *st) +{ + assert(st->name != jl_namedtuple_typename && st->name != jl_tuple_typename); + jl_datatype_t *wt = (jl_datatype_t*)jl_unwrap_unionall(st->name->wrapper); + size_t i, n = jl_svec_len(wt->parameters); + assert(n > 0 && "expected empty case to be handled during construction"); + //if (n == 0) + // return ((st->types = jl_emptysvec)); + jl_typeenv_t *env = (jl_typeenv_t*)alloca(n * sizeof(jl_typeenv_t)); + for (i = 0; i < n; i++) { + env[i].var = (jl_tvar_t*)jl_svecref(wt->parameters, i); + env[i].val = jl_svecref(st->parameters, i); + env[i].prev = i == 0 ? NULL : &env[i - 1]; + } + jl_typestack_t top; + top.tt = st; + top.prev = NULL; + st->types = inst_ftypes(wt->types, &env[n - 1], &top); + jl_gc_wb(st, st->types); + JL_GC_POP(); + return st->types; +} + + void jl_reinstantiate_inner_types(jl_datatype_t *t) // can throw! { inside_typedef = 0; @@ -1575,19 +1611,20 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) // can throw! return; } - jl_value_t **env = (jl_value_t**)alloca(n * 2 * sizeof(void*)); + jl_typeenv_t *env = (jl_typeenv_t*)alloca(n * sizeof(jl_typeenv_t)); for (i = 0; i < n; i++) { - env[i * 2] = jl_svecref(t->parameters, i); - env[i * 2 + 1] = NULL; + env[i].var = (jl_tvar_t*)jl_svecref(t->parameters, i); + env[i].val = NULL; + env[i].prev = i == 0 ? NULL : &env[i - 1]; } for (j = 0; j < partial_inst.len; j++) { jl_datatype_t *ndt = (jl_datatype_t*)partial_inst.items[j]; assert(jl_unwrap_unionall(ndt->name->wrapper) == (jl_value_t*)t); for (i = 0; i < n; i++) - env[i * 2 + 1] = jl_svecref(ndt->parameters, i); + env[i].val = jl_svecref(ndt->parameters, i); - ndt->super = (jl_datatype_t*)instantiate_with((jl_value_t*)t->super, env, n, NULL, &top); + ndt->super = (jl_datatype_t*)inst_type_w_((jl_value_t*)t->super, env, &top, 1); jl_gc_wb(ndt, ndt->super); } @@ -1595,15 +1632,10 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) // can throw! for (j = 0; j < partial_inst.len; j++) { jl_datatype_t *ndt = (jl_datatype_t*)partial_inst.items[j]; for (i = 0; i < n; i++) - env[i * 2 + 1] = jl_svecref(ndt->parameters, i); - - int k; + env[i].val = jl_svecref(ndt->parameters, i); assert(ndt->types == NULL); - ndt->types = jl_alloc_svec(jl_svec_len(t->types)); + ndt->types = inst_ftypes(t->types, env, &top); jl_gc_wb(ndt, ndt->types); - for (k=0; k < jl_svec_len(t->types); k++) { - jl_svecset(ndt->types, k, instantiate_with(jl_svecref(t->types,k), env, n, NULL, &top)); - } if (ndt->uid) { // cacheable jl_compute_field_offsets(ndt); } @@ -1707,7 +1739,7 @@ void jl_init_types(void) JL_GC_DISABLED // NOTE: types should not really be mutable, but the instance and // struct_decl fields are basically caches, which are mutated. jl_datatype_type->mutabl = 1; - jl_datatype_type->ninitialized = 4; + jl_datatype_type->ninitialized = 3; jl_precompute_memoized_dt(jl_datatype_type); jl_typename_type->name = jl_new_typename_in(jl_symbol("TypeName"), core); diff --git a/src/julia.h b/src/julia.h index 0d4f3855c43e0..ba5348b77d2a9 100644 --- a/src/julia.h +++ b/src/julia.h @@ -896,6 +896,8 @@ STATIC_INLINE void jl_array_uint8_set(void *a, size_t i, uint8_t x) JL_NOTSAFEPO #define jl_gf_name(f) (jl_gf_mtable(f)->name) // struct type info +JL_DLLEXPORT jl_svec_t *jl_compute_fieldtypes(jl_datatype_t *st); +#define jl_get_fieldtypes(st) ((st)->types ? (st)->types : jl_compute_fieldtypes((st))) STATIC_INLINE jl_svec_t *jl_field_names(jl_datatype_t *st) JL_NOTSAFEPOINT { jl_svec_t *names = st->names; @@ -907,8 +909,10 @@ STATIC_INLINE jl_sym_t *jl_field_name(jl_datatype_t *st, size_t i) JL_NOTSAFEPOI { 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) +STATIC_INLINE jl_value_t *jl_field_type(jl_datatype_t *st, size_t i) +{ + return jl_svecref(jl_get_fieldtypes(st), i); +} #define jl_datatype_size(t) (((jl_datatype_t*)t)->size) #define jl_datatype_align(t) (((jl_datatype_t*)t)->layout->alignment) #define jl_datatype_nbits(t) ((((jl_datatype_t*)t)->size)*8) diff --git a/src/subtype.c b/src/subtype.c index 6cee9d9de2eb7..c257bcae89393 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -2791,7 +2791,7 @@ static int num_occurs(jl_tvar_t *v, jl_typeenv_t *env); static jl_value_t *nth_tuple_elt(jl_datatype_t *t JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT { - size_t len = jl_field_count(t); + size_t len = jl_nparams(t); if (len == 0) return NULL; if (i < len-1) diff --git a/src/typemap.c b/src/typemap.c index ef7aa50120204..593e401932ed0 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -30,7 +30,7 @@ static int sig_match_by_type_leaf(jl_value_t **types, jl_tupletype_t *sig, size_ { size_t i; for (i = 0; i < n; i++) { - jl_value_t *decl = jl_field_type(sig, i); + jl_value_t *decl = jl_tparam(sig, i); jl_value_t *a = types[i]; if (jl_is_type_type(a)) // decl is not Type, because it wouldn't be leafsig a = jl_typeof(jl_tparam0(a)); @@ -45,7 +45,7 @@ static int sig_match_by_type_simple(jl_value_t **types, size_t n, jl_tupletype_t size_t i; if (va) lensig -= 1; for (i = 0; i < lensig; i++) { - jl_value_t *decl = jl_field_type(sig, i); + jl_value_t *decl = jl_tparam(sig, i); jl_value_t *a = types[i]; jl_value_t *unw = jl_is_unionall(decl) ? ((jl_unionall_t*)decl)->body : decl; if (jl_is_type_type(unw)) { @@ -78,7 +78,7 @@ static int sig_match_by_type_simple(jl_value_t **types, size_t n, jl_tupletype_t } } if (va) { - jl_value_t *decl = jl_unwrap_unionall(jl_field_type(sig, i)); + jl_value_t *decl = jl_unwrap_unionall(jl_tparam(sig, i)); if (jl_vararg_kind(decl) == JL_VARARG_INT) { if (n - i != jl_unbox_long(jl_tparam1(decl))) return 0; @@ -258,7 +258,7 @@ jl_typemap_t *mtcache_hash_lookup(const struct jl_ordereddict_t *a JL_PROPAGATES t = ((jl_typemap_level_t*)ml)->key; } else { - t = jl_field_type(jl_unwrap_unionall(jl_typemap_entry_sig(ml)), offs); + t = jl_tparam(jl_unwrap_unionall(jl_typemap_entry_sig(ml)), offs); if (tparam) t = jl_tparam0(t); } @@ -281,7 +281,7 @@ static void mtcache_rehash(struct jl_ordereddict_t *pa, size_t newlen, jl_value_ t = ((jl_typemap_level_t*)ml)->key; } else { - t = jl_field_type(jl_unwrap_unionall(jl_typemap_entry_sig(ml)), offs); + t = jl_tparam(jl_unwrap_unionall(jl_typemap_entry_sig(ml)), offs); if (tparam) t = jl_tparam0(t); } @@ -359,7 +359,7 @@ static jl_typemap_t **mtcache_hash_bp(struct jl_ordereddict_t *pa JL_PROPAGATES_ t = ((jl_typemap_level_t*)*pml)->key; } else { - t = jl_field_type(jl_unwrap_unionall( + t = jl_tparam(jl_unwrap_unionall( jl_typemap_entry_sig(*pml)), offs); if (tparam) @@ -437,7 +437,7 @@ static int jl_typemap_intersection_array_visitor(struct jl_ordereddict_t *a, jl_ t = ((jl_typemap_level_t*)ml)->key; } else { - t = jl_field_type(jl_unwrap_unionall(jl_typemap_entry_sig(ml)), offs); + t = jl_tparam(jl_unwrap_unionall(jl_typemap_entry_sig(ml)), offs); if (tparam) t = jl_tparam0(t); } @@ -514,7 +514,7 @@ int jl_typemap_intersection_visitor(jl_typemap_t *map, int offs, if (jl_typeof(map) == (jl_value_t *)jl_typemap_level_type) { jl_typemap_level_t *cache = (jl_typemap_level_t*)map; jl_value_t *ty = NULL; - size_t l = jl_field_count(ttypes); + size_t l = jl_nparams(ttypes); if (closure->va && l <= offs + 1) { ty = closure->va; } @@ -590,16 +590,16 @@ static jl_typemap_entry_t *jl_typemap_assoc_by_type_(jl_typemap_entry_t *ml, jl_ { jl_value_t *unw = jl_unwrap_unionall((jl_value_t*)types); int isua = jl_is_unionall(types); - size_t n = jl_field_count(unw); + size_t n = jl_nparams(unw); int typesisva = n == 0 ? 0 : jl_is_vararg_type(jl_tparam(unw, n-1)); for (; ml != (void*)jl_nothing; ml = ml->next) { if (world < ml->min_world || world > (ml->max_world | max_world_mask)) continue; // ignore replaced methods - size_t lensig = jl_field_count(jl_unwrap_unionall((jl_value_t*)ml->sig)); + size_t lensig = jl_nparams(jl_unwrap_unionall((jl_value_t*)ml->sig)); if (lensig == n || (ml->va && lensig <= n+1)) { int resetenv = 0, ismatch = 1; if (ml->simplesig != (void*)jl_nothing && !isua) { - size_t lensimplesig = jl_field_count(ml->simplesig); + size_t lensimplesig = jl_nparams(ml->simplesig); int isva = lensimplesig > 0 && jl_is_vararg_type(jl_tparam(ml->simplesig, lensimplesig - 1)); if (lensig == n || (isva && lensimplesig <= n + 1)) ismatch = sig_match_by_type_simple(jl_svec_data(((jl_datatype_t*)types)->parameters), n, @@ -690,7 +690,7 @@ jl_typemap_entry_t *jl_typemap_assoc_by_type(jl_typemap_t *ml_or_cache, jl_value jl_value_t *ty = NULL; jl_value_t *ttypes = jl_unwrap_unionall((jl_value_t*)types); assert(jl_is_datatype(ttypes)); - size_t l = jl_field_count(ttypes); + size_t l = jl_nparams(ttypes); int isva = 0; // compute the type at offset `offs` into `types`, which may be a Vararg if (l <= offs + 1) { @@ -760,7 +760,7 @@ jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *ml, jl_valu while (ml->simplesig == (void*)jl_nothing && ml->guardsigs == jl_emptysvec && ml->isleafsig) { // use a tight loop for as long as possible if (world >= ml->min_world && world <= ml->max_world) { - if (n == jl_field_count(ml->sig) && jl_typeof(args[0]) == jl_tparam(ml->sig, 0)) { + if (n == jl_nparams(ml->sig) && jl_typeof(args[0]) == jl_tparam(ml->sig, 0)) { if (n == 1) return ml; if (n == 2) { @@ -786,10 +786,10 @@ jl_typemap_entry_t *jl_typemap_entry_assoc_exact(jl_typemap_entry_t *ml, jl_valu for (; ml != (void*)jl_nothing; ml = ml->next) { if (world < ml->min_world || world > ml->max_world) continue; // ignore replaced methods - size_t lensig = jl_field_count(ml->sig); + size_t lensig = jl_nparams(ml->sig); if (lensig == n || (ml->va && lensig <= n+1)) { if (ml->simplesig != (void*)jl_nothing) { - size_t lensimplesig = jl_field_count(ml->simplesig); + size_t lensimplesig = jl_nparams(ml->simplesig); int isva = lensimplesig > 0 && jl_is_vararg_type(jl_tparam(ml->simplesig, lensimplesig - 1)); if (lensig == n || (isva && lensimplesig <= n + 1)) { if (!sig_match_simple(args, n, jl_svec_data(ml->simplesig->parameters), isva, lensimplesig)) @@ -959,7 +959,7 @@ static void jl_typemap_level_insert_(jl_typemap_level_t *cache, jl_typemap_entry const struct jl_typemap_info *tparams) { jl_value_t *ttypes = jl_unwrap_unionall((jl_value_t*)newrec->sig); - size_t l = jl_field_count(ttypes); + size_t l = jl_nparams(ttypes); // compute the type at offset `offs` into `sig`, which may be a Vararg jl_value_t *t1 = NULL; int isva = 0; @@ -1047,8 +1047,8 @@ jl_typemap_entry_t *jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent, JL_GC_PUSH1(&newrec); assert(jl_is_tuple_type(ttype)); size_t i, l; - for (i = 0, l = jl_field_count(ttype); i < l && newrec->issimplesig; i++) { - jl_value_t *decl = jl_field_type(ttype, i); + for (i = 0, l = jl_nparams(ttype); i < l && newrec->issimplesig; i++) { + jl_value_t *decl = jl_tparam(ttype, i); if (jl_is_kind(decl)) newrec->isleafsig = 0; // Type{} may have a higher priority than a kind else if (jl_is_type_type(decl)) diff --git a/test/core.jl b/test/core.jl index 517bda1fe1812..0a126a8189317 100644 --- a/test/core.jl +++ b/test/core.jl @@ -219,13 +219,16 @@ struct D21923{T,N}; v::D21923{T}; end # issue #22624, more circular definitions struct T22624{A,B,C}; v::Vector{T22624{Int64,A}}; end -let elT = T22624.body.body.body.types[1].parameters[1] +let ft = Base.datatype_fieldtypes + elT = T22624.body.body.body.types[1].parameters[1] @test elT == T22624{Int64, T22624.var, C} where C - elT2 = elT.body.types[1].parameters[1] + elT2 = ft(elT.body)[1].parameters[1] @test elT2 == T22624{Int64, Int64, C} where C - @test elT2.body.types[1].parameters[1] === elT2 - @test Base.isconcretetype(elT2.body.types[1]) + @test ft(elT2.body)[1].parameters[1] === elT2 + @test Base.isconcretetype(ft(elT2.body)[1]) end +struct S22624{A,B,C} <: Ref{S22624{Int64,A}}; end +@test @isdefined S22624 # issue #3890 mutable struct A3890{T1} @@ -3459,15 +3462,22 @@ end mutable struct FooNTuple{N} z::Tuple{Integer, Vararg{Int, N}} end -@test_throws ErrorException FooNTuple{-1} -@test_throws ErrorException FooNTuple{typemin(Int)} -@test_throws TypeError FooNTuple{0x01} +for i in (-1, typemin(Int), 0x01) + T = FooNTuple{i} + @test T.parameters[1] == i + @test fieldtypes(T) == (Union{},) +end @test fieldtype(FooNTuple{0}, 1) == Tuple{Integer} mutable struct FooTupleT{T} z::Tuple{Int, T, Int} end -@test_throws TypeError FooTupleT{Vararg{Int, 2}} +let R = Vararg{Int, 2} + @test_throws TypeError Val{R} + @test_throws TypeError Ref{R} + @test_throws TypeError FooTupleT{R} + @test_throws TypeError Union{R} +end @test fieldtype(FooTupleT{Int}, 1) == NTuple{3, Int} @test Tuple{} === NTuple{0, Any} @@ -4619,7 +4629,9 @@ mutable struct B12238{T,S} end @test B12238.body.body.types[1] === A12238{B12238{Int}.body} @test isa(A12238{B12238{Int}}.instance, A12238{B12238{Int}}) -@test !isdefined(B12238.body.body.types[1], :instance) # has free type vars +let ft = Base.datatype_fieldtypes + @test !isdefined(ft(B12238.body.body)[1], :instance) # has free type vars +end # issue #16315 let a = Any[] @@ -4732,8 +4744,10 @@ end mutable struct C16767{T} b::A16767{C16767{:a}} end -@test B16767.body.types[1].types[1].parameters[1].types[1] === A16767{B16767.body} -@test C16767.body.types[1].types[1].parameters[1].types[1] === A16767{C16767{:a}} +let ft = Base.datatype_fieldtypes + @test ft(ft(B16767.body.types[1])[1].parameters[1])[1] === A16767{B16767.body} + @test ft(C16767.body.types[1].types[1].parameters[1])[1] === A16767{C16767{:a}} +end # issue #16340 function f16340(x::T) where T diff --git a/test/precompile.jl b/test/precompile.jl index b75ffed9e6667..836d73e9393ae 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -293,13 +293,14 @@ try some_method, Tuple{typeof(Base.include), String}, Core.svec(), typemax(UInt)) @test Foo.some_linfo::Core.MethodInstance === some_linfo - PV = Foo.Value18343{Some}.body.types[1] - VR = PV.types[1].parameters[1] - @test PV.types[1] === Array{VR,1} - @test pointer_from_objref(PV.types[1]) === - pointer_from_objref(PV.types[1].parameters[1].types[1].types[1]) - @test PV === PV.types[1].parameters[1].types[1] - @test pointer_from_objref(PV) === pointer_from_objref(PV.types[1].parameters[1].types[1]) + ft = Base.datatype_fieldtypes + PV = ft(Foo.Value18343{Some}.body)[1] + VR = ft(PV)[1].parameters[1] + @test ft(PV)[1] === Array{VR,1} + @test pointer_from_objref(ft(PV)[1]) === + pointer_from_objref(ft(ft(ft(PV)[1].parameters[1])[1])[1]) + @test PV === ft(ft(PV)[1].parameters[1])[1] + @test pointer_from_objref(PV) === pointer_from_objref(ft(ft(PV)[1].parameters[1])[1]) end Baz_file = joinpath(dir, "Baz.jl")