diff --git a/src/subtype.c b/src/subtype.c index a6e7605fc25d5..1baba395ff3b6 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -1382,6 +1382,20 @@ static int try_subtype_in_env(jl_value_t *a, jl_value_t *b, jl_stenv_t *e) return ret; } +static void set_bound(jl_value_t **bound, jl_value_t *val, jl_tvar_t *v, jl_stenv_t *e) +{ + if (in_union(val, (jl_value_t*)v)) + return; + jl_varbinding_t *btemp = e->vars; + while (btemp != NULL) { + if (btemp->lb == (jl_value_t*)v && btemp->ub == (jl_value_t*)v && + in_union(val, (jl_value_t*)btemp->var)) + return; + btemp = btemp->prev; + } + *bound = val; +} + static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int8_t R, int param) { jl_varbinding_t *bb = lookup(e, b); @@ -1445,8 +1459,7 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int JL_GC_POP(); return jl_bottom_type; } - if (ub != (jl_value_t*)b) - bb->ub = ub; + set_bound(&bb->ub, ub, b, e); JL_GC_POP(); return (jl_value_t*)b; } @@ -1456,8 +1469,7 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int if (!subtype_in_env(a, bb->ub, e)) return jl_bottom_type; jl_value_t *lb = simple_join(bb->lb, a); - if (lb != (jl_value_t*)b) - bb->lb = lb; + set_bound(&bb->lb, lb, b, e); return a; } assert(bb->constraintkind == 3); @@ -1471,7 +1483,7 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int // if the var has an equality constraint then make sure bounds stay consistent. // TODO: try to use this check in more cases bb->ub != bb->lb || try_subtype_in_env(bb->lb, ub, e)) { - bb->ub = ub; + set_bound(&bb->ub, ub, b, e); return (jl_value_t*)b; } return ub; @@ -1486,8 +1498,7 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int if (ii == jl_bottom_type) { restore_env(e, root, &se); ii = (jl_value_t*)b; - if (ub != (jl_value_t*)b) - bb->ub = ub; + set_bound(&bb->ub, ub, b, e); } free(se.buf); JL_GC_POP(); @@ -1694,12 +1705,14 @@ static jl_value_t *intersect_unionall_(jl_value_t *t, jl_unionall_t *u, jl_stenv e->vars = vb->prev; if (res != jl_bottom_type) { - // fail on circular constraints - if (jl_has_typevar(vb->lb, u->var) || jl_has_typevar(vb->ub, u->var)) + if (vb->ub == jl_bottom_type && vb->occurs_cov) { + // T=Bottom in covariant position res = jl_bottom_type; - // T=Bottom in covariant position - if (vb->ub == jl_bottom_type && vb->occurs_cov) + } + else if (jl_has_typevar(vb->lb, u->var) || jl_has_typevar(vb->ub, u->var)) { + // fail on circular constraints res = jl_bottom_type; + } } if (res != jl_bottom_type) // res is rooted by callee @@ -2040,6 +2053,11 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa if (R) flip_vars(e); if (!ccheck) return jl_bottom_type; + if (var_occurs_inside(xub, (jl_tvar_t*)y, 0, 0) && var_occurs_inside(yub, (jl_tvar_t*)x, 0, 0)) { + // circular constraint. the result will be Bottom, but in the meantime + // we need to avoid computing intersect(xub, yub) since it won't terminate. + return y; + } jl_value_t *ub=NULL, *lb=NULL; JL_GC_PUSH2(&lb, &ub); ub = intersect_aside(xub, yub, e, xx ? xx->depth0 : 0); diff --git a/test/subtype.jl b/test/subtype.jl index 4bda72de57126..5a8f54b85f02c 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -1420,3 +1420,11 @@ let U = Tuple{Union{LT, LT1},Union{R, R1},Int} where LT1<:R1 where R1<:Tuple{Int @test U2 == V @test_broken U2 == V2 end + +# issue #31082 and #30741 +@testintersect(Tuple{T, Ref{T}, T} where T, + Tuple{Ref{S}, S, S} where S, + Union{}) +@testintersect(Tuple{Pair{B,C},Union{C,Pair{B,C}},Union{B,Real}} where {B,C}, + Tuple{Pair{B,C},C,C} where {B,C}, + Tuple{Pair{B,C},C,C} where C<:Union{Real, B} where B)