Skip to content

Commit 095e92d

Browse files
authored
fix #36104, assign global name during type definitions (#36121)
also fixes #21816
1 parent 186c3bb commit 095e92d

File tree

5 files changed

+81
-31
lines changed

5 files changed

+81
-31
lines changed

base/compiler/tfuncs.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ is_dt_const_field(fld::Int) = (
568568
function const_datatype_getfield_tfunc(@nospecialize(sv), fld::Int)
569569
if fld == DATATYPE_INSTANCE_FIELDINDEX
570570
return isdefined(sv, fld) ? Const(getfield(sv, fld)) : Union{}
571-
elseif is_dt_const_field(fld)
571+
elseif is_dt_const_field(fld) && isdefined(sv, fld)
572572
return Const(getfield(sv, fld))
573573
end
574574
return nothing

src/builtins.c

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,27 @@ JL_CALLABLE(jl_f__setsuper)
12501250

12511251
void jl_reinstantiate_inner_types(jl_datatype_t *t);
12521252

1253+
static int equiv_field_types(jl_value_t *old, jl_value_t *ft)
1254+
{
1255+
size_t nf = jl_svec_len(ft);
1256+
if (jl_svec_len(old) != nf)
1257+
return 0;
1258+
size_t i;
1259+
for (i = 0; i < nf; i++) {
1260+
jl_value_t *ta = jl_svecref(old, i);
1261+
jl_value_t *tb = jl_svecref(ft, i);
1262+
if (jl_has_free_typevars(ta)) {
1263+
if (!jl_has_free_typevars(tb) || !jl_egal(ta, tb))
1264+
return 0;
1265+
}
1266+
else if (jl_has_free_typevars(tb) || jl_typeof(ta) != jl_typeof(tb) ||
1267+
!jl_types_equal(ta, tb)) {
1268+
return 0;
1269+
}
1270+
}
1271+
return 1;
1272+
}
1273+
12531274
JL_CALLABLE(jl_f__typebody)
12541275
{
12551276
JL_NARGS(_typebody!, 1, 2);
@@ -1258,16 +1279,23 @@ JL_CALLABLE(jl_f__typebody)
12581279
if (nargs == 2) {
12591280
jl_value_t *ft = args[1];
12601281
JL_TYPECHK(_typebody!, simplevector, ft);
1261-
dt->types = (jl_svec_t*)ft;
1262-
jl_gc_wb(dt, ft);
1263-
for (size_t i = 0; i < jl_svec_len(dt->types); i++) {
1264-
jl_value_t *elt = jl_svecref(dt->types, i);
1282+
size_t nf = jl_svec_len(ft);
1283+
for (size_t i = 0; i < nf; i++) {
1284+
jl_value_t *elt = jl_svecref(ft, i);
12651285
if ((!jl_is_type(elt) && !jl_is_typevar(elt)) || jl_is_vararg_type(elt)) {
12661286
jl_type_error_rt(jl_symbol_name(dt->name->name),
12671287
"type definition",
12681288
(jl_value_t*)jl_type_type, elt);
12691289
}
12701290
}
1291+
if (dt->types != NULL) {
1292+
if (!equiv_field_types((jl_value_t*)dt->types, ft))
1293+
jl_errorf("invalid redefinition of type %s", jl_symbol_name(dt->name->name));
1294+
}
1295+
else {
1296+
dt->types = (jl_svec_t*)ft;
1297+
jl_gc_wb(dt, ft);
1298+
}
12711299
}
12721300

12731301
JL_TRY {
@@ -1294,15 +1322,13 @@ static int equiv_type(jl_value_t *ta, jl_value_t *tb)
12941322
dta->name->name == dtb->name->name &&
12951323
dta->abstract == dtb->abstract &&
12961324
dta->mutabl == dtb->mutabl &&
1297-
dta->size == dtb->size &&
1325+
(jl_svec_len(jl_field_names(dta)) != 0 || dta->size == dtb->size) &&
12981326
dta->ninitialized == dtb->ninitialized &&
12991327
jl_egal((jl_value_t*)jl_field_names(dta), (jl_value_t*)jl_field_names(dtb)) &&
1300-
jl_nparams(dta) == jl_nparams(dtb) &&
1301-
jl_svec_len(dta->types) == jl_svec_len(dtb->types)))
1328+
jl_nparams(dta) == jl_nparams(dtb)))
13021329
return 0;
13031330
jl_value_t *a=NULL, *b=NULL;
13041331
int ok = 1;
1305-
size_t i, nf = jl_svec_len(dta->types);
13061332
JL_GC_PUSH2(&a, &b);
13071333
a = jl_rewrap_unionall((jl_value_t*)dta->super, dta->name->wrapper);
13081334
b = jl_rewrap_unionall((jl_value_t*)dtb->super, dtb->name->wrapper);
@@ -1328,21 +1354,6 @@ static int equiv_type(jl_value_t *ta, jl_value_t *tb)
13281354
a = jl_instantiate_unionall(ua, (jl_value_t*)ub->var);
13291355
b = ub->body;
13301356
}
1331-
assert(jl_is_datatype(a) && jl_is_datatype(b));
1332-
a = (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)a);
1333-
b = (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)b);
1334-
for (i = 0; i < nf; i++) {
1335-
jl_value_t *ta = jl_svecref(a, i);
1336-
jl_value_t *tb = jl_svecref(b, i);
1337-
if (jl_has_free_typevars(ta)) {
1338-
if (!jl_has_free_typevars(tb) || !jl_egal(ta, tb))
1339-
goto no;
1340-
}
1341-
else if (jl_has_free_typevars(tb) || jl_typeof(ta) != jl_typeof(tb) ||
1342-
!jl_types_equal(ta, tb)) {
1343-
goto no;
1344-
}
1345-
}
13461357
JL_GC_POP();
13471358
return 1;
13481359
no:

src/jltypes.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,6 +1773,9 @@ JL_DLLEXPORT jl_svec_t *jl_compute_fieldtypes(jl_datatype_t *st JL_PROPAGATES_RO
17731773
assert(n > 0 && "expected empty case to be handled during construction");
17741774
//if (n == 0)
17751775
// return ((st->types = jl_emptysvec));
1776+
if (wt->types == NULL)
1777+
jl_errorf("cannot determine field types of incomplete type %s",
1778+
jl_symbol_name(st->name->name));
17761779
jl_typeenv_t *env = (jl_typeenv_t*)alloca(n * sizeof(jl_typeenv_t));
17771780
for (i = 0; i < n; i++) {
17781781
env[i].var = (jl_tvar_t*)jl_svecref(wt->parameters, i);

src/julia-syntax.scm

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,8 @@
884884
(defs2 (if (null? defs)
885885
(default-inner-ctors name field-names field-types params bounds locs)
886886
defs))
887-
(min-initialized (min (ctors-min-initialized defs) (length fields))))
887+
(min-initialized (min (ctors-min-initialized defs) (length fields)))
888+
(prev (make-ssavalue)))
888889
(let ((dups (has-dups field-names)))
889890
(if dups (error (string "duplicate field name: \"" (car dups) "\" is not unique"))))
890891
(for-each (lambda (v)
@@ -898,16 +899,29 @@
898899
(local-def ,name)
899900
,@(map (lambda (v) `(local ,v)) params)
900901
,@(map (lambda (n v) (make-assignment n (bounds-to-TypeVar v #t))) params bounds)
901-
(toplevel-only struct)
902+
(toplevel-only struct (outerref ,name))
902903
(= ,name (call (core _structtype) (thismodule) (inert ,name) (call (core svec) ,@params)
903904
(call (core svec) ,@(map quotify field-names))
904905
,mut ,min-initialized))
905906
(call (core _setsuper!) ,name ,super)
906-
(call (core _typebody!) ,name (call (core svec) ,@field-types))
907-
(if (&& (isdefined (outerref ,name))
908-
(call (core _equiv_typedef) (outerref ,name) ,name))
909-
(null)
907+
(if (isdefined (outerref ,name))
908+
(block
909+
(= ,prev (outerref ,name))
910+
(if (call (core _equiv_typedef) ,prev ,name)
911+
;; if this is compatible with an old definition, use the existing type object
912+
;; and its parameters
913+
(block (= ,name ,prev)
914+
,@(if (pair? params)
915+
`((= (tuple ,@params) (|.|
916+
,(foldl (lambda (_ x) `(|.| ,x (quote body)))
917+
prev
918+
params)
919+
(quote parameters))))
920+
'()))
921+
;; otherwise do an assignment to trigger an error
922+
(= (outerref ,name) ,name)))
910923
(= (outerref ,name) ,name))
924+
(call (core _typebody!) ,name (call (core svec) ,@field-types))
911925
(null)))
912926
;; "inner" constructors
913927
(scope-block
@@ -3351,7 +3365,12 @@ f(x) = yt(x)
33513365
((atom? e) e)
33523366
(else
33533367
(case (car e)
3354-
((quote top core globalref outerref thismodule toplevel-only line break inert module toplevel null true false meta) e)
3368+
((quote top core globalref outerref thismodule line break inert module toplevel null true false meta) e)
3369+
((toplevel-only)
3370+
;; hack to avoid generating a (method x) expr for struct types
3371+
(if (eq? (cadr e) 'struct)
3372+
(put! defined (caddr e) #t))
3373+
e)
33553374
((=)
33563375
(let ((var (cadr e))
33573376
(rhs (cl-convert (caddr e) fname lam namemap defined toplevel interp)))

test/core.jl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7221,3 +7221,20 @@ struct AVL35416{K,V}
72217221
avl:: Union{Nothing,Node35416{AVL35416{K,V},<:K,<:V}}
72227222
end
72237223
@test AVL35416(Node35416{AVL35416{Integer,AbstractString},Int,String}()) isa AVL35416{Integer,AbstractString}
7224+
7225+
# issue #36104
7226+
module M36104
7227+
struct T36104
7228+
v::Vector{M36104.T36104}
7229+
end
7230+
struct T36104 # check that redefining it works, issue #21816
7231+
v::Vector{T36104}
7232+
end
7233+
end
7234+
@test fieldtypes(M36104.T36104) == (Vector{M36104.T36104},)
7235+
@test_throws ErrorException("expected") @eval(struct X36104; x::error("expected"); end)
7236+
@test @isdefined(X36104)
7237+
struct X36104; x::Int; end
7238+
@test fieldtypes(X36104) == (Int,)
7239+
primitive type P36104 8 end
7240+
@test_throws ErrorException("invalid redefinition of constant P36104") @eval(primitive type P36104 16 end)

0 commit comments

Comments
 (0)