Skip to content

Commit a645d7f

Browse files
authored
give IR forms for defining types valid linear structure (#33553)
fixes #33183, fixes #35416
1 parent 5cb3f3f commit a645d7f

18 files changed

+333
-402
lines changed

src/ast.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ jl_sym_t *exc_sym; jl_sym_t *error_sym;
4343
jl_sym_t *new_sym; jl_sym_t *using_sym;
4444
jl_sym_t *splatnew_sym;
4545
jl_sym_t *const_sym; jl_sym_t *thunk_sym;
46-
jl_sym_t *abstracttype_sym; jl_sym_t *primtype_sym;
47-
jl_sym_t *structtype_sym; jl_sym_t *foreigncall_sym;
46+
jl_sym_t *foreigncall_sym;
4847
jl_sym_t *global_sym; jl_sym_t *list_sym;
4948
jl_sym_t *dot_sym; jl_sym_t *newvar_sym;
5049
jl_sym_t *boundscheck_sym; jl_sym_t *inbounds_sym;
@@ -62,7 +61,7 @@ jl_sym_t *throw_undef_if_not_sym; jl_sym_t *getfield_undefref_sym;
6261
jl_sym_t *gc_preserve_begin_sym; jl_sym_t *gc_preserve_end_sym;
6362
jl_sym_t *coverageeffect_sym; jl_sym_t *escape_sym;
6463
jl_sym_t *aliasscope_sym; jl_sym_t *popaliasscope_sym;
65-
jl_sym_t *optlevel_sym;
64+
jl_sym_t *optlevel_sym; jl_sym_t *thismodule_sym;
6665

6766
static uint8_t flisp_system_image[] = {
6867
#include <julia_flisp.boot.inc>
@@ -357,9 +356,6 @@ void jl_init_frontend(void)
357356
const_sym = jl_symbol("const");
358357
global_sym = jl_symbol("global");
359358
thunk_sym = jl_symbol("thunk");
360-
abstracttype_sym = jl_symbol("abstract_type");
361-
primtype_sym = jl_symbol("primitive_type");
362-
structtype_sym = jl_symbol("struct_type");
363359
toplevel_sym = jl_symbol("toplevel");
364360
dot_sym = jl_symbol(".");
365361
colon_sym = jl_symbol(":");
@@ -395,6 +391,7 @@ void jl_init_frontend(void)
395391
coverageeffect_sym = jl_symbol("code_coverage_effect");
396392
aliasscope_sym = jl_symbol("aliasscope");
397393
popaliasscope_sym = jl_symbol("popaliasscope");
394+
thismodule_sym = jl_symbol("thismodule");
398395
}
399396

400397
JL_DLLEXPORT void jl_lisp_prompt(void)
@@ -577,6 +574,9 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *m
577574
assert(jl_is_symbol(ex));
578575
temp = jl_module_globalref(jl_core_module, (jl_sym_t*)ex);
579576
}
577+
else if (sym == thismodule_sym) {
578+
temp = (jl_value_t*)mod;
579+
}
580580
else if (iscons(e) && (sym == inert_sym || (sym == quote_sym && (!iscons(car_(e)))))) {
581581
ex = scm_to_julia_(fl_ctx, car_(e), mod);
582582
temp = jl_new_struct(jl_quotenode_type, ex);

src/ast.scm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,15 @@
358358
(define (globalref? e)
359359
(and (pair? e) (eq? (car e) 'globalref)))
360360

361+
(define (outerref? e)
362+
(and (pair? e) (eq? (car e) 'outerref)))
363+
361364
(define (symbol-like? e)
362365
(or (symbol? e) (ssavalue? e)))
363366

364367
(define (simple-atom? x)
365368
(or (number? x) (string? x) (char? x)
366-
(and (pair? x) (memq (car x) '(ssavalue null true false)))
369+
(and (pair? x) (memq (car x) '(ssavalue null true false thismodule)))
367370
(eq? (typeof x) 'julia_value)))
368371

369372
;; identify some expressions that are safe to repeat

src/builtin_proto.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,14 @@ DECLARE_BUILTIN(arrayset); DECLARE_BUILTIN(arraysize);
3333
DECLARE_BUILTIN(apply_type); DECLARE_BUILTIN(applicable);
3434
DECLARE_BUILTIN(invoke); DECLARE_BUILTIN(_expr);
3535
DECLARE_BUILTIN(typeassert); DECLARE_BUILTIN(ifelse);
36-
DECLARE_BUILTIN(_typevar);
36+
DECLARE_BUILTIN(_typevar); DECLARE_BUILTIN(_typebody);
3737

3838
JL_CALLABLE(jl_f_invoke_kwsorter);
39+
JL_CALLABLE(jl_f__structtype);
40+
JL_CALLABLE(jl_f__abstracttype);
41+
JL_CALLABLE(jl_f__primitivetype);
42+
JL_CALLABLE(jl_f__setsuper);
43+
JL_CALLABLE(jl_f__equiv_typedef);
3944

4045
#ifdef __cplusplus
4146
}

src/builtins.c

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,188 @@ JL_CALLABLE(jl_f_arrayset)
11811181
return args[1];
11821182
}
11831183

1184+
// type definition ------------------------------------------------------------
1185+
1186+
JL_CALLABLE(jl_f__structtype)
1187+
{
1188+
JL_NARGS(_structtype, 6, 6);
1189+
JL_TYPECHK(_structtype, module, args[0]);
1190+
JL_TYPECHK(_structtype, symbol, args[1]);
1191+
JL_TYPECHK(_structtype, simplevector, args[2]);
1192+
JL_TYPECHK(_structtype, simplevector, args[3]);
1193+
JL_TYPECHK(_structtype, bool, args[4]);
1194+
JL_TYPECHK(_structtype, long, args[5]);
1195+
jl_value_t *fieldnames = args[3];
1196+
jl_datatype_t *dt = NULL;
1197+
dt = jl_new_datatype((jl_sym_t*)args[1], (jl_module_t*)args[0], NULL, (jl_svec_t*)args[2],
1198+
(jl_svec_t*)fieldnames, NULL,
1199+
0, args[4]==jl_true ? 1 : 0, jl_unbox_long(args[5]));
1200+
return dt->name->wrapper;
1201+
}
1202+
1203+
JL_CALLABLE(jl_f__abstracttype)
1204+
{
1205+
JL_NARGS(_abstracttype, 3, 3);
1206+
JL_TYPECHK(_abstracttype, module, args[0]);
1207+
JL_TYPECHK(_abstracttype, symbol, args[1]);
1208+
JL_TYPECHK(_abstracttype, simplevector, args[2]);
1209+
jl_datatype_t *dt = jl_new_abstracttype(args[1], (jl_module_t*)args[0], NULL, (jl_svec_t*)args[2]);
1210+
return dt->name->wrapper;
1211+
}
1212+
1213+
JL_CALLABLE(jl_f__primitivetype)
1214+
{
1215+
JL_NARGS(_primitivetype, 4, 4);
1216+
JL_TYPECHK(_primitivetype, module, args[0]);
1217+
JL_TYPECHK(_primitivetype, symbol, args[1]);
1218+
JL_TYPECHK(_primitivetype, simplevector, args[2]);
1219+
jl_sym_t *name = (jl_sym_t*)args[1];
1220+
jl_value_t *vnb = args[3];
1221+
if (!jl_is_long(vnb))
1222+
jl_errorf("invalid declaration of primitive type %s",
1223+
jl_symbol_name((jl_sym_t*)name));
1224+
ssize_t nb = jl_unbox_long(vnb);
1225+
if (nb < 1 || nb >= (1 << 23) || (nb & 7) != 0)
1226+
jl_errorf("invalid number of bits in primitive type %s",
1227+
jl_symbol_name((jl_sym_t*)name));
1228+
jl_datatype_t *dt = jl_new_primitivetype(args[1], (jl_module_t*)args[0], NULL, (jl_svec_t*)args[2], nb);
1229+
return dt->name->wrapper;
1230+
}
1231+
1232+
void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super)
1233+
{
1234+
if (!jl_is_datatype(super) || !jl_is_abstracttype(super) ||
1235+
tt->super != NULL ||
1236+
tt->name == ((jl_datatype_t*)super)->name ||
1237+
jl_subtype(super, (jl_value_t*)jl_vararg_type) ||
1238+
jl_is_tuple_type(super) ||
1239+
jl_is_namedtuple_type(super) ||
1240+
jl_subtype(super, (jl_value_t*)jl_type_type) ||
1241+
jl_subtype(super, (jl_value_t*)jl_builtin_type)) {
1242+
jl_errorf("invalid subtyping in definition of %s",
1243+
jl_symbol_name(tt->name->name));
1244+
}
1245+
tt->super = (jl_datatype_t*)super;
1246+
jl_gc_wb(tt, tt->super);
1247+
}
1248+
1249+
JL_CALLABLE(jl_f__setsuper)
1250+
{
1251+
JL_NARGS(_setsuper!, 2, 2);
1252+
jl_datatype_t *dt = (jl_datatype_t*)jl_unwrap_unionall(args[0]);
1253+
JL_TYPECHK(_setsuper!, datatype, (jl_value_t*)dt);
1254+
jl_set_datatype_super(dt, args[1]);
1255+
return jl_nothing;
1256+
}
1257+
1258+
void jl_reinstantiate_inner_types(jl_datatype_t *t);
1259+
1260+
JL_CALLABLE(jl_f__typebody)
1261+
{
1262+
JL_NARGS(_typebody!, 1, 2);
1263+
jl_datatype_t *dt = (jl_datatype_t*)jl_unwrap_unionall(args[0]);
1264+
JL_TYPECHK(_typebody!, datatype, (jl_value_t*)dt);
1265+
if (nargs == 2) {
1266+
jl_value_t *ft = args[1];
1267+
JL_TYPECHK(_typebody!, simplevector, ft);
1268+
dt->types = (jl_svec_t*)ft;
1269+
jl_gc_wb(dt, ft);
1270+
for (size_t i = 0; i < jl_svec_len(dt->types); i++) {
1271+
jl_value_t *elt = jl_svecref(dt->types, i);
1272+
if ((!jl_is_type(elt) && !jl_is_typevar(elt)) || jl_is_vararg_type(elt)) {
1273+
jl_type_error_rt(jl_symbol_name(dt->name->name),
1274+
"type definition",
1275+
(jl_value_t*)jl_type_type, elt);
1276+
}
1277+
}
1278+
}
1279+
1280+
JL_TRY {
1281+
jl_reinstantiate_inner_types(dt);
1282+
}
1283+
JL_CATCH {
1284+
dt->name->partial = NULL;
1285+
jl_rethrow();
1286+
}
1287+
1288+
if (jl_is_structtype(dt))
1289+
jl_compute_field_offsets(dt);
1290+
return jl_nothing;
1291+
}
1292+
1293+
// this is a heuristic for allowing "redefining" a type to something identical
1294+
static int equiv_type(jl_value_t *ta, jl_value_t *tb)
1295+
{
1296+
jl_datatype_t *dta = (jl_datatype_t*)jl_unwrap_unionall(ta);
1297+
if (!jl_is_datatype(dta))
1298+
return 0;
1299+
jl_datatype_t *dtb = (jl_datatype_t*)jl_unwrap_unionall(tb);
1300+
if (!(jl_typeof(dta) == jl_typeof(dtb) &&
1301+
dta->name->name == dtb->name->name &&
1302+
dta->abstract == dtb->abstract &&
1303+
dta->mutabl == dtb->mutabl &&
1304+
dta->size == dtb->size &&
1305+
dta->ninitialized == dtb->ninitialized &&
1306+
jl_egal((jl_value_t*)jl_field_names(dta), (jl_value_t*)jl_field_names(dtb)) &&
1307+
jl_nparams(dta) == jl_nparams(dtb) &&
1308+
jl_svec_len(dta->types) == jl_svec_len(dtb->types)))
1309+
return 0;
1310+
jl_value_t *a=NULL, *b=NULL;
1311+
int ok = 1;
1312+
size_t i, nf = jl_svec_len(dta->types);
1313+
JL_GC_PUSH2(&a, &b);
1314+
a = jl_rewrap_unionall((jl_value_t*)dta->super, dta->name->wrapper);
1315+
b = jl_rewrap_unionall((jl_value_t*)dtb->super, dtb->name->wrapper);
1316+
if (!jl_types_equal(a, b))
1317+
goto no;
1318+
JL_TRY {
1319+
a = jl_apply_type(dtb->name->wrapper, jl_svec_data(dta->parameters), jl_nparams(dta));
1320+
}
1321+
JL_CATCH {
1322+
ok = 0;
1323+
}
1324+
if (!ok)
1325+
goto no;
1326+
assert(jl_is_datatype(a));
1327+
a = dta->name->wrapper;
1328+
b = dtb->name->wrapper;
1329+
while (jl_is_unionall(a)) {
1330+
jl_unionall_t *ua = (jl_unionall_t*)a;
1331+
jl_unionall_t *ub = (jl_unionall_t*)b;
1332+
if (!jl_egal(ua->var->lb, ub->var->lb) || !jl_egal(ua->var->ub, ub->var->ub) ||
1333+
ua->var->name != ub->var->name)
1334+
goto no;
1335+
a = jl_instantiate_unionall(ua, (jl_value_t*)ub->var);
1336+
b = ub->body;
1337+
}
1338+
assert(jl_is_datatype(a) && jl_is_datatype(b));
1339+
a = (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)a);
1340+
b = (jl_value_t*)jl_get_fieldtypes((jl_datatype_t*)b);
1341+
for (i = 0; i < nf; i++) {
1342+
jl_value_t *ta = jl_svecref(a, i);
1343+
jl_value_t *tb = jl_svecref(b, i);
1344+
if (jl_has_free_typevars(ta)) {
1345+
if (!jl_has_free_typevars(tb) || !jl_egal(ta, tb))
1346+
goto no;
1347+
}
1348+
else if (jl_has_free_typevars(tb) || jl_typeof(ta) != jl_typeof(tb) ||
1349+
!jl_types_equal(ta, tb)) {
1350+
goto no;
1351+
}
1352+
}
1353+
JL_GC_POP();
1354+
return 1;
1355+
no:
1356+
JL_GC_POP();
1357+
return 0;
1358+
}
1359+
1360+
JL_CALLABLE(jl_f__equiv_typedef)
1361+
{
1362+
JL_NARGS(_equiv_typedef, 2, 2);
1363+
return equiv_type(args[0], args[1]) ? jl_true : jl_false;
1364+
}
1365+
11841366
// IntrinsicFunctions ---------------------------------------------------------
11851367

11861368
static void (*runtime_fp[num_intrinsics])(void);
@@ -1343,6 +1525,12 @@ void jl_init_primitives(void) JL_GC_DISABLED
13431525
add_builtin_func("_apply_pure", jl_f__apply_pure);
13441526
add_builtin_func("_apply_latest", jl_f__apply_latest);
13451527
add_builtin_func("_typevar", jl_f__typevar);
1528+
add_builtin_func("_structtype", jl_f__structtype);
1529+
add_builtin_func("_abstracttype", jl_f__abstracttype);
1530+
add_builtin_func("_primitivetype", jl_f__primitivetype);
1531+
add_builtin_func("_setsuper!", jl_f__setsuper);
1532+
jl_builtin__typebody = add_builtin_func("_typebody!", jl_f__typebody);
1533+
add_builtin_func("_equiv_typedef", jl_f__equiv_typedef);
13461534

13471535
// builtin types
13481536
add_builtin("Any", (jl_value_t*)jl_any_type);

src/codegen.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3855,14 +3855,8 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval)
38553855
ctx.builder.CreateCall(prepare_call(jltopeval_func), args);
38563856
return ghostValue(jl_nothing_type);
38573857
}
3858-
if (head == abstracttype_sym || head == structtype_sym ||
3859-
head == primtype_sym) {
3860-
jl_errorf("type definition not allowed inside a local scope");
3861-
}
3862-
else {
3863-
jl_errorf("unsupported or misplaced expression \"%s\" in function %s",
3864-
jl_symbol_name(head), ctx.name);
3865-
}
3858+
jl_errorf("unsupported or misplaced expression \"%s\" in function %s",
3859+
jl_symbol_name(head), ctx.name);
38663860
}
38673861
return jl_cgval_t();
38683862
}

src/datatype.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu
7373
tn->names = NULL;
7474
tn->hash = bitmix(bitmix(module ? module->build_id : 0, name->hash), 0xa1ada1da);
7575
tn->mt = NULL;
76+
tn->partial = NULL;
7677
return tn;
7778
}
7879

src/dump.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2022,6 +2022,7 @@ static jl_value_t *jl_deserialize_value_any(jl_serializer_state *s, uint8_t tag,
20222022
memset(tn, 0, sizeof(jl_typename_t));
20232023
tn->cache = jl_emptysvec; // the cache is refilled later (tag 5)
20242024
tn->linearcache = jl_emptysvec; // the cache is refilled later (tag 5)
2025+
tn->partial = NULL;
20252026
if (usetable)
20262027
backref_list.items[pos] = tn;
20272028
}

src/gc.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2684,8 +2684,6 @@ static void mark_roots(jl_gc_mark_cache_t *gc_cache, jl_gc_mark_sp_t *sp)
26842684
// constants
26852685
gc_mark_queue_obj(gc_cache, sp, jl_typetype_type);
26862686
gc_mark_queue_obj(gc_cache, sp, jl_emptytuple_type);
2687-
2688-
gc_mark_queue_finlist(gc_cache, sp, &partial_inst, 0);
26892687
}
26902688

26912689
// find unmarked objects that need to be finalized from the finalizer list "list".

src/init.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,6 @@ void _julia_init(JL_IMAGE_SEARCH rel)
719719
if (jl_options.cpu_target == NULL)
720720
jl_options.cpu_target = "native";
721721

722-
arraylist_new(&partial_inst, 0);
723722
if (jl_options.image_file) {
724723
jl_restore_system_image(jl_options.image_file);
725724
}

0 commit comments

Comments
 (0)