Skip to content

Commit 09076da

Browse files
committed
subtype: Clean up tuple vararg path some more
Now that we no longer need to introduce tvars, we can get rid of the closure env and reorganize the code a bit.
1 parent 2924cb0 commit 09076da

File tree

1 file changed

+112
-120
lines changed

1 file changed

+112
-120
lines changed

src/subtype.c

Lines changed: 112 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -857,10 +857,13 @@ struct subtype_tuple_env {
857857
jl_vararg_kind_t vvx, vvy;
858858
} JL_ROOTED_VALUE_COLLECTION;
859859

860-
static int subtype_tuple_varargs(struct subtype_tuple_env *env, jl_stenv_t *e, int param)
860+
static int subtype_tuple_varargs(
861+
jl_vararg_t *vtx, jl_vararg_t *vty,
862+
size_t vx, size_t vy,
863+
jl_stenv_t *e, int param)
861864
{
862-
jl_value_t *xp0 = jl_unwrap_vararg(env->vtx); jl_value_t *xp1 = jl_unwrap_vararg_num(env->vtx);
863-
jl_value_t *yp0 = jl_unwrap_vararg(env->vty); jl_value_t *yp1 = jl_unwrap_vararg_num(env->vty);
865+
jl_value_t *xp0 = jl_unwrap_vararg(vtx); jl_value_t *xp1 = jl_unwrap_vararg_num(vtx);
866+
jl_value_t *yp0 = jl_unwrap_vararg(vty); jl_value_t *yp1 = jl_unwrap_vararg_num(vty);
864867

865868
if (!xp1) {
866869
jl_value_t *yl = yp1;
@@ -877,31 +880,28 @@ static int subtype_tuple_varargs(struct subtype_tuple_env *env, jl_stenv_t *e, i
877880
}
878881
}
879882
else {
880-
jl_value_t *xl = jl_unwrap_vararg_num(env->vtx);
883+
jl_value_t *xl = jl_unwrap_vararg_num(vtx);
881884
if (jl_is_typevar(xl)) {
882885
jl_varbinding_t *xlv = lookup(e, (jl_tvar_t*)xl);
883886
if (xlv)
884887
xl = xlv->lb;
885888
}
886889
if (jl_is_long(xl)) {
887-
if (jl_unbox_long(xl) + 1 == env->vx) {
890+
if (jl_unbox_long(xl) + 1 == vx) {
888891
// LHS is exhausted. We're a subtype if the RHS is either
889892
// exhausted as well or unbounded (in which case we need to
890893
// set it to 0).
891-
if (jl_is_vararg(env->vty)) {
892-
jl_value_t *yl = jl_unwrap_vararg_num(env->vty);
893-
if (yl) {
894-
if (jl_is_typevar(yl)) {
895-
jl_varbinding_t *ylv = lookup(e, (jl_tvar_t*)yl);
896-
if (ylv)
897-
yl = ylv->lb;
898-
}
899-
if (jl_is_long(yl)) {
900-
return jl_unbox_long(yl) + 1 == env->vy;
901-
}
894+
jl_value_t *yl = jl_unwrap_vararg_num(vty);
895+
if (yl) {
896+
if (jl_is_typevar(yl)) {
897+
jl_varbinding_t *ylv = lookup(e, (jl_tvar_t*)yl);
898+
if (ylv)
899+
yl = ylv->lb;
902900
}
903-
}
904-
else {
901+
if (jl_is_long(yl)) {
902+
return jl_unbox_long(yl) + 1 == vy;
903+
}
904+
} else {
905905
// We can skip the subtype check, but we still
906906
// need to make sure to constrain the length of y
907907
// to 0.
@@ -955,76 +955,74 @@ static int subtype_tuple_varargs(struct subtype_tuple_env *env, jl_stenv_t *e, i
955955
e->invdepth++;
956956
e->Rinvdepth++;
957957
JL_GC_PUSH2(&xp1, &yp1);
958-
if (xp1 && jl_is_long(xp1) && env->vx != 1)
959-
xp1 = jl_box_long(jl_unbox_long(xp1) - env->vx + 1);
960-
if (jl_is_long(yp1) && env->vy != 1)
961-
yp1 = jl_box_long(jl_unbox_long(yp1) - env->vy + 1);
958+
if (xp1 && jl_is_long(xp1) && vx != 1)
959+
xp1 = jl_box_long(jl_unbox_long(xp1) - vx + 1);
960+
if (jl_is_long(yp1) && vy != 1)
961+
yp1 = jl_box_long(jl_unbox_long(yp1) - vy + 1);
962962
int ans = forall_exists_equal(xp1, yp1, e);
963963
JL_GC_POP();
964964
e->invdepth--;
965965
e->Rinvdepth--;
966966
return ans;
967967
}
968968

969-
static int subtype_tuple_tail(struct subtype_tuple_env *env, int8_t R, jl_stenv_t *e, int param)
969+
static int subtype_tuple_tail(jl_datatype_t *xd, jl_datatype_t *yd, int8_t R, jl_stenv_t *e, int param)
970970
{
971-
int x_reps = 1;
972-
loop: // while (i <= lx) {
973-
if (env->i >= env->lx)
974-
goto done;
971+
size_t lx = jl_nparams(xd);
972+
size_t ly = jl_nparams(yd);
973+
size_t i = 0, j = 0, vx = 0, vy = 0, x_reps = 1;
974+
jl_value_t *lastx = NULL, *lasty = NULL;
975+
jl_value_t *xi = NULL, *yi = NULL;
975976

976-
/* Get the type in the current index. If necessary introduce tvars for
977-
varargs */
978-
jl_value_t *xi = NULL;
979-
if (env->i == env->lx-1 && env->vvx) {
980-
if (!env->vtx) {
981-
xi = jl_tparam(env->xd, env->i);
982-
assert(jl_is_vararg(xi));
983-
env->vtx = xi;
977+
for (;;) {
978+
if (i < lx) {
979+
xi = jl_tparam(xd, i);
980+
if (i == lx-1 && (vx || jl_is_vararg(xi))) {
981+
vx += 1;
984982
}
985-
xi = env->vtx;
986-
}
987-
else {
988-
xi = jl_tparam(env->xd, env->i);
989983
}
990984

991-
jl_value_t *yi = NULL;
992-
if (env->j < env->ly) {
993-
if (env->j == env->ly-1 && env->vvy) {
994-
if (!env->vty) {
995-
yi = jl_tparam(env->yd, env->j);
996-
assert(jl_is_vararg(yi));
997-
env->vty = yi;
998-
}
999-
yi = env->vty;
1000-
}
1001-
else {
1002-
yi = jl_tparam(env->yd, env->j);
985+
if (j < ly) {
986+
yi = jl_tparam(yd, j);
987+
if (j == ly-1 && (vy || jl_is_vararg(yi))) {
988+
vy += 1;
1003989
}
1004990
}
1005991

1006-
if (env->vtx)
1007-
env->vx += 1;
1008-
if (env->vty)
1009-
env->vy += 1;
992+
if (i >= lx)
993+
break;
1010994

1011-
if (env->vx && env->vy) {
1012-
return subtype_tuple_varargs(env, e, param);
995+
int all_varargs = vx && vy;
996+
if (!all_varargs && vy == 1) {
997+
if (jl_unwrap_vararg(yi) == (jl_value_t*)jl_any_type) {
998+
// Tuple{...} <: Tuple{..., Vararg{Any, _}}
999+
// fast path all the type checks away
1000+
xi = jl_tparam(xd, lx-1);
1001+
if (jl_is_vararg(xi)) {
1002+
all_varargs = 1;
1003+
vy += lx - i;
1004+
vx = 1;
1005+
} else {
1006+
break;
1007+
}
1008+
}
10131009
}
10141010

1015-
if (env->vx) {
1016-
xi = jl_unwrap_vararg(env->vtx);
1017-
if (env->j >= env->ly)
1018-
return 1;
1019-
}
1020-
else if (env->j >= env->ly) {
1021-
return 0;
1011+
if (all_varargs) {
1012+
// Tuple{..., Vararg{xi, _}} <: Tuple{..., Vararg{yi, _}}
1013+
return subtype_tuple_varargs(
1014+
(jl_vararg_t*)xi,
1015+
(jl_vararg_t*)yi,
1016+
vx, vy, e, param);
10221017
}
1023-
int x_same = env->lastx && jl_egal(xi, env->lastx);
1024-
if (env->vy) {
1025-
yi = jl_unwrap_vararg(env->vty);
1026-
if (!env->vvx && yi == (jl_value_t*)jl_any_type)
1027-
goto done; // if y ends in `Vararg{Any}` skip checking everything
1018+
1019+
if (j >= ly)
1020+
return !!vx;
1021+
1022+
xi = vx ? jl_unwrap_vararg(xi) : xi;
1023+
int x_same = lastx && jl_egal(xi, lastx);
1024+
if (vy) {
1025+
yi = jl_unwrap_vararg(yi);
10281026
// keep track of number of consecutive identical types compared to Vararg
10291027
if (x_same)
10301028
x_reps++;
@@ -1036,8 +1034,8 @@ static int subtype_tuple_tail(struct subtype_tuple_env *env, int8_t R, jl_stenv_
10361034
// element type on the right more than twice.
10371035
}
10381036
else if (x_same &&
1039-
((yi == env->lasty && !jl_has_free_typevars(xi) && !jl_has_free_typevars(yi)) ||
1040-
(yi == env->lasty && !env->vx && env->vy && jl_is_concrete_type(xi)))) {
1037+
((yi == lasty && !jl_has_free_typevars(xi) && !jl_has_free_typevars(yi)) ||
1038+
(yi == lastx && !vx && vy && jl_is_concrete_type(xi)))) {
10411039
// fast path for repeated elements
10421040
}
10431041
else if (e->Runions.depth == 0 && e->Lunions.depth == 0 && !jl_has_free_typevars(xi) && !jl_has_free_typevars(yi)) {
@@ -1048,73 +1046,71 @@ static int subtype_tuple_tail(struct subtype_tuple_env *env, int8_t R, jl_stenv_
10481046
else if (!subtype(xi, yi, e, param)) {
10491047
return 0;
10501048
}
1051-
env->lastx = xi; env->lasty = yi;
1052-
if (env->i < env->lx-1 || !env->vx)
1053-
env->i++;
1054-
if (env->j < env->ly-1 || !env->vy)
1055-
env->j++;
1056-
1057-
goto loop;
1058-
// } (from loop:)
1049+
lastx = xi; lasty = yi;
1050+
if (i < lx-1 || !vx)
1051+
i++;
1052+
if (j < ly-1 || !vy)
1053+
j++;
1054+
}
10591055

1060-
done:
1061-
if (!env->vy && env->j < env->ly && jl_is_vararg(jl_tparam(env->yd, env->j)))
1062-
env->vy += 1;
1063-
if (env->vy && !env->vx && env->lx+1 >= env->ly) {
1056+
if (vy && !vx && lx+1 >= ly) {
10641057
// in Tuple{...,tn} <: Tuple{...,Vararg{T,N}}, check (lx+1-ly) <: N
1065-
if (!check_vararg_length(jl_tparam(env->yd,env->ly-1), env->lx+1-env->ly, e))
1058+
if (!check_vararg_length(yi, lx+1-ly, e))
10661059
return 0;
10671060
}
1068-
return (env->lx + env->vx == env->ly + env->vy) || (env->vy && (env->lx >= (env->vx ? env->ly : (env->ly-1))));
1061+
return (lx + vx == ly + vy) || (vy && (lx >= (vx ? ly : (ly-1))));
10691062
}
10701063

10711064
static int subtype_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, int param)
10721065
{
1073-
struct subtype_tuple_env env;
1074-
env.xd = xd;
1075-
env.yd = yd;
1076-
env.lx = jl_nparams(xd);
1077-
env.ly = jl_nparams(yd);
1078-
if (env.lx == 0 && env.ly == 0)
1066+
// Check tuple compatibility based on tuple length only (fastpath)
1067+
size_t lx = jl_nparams(xd);
1068+
size_t ly = jl_nparams(yd);
1069+
1070+
if (lx == 0 && ly == 0)
10791071
return 1;
1080-
env.i = env.j = 0;
1081-
env.vx = env.vy = 0;
1082-
env.vvx = env.vvy = JL_VARARG_NONE;
1072+
1073+
jl_vararg_kind_t vvx = JL_VARARG_NONE;
1074+
jl_vararg_kind_t vvy = JL_VARARG_NONE;
10831075
jl_varbinding_t *xbb = NULL;
1084-
if (env.lx > 0) {
1085-
env.vvx = jl_vararg_kind(jl_tparam(env.xd, env.lx-1));
1086-
if (env.vvx == JL_VARARG_BOUND)
1087-
xbb = lookup(e, (jl_tvar_t *)jl_unwrap_vararg_num(jl_tparam(env.xd, env.lx - 1)));
1088-
}
1089-
if (env.ly > 0)
1090-
env.vvy = jl_vararg_kind(jl_tparam(env.yd, env.ly-1));
1091-
if (env.vvx != JL_VARARG_NONE && env.vvx != JL_VARARG_INT &&
1076+
jl_value_t *xva = NULL, *yva = NULL;
1077+
if (lx > 0) {
1078+
xva = jl_tparam(xd, lx-1);
1079+
vvx = jl_vararg_kind(xva);
1080+
if (vvx == JL_VARARG_BOUND)
1081+
xbb = lookup(e, (jl_tvar_t *)jl_unwrap_vararg_num(xva));
1082+
}
1083+
if (ly > 0) {
1084+
yva = jl_tparam(yd, ly-1);
1085+
vvy = jl_vararg_kind(yva);
1086+
}
1087+
if (vvx != JL_VARARG_NONE && vvx != JL_VARARG_INT &&
10921088
(!xbb || !jl_is_long(xbb->lb))) {
1093-
if (env.vvx == JL_VARARG_UNBOUND || (xbb && !xbb->right)) {
1089+
if (vvx == JL_VARARG_UNBOUND || (xbb && !xbb->right)) {
10941090
// Unbounded on the LHS, bounded on the RHS
1095-
if (env.vvy == JL_VARARG_NONE || env.vvy == JL_VARARG_INT)
1091+
if (vvy == JL_VARARG_NONE || vvy == JL_VARARG_INT)
10961092
return 0;
1097-
else if (env.lx < env.ly) // Unbounded includes N == 0
1093+
else if (lx < ly) // Unbounded includes N == 0
10981094
return 0;
10991095
}
1100-
else if (env.vvy == JL_VARARG_NONE && !check_vararg_length(jl_tparam(env.xd, env.lx-1), env.ly+1-env.lx, e)) {
1096+
else if (vvy == JL_VARARG_NONE && !check_vararg_length(xva, ly+1-lx, e)) {
11011097
return 0;
11021098
}
11031099
}
11041100
else {
1105-
size_t nx = env.lx;
1106-
if (env.vvx == JL_VARARG_INT)
1107-
nx += jl_vararg_length(jl_tparam(env.xd, env.lx-1)) - 1;
1101+
size_t nx = lx;
1102+
if (vvx == JL_VARARG_INT)
1103+
nx += jl_vararg_length(xva) - 1;
11081104
else if (xbb && jl_is_long(xbb->lb))
11091105
nx += jl_unbox_long(xbb->lb) - 1;
11101106
else
1111-
assert(env.vvx == JL_VARARG_NONE);
1112-
size_t ny = env.ly;
1113-
if (env.vvy == JL_VARARG_INT)
1114-
ny += jl_vararg_length(jl_tparam(env.yd, env.ly-1)) - 1;
1115-
else if (env.vvy != JL_VARARG_NONE)
1107+
assert(vvx == JL_VARARG_NONE);
1108+
size_t ny = ly;
1109+
if (vvy == JL_VARARG_INT)
1110+
ny += jl_vararg_length(yva) - 1;
1111+
else if (vvy != JL_VARARG_NONE)
11161112
ny -= 1;
1117-
if (env.vvy == JL_VARARG_NONE || env.vvy == JL_VARARG_INT) {
1113+
if (vvy == JL_VARARG_NONE || vvy == JL_VARARG_INT) {
11181114
if (nx != ny)
11191115
return 0;
11201116
}
@@ -1125,11 +1121,7 @@ static int subtype_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, in
11251121
}
11261122

11271123
param = (param == 0 ? 1 : param);
1128-
env.lastx = env.lasty = NULL;
1129-
env.vtx = env.vty = NULL;
1130-
JL_GC_PUSH2(&env.vtx, &env.vty);
1131-
int ans = subtype_tuple_tail(&env, 0, e, param);
1132-
JL_GC_POP();
1124+
int ans = subtype_tuple_tail(xd, yd, 0, e, param);
11331125
return ans;
11341126
}
11351127

0 commit comments

Comments
 (0)