Skip to content

Commit

Permalink
fix #38423, another stack overflow in method definition
Browse files Browse the repository at this point in the history
also fixes #36544 and fixes #36804
  • Loading branch information
JeffBezanson committed Dec 10, 2020
1 parent 9a8a675 commit f9a8d45
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 1 deletion.
15 changes: 14 additions & 1 deletion src/subtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -2892,6 +2892,19 @@ static int compareto_var(jl_value_t *x, jl_tvar_t *y, jl_stenv_t *e, int cmp)
return ans;
}

// See if var y is reachable from x via bounds; used to avoid cycles.
static int reachable_var(jl_value_t *x, jl_tvar_t *y, jl_stenv_t *e)
{
if (x == (jl_value_t*)y)
return 1;
if (!jl_is_typevar(x))
return 0;
jl_varbinding_t *xv = lookup(e, (jl_tvar_t*)x);
if (xv == NULL)
return 0;
return reachable_var(xv->ub, y, e) || reachable_var(xv->lb, y, e);
}

// `param` means we are currently looking at a parameter of a type constructor
// (as opposed to being outside any type constructor, or comparing variable bounds).
// this is used to record the positions where type variables occur for the
Expand Down Expand Up @@ -2970,7 +2983,7 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa
assert(yy->ub != y);
assert(yy->lb != y);
}
if (xx) {
if (xx && !reachable_var(y, (jl_tvar_t*)x, e)) {
if (!compareto_var(y, (jl_tvar_t*)x, e, -1))
xx->lb = y;
if (!compareto_var(y, (jl_tvar_t*)x, e, 1))
Expand Down
20 changes: 20 additions & 0 deletions test/subtype.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1814,3 +1814,23 @@ end

# issue #24333
@test_broken (Type{Union{Ref,Cvoid}} <: Type{Union{T,Cvoid}} where T)

# issue #38423
let
Either{L, R} = Union{Ref{L}, Val{R}}
A = Tuple{Type{Ref{L}}, Type{Either{L, <:Any}}} where L
B = Tuple{Type{Ref{L2}}, Type{Either{L1, R}}} where {L1, R, L2 <: L1}
I = typeintersect(A, B)
@test I != Union{}
@test_broken I <: A
@test_broken I <: B
end

# issue #36544
let A = Tuple{T, Ref{T}, T} where {T},
B = Tuple{T, T, Ref{T}} where {T}
I = typeintersect(A, B)
@test I != Union{}
@test_broken I <: A
@test_broken I <: B
end

0 comments on commit f9a8d45

Please sign in to comment.