Skip to content

Commit

Permalink
make type declarations with triangular constraints work properly
Browse files Browse the repository at this point in the history
e.g. fixes #6721

[ci skip]
  • Loading branch information
JeffBezanson committed Nov 8, 2016
1 parent 324cc24 commit 87468bd
Showing 1 changed file with 63 additions and 31 deletions.
94 changes: 63 additions & 31 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ static int typeenv_has(jl_typeenv_t *env, jl_tvar_t *v)

static int has_free_typevars(jl_value_t *v, jl_typeenv_t *env)
{
if (jl_typeis(v, jl_tvar_type))
if (jl_typeis(v, jl_tvar_type)) {
if (v == jl_ANY_flag) return 0;
return !typeenv_has(env, (jl_tvar_t*)v);
}
if (jl_is_uniontype(v))
return has_free_typevars(((jl_uniontype_t*)v)->a, env) ||
has_free_typevars(((jl_uniontype_t*)v)->b, env);
Expand All @@ -104,8 +106,8 @@ static int has_free_typevars(jl_value_t *v, jl_typeenv_t *env)
}
if (jl_is_datatype(v)) {
int expect = ((jl_datatype_t*)v)->hasfreetypevars;
if (expect == 0)
return 0;
if (expect == 0 || env == NULL)
return expect;
size_t i;
for (i=0; i < jl_nparams(v); i++) {
if (has_free_typevars(jl_tparam(v,i), env)) {
Expand Down Expand Up @@ -273,7 +275,8 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n)
int has_free = temp[i]!=NULL && jl_has_free_typevars(temp[i]);
for(j=0; j < nt; j++) {
if (j != i && temp[i] && temp[j]) {
if (temp[i] == temp[j] ||
if (temp[i] == temp[j] || temp[i] == jl_bottom_type ||
temp[j] == (jl_value_t*)jl_any_type ||
(!has_free && !jl_has_free_typevars(temp[j]) &&
jl_subtype(temp[i], temp[j]))) {
temp[i] = NULL;
Expand All @@ -282,11 +285,11 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n)
}
}
jl_value_t **ptu = &temp[nt];
*ptu = NULL;
*ptu = jl_bottom_type;
int k;
for (k = (int)nt-1; k >= 0; --k) {
if (temp[k] != NULL) {
if (*ptu == NULL)
if (*ptu == jl_bottom_type)
*ptu = temp[k];
else
*ptu = jl_new_struct(jl_uniontype_type, temp[k], *ptu);
Expand Down Expand Up @@ -551,7 +554,7 @@ static int valid_type_param(jl_value_t *v)
return jl_is_type(v) || jl_is_typevar(v) || jl_is_symbol(v) || jl_isbits(jl_typeof(v));
}

static int within_typevar(jl_value_t *t, jl_tvar_t *v)
static int within_typevar(jl_value_t *t, jl_value_t *vlb, jl_value_t *vub)
{
jl_value_t *lb = t, *ub = t;
if (jl_is_typevar(t)) {
Expand All @@ -562,9 +565,9 @@ static int within_typevar(jl_value_t *t, jl_tvar_t *v)
//ub = ((jl_tvar_t*)t)->ub;
}
else if (!jl_is_type(t)) {
return v->lb == jl_bottom_type && v->ub == jl_any_type;
return vlb == jl_bottom_type && vub == (jl_value_t*)jl_any_type;
}
return jl_subtype(v->lb, lb) && jl_subtype(ub, v->ub);
return jl_subtype(vlb, lb) && jl_subtype(ub, vub);
}

jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n)
Expand All @@ -588,9 +591,8 @@ jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n)
}

jl_unionall_t *ua = (jl_unionall_t*)tc;
if (jl_has_free_typevars(ua->var->lb) || jl_has_free_typevars(ua->var->ub))
jl_error("invalid instantiation");
if (!within_typevar(pi, ua->var))
if (!jl_has_free_typevars(ua->var->lb) && !jl_has_free_typevars(ua->var->ub) &&
!within_typevar(pi, ua->var->lb, ua->var->ub))
jl_type_error_rt("type", "parameter", (jl_value_t*)ua->var, pi);

tc = jl_instantiate_unionall(ua, pi);
Expand Down Expand Up @@ -662,7 +664,7 @@ jl_value_t *jl_rewrap_unionall(jl_value_t *t, jl_value_t *u)
return t;
JL_GC_PUSH1(&t);
t = jl_rewrap_unionall(t, ((jl_unionall_t*)u)->body);
t = jl_new_unionall_type(((jl_unionall_t*)u)->var, t);
t = (jl_value_t*)jl_new_unionall_type(((jl_unionall_t*)u)->var, t);
JL_GC_POP();
return t;
}
Expand Down Expand Up @@ -717,6 +719,38 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt)
}
}

static void check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, size_t np)
{
jl_value_t *wrapper = tn->wrapper;
jl_value_t **bounds;
JL_GC_PUSHARGS(bounds, np*2);
int i = 0;
while (jl_is_unionall(wrapper)) {
jl_tvar_t *tv = ((jl_unionall_t*)wrapper)->var;
bounds[i++] = tv->lb;
bounds[i++] = tv->ub;
wrapper = ((jl_unionall_t*)wrapper)->body;
}
assert(i == np*2);
wrapper = tn->wrapper;
for(i=0; i < np; i++) {
assert(jl_is_unionall(wrapper));
jl_tvar_t *tv = ((jl_unionall_t*)wrapper)->var;
if (!within_typevar(params[i], bounds[2*i], bounds[2*i+1])) {
// TODO: pass a new version of `tv` containing the instantiated bounds
jl_type_error_rt(jl_symbol_name(tn->name), jl_symbol_name(tv->name), (jl_value_t*)tv, params[i]);
}
int j;
for(j=2*i+2; j < 2*np; j++) {
jl_value_t*bj = bounds[j];
if (bj != (jl_value_t*)jl_any_type && bj != jl_bottom_type)
bounds[j] = jl_substitute_var(bj, tv, params[i]);
}
wrapper = ((jl_unionall_t*)wrapper)->body;
}
JL_GC_POP();
}

static arraylist_t partial_inst;
int inside_typedef = 0;

Expand Down Expand Up @@ -748,8 +782,10 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
jl_value_t *va = jl_unwrap_unionall(last);
// return same `Tuple` object for types equal to it
if (ntp == 1 && jl_tparam0(va) == (jl_value_t*)jl_any_type &&
jl_is_unionall(last) && jl_tparam1(va) == (jl_value_t*)((jl_unionall_t*)last)->var)
jl_is_unionall(last) && jl_tparam1(va) == (jl_value_t*)((jl_unionall_t*)last)->var) {
if (cacheable) JL_UNLOCK(&typecache_lock); // Might GC
return (jl_value_t*)jl_anytuple_type;
}
if (jl_is_long(jl_tparam1(va))) {
ssize_t nt = jl_unbox_long(jl_tparam1(va));
if (nt < 0)
Expand Down Expand Up @@ -791,6 +827,10 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i
jl_datatype_t *ndt = NULL;
jl_svec_t *ftypes;

// check parameters against bounds in type definition
if (!istuple)
check_datatype_parameters(tn, iparams, ntp);

// move array of instantiated parameters to heap; we need to keep it
JL_GC_PUSH2(&p, &ndt);
if (p == NULL) {
Expand Down Expand Up @@ -946,8 +986,7 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_
jl_svec_t *tp = tt->parameters;
size_t ntp = jl_svec_len(tp);
// Instantiate NTuple{3,Int}
// Note this does not instantiate Tuple{Vararg{Int,3}}; that's done in
// jl_apply_tuple_type_v_
// Note this does not instantiate Tuple{Vararg{Int,3}}; that's done in inst_datatype
if (jl_is_va_tuple(tt) && ntp == 1) {
// If this is a Tuple{Vararg{T,N}} with known N, expand it to
// a fixed-length tuple
Expand Down Expand Up @@ -1009,10 +1048,11 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t
while (e != NULL) {
if (e->var == (jl_tvar_t*)t) {
jl_value_t *val = e->val;
if (check && !jl_is_typevar(val) && !within_typevar(val, (jl_tvar_t*)t)) {
jl_type_error_rt("type parameter",
jl_symbol_name(((jl_tvar_t*)t)->name), t, val);
}
// TODO jb/subtype this seems unnecessary
//if (check && !jl_is_typevar(val) && !within_typevar(val, (jl_tvar_t*)t)) {
// jl_type_error_rt("type parameter",
// jl_symbol_name(((jl_tvar_t*)t)->name), t, val);
//}
return val;
}
e = e->prev;
Expand Down Expand Up @@ -1077,20 +1117,12 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t
if (tn == jl_tuple_typename)
return inst_tuple_w_(t, env, stack, check);
size_t ntp = jl_svec_len(tp);
jl_value_t *wrapper = tn->wrapper;
jl_value_t **iparams;
JL_GC_PUSHARGS(iparams, ntp);
int cacheable = 1, bound = 0;
for(i=0; i < ntp; i++) {
jl_value_t *elt = jl_svecref(tp, i);
iparams[i] = (jl_value_t*)inst_type_w_(elt, env, stack, check);
assert(jl_is_unionall(wrapper));
jl_tvar_t *tv = ((jl_unionall_t*)wrapper)->var;
if (!within_typevar(iparams[i], tv)) {
jl_type_error_rt(jl_symbol_name(tn->name), jl_symbol_name(tv->name),
tv, iparams[i]);
}
wrapper = ((jl_unionall_t*)wrapper)->body;
bound |= (iparams[i] != elt);
if (cacheable && jl_has_free_typevars(iparams[i]))
cacheable = 0;
Expand Down Expand Up @@ -1251,12 +1283,12 @@ static size_t data_vararg_params(jl_value_t **data, size_t lenr, jl_vararg_kind_
return lenf;
}
*lenkind = JL_TUPLE_VAR;
jl_value_t *last = jl_unwrap_unionall(data[lenr-1]);
jl_value_t *last = data[lenr-1];
*kind = jl_vararg_kind(last);
if (*kind == JL_VARARG_NONE || *kind == JL_VARARG_INT)
*lenkind = JL_TUPLE_FIXED;
if (*kind == JL_VARARG_INT || *kind == JL_VARARG_BOUND) {
jl_value_t *N = jl_tparam1(last);
jl_value_t *N = jl_tparam1(jl_unwrap_unionall(last));
if (jl_is_long(N)) {
lenf += jl_unbox_long(N)-1;
*lenkind = JL_TUPLE_FIXED;
Expand Down Expand Up @@ -1292,7 +1324,7 @@ static int jl_tuple_morespecific(jl_datatype_t *cdt, jl_datatype_t *pdt, int inv
pseq = (pi<plenr) && plenkind != JL_TUPLE_FIXED && jl_is_vararg_type(parent[pi]);
if (ci >= clenf && !cseq)
return 1;
if (pi >= plenf && !pseq)
if (pi >= plenf && !pseq && !some_morespecific)
return 0;
if (ci < clenr) {
ce = child[ci];
Expand Down

0 comments on commit 87468bd

Please sign in to comment.