From 46b6c9af0ea222148af442417eb8ee743279a5fc Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Wed, 11 Jan 2023 12:29:35 +0800 Subject: [PATCH] Also check free typevar's bounds in `reachable_var` They might be recreated in `finish_unionall`, (thus `lookup` returns false.) But their bounds might still live in the current env. close #44395. (#44395 could also be fixed by the fast path added in #48221. This commit would skip more `intersect_var` under circular constraint.) --- src/subtype.c | 40 ++++++++++++++-------------------------- test/subtype.jl | 11 +++++------ 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/src/subtype.c b/src/subtype.c index 88859c822f4fc..59055e6bc168e 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -2406,43 +2406,31 @@ static int subtype_in_env_existential(jl_value_t *x, jl_value_t *y, jl_stenv_t * } // 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) +static int _reachable_var(jl_value_t *x, jl_tvar_t *y, jl_stenv_t *e, jl_typeenv_t *log) { if (in_union(x, (jl_value_t*)y)) return 1; if (jl_is_uniontype(x)) - return _reachable_var(((jl_uniontype_t *)x)->a, y, e) || - _reachable_var(((jl_uniontype_t *)x)->b, y, e); + return _reachable_var(((jl_uniontype_t *)x)->a, y, e, log) || + _reachable_var(((jl_uniontype_t *)x)->b, y, e, log); if (!jl_is_typevar(x)) return 0; + jl_typeenv_t *t = log; + while (t != NULL) { + if (x == (jl_value_t *)t->var) + return 0; + t = t->prev; + } jl_varbinding_t *xv = lookup(e, (jl_tvar_t*)x); - if (xv == NULL || xv->right) - return 0; - xv->right = 1; - return _reachable_var(xv->ub, y, e) || _reachable_var(xv->lb, y, e); + jl_value_t *lb = xv == NULL ? ((jl_tvar_t*)x)->lb : xv->lb; + jl_value_t *ub = xv == NULL ? ((jl_tvar_t*)x)->ub : xv->ub; + jl_typeenv_t newlog = { (jl_tvar_t*)x, NULL, log }; + return _reachable_var(ub, y, e, &newlog) || _reachable_var(lb, y, e, &newlog); } static int reachable_var(jl_value_t *x, jl_tvar_t *y, jl_stenv_t *e) { - int len = current_env_length(e); - int8_t *rs = (int8_t*)malloc_s(len); - int n = 0; - jl_varbinding_t *v = e->vars; - while (n < len) { - assert(v != NULL); - rs[n++] = v->right; - v->right = 0; - v = v->prev; - } - int res = _reachable_var(x, y, e); - n = 0; v = e->vars; - while (n < len) { - assert(v != NULL); - v->right = rs[n++]; - v = v->prev; - } - free(rs); - return res; + return _reachable_var(x, y, e, NULL); } // check whether setting v == t implies v == SomeType{v}, which is unsatisfiable. diff --git a/test/subtype.jl b/test/subtype.jl index a182bb99909ee..3517e8fdc906c 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -2352,6 +2352,11 @@ let S = Tuple{Type{T1}, T1, Val{T1}} where T1<:(Val{S1} where S1<:Val), @test_broken I2 <: T end +#issue 44395 +@testintersect(Tuple{Type{T}, T} where {T <: Vector{Union{T, R}} where {R<:Real, T<:Real}}, + Tuple{Type{Vector{Union{T, R}}}, Matrix{Union{T, R}}} where {R<:Real, T<:Real}, + Union{}) + @testset "known subtype/intersect issue" begin #issue 45874 # Causes a hang due to jl_critical_error calling back into malloc... @@ -2361,12 +2366,6 @@ end # @test_broken typeintersect(S,T) === S # end - #issue 44395 - @test_broken typeintersect( - Tuple{Type{T}, T} where {T <: Vector{Union{T, R}} where {R<:Real, T<:Real}}, - Tuple{Type{Vector{Union{T, R}}}, Matrix{Union{T, R}}} where {R<:Real, T<:Real}, - ) === Union{} - #issue 41561 @test_broken typeintersect(Tuple{Vector{VT}, Vector{VT}} where {N1, VT<:AbstractVector{N1}}, Tuple{Vector{VN} where {N, VN<:AbstractVector{N}}, Vector{Vector{Float64}}}) !== Union{}