Skip to content

Commit

Permalink
More placeholder WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Keno committed Jul 22, 2019
1 parent 8d4a91e commit 2dda80d
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 13 deletions.
4 changes: 3 additions & 1 deletion src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,9 @@ static int valid_type_param(jl_value_t *v)
if (jl_is_vararg_type(v))
return 0;
// TODO: maybe more things
return jl_is_type(v) || jl_is_typevar(v) || jl_is_symbol(v) || jl_isbits(jl_typeof(v));
return jl_is_type(v) || jl_is_typevar(v) ||
jl_is_symbol(v) || jl_isbits(jl_typeof(v)) ||
jl_typeis(v, jl_placeholder_type);
}

JL_CALLABLE(jl_f_apply_type)
Expand Down
7 changes: 7 additions & 0 deletions src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,13 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype(
t->name->names = fnames;
jl_gc_wb(t->name, t->name->names);

for (int i = 0; i < jl_svec_len(t->parameters); ++i) {
jl_value_t *p = jl_svecref(t->parameters, i);
if (jl_typeis(p, jl_placeholder_type)) {
dt_mark_incomplete(t, (jl_placeholder_t*)p);
}
}

if (t->name->wrapper == NULL) {
t->name->wrapper = (jl_value_t*)t;
jl_gc_wb(t->name, t);
Expand Down
30 changes: 23 additions & 7 deletions src/interpreter.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ SECT_INTERP static int equiv_type(jl_datatype_t *dta, jl_datatype_t *dtb)

SECT_INTERP static void check_can_assign_type(jl_binding_t *b, jl_value_t *rhs)
{
if (b->constp && b->value != NULL && jl_typeof(b->value) != jl_typeof(rhs))
if (b->constp && b->value != NULL && jl_typeof(b->value) != jl_typeof(rhs) &&
!jl_typeis(b->value, jl_placeholder_type))
jl_errorf("invalid redefinition of constant %s",
jl_symbol_name(b->name));
}
Expand Down Expand Up @@ -363,16 +364,35 @@ static jl_array_t *find_new_cycle(jl_datatype_t *scc_a, jl_datatype_t *scc_b) JL
}
}

static void dt_mark_incomplete(jl_datatype_t *dt)
extern jl_array_t *jl_all_methods;
void dt_mark_incomplete(jl_datatype_t *dt, jl_value_t *v)
{
// While we don't have GC hooked up, just push these into a global root;
if (jl_all_methods == NULL)
jl_all_methods = jl_alloc_vec_any(0);
if (dt->incomplete == 0) {
dt->scc = dt;
dt->depends = jl_alloc_vec_any(0);
jl_array_ptr_1d_push(jl_all_methods, (jl_value_t*)dt->depends);
dt->dependents = jl_alloc_vec_any(0);
jl_array_ptr_1d_push(jl_all_methods, (jl_value_t*)dt->dependents);
}
if (jl_typeis(v, jl_placeholder_type)) {
jl_array_ptr_1d_push(
((jl_placeholder_t*)v)->dependents,
(jl_value_t*)dt);
jl_array_ptr_1d_push(dt->depends, v);
} else if (jl_is_datatype(v)) {
assert(((jl_datatype_t*)v)->incomplete);
jl_array_ptr_1d_push(
((jl_datatype_t*)v)->dependents,
(jl_value_t*)dt);
jl_array_ptr_1d_push(dt->depends, v);
}
dt->incomplete = 1;
}


static void eval_structtype(jl_expr_t *ex, interpreter_state *s)
{
jl_value_t **args = jl_array_ptr_data(ex->args);
Expand Down Expand Up @@ -415,11 +435,7 @@ static void eval_structtype(jl_expr_t *ex, interpreter_state *s)
for (size_t i = 0; i < jl_svec_len(dt->types); i++) {
jl_value_t *elt = jl_svecref(dt->types, i);
if (jl_typeis(elt, jl_placeholder_type)) {
jl_array_ptr_1d_push(
((jl_placeholder_t*)elt)->dependents,
(jl_value_t*)dt);
dt_mark_incomplete(dt);
jl_array_ptr_1d_push(dt->depends, elt);
dt_mark_incomplete(dt, elt);
} else if ((!jl_is_type(elt) && !jl_is_typevar(elt)) || jl_is_vararg_type(elt)) {
jl_type_error_rt(jl_symbol_name(dt->name->name),
"type definition",
Expand Down
18 changes: 18 additions & 0 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,24 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value
jl_compute_field_offsets(ndt);
}

for (int i = 0; ndt->types && i < jl_svec_len(ndt->types); ++i) {
jl_value_t *v = jl_svecref(ndt->types, i);
if (jl_typeis(v, jl_placeholder_type)) {
dt_mark_incomplete(ndt, v);
} else if (jl_is_datatype(v) && ((jl_datatype_t*)v)->incomplete) {
dt_mark_incomplete(ndt, v);
}
}

for (int i = 0; ndt->parameters && i < jl_svec_len(ndt->parameters); ++i) {
jl_value_t *p = jl_svecref(ndt->parameters, i);
if (jl_typeis(p, jl_placeholder_type)) {
dt_mark_incomplete(ndt, p);
} else if (jl_is_datatype(p) && ((jl_datatype_t*)p)->incomplete) {
dt_mark_incomplete(ndt, p);
}
}

if (istuple)
ndt->ninitialized = ntp - isvatuple;
else if (isnamedtuple)
Expand Down
15 changes: 13 additions & 2 deletions src/method.c
Original file line number Diff line number Diff line change
Expand Up @@ -739,9 +739,13 @@ JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata,
m->line);
}

int any_argtypes_incomplete = 0;
for (i = 0; i < na; i++) {
jl_value_t *elt = jl_svecref(atypes, i);
if (!jl_is_type(elt) && !jl_is_typevar(elt)) {
if (jl_typeis(elt, jl_placeholder_type) ||
(jl_is_datatype(elt) && ((jl_datatype_t*)elt)->incomplete)) {
any_argtypes_incomplete = 1;
} else if (!jl_is_type(elt) && !jl_is_typevar(elt)) {
jl_sym_t *argname = (jl_sym_t*)jl_array_ptr_ref(f->slotnames, i);
if (argname == unused_sym)
jl_exceptionf(jl_argumenterror_type,
Expand Down Expand Up @@ -776,7 +780,14 @@ JL_DLLEXPORT void jl_method_def(jl_svec_t *argdata,
jl_array_ptr_1d_push(jl_all_methods, (jl_value_t*)m);
}

jl_method_table_insert(mt, m, NULL);
if (any_argtypes_incomplete) {
if (jl_all_methods == NULL)
jl_all_methods = jl_alloc_vec_any(0);
jl_svec_t *d = jl_svec(2, mt, m);
arraylist_push(&module->deferred, d);
jl_array_ptr_1d_push(jl_all_methods, (jl_value_t*)d);
} else
jl_method_table_insert(mt, m, NULL);
if (jl_newmeth_tracer)
jl_call_tracer(jl_newmeth_tracer, (jl_value_t*)m);
JL_GC_POP();
Expand Down
70 changes: 69 additions & 1 deletion src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -683,10 +683,74 @@ void jl_binding_deprecation_warning(jl_module_t *m, jl_binding_t *b)
}
}

static int is_any_incomplete(jl_value_t *v)
{
return jl_typeis(v, jl_placeholder_type) ||
(jl_is_datatype(v) && ((jl_datatype_t*)v)->incomplete);
}

static void complete_dt(jl_datatype_t *dt);
static void fixup_dependent_dt(jl_datatype_t *dt, jl_value_t *to_replace, jl_value_t *replacement)
{
assert(dt->incomplete);
int incomplete_remains = is_any_incomplete(replacement);
for (int j = 0; j < jl_svec_len(dt->types); ++j) {
jl_value_t *t = jl_svecref(dt->types, j);
if (t == (jl_value_t*)to_replace)
jl_svecset(dt->types, j, replacement);
else if (!incomplete_remains && is_any_incomplete(t))
incomplete_remains = 1;
}
for (int j = 0; j < jl_svec_len(dt->parameters); ++j) {
jl_value_t *t = jl_svecref(dt->parameters, j);
if (t == (jl_value_t*)to_replace)
jl_svecset(dt->parameters, j, replacement);
else if (!incomplete_remains && is_any_incomplete(t))
incomplete_remains = 1;
}
if (!incomplete_remains) {
complete_dt(dt);
}
}

static void complete_dt(jl_datatype_t *dt) {
dt->incomplete = 0;
jl_precompute_memoized_dt(dt);
jl_compute_field_offsets(dt);
for (int i = 0; i < jl_array_len(dt->dependents); ++i) {
jl_value_t *v = jl_array_ptr_ref(dt->dependents, i);
if (jl_is_datatype(v) && ((jl_datatype_t*)v)->incomplete) {
fixup_dependent_dt((jl_datatype_t*)v, (jl_value_t*)dt, (jl_value_t*)dt);
}
}
if (jl_is_tuple_type(dt)) {
jl_module_t *mod = jl_main_module;
for (size_t i = 0; i < mod->deferred.len; ++i) {
jl_svec_t *item = (jl_svec_t*)mod->deferred.items[i];
jl_method_t *m = (jl_method_t*)jl_svecref(item, 1);
if ((jl_datatype_t*)jl_unwrap_unionall(m->sig) == dt) {
jl_method_table_insert(
(jl_methtable_t*)jl_svecref(item, 0), m, NULL);
}
}
}
}

static void resolve_placeholder(jl_placeholder_t *ph, jl_value_t *val)
{
for (int i = 0; i < jl_array_len(ph->dependents); ++i) {
jl_value_t *v = jl_array_ptr_ref(ph->dependents, i);
if (jl_is_datatype(v) && ((jl_datatype_t*)v)->incomplete) {
fixup_dependent_dt((jl_datatype_t*)v, (jl_value_t*) ph, val);
}
}
}

JL_DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs)
{
if (b->constp && b->value != NULL) {
if (!jl_egal(rhs, b->value)) {
if (!jl_typeis(b->value, jl_placeholder_type) &&
!jl_egal(rhs, b->value)) {
if (jl_typeof(rhs) != jl_typeof(b->value) ||
jl_is_type(rhs) /*|| jl_is_function(rhs)*/ || jl_is_module(rhs)) {
jl_errorf("invalid redefinition of constant %s",
Expand All @@ -696,8 +760,12 @@ JL_DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs)
jl_symbol_name(b->name));
}
}
jl_value_t *val = b->value;
b->value = rhs;
jl_gc_wb_binding(b, rhs);
if (val && jl_typeis(val, jl_placeholder_type)) {
resolve_placeholder((jl_placeholder_t*)val, rhs);
}
}

JL_DLLEXPORT void jl_declare_constant(jl_binding_t *b)
Expand Down
4 changes: 2 additions & 2 deletions src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,9 @@ static void jl_write_module(jl_serializer_state *s, uintptr_t item, jl_module_t

// The deferred list should be empty
memset(&newm->deferred._space, 0, sizeof(newm->deferred._space));
newm->deferred.len = 1;
newm->deferred.len = 0;
newm->deferred.max = AL_N_INLINE;
newm->deferred.items = (void**)offsetof(jl_module_t, usings._space);
newm->deferred.items = (void**)offsetof(jl_module_t, deferred._space);
arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, deferred.items)));
arraylist_push(&s->relocs_list, (void*)(((uintptr_t)DataRef << RELOC_TAG_OFFSET) + item));

Expand Down
33 changes: 33 additions & 0 deletions test/incomplete.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Test

macro placeholder(sym)
:(const $(esc(sym)) = $(Expr(:new, Core.Placeholder, :(Any[]))))
end

@placeholder Bar1
struct Foo1
x::Bar1
end
@test length(methods(Foo1)) == 0
@test Foo1.incomplete
struct Bar1
x::Foo1
end
@test length(methods(Bar1)) == 2
@test length(methods(Foo1)) == 2


@placeholder Bar2
@placeholder Baz2
struct Foo2
x::Bar2
y::Baz2
end
@test Foo2.incomplete
struct Bar2
x::Foo2
end
@test length(methods(Bar2)) == 0
@test Bar2.incomplete
struct Baz2; end
@test !Foo2.incomplete && !Bar2.incomplete

0 comments on commit 2dda80d

Please sign in to comment.