-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mutually recursive field types, the easy version #32658
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -428,6 +428,11 @@ function isprimitivetype(@nospecialize(t::Type)) | |
return !hasfield && t.size != 0 && !t.abstract | ||
end | ||
|
||
struct IncompleteTypeException | ||
dt::DataType | ||
end | ||
must_be_complete(t::DataType) = (t.incomplete && throw(IncompleteTypeException(t)); t) | ||
|
||
""" | ||
isbitstype(T) | ||
|
||
|
@@ -449,14 +454,14 @@ julia> isbitstype(Complex) | |
false | ||
``` | ||
""" | ||
isbitstype(@nospecialize(t::Type)) = (@_pure_meta; isa(t, DataType) && t.isbitstype) | ||
isbitstype(@nospecialize(t::Type)) = (@_pure_meta; isa(t, DataType) && must_be_complete(t).isbitstype) | ||
|
||
""" | ||
isbits(x) | ||
|
||
Return `true` if `x` is an instance of an `isbitstype` type. | ||
""" | ||
isbits(@nospecialize x) = (@_pure_meta; typeof(x).isbitstype) | ||
isbits(@nospecialize x) = typeof(x).isbitstype | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inference can do this now? yay! but still, this might have performance implications as we may now infer and store a much larger set of methods. but also, seems unrelated? |
||
|
||
""" | ||
isdispatchtuple(T) | ||
|
@@ -465,7 +470,7 @@ Determine whether type `T` is a tuple "leaf type", | |
meaning it could appear as a type signature in dispatch | ||
and has no subtypes (or supertypes) which could appear in a call. | ||
""" | ||
isdispatchtuple(@nospecialize(t)) = (@_pure_meta; isa(t, DataType) && t.isdispatchtuple) | ||
isdispatchtuple(@nospecialize(t)) = (@_pure_meta; isa(t, DataType) && must_be_complete(t).isdispatchtuple) | ||
|
||
iskindtype(@nospecialize t) = (t === DataType || t === UnionAll || t === Union || t === typeof(Bottom)) | ||
isconcretedispatch(@nospecialize t) = isconcretetype(t) && !iskindtype(t) | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -794,6 +794,8 @@ static jl_value_t *get_fieldtype(jl_value_t *t, jl_value_t *f, int dothrow) | |||||
if (!jl_is_datatype(t)) | ||||||
jl_type_error("fieldtype", (jl_value_t*)jl_datatype_type, t); | ||||||
jl_datatype_t *st = (jl_datatype_t*)t; | ||||||
if (st->incomplete) | ||||||
jl_error("Type is incomplete"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
(or something even longer and clearer) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe: |
||||||
int field_index; | ||||||
if (jl_is_long(f)) { | ||||||
field_index = jl_unbox_long(f) - 1; | ||||||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -166,6 +166,82 @@ static void eval_abstracttype(jl_expr_t *ex, interpreter_state *s) | |||||||
if (temp == NULL || !equiv_type(dt, (jl_datatype_t*)jl_unwrap_unionall(temp))) { | ||||||||
jl_checked_assignment(b, w); | ||||||||
} | ||||||||
dt->incomplete = 0; | ||||||||
JL_GC_POP(); | ||||||||
} | ||||||||
|
||||||||
static void check_type_completion(jl_datatype_t *bdt, jl_value_t *super, jl_value_t *para) | ||||||||
{ | ||||||||
// Check that supertype matches | ||||||||
if (!jl_types_equal((jl_value_t*)bdt->super, super)) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIRC, |
||||||||
jl_error("Super type does not match forward declaration"); | ||||||||
// Check that parameters match | ||||||||
if (jl_svec_len(para) != jl_svec_len(bdt->parameters)) { | ||||||||
jl_error("number of type parameters does not match forward declared type"); | ||||||||
} | ||||||||
for (int i = 0; i < jl_svec_len(para); ++i) { | ||||||||
jl_tvar_t *v = (jl_tvar_t*)jl_svecref(para, i); | ||||||||
jl_tvar_t *w = (jl_tvar_t*)jl_svecref(bdt->parameters, i); | ||||||||
assert(jl_is_typevar(v) && jl_is_typevar(w)); | ||||||||
if (v->name != w->name) | ||||||||
jl_errorf("Name `%s` of type parameter does not match name `%s` from forward declaration.", | ||||||||
jl_symbol_name(v->name), jl_symbol_name(w->name)); | ||||||||
else if (!jl_types_equal(v->lb, w->lb) || !jl_types_equal(v->ub, w->ub)) { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Could we pose this whole loop as a simple question to the type-system? |
||||||||
jl_errorf("Bounds of type parameter `%s` do not match forward declaration", | ||||||||
jl_symbol_name(v->name)); | ||||||||
} | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
static void eval_incompletetype(jl_expr_t *ex, interpreter_state *s) | ||||||||
{ | ||||||||
jl_value_t **args = jl_array_ptr_data(ex->args); | ||||||||
if (inside_typedef) | ||||||||
jl_error("cannot eval a new incomplete type definition while defining another type"); | ||||||||
jl_value_t *name = args[0]; | ||||||||
jl_value_t *para = eval_value(args[1], s); | ||||||||
jl_value_t *super = NULL; | ||||||||
jl_value_t *temp = NULL; | ||||||||
jl_datatype_t *dt = NULL; | ||||||||
jl_value_t *w = NULL; | ||||||||
jl_module_t *modu = s->module; | ||||||||
JL_GC_PUSH5(¶, &super, &temp, &w, &dt); | ||||||||
assert(jl_is_svec(para)); | ||||||||
if (jl_is_globalref(name)) { | ||||||||
modu = jl_globalref_mod(name); | ||||||||
name = (jl_value_t*)jl_globalref_name(name); | ||||||||
} | ||||||||
assert(jl_is_symbol(name)); | ||||||||
assert(jl_is_svec(para)); | ||||||||
jl_binding_t *b = jl_get_binding_wr(modu, (jl_sym_t*)name, 1); | ||||||||
if (b->value && jl_is_datatype(jl_unwrap_unionall(b->value))) { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
super = eval_value(args[2], s); | ||||||||
check_type_completion( | ||||||||
(jl_datatype_t*)jl_unwrap_unionall(b->value), super, para); | ||||||||
return; | ||||||||
} | ||||||||
dt = jl_new_datatype((jl_sym_t*)name, modu, (jl_datatype_t*)super, | ||||||||
(jl_svec_t*)para, NULL, NULL, 0, 0, 0); | ||||||||
w = dt->name->wrapper; | ||||||||
temp = b->value; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is NULL or the assignment later will fail, per the check a few lines earlier to ensure the result is guaranteed to be compatible with |
||||||||
check_can_assign_type(b, w); | ||||||||
b->value = w; | ||||||||
jl_gc_wb_binding(b, w); | ||||||||
JL_TRY { | ||||||||
inside_typedef = 1; | ||||||||
super = eval_value(args[2], s); | ||||||||
jl_set_datatype_super(dt, super); | ||||||||
jl_reinstantiate_inner_types(dt); | ||||||||
} | ||||||||
JL_CATCH { | ||||||||
jl_reset_instantiate_inner_types(dt); | ||||||||
b->value = temp; | ||||||||
jl_rethrow(); | ||||||||
} | ||||||||
b->value = temp; | ||||||||
if (temp == NULL || !equiv_type(dt, (jl_datatype_t*)jl_unwrap_unionall(temp))) { | ||||||||
jl_checked_assignment(b, w); | ||||||||
} | ||||||||
JL_GC_POP(); | ||||||||
} | ||||||||
|
||||||||
|
@@ -217,6 +293,7 @@ static void eval_primitivetype(jl_expr_t *ex, interpreter_state *s) | |||||||
if (temp == NULL || !equiv_type(dt, (jl_datatype_t*)jl_unwrap_unionall(temp))) { | ||||||||
jl_checked_assignment(b, w); | ||||||||
} | ||||||||
dt->incomplete = 0; | ||||||||
JL_GC_POP(); | ||||||||
} | ||||||||
|
||||||||
|
@@ -240,12 +317,28 @@ static void eval_structtype(jl_expr_t *ex, interpreter_state *s) | |||||||
assert(jl_is_symbol(name)); | ||||||||
assert(jl_is_svec(para)); | ||||||||
temp = eval_value(args[2], s); // field names | ||||||||
dt = jl_new_datatype((jl_sym_t*)name, modu, NULL, (jl_svec_t*)para, | ||||||||
(jl_svec_t*)temp, NULL, | ||||||||
0, args[5]==jl_true ? 1 : 0, jl_unbox_long(args[6])); | ||||||||
jl_binding_t *b = jl_get_binding_wr(modu, (jl_sym_t*)name, 1); | ||||||||
jl_datatype_t *bdt = NULL; | ||||||||
if (b->value) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
bdt = (jl_datatype_t *)jl_unwrap_unionall(b->value); | ||||||||
if (bdt && | ||||||||
jl_is_datatype(bdt) && | ||||||||
bdt->name->name == (jl_sym_t*)name && | ||||||||
bdt->name->module == modu && | ||||||||
bdt->incomplete) { | ||||||||
super = eval_value(args[3], s); | ||||||||
check_type_completion(bdt, super, para); | ||||||||
dt = bdt; | ||||||||
dt->mutabl = args[5]==jl_true ? 1 : 0; | ||||||||
dt->name->names = (jl_svec_t*)temp; | ||||||||
jl_gc_wb(dt->name, dt->name->names); | ||||||||
} else { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
dt = jl_new_datatype((jl_sym_t*)name, modu, NULL, (jl_svec_t*)para, | ||||||||
(jl_svec_t*)temp, NULL, | ||||||||
0, args[5]==jl_true ? 1 : 0, jl_unbox_long(args[6])); | ||||||||
} | ||||||||
w = dt->name->wrapper; | ||||||||
|
||||||||
jl_binding_t *b = jl_get_binding_wr(modu, (jl_sym_t*)name, 1); | ||||||||
temp = b->value; // save old value | ||||||||
// temporarily assign so binding is available for field types | ||||||||
check_can_assign_type(b, w); | ||||||||
|
@@ -255,8 +348,10 @@ static void eval_structtype(jl_expr_t *ex, interpreter_state *s) | |||||||
JL_TRY { | ||||||||
inside_typedef = 1; | ||||||||
// operations that can fail | ||||||||
super = eval_value(args[3], s); | ||||||||
jl_set_datatype_super(dt, super); | ||||||||
if (!super) { | ||||||||
super = eval_value(args[3], s); | ||||||||
jl_set_datatype_super(dt, super); | ||||||||
} | ||||||||
dt->types = (jl_svec_t*)eval_value(args[4], s); | ||||||||
jl_gc_wb(dt, dt->types); | ||||||||
for (size_t i = 0; i < jl_svec_len(dt->types); i++) { | ||||||||
|
@@ -280,6 +375,7 @@ static void eval_structtype(jl_expr_t *ex, interpreter_state *s) | |||||||
if (temp == NULL || !equiv_type(dt, (jl_datatype_t*)jl_unwrap_unionall(temp))) { | ||||||||
jl_checked_assignment(b, w); | ||||||||
} | ||||||||
dt->incomplete = 0; | ||||||||
|
||||||||
JL_GC_POP(); | ||||||||
} | ||||||||
|
@@ -745,6 +841,9 @@ SECT_INTERP static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s | |||||||
else if (head == structtype_sym) { | ||||||||
eval_structtype((jl_expr_t*)stmt, s); | ||||||||
} | ||||||||
else if (head == incompletetype_sym) { | ||||||||
eval_incompletetype((jl_expr_t*)stmt, s); | ||||||||
} | ||||||||
else if (jl_is_toplevel_only_expr(stmt)) { | ||||||||
jl_toplevel_eval(s->module, stmt); | ||||||||
} | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't seem like this should need a custom type (which should be subtype Exception if it was kept). Just
error("informative message here about ", dt.name.name)