From 84e00cbf0eb701b53f8d53a0bb004daa554145c7 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 2 May 2019 17:10:00 -0400 Subject: [PATCH] gf: support more dispatch on abstract types This removes the restriction on defining dispatch over user-defined abstract types. The "cannot add methods to an abstract type" error is now only applicable to a couple types (`Any`, `Function`, and functions), and instead now gives a "not implemented yet" message. fixes #14919 for 99% of cases --- base/compiler/abstractinterpretation.jl | 2 +- base/compiler/ssair/inlining.jl | 32 +++++----- base/compiler/tfuncs.jl | 7 +-- base/reflection.jl | 8 +-- src/datatype.c | 39 ++++++------ src/dump.c | 70 +++++++++++++-------- src/gf.c | 40 ++++++------ src/interpreter.c | 9 +-- src/jltypes.c | 28 ++++++--- src/julia.h | 3 +- src/julia_internal.h | 7 ++- src/method.c | 75 +++++++++++++---------- src/rtutils.c | 47 +++++++++++++- src/staticdata.c | 45 +++++++++----- stdlib/Distributed/src/precompile.jl | 38 ++++++------ stdlib/Serialization/src/Serialization.jl | 8 +-- stdlib/Test/src/Test.jl | 20 +++++- test/core.jl | 17 +++++ 18 files changed, 311 insertions(+), 184 deletions(-) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 9895a0c59138f..fc09e02a86127 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -19,7 +19,7 @@ call_result_unused(frame::InferenceState, pc::LineNum=frame.currpc) = function abstract_call_gf_by_type(@nospecialize(f), argtypes::Vector{Any}, @nospecialize(atype), sv::InferenceState, max_methods = sv.params.MAX_METHODS) atype_params = unwrap_unionall(atype).parameters - ft = unwrap_unionall(atype_params[1]) # TODO: ccall jl_first_argument_datatype here + ft = unwrap_unionall(atype_params[1]) # TODO: ccall jl_method_table_for here isa(ft, DataType) || return Any # the function being called is unknown. can't properly handle this backedge right now ftname = ft.name isdefined(ftname, :mt) || return Any # not callable. should be Bottom, but can't track this backedge right now diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index b8924451245ef..9e5e3f2731816 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -1,9 +1,10 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license struct InvokeData - mt::Core.MethodTable entry::Core.TypeMapEntry types0 + min_valid::UInt + max_valid::UInt end struct Signature @@ -581,9 +582,9 @@ function spec_lambda(@nospecialize(atype), sv::OptimizationState, @nospecialize( else invoke_data = invoke_data::InvokeData atype <: invoke_data.types0 || return nothing - mi = ccall(:jl_get_invoke_lambda, Any, (Any, Any, Any, UInt), - invoke_data.mt, invoke_data.entry, atype, sv.params.world) - #XXX: compute min/max_valid + mi = ccall(:jl_get_invoke_lambda, Any, (Any, Any), invoke_data.entry, atype) + min_valid[1] = invoke_data.min_valid + max_valid[1] = invoke_data.max_valid end mi !== nothing && add_backedge!(mi::MethodInstance, sv) update_valid_age!(min_valid[1], max_valid[1], sv) @@ -924,6 +925,7 @@ function inline_invoke!(ir::IRCode, idx::Int, sig::Signature, invoke_data::Invok result = analyze_method!(idx, sig, metharg, methsp, method, stmt, sv, true, invoke_data, calltype) handle_single_case!(ir, stmt, idx, result, true, todo, sv) + update_valid_age!(invoke_data.min_valid, invoke_data.max_valid, sv) return nothing end @@ -1109,26 +1111,26 @@ end function compute_invoke_data(@nospecialize(atypes), params::Params) ft = widenconst(atypes[2]) - invoke_tt = widenconst(atypes[3]) - mt = argument_mt(ft) - if mt === nothing || !isType(invoke_tt) || has_free_typevars(invoke_tt) || - has_free_typevars(ft) || (ft <: Builtin) + if !isdispatchelem(ft) || has_free_typevars(ft) || (ft <: Builtin) # TODO: this can be rather aggressive at preventing inlining of closures - # XXX: this is wrong for `ft <: Type`, since we are failing to check that - # the result doesn't have subtypes, or to do an intersection lookup + # but we need to check that `ft` can't have a subtype at runtime before using the supertype lookup below return nothing end - if !(isa(invoke_tt.parameters[1], Type) && - invoke_tt.parameters[1] <: Tuple) + invoke_tt = widenconst(atypes[3]) + if !isType(invoke_tt) || has_free_typevars(invoke_tt) return nothing end invoke_tt = invoke_tt.parameters[1] + if !(isa(unwrap_unionall(invoke_tt), DataType) && invoke_tt <: Tuple) + return nothing + end invoke_types = rewrap_unionall(Tuple{ft, unwrap_unionall(invoke_tt).parameters...}, invoke_tt) + min_valid = UInt[typemin(UInt)] + max_valid = UInt[typemax(UInt)] invoke_entry = ccall(:jl_gf_invoke_lookup, Any, (Any, UInt), - invoke_types, params.world) + invoke_types, params.world) # XXX: min_valid, max_valid invoke_entry === nothing && return nothing - #XXX: update_valid_age!(min_valid[1], max_valid[1], sv) - invoke_data = InvokeData(mt, invoke_entry, invoke_types) + invoke_data = InvokeData(invoke_entry, invoke_types, min_valid[1], max_valid[1]) atype0 = atypes[2] atypes = atypes[4:end] pushfirst!(atypes, atype0) diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 00dce1b6a3ddd..b957a2e8ed6ff 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -1123,11 +1123,10 @@ end add_tfunc(apply_type, 1, INT_INF, apply_type_tfunc, 10) function invoke_tfunc(@nospecialize(ft), @nospecialize(types), @nospecialize(argtype), sv::InferenceState) - argument_mt(ft) === nothing && return Any argtype = typeintersect(types, argtype) - if argtype === Bottom - return Bottom - end + argtype === Bottom && return Bottom + argtype isa DataType || return Any # other cases are not implemented below + isdispatchelem(ft) || return Any # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below types = rewrap_unionall(Tuple{ft, unwrap_unionall(types).parameters...}, types) argtype = Tuple{ft, argtype.parameters...} entry = ccall(:jl_gf_invoke_lookup, Any, (Any, UInt), types, sv.params.world) diff --git a/base/reflection.jl b/base/reflection.jl index abf5268922933..91dd67ed02dbb 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -634,11 +634,6 @@ function fieldindex(T::DataType, name::Symbol, err::Bool=true) end argument_datatype(@nospecialize t) = ccall(:jl_argument_datatype, Any, (Any,), t) -function argument_mt(@nospecialize t) - dt = argument_datatype(t) - (dt === nothing || !isdefined(dt.name, :mt)) && return nothing - dt.name.mt -end """ fieldcount(t::Type) @@ -1288,8 +1283,7 @@ function delete_method(m::Method) end function get_methodtable(m::Method) - ft = ccall(:jl_first_argument_datatype, Any, (Any,), m.sig) - (ft::DataType).name.mt + return ccall(:jl_method_table_for, Any, (Any,), m.sig)::Core.MethodTable end """ diff --git a/src/datatype.c b/src/datatype.c index dceba56f8ea92..7cab893bb8ff6 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -48,6 +48,7 @@ JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *mo mt->backedges = NULL; JL_MUTEX_INIT(&mt->writelock); mt->offs = 1; + mt->frozen = 0; return mt; } @@ -452,11 +453,8 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype( jl_typename_t *tn = NULL; JL_GC_PUSH2(&t, &tn); - if (t == NULL) - t = jl_new_uninitialized_datatype(); - else - tn = t->name; - // init before possibly calling jl_new_typename_in + // init enough before possibly calling jl_new_typename_in + t = jl_new_uninitialized_datatype(); t->super = super; if (super != NULL) jl_gc_wb(t, t->super); t->parameters = parameters; @@ -471,23 +469,28 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype( t->ditype = NULL; t->size = 0; - if (tn == NULL) { - t->name = NULL; - if (jl_is_typename(name)) { - tn = (jl_typename_t*)name; + t->name = NULL; + if (jl_is_typename(name)) { + // This code-path is used by the Serialization module to by-pass normal expectations + tn = (jl_typename_t*)name; + } + else { + tn = jl_new_typename_in((jl_sym_t*)name, module); + if (super == jl_function_type || super == jl_builtin_type || jl_symbol_name(name)[0] == '#') { + // Callable objects (including compiler-generated closures) get independent method tables + // as an optimization + tn->mt = jl_new_method_table(name, module); + jl_gc_wb(tn, tn->mt); + if (jl_svec_len(parameters) > 0) + tn->mt->offs = 0; } else { - tn = jl_new_typename_in((jl_sym_t*)name, module); - if (!abstract) { - tn->mt = jl_new_method_table(name, module); - jl_gc_wb(tn, tn->mt); - if (jl_svec_len(parameters) > 0) - tn->mt->offs = 0; - } + // Everything else, gets to use the unified table + tn->mt = jl_nonfunction_mt; } - t->name = tn; - jl_gc_wb(t, t->name); } + t->name = tn; + jl_gc_wb(t, t->name); t->name->names = fnames; jl_gc_wb(t->name, t->name->names); diff --git a/src/dump.c b/src/dump.c index 27c8524a2c0b4..743529cbfb8ee 100644 --- a/src/dump.c +++ b/src/dump.c @@ -313,16 +313,33 @@ static void jl_serialize_datatype(jl_serializer_state *s, jl_datatype_t *dt) JL_ tag = 10; } - if (strncmp(jl_symbol_name(dt->name->name), "#kw#", 4) == 0) { - /* XXX: yuck, but the auto-generated kw types from the serializer isn't a real type, so we *must* be very careful */ - assert(tag == 0 || tag == 5 || tag == 6 || tag == 10); - if (tag == 6) { + if (strncmp(jl_symbol_name(dt->name->name), "#kw#", 4) == 0 && !internal && tag != 0) { + /* XXX: yuck, this is horrible, but the auto-generated kw types from the serializer isn't a real type, so we *must* be very careful */ + assert(tag == 6); // other struct types should never exist + tag = 9; + if (jl_type_type_mt->kwsorter != NULL && dt == (jl_datatype_t*)jl_typeof(jl_type_type_mt->kwsorter)) { + dt = jl_datatype_type; // any representative member with this MethodTable + } + else if (jl_nonfunction_mt->kwsorter != NULL && dt == (jl_datatype_t*)jl_typeof(jl_nonfunction_mt->kwsorter)) { + dt = jl_symbol_type; // any representative member with this MethodTable + } + else { + // search for the representative member of this MethodTable jl_methtable_t *mt = dt->name->mt; - jl_datatype_t *primarydt = (jl_datatype_t*)jl_unwrap_unionall(jl_get_global(mt->module, mt->name)); + size_t l = strlen(jl_symbol_name(mt->name)); + char *prefixed; + prefixed = (char*)malloc(l + 2); + prefixed[0] = '#'; + strcpy(&prefixed[1], jl_symbol_name(mt->name)); + jl_sym_t *tname = jl_symbol(prefixed); + free(prefixed); + jl_value_t *primarydt = jl_get_global(mt->module, tname); + if (!primarydt) + primarydt = jl_get_global(mt->module, mt->name); + primarydt = jl_unwrap_unionall(primarydt); assert(jl_is_datatype(primarydt)); - assert(jl_typeof(primarydt->name->mt->kwsorter) == (jl_value_t*)dt); - dt = primarydt; - tag = 9; + assert(primarydt == (jl_value_t*)jl_any_type || jl_typeof(((jl_datatype_t*)primarydt)->name->mt->kwsorter) == (jl_value_t*)dt); + dt = (jl_datatype_t*)primarydt; } } @@ -781,9 +798,9 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li write_uint8(s->s, internal); if (!internal) return; - jl_datatype_t *gf = jl_first_argument_datatype((jl_value_t*)m->sig); - assert(jl_is_datatype(gf) && gf->name->mt); - external_mt = !module_in_worklist(gf->name->mt->module); + jl_methtable_t *mt = jl_method_table_for((jl_value_t*)m->sig); + assert((jl_value_t*)mt != jl_nothing); + external_mt = !module_in_worklist(mt->module); jl_serialize_value(s, m->specializations); jl_serialize_value(s, (jl_value_t*)m->name); jl_serialize_value(s, (jl_value_t*)m->file); @@ -1111,9 +1128,9 @@ static int jl_collect_methcache_from_mod(jl_typemap_entry_t *ml, void *closure) return 1; } -static void jl_collect_methtable_from_mod(jl_array_t *s, jl_typename_t *tn) JL_GC_DISABLED +static void jl_collect_methtable_from_mod(jl_array_t *s, jl_methtable_t *mt) JL_GC_DISABLED { - jl_typemap_visitor(tn->mt->defs, jl_collect_methcache_from_mod, (void*)s); + jl_typemap_visitor(mt->defs, jl_collect_methcache_from_mod, (void*)s); } static void jl_collect_lambdas_from_mod(jl_array_t *s, jl_module_t *m) JL_GC_DISABLED @@ -1133,8 +1150,8 @@ static void jl_collect_lambdas_from_mod(jl_array_t *s, jl_module_t *m) JL_GC_DIS jl_methtable_t *mt = tn->mt; if (mt != NULL && (jl_value_t*)mt != jl_nothing && - (mt != jl_type_type_mt || tn == jl_type_typename)) { - jl_collect_methtable_from_mod(s, tn); + (mt != jl_type_type_mt && mt != jl_nonfunction_mt)) { + jl_collect_methtable_from_mod(s, mt); jl_collect_missing_backedges_to_mod(mt); } } @@ -2171,9 +2188,9 @@ static void jl_insert_methods(jl_array_t *list) jl_method_t *meth = (jl_method_t*)jl_array_ptr_ref(list, i); jl_tupletype_t *simpletype = (jl_tupletype_t*)jl_array_ptr_ref(list, i + 1); assert(jl_is_method(meth)); - jl_datatype_t *gf = jl_first_argument_datatype((jl_value_t*)meth->sig); - assert(jl_is_datatype(gf) && gf->name->mt); - jl_method_table_insert(gf->name->mt, meth, simpletype); + jl_methtable_t *mt = jl_method_table_for((jl_value_t*)meth->sig); + assert((jl_value_t*)mt != jl_nothing); + jl_method_table_insert(mt, meth, simpletype); } } @@ -2240,9 +2257,8 @@ static void jl_insert_backedges(jl_array_t *list, arraylist_t *dependent_worlds) jl_method_instance_add_backedge((jl_method_instance_t*)callee, caller); } else { - jl_datatype_t *ftype = jl_first_argument_datatype(callee); - jl_methtable_t *mt = ftype->name->mt; - assert(jl_is_datatype(ftype) && mt); + jl_methtable_t *mt = jl_method_table_for(callee); + assert((jl_value_t*)mt != jl_nothing); jl_method_table_add_backedge(mt, callee, (jl_value_t*)caller); } } @@ -2767,6 +2783,10 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) assert(jl_is_module(m)); jl_collect_lambdas_from_mod(lambdas, m); } + jl_collect_methtable_from_mod(lambdas, jl_type_type_mt); + jl_collect_missing_backedges_to_mod(jl_type_type_mt); + jl_collect_methtable_from_mod(lambdas, jl_nonfunction_mt); + jl_collect_missing_backedges_to_mod(jl_nonfunction_mt); jl_collect_backedges(edges); @@ -3041,8 +3061,8 @@ static jl_method_t *jl_lookup_method_worldset(jl_methtable_t *mt, jl_datatype_t static jl_method_t *jl_recache_method(jl_method_t *m, size_t start, arraylist_t *dependent_worlds) { jl_datatype_t *sig = (jl_datatype_t*)m->sig; - jl_datatype_t *ftype = jl_first_argument_datatype((jl_value_t*)sig); - jl_methtable_t *mt = ftype->name->mt; + jl_methtable_t *mt = jl_method_table_for((jl_value_t*)m->sig); + assert((jl_value_t*)mt != jl_nothing); jl_set_typeof(m, (void*)(intptr_t)0x30); // invalidate the old value to help catch errors jl_method_t *_new = jl_lookup_method_worldset(mt, sig, dependent_worlds); jl_update_backref_list((jl_value_t*)m, (jl_value_t*)_new, start); @@ -3053,8 +3073,8 @@ static jl_method_instance_t *jl_recache_method_instance(jl_method_instance_t *mi { jl_datatype_t *sig = (jl_datatype_t*)mi->def.value; assert(jl_is_datatype(sig) || jl_is_unionall(sig)); - jl_datatype_t *ftype = jl_first_argument_datatype((jl_value_t*)sig); - jl_methtable_t *mt = ftype->name->mt; + jl_methtable_t *mt = jl_method_table_for((jl_value_t*)sig); + assert((jl_value_t*)mt != jl_nothing); jl_method_t *m = jl_lookup_method_worldset(mt, sig, dependent_worlds); jl_datatype_t *argtypes = (jl_datatype_t*)mi->specTypes; jl_set_typeof(mi, (void*)(intptr_t)0x40); // invalidate the old value to help catch errors diff --git a/src/gf.c b/src/gf.c index a50f9a29d9643..0b6b3dc9f9cf1 100644 --- a/src/gf.c +++ b/src/gf.c @@ -163,6 +163,7 @@ void jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_args_t fptr jl_methtable_t *mt = dt->name->mt; jl_typemap_insert(&mt->cache, (jl_value_t*)mt, jl_anytuple_type, NULL, jl_emptysvec, (jl_value_t*)mi, 0, &lambda_cache, 1, ~(size_t)0, NULL); + mt->frozen = 1; JL_GC_POP(); } @@ -695,11 +696,11 @@ JL_DLLEXPORT int jl_isa_compileable_sig( if (definition->isva) { unsigned nspec_min = nargs + 1; // min number of non-vararg values before vararg unsigned nspec_max = INT32_MAX; // max number of non-vararg values before vararg - jl_datatype_t *gf = jl_first_argument_datatype(decl); - if (gf != NULL && jl_is_datatype(gf) && gf->name->mt != NULL) { + jl_methtable_t *mt = jl_method_table_for(decl); + if ((jl_value_t*)mt != jl_nothing) { // try to refine estimate of min and max - if (gf->name->mt != jl_type_type_mt) - nspec_min = gf->name->mt->max_args + 2; + if (mt != jl_type_type_mt && mt != jl_nonfunction_mt) + nspec_min = mt->max_args + 2; else nspec_max = nspec_min; } @@ -860,7 +861,7 @@ static jl_method_instance_t *cache_method( int cache_with_orig = 1; jl_tupletype_t *compilationsig = tt; - intptr_t nspec = (mt == NULL || mt == jl_type_type_mt ? definition->nargs + 1 : mt->max_args + 2); + intptr_t nspec = (mt == NULL || mt == jl_type_type_mt || mt == jl_nonfunction_mt ? definition->nargs + 1 : mt->max_args + 2); jl_compilation_sig(tt, sparams, definition, nspec, &newparams); if (newparams) { cache_with_orig = 0; @@ -1264,7 +1265,7 @@ static void method_overwrite(jl_typemap_entry_t *newentry, jl_method_t *oldvalue static void update_max_args(jl_methtable_t *mt, jl_value_t *type) { - if (mt == jl_type_type_mt) + if (mt == jl_type_type_mt || mt == jl_nonfunction_mt) return; type = jl_unwrap_unionall(type); assert(jl_is_datatype(type)); @@ -1690,12 +1691,9 @@ JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, int lim, int jl_value_t *unw = jl_unwrap_unionall((jl_value_t*)types); if (jl_is_tuple_type(unw) && jl_tparam0(unw) == jl_bottom_type) return (jl_value_t*)jl_alloc_vec_any(0); - jl_datatype_t *dt = jl_first_argument_datatype(unw); - if (dt == NULL || !jl_is_datatype(dt)) + jl_methtable_t *mt = jl_method_table_for(unw); + if ((jl_value_t*)mt == jl_nothing) return jl_false; // indeterminate - ml_matches can't deal with this case - jl_methtable_t *mt = dt->name->mt; - if (mt == NULL) - return (jl_value_t*)jl_alloc_vec_any(0); return ml_matches(mt->defs, 0, types, lim, include_ambiguous, world, min_valid, max_valid); } @@ -1852,22 +1850,20 @@ jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types JL_PROPAGATES jl_tupletype_t *ti = (jl_tupletype_t*)jl_svecref(match, 0); jl_method_instance_t *nf = NULL; if (jl_is_datatype(ti)) { - jl_datatype_t *dt = jl_first_argument_datatype((jl_value_t*)ti); - if (dt && jl_is_datatype(dt)) { + jl_methtable_t *mt = jl_method_table_for((jl_value_t*)ti); + if ((jl_value_t*)mt != jl_nothing) { // get the specialization without caching it - jl_methtable_t *mt = dt->name->mt; if (mt_cache && ((jl_datatype_t*)ti)->isdispatchtuple) { // Since we also use this presence in the cache // to trigger compilation when producing `.ji` files, // inject it there now if we think it will be // used via dispatch later (e.g. because it was hinted via a call to `precompile`) - jl_methtable_t *mt = dt->name->mt; JL_LOCK(&mt->writelock); nf = cache_method(mt, &mt->cache, (jl_value_t*)mt, ti, m, world, env); JL_UNLOCK(&mt->writelock); } else { - intptr_t nspec = (mt == jl_type_type_mt ? m->nargs + 1 : mt->max_args + 2); + intptr_t nspec = (mt == jl_type_type_mt || mt == jl_nonfunction_mt ? m->nargs + 1 : mt->max_args + 2); jl_compilation_sig(ti, env, m, nspec, &newparams); tt = (newparams ? jl_apply_tuple_type(newparams) : ti); int is_compileable = ((jl_datatype_t*)ti)->isdispatchtuple || @@ -2200,7 +2196,9 @@ JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t **args, uint32_t nargs) JL_DLLEXPORT jl_value_t *jl_gf_invoke_lookup(jl_value_t *types JL_PROPAGATES_ROOT, size_t world) { - jl_methtable_t *mt = jl_first_argument_datatype(types)->name->mt; + jl_methtable_t *mt = jl_method_table_for(types); + if ((jl_value_t*)mt == jl_nothing) + return jl_nothing; jl_svec_t *env = jl_emptysvec; JL_GC_PUSH1(&env); jl_typemap_entry_t *entry = jl_typemap_assoc_by_type( @@ -2361,15 +2359,13 @@ jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_ JL_DLLEXPORT jl_function_t *jl_get_kwsorter(jl_value_t *ty) { - jl_datatype_t *dt = (jl_datatype_t*)jl_argument_datatype(ty); - if ((jl_value_t*)dt == jl_nothing) + jl_methtable_t *mt = jl_argument_method_table(ty); + if ((jl_value_t*)mt == jl_nothing) jl_error("cannot get keyword sorter for abstract type"); - jl_typename_t *tn = dt->name; - jl_methtable_t *mt = tn->mt; if (!mt->kwsorter) { JL_LOCK(&mt->writelock); if (!mt->kwsorter) { - mt->kwsorter = jl_new_generic_function_with_supertype(tn->name, mt->module, jl_function_type, 1); + mt->kwsorter = jl_new_generic_function_with_supertype(mt->name, mt->module, jl_function_type, 1); jl_gc_wb(mt, mt->kwsorter); } JL_UNLOCK(&mt->writelock); diff --git a/src/interpreter.c b/src/interpreter.c index f4b93fe3ffa39..7838a5f25b067 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -110,10 +110,11 @@ SECT_INTERP 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_namedtuple_type(super) || - jl_subtype(super,(jl_value_t*)jl_type_type) || - super == (jl_value_t*)jl_builtin_type) { + jl_subtype(super, (jl_value_t*)jl_vararg_type) || + jl_is_tuple_type(super) || + jl_is_namedtuple_type(super) || + jl_subtype(super, (jl_value_t*)jl_type_type) || + jl_subtype(super, (jl_value_t*)jl_builtin_type)) { jl_errorf("invalid subtyping in definition of %s", jl_symbol_name(tt->name->name)); } diff --git a/src/jltypes.c b/src/jltypes.c index 0d59bdc3e659e..ae23f65c07eef 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -23,6 +23,7 @@ jl_datatype_t *jl_any_type; jl_unionall_t *jl_type_type; jl_typename_t *jl_type_typename; jl_methtable_t *jl_type_type_mt; +jl_methtable_t *jl_nonfunction_mt; jl_datatype_t *jl_typename_type; jl_datatype_t *jl_sym_type; jl_datatype_t *jl_symbol_type; @@ -1658,6 +1659,10 @@ void jl_init_types(void) JL_GC_DISABLED jl_any_type = (jl_datatype_t*)jl_new_abstracttype((jl_value_t*)jl_symbol("Any"), core, NULL, jl_emptysvec); jl_any_type->super = jl_any_type; + jl_nonfunction_mt = jl_any_type->name->mt; + jl_any_type->name->mt = NULL; + jl_nonfunction_mt->offs = 0; + jl_type_type = (jl_unionall_t*)jl_new_abstracttype((jl_value_t*)jl_symbol("Type"), core, jl_any_type, jl_emptysvec); jl_type_typename = ((jl_datatype_t*)jl_type_type)->name; jl_type_type_mt = jl_new_method_table(jl_type_typename->name, core); @@ -1712,7 +1717,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_typename_type->name = jl_new_typename_in(jl_symbol("TypeName"), core); jl_typename_type->name->wrapper = (jl_value_t*)jl_typename_type; - jl_typename_type->name->mt = jl_new_method_table(jl_typename_type->name->name, core); + jl_typename_type->name->mt = jl_nonfunction_mt; jl_typename_type->super = jl_any_type; jl_typename_type->parameters = jl_emptysvec; jl_typename_type->name->names = jl_perm_symsvec(8, "name", "module", @@ -1733,17 +1738,17 @@ void jl_init_types(void) JL_GC_DISABLED jl_methtable_type->name = jl_new_typename_in(jl_symbol("MethodTable"), core); jl_methtable_type->name->wrapper = (jl_value_t*)jl_methtable_type; - jl_methtable_type->name->mt = jl_new_method_table(jl_methtable_type->name->name, core); + jl_methtable_type->name->mt = jl_nonfunction_mt; jl_methtable_type->super = jl_any_type; jl_methtable_type->parameters = jl_emptysvec; - jl_methtable_type->name->names = jl_perm_symsvec(10, "name", "defs", + jl_methtable_type->name->names = jl_perm_symsvec(11, "name", "defs", "cache", "max_args", "kwsorter", "module", - "backedges", "", "", "offs"); - jl_methtable_type->types = jl_svec(10, jl_sym_type, jl_any_type, jl_any_type, jl_any_type/*jl_long*/, + "backedges", "", "", "offs", ""); + jl_methtable_type->types = jl_svec(11, jl_sym_type, jl_any_type, jl_any_type, jl_any_type/*jl_long*/, jl_any_type, jl_any_type/*module*/, jl_any_type/*any vector*/, jl_any_type/*long*/, jl_any_type/*int32*/, - jl_any_type/*uint8*/); + jl_any_type/*uint8*/, jl_any_type/*uint8*/); jl_methtable_type->uid = jl_assign_type_uid(); jl_methtable_type->instance = NULL; jl_methtable_type->struct_decl = NULL; @@ -1755,7 +1760,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_sym_type->name = jl_new_typename_in(jl_symbol("Symbol"), core); jl_sym_type->name->wrapper = (jl_value_t*)jl_sym_type; - jl_sym_type->name->mt = jl_new_method_table(jl_sym_type->name->name, core); + jl_sym_type->name->mt = jl_nonfunction_mt; jl_sym_type->super = jl_any_type; jl_sym_type->parameters = jl_emptysvec; jl_sym_type->name->names = jl_emptysvec; @@ -1772,7 +1777,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_simplevector_type->name = jl_new_typename_in(jl_symbol("SimpleVector"), core); jl_simplevector_type->name->wrapper = (jl_value_t*)jl_simplevector_type; - jl_simplevector_type->name->mt = jl_new_method_table(jl_simplevector_type->name->name, core); + jl_simplevector_type->name->mt = jl_nonfunction_mt; jl_simplevector_type->super = jl_any_type; jl_simplevector_type->parameters = jl_emptysvec; jl_simplevector_type->name->names = jl_emptysvec; @@ -1936,6 +1941,8 @@ void jl_init_types(void) JL_GC_DISABLED jl_function_type = jl_new_abstracttype((jl_value_t*)jl_symbol("Function"), core, jl_any_type, jl_emptysvec); jl_builtin_type = jl_new_abstracttype((jl_value_t*)jl_symbol("Builtin"), core, jl_function_type, jl_emptysvec); + jl_function_type->name->mt = NULL; // subtypes of Function have independent method tables + jl_builtin_type->name->mt = NULL; // so they don't share the Any type table tv = jl_svec2(tvar("T"), tvar("N")); jl_abstractarray_type = (jl_unionall_t*) @@ -2164,9 +2171,9 @@ void jl_init_types(void) JL_GC_DISABLED 0, 1, 1); jl_svecset(jl_code_instance_type->types, 1, jl_code_instance_type); - // all kinds of types share a method table + // all Kinds share the Type method table (not the nonfunction one) jl_unionall_type->name->mt = jl_uniontype_type->name->mt = jl_datatype_type->name->mt = - jl_type_typename->mt; + jl_type_type_mt; jl_intrinsic_type = jl_new_primitivetype((jl_value_t*)jl_symbol("IntrinsicFunction"), core, jl_builtin_type, jl_emptysvec, 32); @@ -2235,6 +2242,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_svecset(jl_methtable_type->types, 8, jl_int32_type); // uint32_t #endif jl_svecset(jl_methtable_type->types, 9, jl_uint8_type); + jl_svecset(jl_methtable_type->types, 10, jl_uint8_type); jl_svecset(jl_method_type->types, 11, jl_method_instance_type); jl_svecset(jl_method_instance_type->types, 5, jl_code_instance_type); jl_svecset(jl_code_instance_type->types, 7, jl_voidpointer_type); diff --git a/src/julia.h b/src/julia.h index 25b947d81cfec..89de167988222 100644 --- a/src/julia.h +++ b/src/julia.h @@ -521,7 +521,7 @@ typedef struct _jl_typemap_level_t { // contains the TypeMap for one Type typedef struct _jl_methtable_t { JL_DATA_TYPE - jl_sym_t *name; + jl_sym_t *name; // sometimes a hack used by serialization to handle kwsorter jl_typemap_t *defs; jl_typemap_t *cache; intptr_t max_args; // max # of non-vararg arguments in a signature @@ -530,6 +530,7 @@ typedef struct _jl_methtable_t { jl_array_t *backedges; jl_mutex_t writelock; uint8_t offs; // 0, or 1 to skip splitting typemap on first (function) argument + uint8_t frozen; // whether this accepts adding new methods } jl_methtable_t; typedef struct { diff --git a/src/julia_internal.h b/src/julia_internal.h index 7c690254316d7..4a58404206979 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -149,6 +149,7 @@ STATIC_INLINE uint32_t jl_int32hash_fast(uint32_t a) // useful constants extern jl_methtable_t *jl_type_type_mt JL_GLOBALLY_ROOTED; +extern jl_methtable_t *jl_nonfunction_mt JL_GLOBALLY_ROOTED; JL_DLLEXPORT extern size_t jl_world_counter; typedef void (*tracer_cb)(jl_value_t *tracee); @@ -468,9 +469,11 @@ jl_method_instance_t *jl_lookup_generic(jl_value_t **args, uint32_t nargs, uint3 JL_DLLEXPORT jl_value_t *jl_matching_methods(jl_tupletype_t *types, int lim, int include_ambiguous, size_t world, size_t *min_valid, size_t *max_valid); -JL_DLLEXPORT jl_datatype_t *jl_first_argument_datatype( +JL_DLLEXPORT jl_datatype_t *jl_first_argument_datatype(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_value_t *jl_argument_datatype(jl_value_t *argt JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_methtable_t *jl_method_table_for( jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_argument_datatype(jl_value_t *argt JL_PROPAGATES_ROOT); +jl_methtable_t *jl_argument_method_table(jl_value_t *argt JL_PROPAGATES_ROOT); jl_value_t *jl_nth_slot_type(jl_value_t *sig JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT; void jl_compute_field_offsets(jl_datatype_t *st); diff --git a/src/method.c b/src/method.c index eb46db959621f..42021a9a73a7e 100644 --- a/src/method.c +++ b/src/method.c @@ -621,49 +621,47 @@ JL_DLLEXPORT jl_value_t *jl_generic_function_def(jl_sym_t *name, return gf; } -static jl_datatype_t *first_arg_datatype(jl_value_t *a JL_PROPAGATES_ROOT, int got_tuple1) JL_NOTSAFEPOINT +static jl_methtable_t *first_methtable(jl_value_t *a JL_PROPAGATES_ROOT, int got_tuple1) JL_NOTSAFEPOINT { if (jl_is_datatype(a)) { - if (got_tuple1) - return (jl_datatype_t*)a; + if (got_tuple1) { + jl_methtable_t *mt = ((jl_datatype_t*)a)->name->mt; + if (mt != NULL) + return mt; + } if (jl_is_tuple_type(a)) { - if (jl_nparams(a) < 1) - return NULL; - return first_arg_datatype(jl_tparam0(a), 1); + if (jl_nparams(a) >= 1) + return first_methtable(jl_tparam0(a), 1); } - return NULL; } else if (jl_is_typevar(a)) { - return first_arg_datatype(((jl_tvar_t*)a)->ub, got_tuple1); + return first_methtable(((jl_tvar_t*)a)->ub, got_tuple1); } else if (jl_is_unionall(a)) { - return first_arg_datatype(((jl_unionall_t*)a)->body, got_tuple1); + return first_methtable(((jl_unionall_t*)a)->body, got_tuple1); } else if (jl_is_uniontype(a)) { jl_uniontype_t *u = (jl_uniontype_t*)a; - jl_datatype_t *d1 = first_arg_datatype(u->a, got_tuple1); - if (d1 == NULL) return NULL; - jl_datatype_t *d2 = first_arg_datatype(u->b, got_tuple1); - if (d2 == NULL || d1->name != d2->name) - return NULL; - return d1; + jl_methtable_t *m1 = first_methtable(u->a, got_tuple1); + if ((jl_value_t*)m1 != jl_nothing) { + jl_methtable_t *m2 = first_methtable(u->b, got_tuple1); + if (m1 == m2) + return m1; + } } - return NULL; + return (jl_methtable_t*)jl_nothing; } -// get DataType of first tuple element, or NULL if cannot be determined -JL_DLLEXPORT jl_datatype_t *jl_first_argument_datatype(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT +// get the MethodTable for dispatch, or `nothing` if cannot be determined +JL_DLLEXPORT jl_methtable_t *jl_method_table_for(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT { - return first_arg_datatype(argtypes, 0); + return first_methtable(argtypes, 0); } -// get DataType implied by a single given type, or `nothing` -JL_DLLEXPORT jl_value_t *jl_argument_datatype(jl_value_t *argt JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT +// get the MethodTable implied by a single given type, or `nothing` +JL_DLLEXPORT jl_methtable_t *jl_argument_method_table(jl_value_t *argt JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT { - jl_datatype_t *dt = first_arg_datatype(argt, 1); - if (dt == NULL) - return jl_nothing; - return (jl_value_t*)dt; + return first_methtable(argt, 1); } extern tracer_cb jl_newmeth_tracer; @@ -683,7 +681,6 @@ JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata, assert(jl_is_svec(tvars)); if (!jl_is_type(jl_svecref(atypes, 0)) || (isva && nargs == 1)) jl_error("function type in method definition is not a type"); - jl_methtable_t *mt; jl_sym_t *name; jl_method_t *m = NULL; jl_value_t *argtype = NULL; @@ -698,16 +695,28 @@ JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata, argtype = jl_new_struct(jl_unionall_type, tv, argtype); } - jl_datatype_t *ftype = jl_first_argument_datatype(argtype); - if (ftype == NULL || - ((!jl_is_type_type((jl_value_t*)ftype)) && - (!jl_is_datatype(ftype) || ftype->abstract || ftype->name->mt == NULL))) - jl_error("cannot add methods to an abstract type"); - if (jl_subtype((jl_value_t*)ftype, (jl_value_t*)jl_builtin_type)) + jl_methtable_t *mt = jl_method_table_for(argtype); + if ((jl_value_t*)mt == jl_nothing) + jl_error("Method dispatch is unimplemented currently for this method signature"); + if (mt->frozen) jl_error("cannot add methods to a builtin function"); - mt = ftype->name->mt; + // TODO: derive our debug name from the syntax instead of the type name = mt->name; + if (mt == jl_type_type_mt || mt == jl_nonfunction_mt) { + // our value for `name` is bad, try to guess what the syntax might have had, + // like `jl_static_show_func_sig` might have come up with + jl_datatype_t *dt = jl_first_argument_datatype(argtype); + if (dt != NULL) { + name = dt->name->name; + if (jl_is_type_type((jl_value_t*)dt)) { + dt = (jl_datatype_t*)jl_argument_datatype(jl_tparam0(dt)); + if ((jl_value_t*)dt != jl_nothing) { + name = dt->name->name; + } + } + } + } if (!jl_is_code_info(f)) { // this occurs when there is a closure being added to an out-of-scope function // the user should only do this at the toplevel diff --git a/src/rtutils.c b/src/rtutils.c index 2275dbb7bf71b..20e3948b89b8d 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -575,6 +575,51 @@ JL_DLLEXPORT int jl_is_identifier(char *str) JL_NOTSAFEPOINT return 1; } +static jl_datatype_t *first_arg_datatype(jl_value_t *a JL_PROPAGATES_ROOT, int got_tuple1) JL_NOTSAFEPOINT +{ + if (jl_is_datatype(a)) { + if (got_tuple1) + return (jl_datatype_t*)a; + if (jl_is_tuple_type(a)) { + if (jl_nparams(a) < 1) + return NULL; + return first_arg_datatype(jl_tparam0(a), 1); + } + return NULL; + } + else if (jl_is_typevar(a)) { + return first_arg_datatype(((jl_tvar_t*)a)->ub, got_tuple1); + } + else if (jl_is_unionall(a)) { + return first_arg_datatype(((jl_unionall_t*)a)->body, got_tuple1); + } + else if (jl_is_uniontype(a)) { + jl_uniontype_t *u = (jl_uniontype_t*)a; + jl_datatype_t *d1 = first_arg_datatype(u->a, got_tuple1); + if (d1 == NULL) return NULL; + jl_datatype_t *d2 = first_arg_datatype(u->b, got_tuple1); + if (d2 == NULL || d1->name != d2->name) + return NULL; + return d1; + } + return NULL; +} + +// get DataType of first tuple element (if present), or NULL if cannot be determined +JL_DLLEXPORT jl_datatype_t *jl_first_argument_datatype(jl_value_t *argtypes JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT +{ + return first_arg_datatype(argtypes, 0); +} + +// get DataType implied by a single given type, or `nothing` +JL_DLLEXPORT jl_value_t *jl_argument_datatype(jl_value_t *argt JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT +{ + jl_datatype_t *dt = first_arg_datatype(argt, 1); + if (dt == NULL) + return jl_nothing; + return (jl_value_t*)dt; +} + // `v` might be pointing to a field inlined in a structure therefore // `jl_typeof(v)` may not be the same with `vt` and only `vt` should be // used to determine the type of the value. @@ -650,7 +695,7 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt !strchr(jl_symbol_name(globname), '@') && dv->name->module && jl_binding_resolved_p(dv->name->module, globname)) { jl_binding_t *b = jl_get_module_binding(dv->name->module, globname); - if (b && jl_typeof(b->value) == v) + if (b && b->value && jl_typeof(b->value) == v) globfunc = 1; } jl_sym_t *sym = globfunc ? globname : dv->name->name; diff --git a/src/staticdata.c b/src/staticdata.c index e41d377cdc231..3a8bb882306df 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -94,7 +94,7 @@ static jl_value_t *jl_idtable_type = NULL; static jl_typename_t *jl_idtable_typename = NULL; static jl_value_t *jl_bigint_type = NULL; static int gmp_limb_size = 0; -static arraylist_t builtin_typenames; +static arraylist_t builtin_typenames; // builtin types with parameters enum RefTags { DataRef, @@ -1278,11 +1278,15 @@ static void jl_save_system_image_to_stream(ios_t *f) jl_serialize_value(&s, jl_module_init_order); // serialize method tables of builtin types - jl_serialize_value(&s, jl_type_typename->mt); + jl_serialize_value(&s, jl_type_type_mt->defs); + jl_serialize_value(&s, jl_type_type_mt->cache); + jl_serialize_value(&s, jl_type_type_mt->kwsorter); + jl_serialize_value(&s, jl_type_type_mt->backedges); + jl_serialize_value(&s, jl_nonfunction_mt->defs); + jl_serialize_value(&s, jl_nonfunction_mt->cache); + jl_serialize_value(&s, jl_nonfunction_mt->kwsorter); + jl_serialize_value(&s, jl_nonfunction_mt->backedges); jl_serialize_value(&s, jl_intrinsic_type->name->mt); - jl_serialize_value(&s, jl_sym_type->name->mt); - jl_serialize_value(&s, jl_array_typename->mt); - jl_serialize_value(&s, jl_module_type->name->mt); jl_prune_type_cache(jl_tuple_typename->cache); jl_prune_type_cache(jl_tuple_typename->linearcache); @@ -1348,11 +1352,15 @@ static void jl_save_system_image_to_stream(ios_t *f) jl_write_value(&s, jl_top_module); jl_write_value(&s, jl_typeinf_func); write_uint32(f, jl_typeinf_world); - jl_write_value(&s, jl_type_typename->mt); + jl_write_value(&s, jl_type_type_mt->defs); + jl_write_value(&s, jl_type_type_mt->cache); + jl_write_value(&s, jl_type_type_mt->kwsorter); + jl_write_value(&s, jl_type_type_mt->backedges); + jl_write_value(&s, jl_nonfunction_mt->defs); + jl_write_value(&s, jl_nonfunction_mt->cache); + jl_write_value(&s, jl_nonfunction_mt->kwsorter); + jl_write_value(&s, jl_nonfunction_mt->backedges); jl_write_value(&s, jl_intrinsic_type->name->mt); - jl_write_value(&s, jl_sym_type->name->mt); - jl_write_value(&s, jl_array_typename->mt); - jl_write_value(&s, jl_module_type->name->mt); uintptr_t i; for (i = 0; i < builtin_typenames.len; i++) { jl_write_value(&s, ((jl_typename_t*)builtin_typenames.items[i])->cache); @@ -1521,15 +1529,17 @@ static void jl_restore_system_image_from_stream(ios_t *f) jl_typeinf_func = (jl_function_t*)jl_read_value(&s); jl_typeinf_world = read_uint32(f); - jl_type_type_mt = (jl_methtable_t*)jl_read_value(&s); - jl_type_typename->mt = jl_type_type_mt; - jl_unionall_type->name->mt = jl_type_type_mt; - jl_uniontype_type->name->mt = jl_type_type_mt; - jl_datatype_type->name->mt = jl_type_type_mt; + + // load several method tables from the image + jl_type_type_mt->defs = jl_read_value(&s); + jl_type_type_mt->cache = jl_read_value(&s); + jl_type_type_mt->kwsorter = jl_read_value(&s); + jl_type_type_mt->backedges = (jl_array_t*)jl_read_value(&s); + jl_nonfunction_mt->defs = jl_read_value(&s); + jl_nonfunction_mt->cache = jl_read_value(&s); + jl_nonfunction_mt->kwsorter = jl_read_value(&s); + jl_nonfunction_mt->backedges = (jl_array_t*)jl_read_value(&s); jl_intrinsic_type->name->mt = (jl_methtable_t*)jl_read_value(&s); - jl_sym_type->name->mt = (jl_methtable_t*)jl_read_value(&s); - jl_array_typename->mt = (jl_methtable_t*)jl_read_value(&s); - jl_module_type->name->mt = (jl_methtable_t*)jl_read_value(&s); uintptr_t i; for (i = 0; i < builtin_typenames.len; i++) { @@ -1666,6 +1676,7 @@ static void jl_init_serializer2(int for_serialize) jl_globalref_type->name, jl_typeofbottom_type->name, jl_string_type->name, jl_abstractstring_type->name, jl_namedtuple_type, jl_namedtuple_typename, + jl_type_type_mt, jl_nonfunction_mt, jl_int32_type, jl_int64_type, jl_bool_type, jl_uint8_type, jl_uint32_type, jl_uint64_type, diff --git a/stdlib/Distributed/src/precompile.jl b/stdlib/Distributed/src/precompile.jl index 8d7ebebc6d013..c6a57e1b2bcc2 100644 --- a/stdlib/Distributed/src/precompile.jl +++ b/stdlib/Distributed/src/precompile.jl @@ -6,28 +6,28 @@ precompile(Tuple{typeof(Distributed.init_worker), String, Distributed.DefaultClu precompile(Tuple{typeof(Distributed.local_remotecall_thunk), typeof(Distributed.set_valid_processes), Tuple{Array{Int64, 1}}, Array{Any, 1}}) precompile(Tuple{typeof(Distributed.remote_do), typeof(Distributed.set_valid_processes), Distributed.Worker, Array{Int64, 1}}) precompile(Tuple{typeof(Distributed.remote_do), typeof(Distributed.set_valid_processes), Distributed.LocalProcess, Array{Int64, 1}}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.set_valid_processes), Distributed.Worker, Array{Int64, 1}}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.set_valid_processes), Distributed.LocalProcess, Array{Int64, 1}}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.set_valid_processes), Distributed.Worker, Array{Int64, 1}}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.set_valid_processes), Distributed.LocalProcess, Array{Int64, 1}}) precompile(Tuple{typeof(Distributed.default_addprocs_params)}) precompile(Tuple{typeof(Distributed.topology), Symbol}) precompile(Tuple{typeof(Base.popfirst!), Array{Distributed.WorkerConfig, 1}}) precompile(Tuple{typeof(Distributed.workers)}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##addprocs_locked")), Array{Any, 1}, typeof(Distributed.addprocs_locked), Distributed.SSHManager}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#addprocs_locked")), Array{Any, 1}, typeof(Distributed.addprocs_locked), Distributed.SSHManager}) precompile(Tuple{typeof(Distributed.check_addprocs_args), Array{Any, 1}}) precompile(Tuple{Type{Distributed.SSHManager}, Array{Any, 1}}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##addprocs")), Array{Any, 1}, typeof(Distributed.addprocs), Distributed.SSHManager}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##addprocs_locked")), Array{Any, 1}, typeof(Distributed.addprocs_locked), Distributed.LocalManager}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##addprocs")), Array{Any, 1}, typeof(Distributed.addprocs), Distributed.LocalManager}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#addprocs")), Array{Any, 1}, typeof(Distributed.addprocs), Distributed.SSHManager}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#addprocs_locked")), Array{Any, 1}, typeof(Distributed.addprocs_locked), Distributed.LocalManager}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#addprocs")), Array{Any, 1}, typeof(Distributed.addprocs), Distributed.LocalManager}) precompile(Tuple{typeof(Distributed.check_master_connect)}) precompile(Tuple{typeof(Distributed.terminate_all_workers)}) precompile(Tuple{typeof(Distributed.local_remotecall_thunk), typeof(Base.exit), Tuple{}, Array{Any, 1}}) precompile(Tuple{typeof(Distributed.remote_do), typeof(Base.exit), Distributed.Worker}) precompile(Tuple{typeof(Distributed.remote_do), typeof(Base.exit), Distributed.LocalProcess}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Base.exit), Distributed.Worker}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Base.exit), Distributed.LocalProcess}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Base.exit), Distributed.Worker}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Base.exit), Distributed.LocalProcess}) precompile(Tuple{typeof(Distributed.set_worker_state), Distributed.Worker, Distributed.WorkerState}) precompile(Tuple{typeof(Distributed.set_worker_state), Distributed.LocalProcess, Distributed.WorkerState}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##rmprocs")), Array{Any, 1}, typeof(Distributed.rmprocs), Array{Int64, 1}}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#rmprocs")), Array{Any, 1}, typeof(Distributed.rmprocs), Array{Int64, 1}}) precompile(Tuple{typeof(Distributed.interrupt), Array{Int64, 1}}) precompile(Tuple{typeof(Distributed.flush_gc_msgs)}) precompile(Tuple{typeof(Distributed.addprocs), Int64}) @@ -66,8 +66,8 @@ precompile(Tuple{typeof(Base.ht_keyindex), Base.Dict{Any, Any}, Distributed.RRID precompile(Tuple{typeof(Distributed.local_remotecall_thunk), typeof(Distributed.rmprocs), Tuple{Int64}, Array{Any, 1}}) precompile(Tuple{typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.Worker, Int64}) precompile(Tuple{typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.LocalProcess, Int64}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.Worker, Int64}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.LocalProcess, Int64}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.Worker, Int64}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.LocalProcess, Int64}) precompile(Tuple{Type{Distributed.ResultMsg}, Distributed.RemoteException}) precompile(Tuple{Type{Distributed.ResultMsg}, Symbol}) precompile(Tuple{typeof(Distributed.send_msg_now), Sockets.TCPSocket, Distributed.MsgHeader, Distributed.ResultMsg}) @@ -116,8 +116,8 @@ precompile(Tuple{typeof(Distributed.send_msg_now), Distributed.Worker, Distribut precompile(Tuple{typeof(Distributed.local_remotecall_thunk), typeof(Distributed.rmprocs), Tuple{Int64}, Array{Any, 1}}) precompile(Tuple{typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.Worker, Int64}) precompile(Tuple{typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.LocalProcess, Int64}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.Worker, Int64}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.LocalProcess, Int64}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.Worker, Int64}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Distributed.rmprocs), Distributed.LocalProcess, Int64}) precompile(Tuple{Type{Distributed.ResultMsg}, Distributed.RemoteException}) precompile(Tuple{Type{Distributed.ResultMsg}, Symbol}) precompile(Tuple{typeof(Distributed.send_msg_now), Sockets.TCPSocket, Distributed.MsgHeader, Distributed.ResultMsg}) @@ -160,8 +160,8 @@ precompile(Tuple{typeof(Base.hash), Distributed.RemoteChannel{Base.Channel{Any}} precompile(Tuple{typeof(Base.ht_keyindex), Base.Dict{WeakRef, Nothing}, Distributed.RemoteChannel{Base.Channel{Any}}}) precompile(Tuple{typeof(Distributed.remotecall_fetch), typeof(Distributed.put_ref), Distributed.Worker, Distributed.RRID, Distributed.WorkerPool}) precompile(Tuple{typeof(Distributed.remotecall_fetch), typeof(Distributed.put_ref), Distributed.LocalProcess, Distributed.RRID, Distributed.WorkerPool}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Distributed.remotecall_fetch), typeof(Distributed.put_ref), Distributed.Worker, Distributed.RRID, Distributed.WorkerPool}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Distributed.remotecall_fetch), typeof(Distributed.put_ref), Distributed.LocalProcess, Distributed.RRID, Distributed.WorkerPool}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remotecall_fetch")), Array{Any, 1}, typeof(Distributed.remotecall_fetch), typeof(Distributed.put_ref), Distributed.Worker, Distributed.RRID, Distributed.WorkerPool}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remotecall_fetch")), Array{Any, 1}, typeof(Distributed.remotecall_fetch), typeof(Distributed.put_ref), Distributed.LocalProcess, Distributed.RRID, Distributed.WorkerPool}) precompile(Tuple{typeof(Base.finalizer), Distributed.RemoteChannel{Base.Channel{Any}}, typeof(Distributed.finalize_ref)}) precompile(Tuple{typeof(Distributed.test_existing_ref), Distributed.RemoteChannel{Base.Channel{Any}}}) precompile(Tuple{Type{Distributed.RemoteChannel{T} where T<:Base.AbstractChannel}, Int64}) @@ -189,10 +189,10 @@ precompile(Tuple{typeof(Serialization.deserialize), Distributed.ClusterSerialize precompile(Tuple{typeof(Distributed.finalize_ref), Distributed.RemoteChannel{Base.Channel{Any}}}) precompile(Tuple{typeof(Distributed.send_del_client), Distributed.RemoteChannel{Base.Channel{Any}}}) precompile(Tuple{typeof(Base.:(==)), Distributed.RemoteChannel{Base.Channel{Any}}, Distributed.RemoteChannel{Base.Channel{Any}}}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Distributed.remotecall_fetch), typeof(Base.open), Distributed.LocalProcess, typeof(Base.read), String}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Distributed.remotecall_fetch), typeof(Base.open), Distributed.Worker, typeof(Base.read), String}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Base.exit), Distributed.Worker}) -precompile(Tuple{getfield(Distributed, Symbol("#kw##rmprocs")), Array{Any, 1}, typeof(Distributed.rmprocs), Array{Int64, 1}}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remotecall_fetch")), Array{Any, 1}, typeof(Distributed.remotecall_fetch), typeof(Base.open), Distributed.LocalProcess, typeof(Base.read), String}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remotecall_fetch")), Array{Any, 1}, typeof(Distributed.remotecall_fetch), typeof(Base.open), Distributed.Worker, typeof(Base.read), String}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#remote_do")), Array{Any, 1}, typeof(Distributed.remote_do), typeof(Base.exit), Distributed.Worker}) +precompile(Tuple{getfield(Distributed, Symbol("#kw#rmprocs")), Array{Any, 1}, typeof(Distributed.rmprocs), Array{Int64, 1}}) precompile(Tuple{Type{Distributed.Future}, Int64}) precompile(Tuple{typeof(Distributed.flush_gc_msgs), Distributed.Worker}) precompile(Tuple{typeof(Distributed.remote_do), typeof(Base.exit), Distributed.Worker}) diff --git a/stdlib/Serialization/src/Serialization.jl b/stdlib/Serialization/src/Serialization.jl index 7e040abb19a77..2bcbcbeefcb77 100644 --- a/stdlib/Serialization/src/Serialization.jl +++ b/stdlib/Serialization/src/Serialization.jl @@ -466,7 +466,7 @@ function serialize_typename(s::AbstractSerializer, t::Core.TypeName) serialize(s, primary.abstract) serialize(s, primary.mutable) serialize(s, primary.ninitialized) - if isdefined(t, :mt) + if isdefined(t, :mt) && t.mt !== Symbol.name.mt serialize(s, t.mt.name) serialize(s, collect(Base.MethodList(t.mt))) serialize(s, t.mt.max_args) @@ -941,9 +941,9 @@ function deserialize(s::AbstractSerializer, ::Type{Method}) linfo.def = meth meth.generator = linfo end - ftype = ccall(:jl_first_argument_datatype, Any, (Any,), sig)::DataType - if isdefined(ftype.name, :mt) && nothing === ccall(:jl_methtable_lookup, Any, (Any, Any, UInt), ftype.name.mt, sig, typemax(UInt)) - ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), ftype.name.mt, meth, C_NULL) + mt = ccall(:jl_method_table_for, Any, (Any,), sig) + if mt !== nothing && nothing === ccall(:jl_methtable_lookup, Any, (Any, Any, UInt), mt, sig, typemax(UInt)) + ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, meth, C_NULL) end remember_object(s, meth, lnumber) end diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index bd3bf2e53cfd5..07b1520cad856 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1431,7 +1431,7 @@ function detect_ambiguities(mods...; subambs = detect_ambiguities(f, imported=imported, recursive=recursive, ambiguous_bottom=ambiguous_bottom) union!(ambs, subambs) - elseif isa(f, DataType) && isdefined(f.name, :mt) + elseif isa(f, DataType) && isdefined(f.name, :mt) && f.name.mt !== Symbol.name.mt mt = Base.MethodList(f.name.mt) for m in mt if m.ambig !== nothing @@ -1445,6 +1445,24 @@ function detect_ambiguities(mods...; end end end + function is_in_mods(m::Module) + while true + m in mods && return true + recursive || return false + p = parentmodule(m) + p === m && return false + m = parent + end + end + for m in Base.MethodList(Symbol.name.mt) + if m.ambig !== nothing && is_in_mods(m.module) + for m2 in m.ambig + if Base.isambiguous(m, m2.func, ambiguous_bottom=ambiguous_bottom) + push!(ambs, sortdefs(m, m2.func)) + end + end + end + end return collect(ambs) end diff --git a/test/core.jl b/test/core.jl index d25568f8adf53..f8b170a8d2338 100644 --- a/test/core.jl +++ b/test/core.jl @@ -2384,6 +2384,23 @@ let x = Issue2403(20) @test issue2403func(x) == 34 end +# issue #14919 +abstract type A14919; end +struct B14919 <: A14919; end +struct C14919 <: A14919; end +struct D14919 <: Function; end +(::A14919)() = "It's a brand new world" +(::Union{C14919,D14919})() = "Boo." +@test B14919()() == "It's a brand new world" +@test C14919()() == D14919()() == "Boo." + +for f in (:Any, :Function, :(Core.Builtin), :(Union{Nothing, Type}), :(Union{typeof(+), Type}), :(Union{typeof(+), typeof(-)}), :(Base.Callable)) + @test_throws ErrorException("Method dispatch is unimplemented currently for this method signature") @eval (::$f)() = 1 +end +for f in (:(Core.arrayref), :((::typeof(Core.arrayref))), :((::Core.IntrinsicFunction))) + @test_throws ErrorException("cannot add methods to a builtin function") @eval $f() = 1 +end + # issue #8798 let npy_typestrs = Dict("b1"=>Bool,