Skip to content

Commit

Permalink
fix #14482, inference regression on map(::Type{Int8}, ::Vector{Int})
Browse files Browse the repository at this point in the history
also fixes an older problem where `convert(Type{Int}, Float32)` sometimes
returned a value, depending on what got into the method cache.
  • Loading branch information
JeffBezanson committed Dec 29, 2015
1 parent c671df9 commit b438225
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 21 deletions.
4 changes: 2 additions & 2 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -698,9 +698,10 @@ function abstract_call_gf(f, fargs, argtype, e)
return Any
end
for (m::SimpleVector) in x
sig = m[1]
local linfo
linfo = try
func_for_method(m[3],argtype,m[2])
func_for_method(m[3],sig,m[2])
catch
NF
end
Expand All @@ -709,7 +710,6 @@ function abstract_call_gf(f, fargs, argtype, e)
break
end
linfo = linfo::LambdaStaticData
sig = m[1]
lsig = length(m[3].sig.parameters)
# limit argument type tuple based on size of definition signature.
# for example, given function f(T, Any...), limit to 3 arguments
Expand Down
9 changes: 9 additions & 0 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,15 @@ static jl_function_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_datatype_t *tt,
assert(jl_is_svec(env));
func = m->func;

if (inexact && !jl_types_equal(ti, (jl_value_t*)tt)) {
// the compiler might attempt jl_get_specialization on e.g.
// convert(::Type{Type{Int}}, ::DataType), which is concrete but might not
// equal the run time type. in this case ti would be {Type{Type{Int}}, Type{Int}}
// but tt would be {Type{Type{Int}}, DataType}.
JL_GC_POP();
return jl_bottom_func;
}

if (m->isstaged)
func = jl_instantiate_staged(m,tt,env);

Expand Down
42 changes: 25 additions & 17 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1238,8 +1238,15 @@ static jl_value_t *meet(jl_value_t *X, jl_value_t *Y, variance_t var)
// example: {Type{Int},} => {DataType,}
// calling f{T}(x::T) as f({Int,}) should give T == {DataType,}, but we
// might temporarily represent this type as {Type{Int},} for more precision.
static jl_value_t *type_to_static_parameter_value(jl_value_t *t)
static jl_value_t *type_to_static_parameter_value(jl_value_t *t, jl_value_t *tv, jl_value_t **tvs, int ntv)
{
int i;
for(i=0; i < ntv; i++) {
if (tv == tvs[i])
break;
}
if (i >= ntv)
return t; // don't widen vars not in env
if (jl_is_type_type(t) && !jl_is_typevar(jl_tparam0(t)))
return jl_typeof(jl_tparam0(t));
if (jl_is_tuple_type(t)) {
Expand All @@ -1249,7 +1256,7 @@ static jl_value_t *type_to_static_parameter_value(jl_value_t *t)
jl_svec_t *np = jl_alloc_svec(l);
JL_GC_PUSH1(&np);
for(size_t i=0; i < l; i++) {
jl_value_t *el = type_to_static_parameter_value(jl_svecref(p,i));
jl_value_t *el = type_to_static_parameter_value(jl_svecref(p,i), NULL, NULL, 0);
jl_svecset(np, i, el);
if (el != jl_svecref(p,i))
changed = 1;
Expand All @@ -1275,7 +1282,7 @@ void print_env(cenv_t *soln)
}
*/

static int solve_tvar_constraints(cenv_t *env, cenv_t *soln)
static int solve_tvar_constraints(cenv_t *env, cenv_t *soln, jl_value_t **tvs, int ntv)
{
jl_value_t *rt1=NULL, *rt2=NULL, *S=NULL;
JL_GC_PUSH3(&rt1, &rt2, &S);
Expand Down Expand Up @@ -1319,8 +1326,8 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln)
if (TT == T) {
// found T=SS in env
if (!jl_is_typevar(SS)) {
rt1 = type_to_static_parameter_value(S);
rt2 = type_to_static_parameter_value(SS);
rt1 = type_to_static_parameter_value(S, T, tvs, ntv);
rt2 = type_to_static_parameter_value(SS, TT, tvs, ntv);
jl_value_t *m = meet(rt1, rt2, covariant);
if (m == NULL) goto ret_no;
S = m;
Expand Down Expand Up @@ -1359,7 +1366,7 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln)
}
}
else {
extend(T, type_to_static_parameter_value(S), soln);
extend(T, type_to_static_parameter_value(S, T, tvs, ntv), soln);
}
}
else {
Expand Down Expand Up @@ -1389,8 +1396,8 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln)
jl_value_t *TT = env->data[j];
jl_value_t *SS = env->data[j+1];
if (TT == T) {
rt1 = type_to_static_parameter_value(S);
rt2 = type_to_static_parameter_value(SS);
rt1 = type_to_static_parameter_value(S, T, tvs, ntv);
rt2 = type_to_static_parameter_value(SS, TT, tvs, ntv);
jl_value_t *m = meet(rt1, rt2, covariant);
if (m == NULL) goto ret_no;
S = m;
Expand All @@ -1406,7 +1413,7 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln)
S = (jl_value_t*)jl_new_typevar(underscore_sym,
(jl_value_t*)jl_bottom_type, S);
}
extend(T, type_to_static_parameter_value(S), soln);
extend(T, type_to_static_parameter_value(S, T, tvs, ntv), soln);
}
}
}
Expand Down Expand Up @@ -1473,14 +1480,6 @@ jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b,
}
}

if (!solve_tvar_constraints(&env, &eqc)) {
JL_GC_POP();
return (jl_value_t*)jl_bottom_type;
}
//jl_printf(JL_STDOUT, "env: "); print_env(&env);
//jl_printf(JL_STDOUT, "sol: "); print_env(&eqc);

int env0 = eqc.n;
jl_value_t **tvs;
int tvarslen;
if (jl_is_typevar(tvars)) {
Expand All @@ -1492,6 +1491,15 @@ jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b,
tvs = jl_svec_data(tvars);
tvarslen = jl_svec_len(tvars);
}

if (!solve_tvar_constraints(&env, &eqc, tvs, tvarslen)) {
JL_GC_POP();
return (jl_value_t*)jl_bottom_type;
}
//jl_printf(JL_STDOUT, "env: "); print_env(&env);
//jl_printf(JL_STDOUT, "sol: "); print_env(&eqc);

int env0 = eqc.n;
for(int tk=0; tk < tvarslen; tk++) {
jl_tvar_t *tv = (jl_tvar_t*)tvs[tk];
for(e=0; e < env0; e+=2) {
Expand Down
3 changes: 3 additions & 0 deletions test/arrayops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1443,3 +1443,6 @@ let A = zeros(Int, 2, 2), B = zeros(Float64, 2, 2)
@test isleaftype(Base.return_types(f, ())[1])
end
end

# issue #14482
@inferred Base.map_to!(Int8, 1, Int8[0], Int[0])
9 changes: 7 additions & 2 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3468,8 +3468,7 @@ end

# issue #11327 and #13547
@test_throws MethodError convert(Type{Int}, Float32)
# TODO: this should probably be a MethodError in `convert`; not sure what's going on
@test_throws TypeError Array{Type{Int64}}([Float32])
@test_throws MethodError Array{Type{Int64}}([Float32])
abstract A11327
abstract B11327 <: A11327
f11327{T}(::Type{T},x::T) = x
Expand Down Expand Up @@ -3606,3 +3605,9 @@ let z1 = Z14477()
@test isa(z1, Z14477)
@test isa(z1.fld, Z14477)
end

# issue #14482
let T = TypeVar(:T, true)
@test typeintersect(T, Type{Int8}) == Type{Int8}
@test typeintersect(Tuple{T}, Tuple{Type{Int8}}) == Tuple{Type{Int8}}
end

0 comments on commit b438225

Please sign in to comment.