Skip to content

Commit

Permalink
typeintersect: fuse savedenv for adjacent subtype_in_env
Browse files Browse the repository at this point in the history
  • Loading branch information
N5N3 committed Jun 9, 2024
1 parent 05255ae commit 843e403
Showing 1 changed file with 57 additions and 27 deletions.
84 changes: 57 additions & 27 deletions src/subtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -1513,7 +1513,7 @@ static int is_definite_length_tuple_type(jl_value_t *x)
return k == JL_VARARG_NONE || k == JL_VARARG_INT;
}

static int _forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param, int *count, int *noRmore);
static int _forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param, int *count, int *noRmore, jl_savedenv_t *saved, int allow_resave);

static int may_contain_union_decision(jl_value_t *x, jl_stenv_t *e, jl_typeenv_t *log) JL_NOTSAFEPOINT
{
Expand Down Expand Up @@ -1580,7 +1580,7 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t
e->Lunions.depth = e->Runions.depth = 0;
e->Lunions.more = e->Runions.more = 0;
int count = 0, noRmore = 0;
sub = _forall_exists_subtype(x, y, e, param, &count, &noRmore);
sub = _forall_exists_subtype(x, y, e, param, &count, &noRmore, NULL, 0);
pop_unionstate(&e->Runions, &oldRunions);
// We could skip the slow path safely if
// 1) `_∀_∃_subtype` has tested all cases
Expand Down Expand Up @@ -1677,36 +1677,47 @@ static int exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_savede
}
}

static int _forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param, int *count, int *noRmore)
static int _forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param, int *count, int *noRmore, jl_savedenv_t *saved, int resave)
{
// The depth recursion has the following shape, after simplification:
// ∀₁
// ∃₁
assert(e->Runions.depth == 0);
assert(e->Lunions.depth == 0);
jl_savedenv_t se;
save_env(e, &se, 1);
assert(!resave || saved);
jl_savedenv_t nse;
jl_savedenv_t *se = saved;
if (se == NULL) {
se = &nse;
alloc_env(e, se, 1);
}
if (resave || se == &nse)
re_save_env(e, se, 1);

e->Lunions.used = 0;
int sub;
if (count) *count = 0;
if (noRmore) *noRmore = 1;
while (1) {
sub = exists_subtype(x, y, e, &se, param);
sub = exists_subtype(x, y, e, se, param);
if (count) *count = (*count < 4) ? *count + 1 : 4;
if (noRmore) *noRmore = *noRmore && e->Runions.more == 0;
if (!sub || !next_union_state(e, 0))
break;
re_save_env(e, &se, 1);
if (se == saved && !resave) {
se = &nse;
alloc_env(e, se, 1);
}
re_save_env(e, se, 1);
}

free_env(&se);
if (se != saved)
free_env(se);
return sub;
}

static int forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param)
{
return _forall_exists_subtype(x, y, e, param, NULL, NULL);
return _forall_exists_subtype(x, y, e, param, NULL, NULL, NULL, 0);
}

static void init_stenv(jl_stenv_t *e, jl_value_t **env, int envsz)
Expand Down Expand Up @@ -2175,7 +2186,7 @@ JL_DLLEXPORT int jl_subtype_env(jl_value_t *x, jl_value_t *y, jl_value_t **env,
return subtype;
}

static int subtype_in_env(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
static int subtype_in_env(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_savedenv_t *se, int resave)
{
jl_stenv_t e2;
init_stenv(&e2, NULL, 0);
Expand All @@ -2187,7 +2198,7 @@ static int subtype_in_env(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
e2.envout = e->envout;
e2.envidx = e->envidx;
e2.Loffset = e->Loffset;
return forall_exists_subtype(x, y, &e2, 0);
return _forall_exists_subtype(x, y, &e2, 0, NULL, NULL, se, resave);
}

JL_DLLEXPORT int jl_subtype(jl_value_t *x, jl_value_t *y)
Expand Down Expand Up @@ -2563,7 +2574,7 @@ static int try_subtype_in_env(jl_value_t *a, jl_value_t *b, jl_stenv_t *e)
return 1;
jl_savedenv_t se;
save_env(e, &se, 1);
int ret = subtype_in_env(a, b, e);
int ret = subtype_in_env(a, b, e, &se, 0);
restore_env(e, &se, 1);
free_env(&se);
return ret;
Expand All @@ -2584,7 +2595,7 @@ static void set_bound(jl_value_t **bound, jl_value_t *val, jl_tvar_t *v, jl_sten
}

// subtype, treating all vars as existential
static int subtype_in_env_existential(jl_value_t *x, jl_value_t *y, jl_stenv_t *e)
static int subtype_in_env_existential(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, jl_savedenv_t *se, int resave)
{
jl_varbinding_t *v = e->vars;
int len = 0;
Expand All @@ -2603,7 +2614,7 @@ static int subtype_in_env_existential(jl_value_t *x, jl_value_t *y, jl_stenv_t *
v->right = 1;
v = v->prev;
}
int issub = subtype_in_env(x, y, e);
int issub = subtype_in_env(x, y, e, se, resave);
n = 0; v = e->vars;
while (n < len) {
assert(v != NULL);
Expand Down Expand Up @@ -2669,18 +2680,23 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int
return R ? intersect(a, bb->lb, e, param) : intersect(bb->lb, a, e, param);
if (!jl_is_type(a) && !jl_is_typevar(a))
return set_var_to_const(bb, a, e, R);
jl_savedenv_t se;
if (param == 2) {
jl_savedenv_t se, se2;
jl_value_t *ub = NULL;
JL_GC_PUSH1(&ub);
if (!jl_has_free_typevars(a)) {
int tryfuse = may_contain_union_decision(bb->lb, e, NULL) || may_contain_union_decision(a, e, NULL);
save_env(e, &se, 1);
int issub = subtype_in_env_existential(bb->lb, a, e);
if (tryfuse)
alloc_env(e, &se2, 1);
int issub = subtype_in_env_existential(bb->lb, a, e, tryfuse ? &se2 : &se, tryfuse);
restore_env(e, &se, 1);
if (issub) {
issub = subtype_in_env_existential(a, bb->ub, e);
issub = subtype_in_env_existential(a, bb->ub, e, tryfuse ? &se2 : &se, tryfuse);
restore_env(e, &se, 1);
}
if (tryfuse)
free_env(&se2);
free_env(&se);
if (!issub) {
JL_GC_POP();
Expand All @@ -2693,7 +2709,7 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int
ub = R ? intersect_aside(a, bb->ub, e, bb->depth0) : intersect_aside(bb->ub, a, e, bb->depth0);
e->triangular--;
save_env(e, &se, 1);
int issub = subtype_in_env_existential(bb->lb, ub, e);
int issub = subtype_in_env_existential(bb->lb, ub, e, &se, 0);
restore_env(e, &se, 1);
free_env(&se);
if (!issub) {
Expand Down Expand Up @@ -3684,29 +3700,40 @@ static jl_value_t *intersect_invariant(jl_value_t *x, jl_value_t *y, jl_stenv_t
if (jl_is_typevar(x) && jl_is_typevar(y) && jl_is_typevar(ii))
return ii; // skip the following check due to possible circular constraints.
if (ii == jl_bottom_type) {
if (!subtype_in_env(x, jl_bottom_type, e))
jl_savedenv_t se;
alloc_env(e, &se, 1);
if (!subtype_in_env(x, jl_bottom_type, e, &se, 1)) {
free_env(&se);
return NULL;
}
flip_vars(e); flip_offset(e);
if (!subtype_in_env(y, jl_bottom_type, e)) {
if (!subtype_in_env(y, jl_bottom_type, e, &se, 1)) {
flip_vars(e); flip_offset(e);
free_env(&se);
return NULL;
}
flip_vars(e); flip_offset(e);
free_env(&se);
return jl_bottom_type;
}
jl_savedenv_t se;
jl_savedenv_t se, se2;
int tryfuse = may_contain_union_decision(x, e, NULL) || may_contain_union_decision(y, e, NULL);
JL_GC_PUSH1(&ii);
save_env(e, &se, 1);
if (!subtype_in_env_existential(x, y, e))
if (tryfuse)
alloc_env(e, &se2, 1);
if (!subtype_in_env_existential(x, y, e, tryfuse ? &se2 : &se, tryfuse))
ii = NULL;
else {
restore_env(e, &se, 1);
flip_offset(e);
if (!subtype_in_env_existential(y, x, e))
if (!subtype_in_env_existential(y, x, e, tryfuse ? &se2 : &se, tryfuse))
ii = NULL;
flip_offset(e);
}
restore_env(e, &se, 1);
if (tryfuse)
free_env(&se2);
free_env(&se);
JL_GC_POP();
return ii;
Expand Down Expand Up @@ -3810,7 +3837,7 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa
if (xx && yy && xx->depth0 != yy->depth0) {
record_var_occurrence(xx, e, param);
record_var_occurrence(yy, e, param);
return subtype_in_env(yy->ub, yy->lb, e) ? y : jl_bottom_type;
return subtype_in_env(yy->ub, yy->lb, e, NULL, 0) ? y : jl_bottom_type;
}
if (xub == xlb && jl_is_typevar(xub)) {
record_var_occurrence(xx, e, param);
Expand Down Expand Up @@ -3896,14 +3923,17 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa
ccheck = 1;
}
else {
jl_savedenv_t se;
alloc_env(e, &se, 1);
if (R) flip_vars(e);
ccheck = subtype_in_env(xlb, yub, e);
ccheck = subtype_in_env(xlb, yub, e, &se, 1);
if (ccheck) {
flip_offset(e);
ccheck = subtype_in_env(ylb, xub, e);
ccheck = subtype_in_env(ylb, xub, e, &se, 1);
flip_offset(e);
}
if (R) flip_vars(e);
free_env(&se);
}
if (R) flip_offset(e);
if (!ccheck)
Expand Down

0 comments on commit 843e403

Please sign in to comment.