Skip to content

Commit e4217a4

Browse files
vtjnashJeffBezanson
authored andcommitted
fix another bug in circular type detection (#41516)
Co-authored-by: Jeff Bezanson <jeff.bezanson@gmail.com> (cherry picked from commit 1c92e0d)
1 parent 9178941 commit e4217a4

File tree

2 files changed

+39
-9
lines changed

2 files changed

+39
-9
lines changed

src/builtins.c

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,22 +1487,38 @@ static int equiv_field_types(jl_value_t *old, jl_value_t *ft)
14871487
return 1;
14881488
}
14891489

1490+
// If a field can reference its enclosing type, then the inlining
1491+
// recursive depth is not statically bounded for some layouts, so we cannot
1492+
// inline it. The only way fields can reference this type (due to
1493+
// syntax-enforced restrictions) is via being passed as a type parameter. Thus
1494+
// we can conservatively check this by examining only the parameters of the
1495+
// dependent types.
1496+
// affects_layout is a hack introduced by #35275 to workaround a problem
1497+
// introduced by #34223: it checks whether we will potentially need to
1498+
// compute the layout of the object before we have fully computed the types of
1499+
// the fields during recursion over the allocation of the parameters for the
1500+
// field types (of the concrete subtypes)
14901501
static int references_name(jl_value_t *p, jl_typename_t *name, int affects_layout) JL_NOTSAFEPOINT
14911502
{
14921503
if (jl_is_uniontype(p))
14931504
return references_name(((jl_uniontype_t*)p)->a, name, affects_layout) ||
14941505
references_name(((jl_uniontype_t*)p)->b, name, affects_layout);
14951506
if (jl_is_unionall(p))
1496-
return references_name((jl_value_t*)((jl_unionall_t*)p)->var, name, 0) ||
1507+
return references_name((jl_value_t*)((jl_unionall_t*)p)->var->lb, name, 0) ||
1508+
references_name((jl_value_t*)((jl_unionall_t*)p)->var->ub, name, 0) ||
14971509
references_name(((jl_unionall_t*)p)->body, name, affects_layout);
14981510
if (jl_is_typevar(p))
1499-
return references_name(((jl_tvar_t*)p)->ub, name, 0) ||
1500-
references_name(((jl_tvar_t*)p)->lb, name, 0);
1511+
return 0; // already checked by unionall, if applicable
15011512
if (jl_is_datatype(p)) {
15021513
jl_datatype_t *dp = (jl_datatype_t*)p;
15031514
if (affects_layout && dp->name == name)
15041515
return 1;
1505-
affects_layout = dp->types == NULL || jl_svec_len(dp->types) != 0;
1516+
// affects_layout checks whether we will need to attempt to layout this
1517+
// type (based on whether all copies of it have the same layout) in
1518+
// that case, we still need to check the recursive parameters for
1519+
// layout recursion happening also, but we know it won't itself cause
1520+
// problems for the layout computation
1521+
affects_layout = ((jl_datatype_t*)jl_unwrap_unionall(dp->name->wrapper))->layout == NULL;
15061522
size_t i, l = jl_nparams(p);
15071523
for (i = 0; i < l; i++) {
15081524
if (references_name(jl_tparam(p, i), name, affects_layout))
@@ -1537,16 +1553,21 @@ JL_CALLABLE(jl_f__typebody)
15371553
else {
15381554
dt->types = (jl_svec_t*)ft;
15391555
jl_gc_wb(dt, ft);
1540-
if (!dt->name->mutabl) {
1541-
dt->name->mayinlinealloc = 1;
1556+
// If a supertype can reference the same type, then we may not be
1557+
// able to compute the layout of the object before needing to
1558+
// publish it, so we must assume it cannot be inlined, if that
1559+
// check passes, then we also still need to check the fields too.
1560+
if (!dt->name->mutabl && !references_name((jl_value_t*)dt->super, dt->name, 1)) {
1561+
int mayinlinealloc = 1;
15421562
size_t i, nf = jl_svec_len(ft);
15431563
for (i = 0; i < nf; i++) {
15441564
jl_value_t *fld = jl_svecref(ft, i);
15451565
if (references_name(fld, dt->name, 1)) {
1546-
dt->name->mayinlinealloc = 0;
1566+
mayinlinealloc = 0;
15471567
break;
15481568
}
15491569
}
1570+
dt->name->mayinlinealloc = mayinlinealloc;
15501571
}
15511572
}
15521573
}

test/core.jl

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7217,8 +7217,17 @@ end
72177217
struct B33954
72187218
x::Q33954{B33954}
72197219
end
7220-
@test_broken isbitstype(Tuple{B33954})
7221-
@test_broken isbitstype(B33954)
7220+
@test isbitstype(Tuple{B33954})
7221+
@test isbitstype(B33954)
7222+
7223+
struct A41503{d}
7224+
e::d
7225+
end
7226+
struct B41503{j,k} <: AbstractArray{A41503{B41503{Any,k}},Any}
7227+
l::k
7228+
end
7229+
@test !isbitstype(B41503{Any,Any})
7230+
@test_broken isbitstype(B41503{Any,Int})
72227231

72237232
struct B40050 <: Ref{Tuple{B40050}}
72247233
end

0 commit comments

Comments
 (0)