From 5ef0d8fc97c758ffb741068d15cc72b3ccc28f07 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sun, 13 Jul 2014 02:56:42 -0400 Subject: [PATCH] fix #7564 this is a combination of convert(Rational{T},x) not returning the correct type, and the lack of a type check in codegen for new(). --- base/inference.jl | 1 + base/rational.jl | 4 ++-- src/cgutils.cpp | 14 ++++++++++++-- src/codegen.cpp | 20 ++++++++++++++++++-- test/numbers.jl | 3 +++ 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index a3a96eaab9c73..fa9b58a446cb4 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -155,6 +155,7 @@ t_func[pointerref] = (2,2,(a,i)->(isa(a,DataType) && a<:Ptr ? a.parameters[1] : t_func[pointerset] = (3, 3, (a,v,i)->a) const convert_default_tfunc = function (to, from, f) + to === () && return to !isType(to) && return Any to = to.parameters[1] diff --git a/base/rational.jl b/base/rational.jl index 9ed6d60b20f3f..8c0e7ececd095 100644 --- a/base/rational.jl +++ b/base/rational.jl @@ -35,8 +35,8 @@ function show(io::IO, x::Rational) show(io, den(x)) end -convert{T<:Integer}(::Type{Rational{T}}, x::Rational) = Rational(convert(T,x.num),convert(T,x.den)) -convert{T<:Integer}(::Type{Rational{T}}, x::Integer) = Rational(convert(T,x), convert(T,1)) +convert{T<:Integer}(::Type{Rational{T}}, x::Rational) = Rational{T}(convert(T,x.num),convert(T,x.den)) +convert{T<:Integer}(::Type{Rational{T}}, x::Integer) = Rational{T}(convert(T,x), convert(T,1)) convert(::Type{Rational}, x::Rational) = x convert(::Type{Rational}, x::Integer) = convert(Rational{typeof(x)},x) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 7d2d76f119688..7b813e07d0682 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -778,8 +778,16 @@ static void emit_type_error(Value *x, jl_value_t *type, const std::string &msg, static void emit_typecheck(Value *x, jl_value_t *type, const std::string &msg, jl_codectx_t *ctx) { - Value *istype = - builder.CreateICmpEQ(emit_typeof(x), literal_pointer_val(type)); + Value *istype; + if (jl_is_tuple(type) && type != (jl_value_t*)jl_tuple_type) { + istype = builder. + CreateICmpNE(builder.CreateCall3(jlsubtype_func, x, literal_pointer_val(type), + ConstantInt::get(T_int32,1)), + ConstantInt::get(T_int32,0)); + } + else { + istype = builder.CreateICmpEQ(emit_typeof(x), literal_pointer_val(type)); + } BasicBlock *failBB = BasicBlock::Create(getGlobalContext(),"fail",ctx->f); BasicBlock *passBB = BasicBlock::Create(getGlobalContext(),"pass"); builder.CreateCondBr(istype, passBB, failBB); @@ -922,6 +930,8 @@ static jl_value_t *expr_type(jl_value_t *e, jl_codectx_t *ctx) { if (jl_is_expr(e)) return ((jl_expr_t*)e)->etype; + if (e == (jl_value_t*)jl_null) + return e; if (jl_is_symbolnode(e)) return jl_symbolnode_type(e); if (jl_is_quotenode(e)) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 7d1cce824ce40..985652959e8bb 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -297,6 +297,7 @@ static Function *jlallocobj_func; static Function *jlalloc2w_func; static Function *jlalloc3w_func; static Function *jl_alloc_tuple_func; +static Function *jlsubtype_func; static Function *setjmp_func; static Function *box_int8_func; static Function *box_uint8_func; @@ -2704,8 +2705,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, else if (head == new_sym) { jl_value_t *ty = expr_type(args[0], ctx); size_t nargs = jl_array_len(ex->args); - if (jl_is_type_type(ty) && - jl_is_datatype(jl_tparam0(ty)) && + if (jl_is_type_type(ty) && jl_is_datatype(jl_tparam0(ty)) && jl_is_leaf_type(jl_tparam0(ty))) { ty = jl_tparam0(ty); jl_datatype_t *sty = (jl_datatype_t*)ty; @@ -2756,6 +2756,8 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, builder.CreateStore(literal_pointer_val((jl_value_t*)ty), emit_nthptr_addr(strct, (size_t)0)); if (f1) { + if (!jl_subtype(expr_type(args[1],ctx), jl_t0(sty->types), 0)) + emit_typecheck(f1, jl_t0(sty->types), "new", ctx); emit_setfield(sty, strct, 0, f1, ctx, false); ctx->argDepth = fieldStart; if (nf > 1 && needroots) @@ -2778,6 +2780,10 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, make_gcroot(strct, ctx); needroots = true; } + if (rhs->getType() == jl_pvalue_llvmt) { + if (!jl_subtype(expr_type(args[i],ctx), jl_tupleref(sty->types,i-1), 0)) + emit_typecheck(rhs, jl_tupleref(sty->types,i-1), "new", ctx); + } emit_setfield(sty, strct, i-1, rhs, ctx, false); } ctx->argDepth = fieldStart; @@ -4209,6 +4215,16 @@ static void init_julia_llvm_env(Module *m) "jl_egal", m); add_named_global(jlegal_func, (void*)&jl_egal); + std::vector subt_args(0); + subt_args.push_back(jl_pvalue_llvmt); + subt_args.push_back(jl_pvalue_llvmt); + subt_args.push_back(T_int32); + jlsubtype_func = + Function::Create(FunctionType::get(T_int32, subt_args, false), + Function::ExternalLinkage, + "jl_subtype", m); + add_named_global(jlsubtype_func, (void*)&jl_subtype); + std::vector aoargs(0); aoargs.push_back(T_size); jlallocobj_func = diff --git a/test/numbers.jl b/test/numbers.jl index 3e8b86998aa90..bc2633338365a 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -825,6 +825,9 @@ for N = int_types, D = int_types @test typeof(convert(N,2)//convert(D,3)) <: Rational{T} end +# issue #7564 +@test typeof(convert(Rational{Integer},1)) === Rational{Integer} + # check type of constructed complexes real_types = {Int8, Uint8, Int16, Uint16, Int32, Uint32, Int64, Uint64, Float32, Float64, Rational{Int8}, Rational{Uint8}, Rational{Int16}, Rational{Uint16},