diff --git a/src/gf.c b/src/gf.c index c6df93465cf1a..c61853f0e3218 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1397,7 +1397,7 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method size_t ins = 0; for (i = 1; i < na; i += 2) { jl_value_t *backedgetyp = backedges[i - 1]; - if (jl_type_intersection(backedgetyp, (jl_value_t*)type) != (jl_value_t*)jl_bottom_type) { + if (!jl_has_empty_intersection(backedgetyp, (jl_value_t*)type)) { jl_method_instance_t *backedge = (jl_method_instance_t*)backedges[i]; invalidate_method_instance(backedge, env.max_world, 0); env.invalidated = 1; @@ -1731,10 +1731,8 @@ JL_DLLEXPORT int jl_has_call_ambiguities(jl_tupletype_t *types, jl_method_t *m) if (m->ambig == jl_nothing) return 0; for (size_t i = 0; i < jl_array_len(m->ambig); i++) { jl_method_t *mambig = (jl_method_t*)jl_array_ptr_ref(m->ambig, i); - if (jl_type_intersection((jl_value_t*)mambig->sig, - (jl_value_t*)types) != (jl_value_t*)jl_bottom_type) { + if (!jl_has_empty_intersection((jl_value_t*)mambig->sig, (jl_value_t*)types)) return 1; - } } return 0; } diff --git a/src/julia.h b/src/julia.h index f5efda7e378c7..b3188fa2b5905 100644 --- a/src/julia.h +++ b/src/julia.h @@ -982,6 +982,7 @@ JL_DLLEXPORT int jl_isa(jl_value_t *a, jl_value_t *t); JL_DLLEXPORT int jl_types_equal(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n); JL_DLLEXPORT jl_value_t *jl_type_intersection(jl_value_t *a, jl_value_t *b); +JL_DLLEXPORT int jl_has_empty_intersection(jl_value_t *x, jl_value_t *y); JL_DLLEXPORT jl_value_t *jl_type_unionall(jl_tvar_t *v, jl_value_t *body); JL_DLLEXPORT const char *jl_typename_str(jl_value_t *v); JL_DLLEXPORT const char *jl_typeof_str(jl_value_t *v); diff --git a/src/subtype.c b/src/subtype.c index 8a1984c7a285f..113cb1675085e 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -91,6 +91,7 @@ typedef struct { int invdepth; // current number of invariant constructors we're nested in int ignore_free; // treat free vars as black boxes; used during intersection int intersection; // true iff subtype is being called from intersection + int emptiness_only; // true iff intersection only needs to test for emptiness } jl_stenv_t; // state manipulation utilities @@ -238,7 +239,7 @@ static int obviously_unequal(jl_value_t *a, jl_value_t *b) return 0; } -static int obviously_disjoint(jl_value_t *a, jl_value_t *b) +static int obviously_disjoint(jl_value_t *a, jl_value_t *b, int specificity) { if (a == b || a == (jl_value_t*)jl_any_type || b == (jl_value_t*)jl_any_type) return 0; @@ -280,7 +281,8 @@ static int obviously_disjoint(jl_value_t *a, jl_value_t *b) else if (jl_is_va_tuple(bd)) { nb -= 1; } - else if (na != nb) { + else if (!specificity && na != nb) { + // note: some disjoint types (e.g. tuples of different lengths) can be more specific return 1; } np = na < nb ? na : nb; @@ -298,13 +300,18 @@ static int obviously_disjoint(jl_value_t *a, jl_value_t *b) if (jl_is_type(bi)) { if (istuple && (ai == jl_bottom_type || bi == jl_bottom_type)) ; // TODO: this can return 1 if and when Tuple{Union{}} === Union{} - else if (obviously_disjoint(ai, bi)) + else if (obviously_disjoint(ai, bi, specificity)) return 1; } - else { + else if (!specificity) { + // Tuple{1} is more specific than Tuple{Any} return 1; } } + else if (jl_is_type(bi)) { + if (!specificity) + return 1; + } else if (!jl_egal(ai, bi)) { return 1; } @@ -534,8 +541,9 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8 // if the var for this unionall (based on identity) already appears somewhere // in the environment, rename to get a fresh var. while (btemp != NULL) { - if (btemp->var == u->var || jl_has_typevar(btemp->lb, u->var) || - jl_has_typevar(btemp->ub, u->var)) { + if (btemp->var == u->var || + (btemp->lb != jl_bottom_type && jl_has_typevar(btemp->lb, u->var)) || + (btemp->ub != (jl_value_t*)jl_any_type && jl_has_typevar(btemp->ub, u->var))) { u = rename_unionall(u); break; } @@ -619,7 +627,7 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8 btemp = e->vars; while (btemp != NULL) { jl_value_t *vi = btemp->ub; - if (vi != (jl_value_t*)vb.var && jl_has_typevar(vi, vb.var)) { + if (vi != (jl_value_t*)vb.var && vi != (jl_value_t*)jl_any_type && jl_has_typevar(vi, vb.var)) { btemp->ub = jl_new_struct(jl_unionall_type, vb.var, vi); btemp->lb = jl_bottom_type; } @@ -1003,6 +1011,7 @@ static void init_stenv(jl_stenv_t *e, jl_value_t **env, int envsz) e->invdepth = 0; e->ignore_free = 0; e->intersection = 0; + e->emptiness_only = 0; e->Lunions.depth = 0; e->Runions.depth = 0; e->Lunions.more = 0; e->Runions.more = 0; } @@ -2012,6 +2021,8 @@ static jl_value_t *intersect_all(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) int lastset = 0, niter = 0; jl_value_t *ii = intersect(x, y, e, 0); while (e->Runions.more) { + if (e->emptiness_only && ii != jl_bottom_type) + return ii; e->Runions.depth = 0; int set = e->Runions.more - 1; e->Runions.more = 0; @@ -2042,16 +2053,28 @@ static jl_value_t *intersect_all(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) // type intersection entry points -JL_DLLEXPORT jl_value_t *jl_intersect_types(jl_value_t *x, jl_value_t *y) +static jl_value_t *intersect_types(jl_value_t *x, jl_value_t *y, int emptiness_only) { jl_stenv_t e; - if (obviously_disjoint(x, y)) + if (obviously_disjoint(x, y, 0)) return jl_bottom_type; init_stenv(&e, NULL, 0); e.intersection = 1; + e.emptiness_only = emptiness_only; return intersect_all(x, y, &e); } +JL_DLLEXPORT jl_value_t *jl_intersect_types(jl_value_t *x, jl_value_t *y) +{ + return intersect_types(x, y, 0); +} + +// TODO: this can probably be done more efficiently +JL_DLLEXPORT int jl_has_empty_intersection(jl_value_t *x, jl_value_t *y) +{ + return intersect_types(x, y, 1) == jl_bottom_type; +} + // return a SimpleVector of all vars from UnionAlls wrapping a given type jl_svec_t *jl_outer_unionall_vars(jl_value_t *u) { @@ -2073,7 +2096,7 @@ jl_svec_t *jl_outer_unionall_vars(jl_value_t *u) jl_value_t *jl_type_intersection_env_s(jl_value_t *a, jl_value_t *b, jl_svec_t **penv, int *issubty) { if (issubty) *issubty = 0; - if (obviously_disjoint(a, b)) { + if (obviously_disjoint(a, b, 0)) { if (issubty && a == jl_bottom_type) *issubty = 1; return jl_bottom_type; } @@ -2570,6 +2593,8 @@ static int type_morespecific_(jl_value_t *a, jl_value_t *b, int invariant, jl_ty JL_DLLEXPORT int jl_type_morespecific(jl_value_t *a, jl_value_t *b) { + if (obviously_disjoint(a, b, 1)) + return 0; if (jl_subtype(b, a)) return 0; if (jl_subtype(a, b)) return 1; return type_morespecific_(a, b, 0, NULL); diff --git a/src/typemap.c b/src/typemap.c index 0119678b92584..b70accd357b87 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -515,7 +515,7 @@ int jl_typemap_intersection_visitor(union jl_typemap_t map, int offs, else { // else an array scan is required to check subtypes // first, fast-path: optimized pre-intersection test to see if `ty` could intersect with any Type - if (typetype || jl_type_intersection((jl_value_t*)jl_type_type, ty) != jl_bottom_type) + if (typetype || !jl_has_empty_intersection((jl_value_t*)jl_type_type, ty)) if (!jl_typemap_intersection_array_visitor(&cache->targ, ty, 1, offs, closure)) return 0; } }