From 1f527b7a4799fbfd45ee5e7dccead01de864b72c Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Tue, 12 Aug 2014 14:16:51 -0400 Subject: [PATCH 01/44] initial implementation of call overloading: f(x...) gets turned into call(f, x...) as a fallback (if f is not a function); to do: update inference, fallback to call when f is a type --- base/boot.jl | 5 ++++- src/alloc.c | 1 + src/codegen.cpp | 31 ++++++++++++++++++------------- src/init.c | 2 ++ src/interpreter.c | 22 +++++++++++++++------- src/julia_internal.h | 2 ++ 6 files changed, 42 insertions(+), 21 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 72d74827a1129..1a4a764736fdd 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -135,7 +135,7 @@ export Expr, GotoNode, LabelNode, LineNumberNode, QuoteNode, SymbolNode, TopNode, GetfieldNode, NewvarNode, # object model functions - apply, fieldtype, getfield, setfield!, yieldto, throw, tuple, is, ===, isdefined, + apply, fieldtype, getfield, setfield!, yieldto, throw, tuple, is, ===, isdefined, call, # arraylen, arrayref, arrayset, arraysize, tuplelen, tupleref, convert_default, # kwcall, # type reflection @@ -243,3 +243,6 @@ end typealias ByteString Union(ASCIIString,UTF8String) include(fname::ByteString) = ccall(:jl_load_, Any, (Any,), fname) + +call(f::Function, args...) = f(args...) +call{T}(::Type{T}, x) = convert(T, x) diff --git a/src/alloc.c b/src/alloc.c index 901267b6fe9d3..28c5155571bc4 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -66,6 +66,7 @@ jl_value_t *jl_undefref_exception; jl_value_t *jl_interrupt_exception; jl_value_t *jl_bounds_exception; jl_value_t *jl_memory_exception; +jl_function_t *jl_call_func; jl_sym_t *call_sym; jl_sym_t *dots_sym; jl_sym_t *call1_sym; jl_sym_t *module_sym; diff --git a/src/codegen.cpp b/src/codegen.cpp index 132de23c44ce6..c487ef28c75b2 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2214,25 +2214,30 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, Value *theFunc = emit_expr(args[0], ctx); if (theFunc->getType() != jl_pvalue_llvmt || jl_is_tuple(hdtype)) { // we know it's not a function - emit_type_error(theFunc, (jl_value_t*)jl_function_type, "apply", ctx); - ctx->argDepth = last_depth; - return V_null; + headIsGlobal = true; + Value *result = emit_known_call((jl_value_t*)jl_call_func, + --args, ++nargs, ctx, + &theFptr, &f, expr); + if (result != NULL) return result; + theF = literal_pointer_val((jl_value_t*)f); } + else { #ifdef JL_GC_MARKSWEEP - if (!headIsGlobal && (jl_is_expr(a0) || jl_is_lambda_info(a0))) { + if (!headIsGlobal && (jl_is_expr(a0) || jl_is_lambda_info(a0))) { make_gcroot(boxed(theFunc,ctx), ctx); - } + } #endif - if (hdtype!=(jl_value_t*)jl_function_type && - hdtype!=(jl_value_t*)jl_datatype_type && - !(jl_is_type_type(hdtype) && - jl_is_datatype(jl_tparam0(hdtype)))) { + if (hdtype!=(jl_value_t*)jl_function_type && + hdtype!=(jl_value_t*)jl_datatype_type && + !(jl_is_type_type(hdtype) && + jl_is_datatype(jl_tparam0(hdtype)))) { emit_func_check(theFunc, ctx); + } + // extract pieces of the function object + // TODO: try extractvalue instead + theFptr = builder.CreateBitCast(emit_nthptr(theFunc, 1, tbaa_func), jl_fptr_llvmt); + theF = theFunc; } - // extract pieces of the function object - // TODO: try extractvalue instead - theFptr = builder.CreateBitCast(emit_nthptr(theFunc, 1, tbaa_func), jl_fptr_llvmt); - theF = theFunc; } else { theF = literal_pointer_val((jl_value_t*)f); diff --git a/src/init.c b/src/init.c index 9ee349a8dc5bc..59b0bba872093 100644 --- a/src/init.c +++ b/src/init.c @@ -1090,6 +1090,8 @@ void jl_get_builtin_hooks(void) jl_array_uint8_type = jl_apply_type((jl_value_t*)jl_array_type, jl_tuple2(jl_uint8_type, jl_box_long(1))); + + jl_call_func = (jl_function_t*)core("call"); } DLLEXPORT void jl_get_system_hooks(void) diff --git a/src/interpreter.c b/src/interpreter.c index be4e1c6d48c7b..0b0bac92fe1e3 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -53,15 +53,22 @@ DLLEXPORT jl_value_t *jl_interpret_toplevel_expr_in(jl_module_t *m, jl_value_t * } static jl_value_t *do_call(jl_function_t *f, jl_value_t **args, size_t nargs, - jl_value_t **locals, size_t nl) + jl_value_t *eval0, jl_value_t **locals, size_t nl) { jl_value_t **argv; JL_GC_PUSHARGS(argv, nargs+1); size_t i; argv[0] = (jl_value_t*)f; for(i=1; i < nargs+1; i++) argv[i] = NULL; - for(i=0; i < nargs; i++) - argv[i+1] = eval(args[i], locals, nl); + if (eval0) { /* 0-th argument has already been evaluated */ + argv[1] = eval0; + for(i=1; i < nargs; i++) + argv[i+1] = eval(args[i], locals, nl); + } + else { + for(i=0; i < nargs; i++) + argv[i+1] = eval(args[i], locals, nl); + } jl_value_t *result = jl_apply(f, &argv[1], nargs); JL_GC_POP(); return result; @@ -201,10 +208,11 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) } } jl_function_t *f = (jl_function_t*)eval(args[0], locals, nl); - if (!jl_is_func(f)) - jl_type_error("apply", (jl_value_t*)jl_function_type, - (jl_value_t*)f); - return do_call(f, &args[1], nargs-1, locals, nl); + if (jl_is_func(f)) + return do_call(f, &args[1], nargs-1, NULL, locals, nl); + else + return do_call(jl_call_func, args, nargs, (jl_value_t*)f, + locals, nl); } else if (ex->head == assign_sym) { jl_value_t *sym = args[0]; diff --git a/src/julia_internal.h b/src/julia_internal.h index 157740f37f110..cff0a90698935 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -129,6 +129,8 @@ DLLEXPORT void jl_raise_debugger(void); // Returns time in nanosec DLLEXPORT uint64_t jl_hrtime(void); +extern DLLEXPORT jl_function_t *jl_call_func; + #ifdef __cplusplus } #endif From 4a58fa499a4cf7238cf734f33d1f531a0190fb7c Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Tue, 12 Aug 2014 15:19:36 -0400 Subject: [PATCH 02/44] make sure call passes through keywords --- base/boot.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/boot.jl b/base/boot.jl index 1a4a764736fdd..490d8c8426354 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -244,5 +244,5 @@ typealias ByteString Union(ASCIIString,UTF8String) include(fname::ByteString) = ccall(:jl_load_, Any, (Any,), fname) -call(f::Function, args...) = f(args...) +call(f::Function, args...; kws...) = f(args...; kws...) call{T}(::Type{T}, x) = convert(T, x) From 5b0aedd38e73c0bc3a071c46b9f459e4d92166b9 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Tue, 12 Aug 2014 16:03:41 -0400 Subject: [PATCH 03/44] fix call overloading for type constructors, add some tests --- base/base.jl | 5 ++++- base/boot.jl | 1 - src/codegen.cpp | 11 +++++++++-- src/interpreter.c | 2 +- test/core.jl | 18 ++++++++++++++++++ 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/base/base.jl b/base/base.jl index 05b8c2a9e20ed..a726c55202145 100644 --- a/base/base.jl +++ b/base/base.jl @@ -4,7 +4,7 @@ using Core: Intrinsics, arraylen, arrayref, arrayset, arraysize, tuplelen, tupleref, convert_default, kwcall, typeassert, apply_type -import Core.Array # to add methods +import Core: Array, call # to add methods const NonTupleType = Union(DataType,UnionType,TypeConstructor) @@ -15,6 +15,9 @@ convert(T, x) = convert_default(T, x, convert) convert(::(), ::()) = () convert(::Type{Tuple}, x::Tuple) = x +# allow convert to be called as if it were a single-argument constructor +call{T}(::Type{T}, x) = convert(T, x) + argtail(x, rest...) = rest tupletail(x::Tuple) = argtail(x...) diff --git a/base/boot.jl b/base/boot.jl index 490d8c8426354..2f964530110a7 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -245,4 +245,3 @@ typealias ByteString Union(ASCIIString,UTF8String) include(fname::ByteString) = ccall(:jl_load_, Any, (Any,), fname) call(f::Function, args...; kws...) = f(args...; kws...) -call{T}(::Type{T}, x) = convert(T, x) diff --git a/src/codegen.cpp b/src/codegen.cpp index c487ef28c75b2..a2348f7b1e01a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2201,9 +2201,16 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, jl_function_t *f = (jl_function_t*)static_eval(a0, ctx, true); if (f != NULL) { + Value *result; headIsGlobal = true; - Value *result = emit_known_call((jl_value_t*)f, args, nargs, ctx, - &theFptr, &f, expr); + if (f->fptr != jl_f_no_function) { + result = emit_known_call((jl_value_t*)f, args, nargs, ctx, + &theFptr, &f, expr); + } + else { + result = emit_known_call((jl_value_t*)jl_call_func, + --args, ++nargs, ctx, &theFptr, &f, expr); + } if (result != NULL) return result; } bool specialized = true; diff --git a/src/interpreter.c b/src/interpreter.c index 0b0bac92fe1e3..7e006cae03761 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -208,7 +208,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) } } jl_function_t *f = (jl_function_t*)eval(args[0], locals, nl); - if (jl_is_func(f)) + if (jl_is_func(f) && f->fptr != jl_f_no_function) return do_call(f, &args[1], nargs-1, NULL, locals, nl); else return do_call(jl_call_func, args, nargs, (jl_value_t*)f, diff --git a/test/core.jl b/test/core.jl index a04bf1443ac20..3e7ca148a8d9e 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1829,3 +1829,21 @@ end # issue #7582 aₜ = "a variable using Unicode 6" + +# call and constructor overloading (#1470, #2403) +typealias FooInt32 Int32 +@test isa(FooInt32(3), FooInt32) +Base.call(x::Int, y::Int) = x + 3y +issue2403func(f) = f(7) +let x = 10 + @test x(3) == 19 + @test issue2403func(x) == 31 +end +type Issue2403 + x +end +Base.call(i::Issue2403, y) = i.x + 2y +let x = Issue2403(20) + @test x(3) == 26 + # @test issue2403func(x) == 34 -- FIXME +end From 0df037e87c774bb34c5054f1bbede2ffe27a28ab Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 14 Aug 2014 11:53:03 -0400 Subject: [PATCH 04/44] support generic call in apply(f, ...) --- src/builtins.c | 45 +++++++++++++++++++++++++++++++++++---------- test/core.jl | 1 + 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index c39e0dc14ff9f..77de8b2504293 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -256,9 +256,15 @@ extern size_t jl_page_size; JL_CALLABLE(jl_f_apply) { JL_NARGSV(apply, 1); - JL_TYPECHK(apply, function, args[0]); + jl_function_t *f; + if (jl_is_function(args[0])) + f = (jl_function_t*)args[0]; + else { /* do generic call(args...) instead */ + f = jl_call_func; + ++nargs; --args; /* args[0] becomes args[1] */ + } if (nargs == 2) { - if (((jl_function_t*)args[0])->fptr == &jl_f_tuple) { + if (f->fptr == &jl_f_tuple) { if (jl_is_tuple(args[1])) return args[1]; if (jl_is_array(args[1])) { @@ -273,7 +279,7 @@ JL_CALLABLE(jl_f_apply) } } if (jl_is_tuple(args[1])) { - return jl_apply((jl_function_t*)args[0], &jl_tupleref(args[1],0), + return jl_apply(f, &jl_tupleref(args[1],0), jl_tuple_len(args[1])); } } @@ -301,7 +307,7 @@ JL_CALLABLE(jl_f_apply) } argarr = jl_apply(jl_append_any_func, &args[1], nargs-1); assert(jl_typeis(argarr, jl_array_any_type)); - result = jl_apply((jl_function_t*)args[0], jl_cell_data(argarr), jl_array_len(argarr)); + result = jl_apply(f, jl_cell_data(argarr), jl_array_len(argarr)); JL_GC_POP(); return result; } @@ -328,7 +334,7 @@ JL_CALLABLE(jl_f_apply) newargs[n++] = jl_cellref(args[i], j); } } - result = jl_apply((jl_function_t*)args[0], newargs, n); + result = jl_apply(f, newargs, n); JL_GC_POP(); return result; } @@ -339,8 +345,16 @@ JL_CALLABLE(jl_f_kwcall) { if (nargs < 3) jl_error("internal error: malformed keyword argument call"); - JL_TYPECHK(apply, function, args[0]); - jl_function_t *f = (jl_function_t*)args[0]; + jl_function_t *f; + jl_value_t *args0; + if (jl_is_function(args[0])) { + f = (jl_function_t*)args[0]; + args0 = NULL; + } + else { /* do generic call(args...; kws...) instead */ + f = jl_call_func; + args0 = args[0]; + } if (f->fptr == jl_f_ctor_trampoline) jl_add_constructors((jl_datatype_t*)f); if (!jl_is_gf(f)) @@ -360,13 +374,24 @@ JL_CALLABLE(jl_f_kwcall) jl_cellset(container, i+1, args[2+i+1]); } + args += pa-1; + nargs -= pa-1; + if (args0) { + jl_value_t **newargs = (jl_value_t**)alloca((nargs+1) * sizeof(jl_value_t*)); + newargs[0] = args[0]; + newargs[1] = args0; /* original 0th argument = "function" */ + memcpy(newargs+2, args+1, sizeof(jl_value_t*) * (nargs-1)); + args = newargs; + nargs += 1; + } + assert(jl_is_gf(sorter)); - jl_function_t *m = jl_method_lookup((jl_methtable_t*)sorter->env, &args[pa-1], nargs-(pa-1), 1); + jl_function_t *m = jl_method_lookup((jl_methtable_t*)sorter->env, args, nargs, 1); if (m == jl_bottom_func) { - return jl_no_method_error(f, &args[pa], nargs-pa); + return jl_no_method_error(f, args+1, nargs-1); } - return jl_apply(m, &args[pa-1], nargs-(pa-1)); + return jl_apply(m, args, nargs); } // eval ----------------------------------------------------------------------- diff --git a/test/core.jl b/test/core.jl index 3e7ca148a8d9e..cf782197d8d07 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1837,6 +1837,7 @@ Base.call(x::Int, y::Int) = x + 3y issue2403func(f) = f(7) let x = 10 @test x(3) == 19 + @test apply(x, (3,)) == 19 @test issue2403func(x) == 31 end type Issue2403 From 762a7279a40e4eababa14b29b704e7d057b6f347 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 14 Aug 2014 12:15:22 -0400 Subject: [PATCH 05/44] (broken) patch to eliminate emit_func_check --- src/cgutils.cpp | 23 ----------------------- src/codegen.cpp | 14 ++++++-------- 2 files changed, 6 insertions(+), 31 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index b341b84ee81fe..ba5f9b264c5d3 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -824,29 +824,6 @@ static Value *emit_bounds_check(Value *i, Value *len, jl_codectx_t *ctx) return im1; } -static void emit_func_check(Value *x, jl_codectx_t *ctx) -{ - Value *xty = emit_typeof(x); - Value *isfunc = - builder. - CreateOr(builder. - CreateICmpEQ(xty, - literal_pointer_val((jl_value_t*)jl_function_type)), - builder. - CreateICmpEQ(xty, - literal_pointer_val((jl_value_t*)jl_datatype_type))); - BasicBlock *elseBB1 = BasicBlock::Create(getGlobalContext(),"notf", ctx->f); - BasicBlock *mergeBB1 = BasicBlock::Create(getGlobalContext(),"isf"); - builder.CreateCondBr(isfunc, mergeBB1, elseBB1); - - builder.SetInsertPoint(elseBB1); - emit_type_error(x, (jl_value_t*)jl_function_type, "apply", ctx); - - builder.CreateBr(mergeBB1); - ctx->f->getBasicBlockList().push_back(mergeBB1); - builder.SetInsertPoint(mergeBB1); -} - // --- loading and storing --- static Value *emit_nthptr_addr(Value *v, size_t n) diff --git a/src/codegen.cpp b/src/codegen.cpp index a2348f7b1e01a..5c33908080823 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2219,8 +2219,12 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, if (theFptr == NULL) { specialized = false; Value *theFunc = emit_expr(args[0], ctx); - if (theFunc->getType() != jl_pvalue_llvmt || jl_is_tuple(hdtype)) { - // we know it's not a function + if ((hdtype!=(jl_value_t*)jl_function_type && + hdtype!=(jl_value_t*)jl_datatype_type && + !(jl_is_type_type(hdtype) && + jl_is_datatype(jl_tparam0(hdtype)))) || + jl_is_tuple(hdtype) || theFunc->getType() != jl_pvalue_llvmt) { + // it may not be a function, use call(f, ...) instead headIsGlobal = true; Value *result = emit_known_call((jl_value_t*)jl_call_func, --args, ++nargs, ctx, @@ -2234,12 +2238,6 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, make_gcroot(boxed(theFunc,ctx), ctx); } #endif - if (hdtype!=(jl_value_t*)jl_function_type && - hdtype!=(jl_value_t*)jl_datatype_type && - !(jl_is_type_type(hdtype) && - jl_is_datatype(jl_tparam0(hdtype)))) { - emit_func_check(theFunc, ctx); - } // extract pieces of the function object // TODO: try extractvalue instead theFptr = builder.CreateBitCast(emit_nthptr(theFunc, 1, tbaa_func), jl_fptr_llvmt); From b430c48e46c875306c4baaf00b44d991a9fe1fe3 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 1 Sep 2014 14:47:04 -0400 Subject: [PATCH 06/44] get basic call overloading working with 1 bootstrap stage --- base/base.jl | 2 +- base/boot.jl | 4 +- src/codegen.cpp | 208 ++++++++++++++++++++++++++++++++-------------- src/init.c | 3 +- src/interpreter.c | 5 +- test/core.jl | 6 +- 6 files changed, 151 insertions(+), 77 deletions(-) diff --git a/base/base.jl b/base/base.jl index a726c55202145..05dbba7b4c1eb 100644 --- a/base/base.jl +++ b/base/base.jl @@ -4,7 +4,7 @@ using Core: Intrinsics, arraylen, arrayref, arrayset, arraysize, tuplelen, tupleref, convert_default, kwcall, typeassert, apply_type -import Core: Array, call # to add methods +import Core: Array # to add methods const NonTupleType = Union(DataType,UnionType,TypeConstructor) diff --git a/base/boot.jl b/base/boot.jl index 2f964530110a7..72d74827a1129 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -135,7 +135,7 @@ export Expr, GotoNode, LabelNode, LineNumberNode, QuoteNode, SymbolNode, TopNode, GetfieldNode, NewvarNode, # object model functions - apply, fieldtype, getfield, setfield!, yieldto, throw, tuple, is, ===, isdefined, call, + apply, fieldtype, getfield, setfield!, yieldto, throw, tuple, is, ===, isdefined, # arraylen, arrayref, arrayset, arraysize, tuplelen, tupleref, convert_default, # kwcall, # type reflection @@ -243,5 +243,3 @@ end typealias ByteString Union(ASCIIString,UTF8String) include(fname::ByteString) = ccall(:jl_load_, Any, (Any,), fname) - -call(f::Function, args...; kws...) = f(args...; kws...) diff --git a/src/codegen.cpp b/src/codegen.cpp index 5c33908080823..afad7f79405a5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2176,85 +2176,29 @@ static Value *emit_jlcall(Value *theFptr, Value *theF, jl_value_t **args, } // call - Value *myargs; + Value *myargs = Constant::getNullValue(jl_ppvalue_llvmt); if (ctx->argTemp != NULL && nargs > 0) { myargs = builder.CreateGEP(ctx->argTemp, ConstantInt::get(T_size, argStart+ctx->argSpaceOffs)); } - else { - myargs = Constant::getNullValue(jl_ppvalue_llvmt); - } Value *result = builder.CreateCall3(prepare_call(theFptr), theF, myargs, ConstantInt::get(T_int32,nargs)); ctx->argDepth = argStart; return result; } -static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, - jl_value_t *expr) +static Value *emit_call_function_object(jl_function_t *f, Value *theF, Value *theFptr, + bool specialized, + jl_value_t **args, size_t nargs, + jl_codectx_t *ctx) { - size_t nargs = arglen-1; - Value *theFptr=NULL, *theF=NULL; - jl_value_t *a0 = args[0]; - jl_value_t *hdtype; - bool headIsGlobal = false; - - jl_function_t *f = (jl_function_t*)static_eval(a0, ctx, true); - if (f != NULL) { - Value *result; - headIsGlobal = true; - if (f->fptr != jl_f_no_function) { - result = emit_known_call((jl_value_t*)f, args, nargs, ctx, - &theFptr, &f, expr); - } - else { - result = emit_known_call((jl_value_t*)jl_call_func, - --args, ++nargs, ctx, &theFptr, &f, expr); - } - if (result != NULL) return result; - } - bool specialized = true; - int last_depth = ctx->argDepth; - hdtype = expr_type(a0, ctx); - if (theFptr == NULL) { - specialized = false; - Value *theFunc = emit_expr(args[0], ctx); - if ((hdtype!=(jl_value_t*)jl_function_type && - hdtype!=(jl_value_t*)jl_datatype_type && - !(jl_is_type_type(hdtype) && - jl_is_datatype(jl_tparam0(hdtype)))) || - jl_is_tuple(hdtype) || theFunc->getType() != jl_pvalue_llvmt) { - // it may not be a function, use call(f, ...) instead - headIsGlobal = true; - Value *result = emit_known_call((jl_value_t*)jl_call_func, - --args, ++nargs, ctx, - &theFptr, &f, expr); - if (result != NULL) return result; - theF = literal_pointer_val((jl_value_t*)f); - } - else { -#ifdef JL_GC_MARKSWEEP - if (!headIsGlobal && (jl_is_expr(a0) || jl_is_lambda_info(a0))) { - make_gcroot(boxed(theFunc,ctx), ctx); - } -#endif - // extract pieces of the function object - // TODO: try extractvalue instead - theFptr = builder.CreateBitCast(emit_nthptr(theFunc, 1, tbaa_func), jl_fptr_llvmt); - theF = theFunc; - } - } - else { - theF = literal_pointer_val((jl_value_t*)f); - } - Value *result; if (f!=NULL && specialized && f->linfo!=NULL && f->linfo->cFunctionObject!=NULL) { // emit specialized call site Function *cf = (Function*)f->linfo->cFunctionObject; FunctionType *cft = cf->getFunctionType(); size_t nfargs = cft->getNumParams(); - Value **argvals = (Value**) alloca(nfargs*sizeof(Value*)); + Value **argvals = (Value**)alloca(nfargs*sizeof(Value*)); unsigned idx = 0; for(size_t i=0; i < nargs; i++) { Type *at = cft->getParamType(idx); @@ -2277,8 +2221,8 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, } else { assert(at == et); - argvals[idx] = emit_unbox(at, - emit_unboxed(args[i+1], ctx),jl_tupleref(f->linfo->specTypes,i)); + argvals[idx] = emit_unbox(at, emit_unboxed(args[i+1], ctx), + jl_tupleref(f->linfo->specTypes,i)); assert(dyn_cast(argvals[idx]) == 0); } idx++; @@ -2290,6 +2234,142 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, else { result = emit_jlcall(theFptr, theF, &args[1], nargs, ctx); } + return result; +} + +static Value *emit_is_function(Value *x, jl_codectx_t *ctx) +{ + Value *xty = emit_typeof(x); + Value *isfunc = + builder. + CreateOr(builder. + CreateICmpEQ(xty, + literal_pointer_val((jl_value_t*)jl_function_type)), + builder. + CreateICmpEQ(xty, + literal_pointer_val((jl_value_t*)jl_datatype_type))); + return isfunc; +} + +static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, jl_value_t *expr) +{ + size_t nargs = arglen-1; + Value *theFptr=NULL, *theF=NULL; + jl_value_t *a0 = args[0]; + jl_value_t *hdtype; + bool headIsGlobal = false; + bool definitely_function = false; + bool definitely_not_function = false; + + jl_function_t *f = (jl_function_t*)static_eval(a0, ctx, true); + if (f != NULL) { + // function is a compile-time constant + Value *result; + headIsGlobal = true; + definitely_function = jl_is_func(f); + definitely_not_function = !definitely_function; + if (jl_typeis(f, jl_intrinsic_type) || jl_is_func(f)) { + result = emit_known_call((jl_value_t*)f, args, nargs, ctx, + &theFptr, &f, expr); + assert(!jl_typeis(f,jl_intrinsic_type) || result!=NULL); + } + else { + result = emit_known_call((jl_value_t*)jl_call_func, + args-1, nargs+1, ctx, &theFptr, &f, expr); + } + if (result != NULL) return result; + } + + hdtype = expr_type(a0, ctx); + definitely_function |= (hdtype == (jl_value_t*)jl_function_type || + hdtype == (jl_value_t*)jl_datatype_type || + (jl_is_type_type(hdtype) && + jl_is_datatype(jl_tparam0(hdtype)))); + definitely_not_function |= (jl_is_leaf_type(hdtype) && !definitely_function); + + assert(!(definitely_function && definitely_not_function)); + + int last_depth = ctx->argDepth; + Value *result; + + if (definitely_not_function) { + if (f == NULL) { + f = jl_call_func; + Value *r = emit_known_call((jl_value_t*)jl_call_func, + args-1, nargs+1, ctx, &theFptr, &f, expr); + assert(r == NULL); + assert(theFptr != NULL); + } + theF = literal_pointer_val((jl_value_t*)f); + result = emit_call_function_object(f, theF, theFptr, true, args-1, nargs+1, ctx); + } + else if (definitely_function) { + bool specialized = true; + if (theFptr == NULL) { + specialized = false; + Value *theFunc = emit_expr(args[0], ctx); +#ifdef JL_GC_MARKSWEEP + if (!headIsGlobal && (jl_is_expr(a0) || jl_is_lambda_info(a0))) { + make_gcroot(boxed(theFunc,ctx), ctx); + } +#endif + // extract pieces of the function object + // TODO: try extractvalue instead + theFptr = builder.CreateBitCast(emit_nthptr(theFunc, 1, tbaa_func), jl_fptr_llvmt); + theF = theFunc; + } + else { + theF = literal_pointer_val((jl_value_t*)f); + } + result = emit_call_function_object(f, theF, theFptr, specialized, args, nargs, ctx); + } + else { + // either direct function, or use call(), based on run-time branch + + // emit "function" and arguments + int argStart = ctx->argDepth; + Value *theFunc = boxed(emit_expr(args[0], ctx), ctx); + make_gcroot(theFunc, ctx); + for(size_t i=0; i < nargs; i++) { + Value *anArg = emit_expr(args[i+1], ctx); + // put into argument space + make_gcroot(boxed(anArg, ctx, expr_type(args[i+1],ctx)), ctx); + } + + Value *isfunc = emit_is_function(theFunc, ctx); + BasicBlock *funcBB1 = BasicBlock::Create(getGlobalContext(),"isf", ctx->f); + BasicBlock *elseBB1 = BasicBlock::Create(getGlobalContext(),"notf"); + BasicBlock *mergeBB1 = BasicBlock::Create(getGlobalContext(),"mergef"); + builder.CreateCondBr(isfunc, funcBB1, elseBB1); + + builder.SetInsertPoint(funcBB1); + // is function + Value *myargs = Constant::getNullValue(jl_ppvalue_llvmt); + if (ctx->argTemp != NULL && nargs > 0) { + myargs = builder.CreateGEP(ctx->argTemp, + ConstantInt::get(T_size, argStart+1+ctx->argSpaceOffs)); + } + theFptr = builder.CreateBitCast(emit_nthptr(theFunc, 1, tbaa_func), jl_fptr_llvmt); + Value *r1 = builder.CreateCall3(prepare_call(theFptr), theFunc, myargs, + ConstantInt::get(T_int32,nargs)); + builder.CreateBr(mergeBB1); + ctx->f->getBasicBlockList().push_back(elseBB1); + builder.SetInsertPoint(elseBB1); + // not function + myargs = builder.CreateGEP(ctx->argTemp, + ConstantInt::get(T_size, argStart+ctx->argSpaceOffs)); + Value *r2 = builder.CreateCall3(prepare_call(jlapplygeneric_func), + literal_pointer_val((jl_value_t*)jl_call_func), + myargs, + ConstantInt::get(T_int32,nargs+1)); + builder.CreateBr(mergeBB1); + ctx->f->getBasicBlockList().push_back(mergeBB1); + builder.SetInsertPoint(mergeBB1); + PHINode *ph = builder.CreatePHI(jl_pvalue_llvmt, 2); + ph->addIncoming(r1, funcBB1); + ph->addIncoming(r2, elseBB1); + result = ph; + } ctx->argDepth = last_depth; return result; diff --git a/src/init.c b/src/init.c index 59b0bba872093..8bb89eb632344 100644 --- a/src/init.c +++ b/src/init.c @@ -1090,8 +1090,6 @@ void jl_get_builtin_hooks(void) jl_array_uint8_type = jl_apply_type((jl_value_t*)jl_array_type, jl_tuple2(jl_uint8_type, jl_box_long(1))); - - jl_call_func = (jl_function_t*)core("call"); } DLLEXPORT void jl_get_system_hooks(void) @@ -1103,6 +1101,7 @@ DLLEXPORT void jl_get_system_hooks(void) jl_methoderror_type = (jl_datatype_t*)basemod("MethodError"); jl_loaderror_type = (jl_datatype_t*)basemod("LoadError"); jl_weakref_type = (jl_datatype_t*)basemod("WeakRef"); + jl_call_func = (jl_function_t*)basemod("call"); } DLLEXPORT void jl_exit_on_sigint(int on) {exit_on_sigint = on;} diff --git a/src/interpreter.c b/src/interpreter.c index 7e006cae03761..8d7f312771271 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -208,11 +208,10 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) } } jl_function_t *f = (jl_function_t*)eval(args[0], locals, nl); - if (jl_is_func(f) && f->fptr != jl_f_no_function) + if (jl_is_func(f)) return do_call(f, &args[1], nargs-1, NULL, locals, nl); else - return do_call(jl_call_func, args, nargs, (jl_value_t*)f, - locals, nl); + return do_call(jl_call_func, args, nargs, (jl_value_t*)f, locals, nl); } else if (ex->head == assign_sym) { jl_value_t *sym = args[0]; diff --git a/test/core.jl b/test/core.jl index cf782197d8d07..9d95a2b4eebd8 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1830,9 +1830,7 @@ end # issue #7582 aₜ = "a variable using Unicode 6" -# call and constructor overloading (#1470, #2403) -typealias FooInt32 Int32 -@test isa(FooInt32(3), FooInt32) +# call overloading (#2403) Base.call(x::Int, y::Int) = x + 3y issue2403func(f) = f(7) let x = 10 @@ -1846,5 +1844,5 @@ end Base.call(i::Issue2403, y) = i.x + 2y let x = Issue2403(20) @test x(3) == 26 - # @test issue2403func(x) == 34 -- FIXME + @test issue2403func(x) == 34 end From bd955f2d08dfe295056c55aa9677d1cc7039188a Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 1 Sep 2014 15:01:56 -0400 Subject: [PATCH 07/44] update emit_call for jl_fptr_llvmt => jl_pfptr_llvmt change --- src/codegen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index e724878ff9124..fd40638c3f427 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2387,7 +2387,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, jl_ #endif // extract pieces of the function object // TODO: try extractvalue instead - theFptr = builder.CreateBitCast(emit_nthptr(theFunc, 1, tbaa_func), jl_fptr_llvmt); + theFptr = emit_nthptr_recast(theFunc, 1, tbaa_func, jl_pfptr_llvmt); theF = theFunc; } else { @@ -2421,7 +2421,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, jl_ myargs = builder.CreateGEP(ctx->argTemp, ConstantInt::get(T_size, argStart+1+ctx->argSpaceOffs)); } - theFptr = builder.CreateBitCast(emit_nthptr(theFunc, 1, tbaa_func), jl_fptr_llvmt); + theFptr = emit_nthptr_recast(theFunc, 1, tbaa_func, jl_pfptr_llvmt); Value *r1 = builder.CreateCall3(prepare_call(theFptr), theFunc, myargs, ConstantInt::get(T_int32,nargs)); builder.CreateBr(mergeBB1); From aeae50f4e84870020bb4d65d8a26d7ba7e08cb69 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 9 Oct 2014 20:22:27 -0400 Subject: [PATCH 08/44] some work on call overloading - look up call in the right module instead of using jl_call_func - some inference support for call overloading - pass `call` to _apply and kwcall so they use the containing module's definition - deprecate explicit apply(), rename the builtin to _apply --- base/base.jl | 5 +- base/boot.jl | 12 +-- base/deprecated.jl | 6 ++ base/exports.jl | 1 + base/inference.jl | 159 +++++++++++++++++++++++++-------------- base/linalg/bidiag.jl | 4 +- base/operators.jl | 5 +- base/sysimg.jl | 2 +- src/alloc.c | 1 - src/builtins.c | 56 +++++++------- src/codegen.cpp | 8 +- src/init.c | 1 - src/interpreter.c | 2 +- src/julia-syntax.scm | 10 +-- src/julia.h | 2 + src/julia_internal.h | 2 - src/module.c | 12 +++ test/core.jl | 2 +- test/perf/perfgeneric.jl | 3 +- 19 files changed, 182 insertions(+), 111 deletions(-) diff --git a/base/base.jl b/base/base.jl index 47d0e7bd1343a..4eab0c592c5cc 100644 --- a/base/base.jl +++ b/base/base.jl @@ -11,8 +11,11 @@ convert(T, x) = convert_default(T, x, convert) convert(::(), ::()) = () convert(::Type{Tuple}, x::Tuple) = x +# fall back to Core.call +call(args...) = Core.call(args...) + # allow convert to be called as if it were a single-argument constructor -call{T}(::Type{T}, x) = convert(T, x) +# call(T::Type, x) = convert(T, x) argtail(x, rest...) = rest tupletail(x::Tuple) = argtail(x...) diff --git a/base/boot.jl b/base/boot.jl index 0503e5ec50055..ffe6e6d3cb353 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -137,9 +137,9 @@ export Expr, GotoNode, LabelNode, LineNumberNode, QuoteNode, SymbolNode, TopNode, GetfieldNode, NewvarNode, # object model functions - apply, fieldtype, getfield, setfield!, yieldto, throw, tuple, is, ===, isdefined, + fieldtype, getfield, setfield!, yieldto, throw, tuple, is, ===, isdefined, # arraylen, arrayref, arrayset, arraysize, tuplelen, tupleref, convert_default, - # kwcall, + # _apply, kwcall, # sizeof # not exported, to avoid conflicting with Base.sizeof # type reflection issubtype, typeof, isa, @@ -168,6 +168,11 @@ export const (===) = is +# simple convert for use by constructors of types in Core +convert(T, x) = convert_default(T, x, convert) + +call(T::Type, arg) = convert(T, arg) + abstract Number abstract Real <: Number abstract FloatingPoint <: Real @@ -217,9 +222,6 @@ type InterruptException <: Exception end abstract String abstract DirectIndexString <: String -# simple convert for use by constructors of types in Core -convert(T, x) = convert_default(T, x, convert) - type SymbolNode name::Symbol typ diff --git a/base/deprecated.jl b/base/deprecated.jl index 466e270d5b389..aeb537b761b7f 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -185,3 +185,9 @@ const Nothing = Void export None const None = Union() + +export apply +function apply(f, args...) + depwarn("apply() is deprecated, use `...` instead", :apply) + return Core._apply(call, f, args...) +end diff --git a/base/exports.jl b/base/exports.jl index 22847d26f05ba..ac9df7c3df390 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -269,6 +269,7 @@ export At_mul_Bt!, At_rdiv_B, At_rdiv_Bt, + call, # scalar math @evalpoly, diff --git a/base/inference.jl b/base/inference.jl index 0ecb096029962..e022c01a3e478 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -476,8 +476,6 @@ const apply_type_tfunc = function (A, args...) end t_func[apply_type] = (1, Inf, apply_type_tfunc) -# other: apply - function tuple_tfunc(argtypes::ANY, limit) t = argtypes if limit @@ -787,53 +785,80 @@ function to_tuple_of_Types(t::ANY) return t end +# do apply(af, fargs...), where af is a function value +function abstract_apply(af, aargtypes, vtypes, sv, e) + if all(x->isa(x,Tuple), aargtypes) && + !any(isvatuple, aargtypes[1:(length(aargtypes)-1)]) + e.head = :call1 + # apply with known func with known tuple types + # can be collapsed to a call to the applied func + at = length(aargtypes) > 0 ? + limit_tuple_type(tuple(append_any(aargtypes...)...)) : () + return abstract_call(af, (), at, vtypes, sv, ()) + end + if is(af,tuple) && length(aargtypes)==1 + # tuple(xs...) + aat = aargtypes[1] + if aat <: AbstractArray + # tuple(array...) + # TODO: > 1 array of the same type + tn = AbstractArray.name + while isa(aat, DataType) + if is(aat.name, tn) + et = aat.parameters[1] + if !isa(et,TypeVar) + return (et...) + end + end + if is(aat, Any) + break + end + aat = aat.super + end + end + return Tuple + end + if is(af,kwcall) + return Any + end + # apply known function with unknown args => f(Any...) + return abstract_call(af, (), Tuple, vtypes, sv, ()) +end + function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e) - if is(f,apply) && length(fargs)>0 - if isType(argtypes[1]) && isleaftype(argtypes[1].parameters[1]) - af = argtypes[1].parameters[1] + if is(f,_apply) && length(fargs)>1 + a2type = argtypes[2] + if isType(a2type) && isleaftype(a2type.parameters[1]) + af = a2type.parameters[1] _methods(af,(),0) else - af = isconstantfunc(fargs[1], sv) + af = isconstantfunc(fargs[2], sv) end + if !is(af,false) - aargtypes = map(to_tuple_of_Types, argtypes[2:end]) - if all(x->isa(x,Tuple), aargtypes) && - !any(isvatuple, aargtypes[1:(length(aargtypes)-1)]) - e.head = :call1 - # apply with known func with known tuple types - # can be collapsed to a call to the applied func - at = length(aargtypes) > 0 ? - limit_tuple_type(apply(tuple,aargtypes...)) : () - return abstract_call(_ieval(af), (), at, vtypes, sv, ()) - end af = _ieval(af) - if is(af,tuple) && length(fargs)==2 - # tuple(xs...) - aat = aargtypes[1] - if aat <: AbstractArray - # tuple(array...) - # TODO: > 1 array of the same type - tn = AbstractArray.name - while isa(aat, DataType) - if is(aat.name, tn) - et = aat.parameters[1] - if !isa(et,TypeVar) - return (et...) - end - end - if is(aat, Any) - break - end - aat = aat.super - end + if isa(af,Function) || isa(af,DataType) + aargtypes = map(to_tuple_of_Types, argtypes[3:end]) + return abstract_apply(af, aargtypes, vtypes, sv, e) + else + call_func = isconstantfunc(fargs[1]) + if !is(call_func,false) + aargtypes = map(to_tuple_of_Types, argtypes[2:end]) + aargtypes[1] = (aargtypes[1],) # don't splat "function" + return abstract_apply(_ieval(call_func), aargtypes, vtypes, sv, e) end - return Tuple end - if is(af,kwcall) - return Any + else + # non-constant function + if !(Function <: a2type) && typeintersect(DataType, a2type)==Bottom + # would definitely use call() + call_func = isconstantfunc(fargs[1]) + if !is(call_func,false) + aargtypes = map(to_tuple_of_Types, argtypes[2:end]) + aargtypes[1] = (aargtypes[1],) # don't splat "function" + return abstract_apply(_ieval(call_func), aargtypes, vtypes, sv, e) + end end - # apply known function with unknown args => f(Any...) - return abstract_call(af, (), Tuple, vtypes, sv, ()) end end if isgeneric(f) @@ -849,7 +874,7 @@ function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e) end end end - if !is(f,apply) && isa(e,Expr) && (isa(f,Function) || isa(f,IntrinsicFunction)) + if !is(f,_apply) && isa(e,Expr) && (isa(f,Function) || isa(f,IntrinsicFunction)) e.head = :call1 end if is(f,getfield) @@ -859,25 +884,32 @@ function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e) end end if is(f,kwcall) - if length(argtypes) < 3 + if length(argtypes) < 4 return Bottom end - if length(fargs) < 2 + if length(fargs) < 3 return Any end - ff = isconstantfunc(fargs[1], sv) + kwcount = fargs[2] + ff = isconstantfunc(fargs[4 + 2*kwcount], sv) if !(ff===false) ff = _ieval(ff) if isgeneric(ff) && isdefined(ff.env,:kwsorter) # use the fact that kwcall(...) calls ff.env.kwsorter - kwcount = fargs[2] - posargt = argtypes[(4+2*kwcount):end] + posargt = argtypes[(5+2*kwcount):end] return abstract_call_gf(ff.env.kwsorter, (), tuple(Array{Any,1}, posargt...), e) end end + # TODO: call() case return Any end + if !isa(f,Function) && !isa(f,DataType) && !isa(f,IntrinsicFunction) + call_func = isconstantfunc(:call, sv) + if !is(call_func,false) + return abstract_call(_ieval(call_func), e.args, tuple(typeof(f),argtypes...), vtypes, sv, e) + end + end rt = builtin_tfunction(f, fargs, argtypes) #print("=> ", rt, "\n") return rt @@ -924,6 +956,12 @@ function abstract_eval_call(e, vtypes, sv::StaticVarInfo) return st end end + if !(Function <: ft) && typeintersect(DataType, ft)==Bottom + call_func = isconstantfunc(:call, sv) + if !is(call_func,false) + return abstract_call(_ieval(call_func), e.args, tuple(ft,argtypes...), vtypes, sv, e) + end + end return Any end #print("call ", e.args[1], argtypes, " ") @@ -1313,6 +1351,8 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop) end #if dbg print("typeinf ", linfo.name, " ", atypes, "\n") end + #ccall(:jl_,Void,(Any,),linfo.name) + #ccall(:jl_,Void,(Any,),atypes) if cop sparams = tuple(sparams..., linfo.sparams...) @@ -2648,7 +2688,14 @@ function inlining_pass(e::Expr, sv, ast) if isType(ET) f = ET.parameters[1] else - f = _ieval(arg1) + f1 = f = isconstantfunc(arg1, sv) + if !is(f,false) + f = _ieval(f) + end + if f1===false || !(isa(f,Function) || isa(f,Type) || isa(f,IntrinsicFunction)) + f = _ieval(:call) + e.args = Any[f, e.args...] + end end if is(f, ^) || is(f, .^) @@ -2683,34 +2730,34 @@ function inlining_pass(e::Expr, sv, ast) if !is(res,NF) # iteratively inline apply(f, tuple(...), tuple(...), ...) in order # to simplify long vararg lists as in multi-arg + - if isa(res,Expr) && is_known_call(res, apply, sv) + if isa(res,Expr) && is_known_call(res, _apply, sv) e = res::Expr - f = apply + f = _apply else return (res,stmts) end end - if is(f,apply) + if is(f,_apply) na = length(e.args) - newargs = cell(na-2) - for i = 3:na + newargs = cell(na-3) + for i = 4:na aarg = e.args[i] t = to_tuple_of_Types(exprtype(aarg)) if isa(aarg,Expr) && is_known_call(aarg, tuple, sv) # apply(f,tuple(x,y,...)) => f(x,y,...) - newargs[i-2] = aarg.args[2:end] + newargs[i-3] = aarg.args[2:end] elseif isa(aarg, Tuple) - newargs[i-2] = { QuoteNode(x) for x in aarg } + newargs[i-3] = { QuoteNode(x) for x in aarg } elseif isa(t,Tuple) && !isvatuple(t) && effect_free(aarg,sv,true) # apply(f,t::(x,y)) => f(t[1],t[2]) - newargs[i-2] = { mk_tupleref(aarg,j,t[j]) for j=1:length(t) } + newargs[i-3] = { mk_tupleref(aarg,j,t[j]) for j=1:length(t) } else # not all args expandable return (e,stmts) end end - e.args = [{e.args[2]}, newargs...] + e.args = [{e.args[3]}, newargs...] # now try to inline the simplified call diff --git a/base/linalg/bidiag.jl b/base/linalg/bidiag.jl index e83403ded6590..f7febba36574c 100644 --- a/base/linalg/bidiag.jl +++ b/base/linalg/bidiag.jl @@ -92,7 +92,7 @@ function +(A::Bidiagonal, B::Bidiagonal) if A.isupper==B.isupper Bidiagonal(A.dv+B.dv, A.ev+B.ev, A.isupper) else - apply(Tridiagonal, A.isupper ? (B.ev,A.dv+B.dv,A.ev) : (A.ev,A.dv+B.dv,B.ev)) + Tridiagonal((A.isupper ? (B.ev,A.dv+B.dv,A.ev) : (A.ev,A.dv+B.dv,B.ev))...) end end @@ -100,7 +100,7 @@ function -(A::Bidiagonal, B::Bidiagonal) if A.isupper==B.isupper Bidiagonal(A.dv-B.dv, A.ev-B.ev, A.isupper) else - apply(Tridiagonal, A.isupper ? (-B.ev,A.dv-B.dv,A.ev) : (A.ev,A.dv-B.dv,-B.ev)) + Tridiagonal((A.isupper ? (-B.ev,A.dv-B.dv,A.ev) : (A.ev,A.dv-B.dv,-B.ev))...) end end diff --git a/base/operators.jl b/base/operators.jl index ded6dfd9e42ed..34916c15fd5a0 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -498,12 +498,13 @@ export getindex, setindex!, transpose, - ctranspose + ctranspose, + call import Base: !, !=, $, %, .%, &, *, +, -, .!=, .+, .-, .*, ./, .<, .<=, .==, .>, .>=, .\, .^, /, //, <, <:, <<, <=, ==, >, >=, >>, .>>, .<<, >>>, <|, |>, \, ^, |, ~, !==, >:, colon, hcat, vcat, hvcat, getindex, setindex!, - transpose, ctranspose, + transpose, ctranspose, call, ≥, ≤, ≠, .≥, .≤, .≠, ÷, ⋅, ×, ∈, ∉, ∋, ∌, ⊆, ⊈, ⊊, ∩, ∪, √, ∛ end diff --git a/base/sysimg.jl b/base/sysimg.jl index b31e71e221707..4f8d4fd44ca26 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -9,7 +9,7 @@ eval(m,x) = Core.eval(m,x) include = Core.include using Core: Intrinsics, arraylen, arrayref, arrayset, arraysize, - tuplelen, tupleref, convert_default, kwcall, + tuplelen, tupleref, convert_default, kwcall, _apply, typeassert, apply_type include("exports.jl") diff --git a/src/alloc.c b/src/alloc.c index 2eb1975728eae..daaa3f64ac007 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -67,7 +67,6 @@ jl_value_t *jl_undefref_exception; jl_value_t *jl_interrupt_exception; jl_value_t *jl_bounds_exception; jl_value_t *jl_memory_exception; -jl_function_t *jl_call_func; jl_sym_t *call_sym; jl_sym_t *dots_sym; jl_sym_t *call1_sym; jl_sym_t *module_sym; diff --git a/src/builtins.c b/src/builtins.c index 796f9bfa2fa14..4adb71c505160 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -284,13 +284,18 @@ extern size_t jl_page_size; JL_CALLABLE(jl_f_apply) { - JL_NARGSV(apply, 1); + JL_NARGSV(apply, 2); jl_function_t *f; - if (jl_is_function(args[0])) - f = (jl_function_t*)args[0]; + jl_function_t *call_func = (jl_function_t*)args[0]; + assert(jl_is_function(call_func)); + if (jl_is_function(args[1])) { + f = (jl_function_t*)args[1]; + --nargs; ++args; /* args[1] becomes args[0] */ + } else { /* do generic call(args...) instead */ - f = jl_call_func; - ++nargs; --args; /* args[0] becomes args[1] */ + f = call_func; + // protect "function" arg from splicing + args[1] = (jl_value_t*)jl_tuple1(args[1]); } if (nargs == 2) { if (f->fptr == &jl_f_tuple) { @@ -372,18 +377,28 @@ void jl_add_constructors(jl_datatype_t *t); JL_CALLABLE(jl_f_kwcall) { - if (nargs < 3) + if (nargs < 4) jl_error("internal error: malformed keyword argument call"); jl_function_t *f; - jl_value_t *args0; - if (jl_is_function(args[0])) { - f = (jl_function_t*)args[0]; - args0 = NULL; + jl_function_t *call_func = (jl_function_t*)args[0]; + assert(jl_is_function(call_func)); + size_t nkeys = jl_unbox_long(args[1]); + size_t pa = 4 + 2*nkeys; + jl_array_t *container = (jl_array_t*)args[pa-2]; + assert(jl_array_len(container) > 0); + f = (jl_function_t*)args[pa-1]; + if (!jl_is_function(f)) { + // do generic call(args...; kws...) instead + f = call_func; + pa--; } - else { /* do generic call(args...; kws...) instead */ - f = jl_call_func; - args0 = args[0]; + else { + // switch (container f pa...) to (f container pa...) + // TODO: this is not as legitimate as it could be. + args[pa-1] = args[pa-2]; + args[pa-2] = (jl_value_t*)f; } + if (f->fptr == jl_f_ctor_trampoline) jl_add_constructors((jl_datatype_t*)f); if (!jl_is_gf(f)) @@ -394,10 +409,6 @@ JL_CALLABLE(jl_f_kwcall) jl_gf_name(f)->name); } - size_t nkeys = jl_unbox_long(args[1]); - size_t pa = 3 + 2*nkeys; - jl_array_t *container = (jl_array_t*)args[pa-1]; - assert(jl_array_len(container) > 0); for(size_t i=0; i < nkeys*2; i+=2) { jl_cellset(container, i , args[2+i]); jl_cellset(container, i+1, args[2+i+1]); @@ -405,15 +416,6 @@ JL_CALLABLE(jl_f_kwcall) args += pa-1; nargs -= pa-1; - if (args0) { - jl_value_t **newargs = (jl_value_t**)alloca((nargs+1) * sizeof(jl_value_t*)); - newargs[0] = args[0]; - newargs[1] = args0; /* original 0th argument = "function" */ - memcpy(newargs+2, args+1, sizeof(jl_value_t*) * (nargs-1)); - args = newargs; - nargs += 1; - } - assert(jl_is_gf(sorter)); jl_function_t *m = jl_method_lookup((jl_methtable_t*)sorter->env, args, nargs, 1); if (m == jl_bottom_func) { @@ -1055,7 +1057,7 @@ void jl_init_primitives(void) add_builtin_func("issubtype", jl_f_subtype); add_builtin_func("isa", jl_f_isa); add_builtin_func("typeassert", jl_f_typeassert); - add_builtin_func("apply", jl_f_apply); + add_builtin_func("_apply", jl_f_apply); add_builtin_func("kwcall", jl_f_kwcall); add_builtin_func("throw", jl_f_throw); add_builtin_func("tuple", jl_f_tuple); diff --git a/src/codegen.cpp b/src/codegen.cpp index 9a86481f9e805..b711ad4284d5f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2357,7 +2357,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, jl_ assert(!jl_typeis(f,jl_intrinsic_type) || result!=NULL); } else { - result = emit_known_call((jl_value_t*)jl_call_func, + result = emit_known_call((jl_value_t*)jl_module_call_func(ctx->module), args-1, nargs+1, ctx, &theFptr, &f, expr); } if (result != NULL) return result; @@ -2377,8 +2377,8 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, jl_ if (definitely_not_function) { if (f == NULL) { - f = jl_call_func; - Value *r = emit_known_call((jl_value_t*)jl_call_func, + f = jl_module_call_func(ctx->module); + Value *r = emit_known_call((jl_value_t*)f, args-1, nargs+1, ctx, &theFptr, &f, expr); assert(r == NULL); assert(theFptr != NULL); @@ -2442,7 +2442,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, jl_ myargs = builder.CreateGEP(ctx->argTemp, ConstantInt::get(T_size, argStart+ctx->argSpaceOffs)); Value *r2 = builder.CreateCall3(prepare_call(jlapplygeneric_func), - literal_pointer_val((jl_value_t*)jl_call_func), + literal_pointer_val((jl_value_t*)jl_module_call_func(ctx->module)), myargs, ConstantInt::get(T_int32,nargs+1)); builder.CreateBr(mergeBB1); diff --git a/src/init.c b/src/init.c index a327370eaee99..02dee85ab1ab7 100644 --- a/src/init.c +++ b/src/init.c @@ -1121,7 +1121,6 @@ DLLEXPORT void jl_get_system_hooks(void) jl_methoderror_type = (jl_datatype_t*)basemod("MethodError"); jl_loaderror_type = (jl_datatype_t*)basemod("LoadError"); jl_weakref_type = (jl_datatype_t*)basemod("WeakRef"); - jl_call_func = (jl_function_t*)basemod("call"); } DLLEXPORT void jl_exit_on_sigint(int on) {exit_on_sigint = on;} diff --git a/src/interpreter.c b/src/interpreter.c index 1fbb6410dd7c3..6bfdf341f731b 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -211,7 +211,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) if (jl_is_func(f)) return do_call(f, &args[1], nargs-1, NULL, locals, nl); else - return do_call(jl_call_func, args, nargs, (jl_value_t*)f, locals, nl); + return do_call(jl_module_call_func(jl_current_module), args, nargs, (jl_value_t*)f, locals, nl); } else if (ex->head == assign_sym) { jl_value_t *sym = args[0]; diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 4c216d7502ac3..da54ef8fd3c3e 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1469,9 +1469,9 @@ `((quote ,(cadr a)) ,(caddr a))) keys)))) (if (null? restkeys) - `(call (top kwcall) ,f ,(length keys) ,@keyargs + `(call (top kwcall) call ,(length keys) ,@keyargs (call (top Array) (top Any) ,(* 2 (length keys))) - ,@pa) + ,f ,@pa) (let ((container (gensy))) `(block (= ,container (call (top Array) (top Any) ,(* 2 (length keys)))) @@ -1491,8 +1491,8 @@ restkeys)) (if (call (top isempty) ,container) (call ,f ,@pa) - (call (top kwcall) ,f ,(length keys) ,@keyargs - ,container ,@pa)))))))) + (call (top kwcall) call ,(length keys) ,@keyargs + ,container ,f ,@pa)))))))) (define (expand-transposed-op e ops) (let ((a (caddr e)) @@ -1737,7 +1737,7 @@ (tuple-wrap (cdr a) '()))) (tuple-wrap (cdr a) (cons x run)))))) (expand-forms - `(call (top apply) ,f ,@(tuple-wrap argl '()))))) + `(call (top _apply) call ,f ,@(tuple-wrap argl '()))))) ((and (eq? (cadr e) '*) (length= e 4)) (expand-transposed-op diff --git a/src/julia.h b/src/julia.h index f12ccbd3ae884..2952851f27df2 100644 --- a/src/julia.h +++ b/src/julia.h @@ -255,6 +255,7 @@ typedef struct _jl_module_t { htable_t bindings; arraylist_t usings; // modules with all bindings potentially imported jl_array_t *constant_table; + jl_function_t *call_func; // cached lookup of `call` within this module } jl_module_t; typedef struct _jl_methlist_t { @@ -817,6 +818,7 @@ STATIC_INLINE jl_function_t *jl_get_function(jl_module_t *m, const char *name) } DLLEXPORT int jl_module_has_initializer(jl_module_t *m); DLLEXPORT void jl_module_run_initializer(jl_module_t *m); +jl_function_t *jl_module_call_func(jl_module_t *m); // eq hash tables DLLEXPORT jl_array_t *jl_eqtable_put(jl_array_t *h, void *key, void *val); diff --git a/src/julia_internal.h b/src/julia_internal.h index cff0a90698935..157740f37f110 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -129,8 +129,6 @@ DLLEXPORT void jl_raise_debugger(void); // Returns time in nanosec DLLEXPORT uint64_t jl_hrtime(void); -extern DLLEXPORT jl_function_t *jl_call_func; - #ifdef __cplusplus } #endif diff --git a/src/module.c b/src/module.c index 41aa9513e707d..328024264535e 100644 --- a/src/module.c +++ b/src/module.c @@ -22,6 +22,7 @@ jl_module_t *jl_new_module(jl_sym_t *name) assert(jl_is_symbol(name)); m->name = name; m->constant_table = NULL; + m->call_func = NULL; htable_new(&m->bindings, 0); arraylist_new(&m->usings, 0); if (jl_core_module) { @@ -446,6 +447,17 @@ void jl_module_run_initializer(jl_module_t *m) } } +jl_function_t *jl_module_call_func(jl_module_t *m) +{ + if (m->call_func == NULL) { + jl_function_t *cf = (jl_function_t*)jl_get_global(m, call_sym); + if (cf == NULL || !jl_is_function(cf)) + return jl_bottom_func; + m->call_func = cf; + } + return m->call_func; +} + #ifdef __cplusplus } #endif diff --git a/test/core.jl b/test/core.jl index e637d2358a701..55fe81148f8fe 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1885,7 +1885,7 @@ Base.call(x::Int, y::Int) = x + 3y issue2403func(f) = f(7) let x = 10 @test x(3) == 19 - @test apply(x, (3,)) == 19 + @test x((3,)...) == 19 @test issue2403func(x) == 31 end type Issue2403 diff --git a/test/perf/perfgeneric.jl b/test/perf/perfgeneric.jl index 4ebb96f338096..203e8f9236a42 100644 --- a/test/perf/perfgeneric.jl +++ b/test/perf/perfgeneric.jl @@ -1,7 +1,6 @@ #Generic benchmark driver for (testfunc, testname, longtestname, problem_sizes) in testdata for (n, t, size) in problem_sizes - @timeit apply(testfunc, n, t) string(testname,"_",size) string(uppercase(size[1]),size[2:end]," ",longtestname," test") + @timeit testfunc(n, t) string(testname,"_",size) string(uppercase(size[1]),size[2:end]," ",longtestname," test") end end - From 24637047860ab7f4cfc0c0d51dd523f6aeca3dc1 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 9 Oct 2014 21:57:20 -0400 Subject: [PATCH 09/44] fix codegen for changes to apply() for call overloading --- src/codegen.cpp | 12 ++++++------ src/module.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index b711ad4284d5f..84ff537beae60 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1189,8 +1189,8 @@ static void simple_escape_analysis(jl_value_t *expr, bool esc, jl_codectx_t *ctx jl_function_t *ff = (jl_function_t*)fv; if (ff->fptr == jl_f_tuplelen || ff->fptr == jl_f_tupleref || - (ff->fptr == jl_f_apply && alen==3 && - expr_type(jl_exprarg(e,1),ctx) == (jl_value_t*)jl_function_type)) { + (ff->fptr == jl_f_apply && alen==4 && + expr_type(jl_exprarg(e,2),ctx) == (jl_value_t*)jl_function_type)) { esc = false; } } @@ -1811,10 +1811,10 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, } } } - else if (f->fptr == &jl_f_apply && nargs==2 && ctx->vaStack && - symbol_eq(args[2], ctx->vaName)) { - Value *theF = emit_expr(args[1],ctx); - Value *theFptr = emit_nthptr_recast(theF,1, tbaa_func,jl_pfptr_llvmt); + else if (f->fptr == &jl_f_apply && nargs==3 && ctx->vaStack && + symbol_eq(args[3], ctx->vaName) && expr_type(args[2],ctx) == (jl_value_t*)jl_function_type) { + Value *theF = emit_expr(args[2],ctx); + Value *theFptr = emit_nthptr_recast(theF,1, tbaa_func, jl_pfptr_llvmt); Value *nva = emit_n_varargs(ctx); #ifdef _P64 nva = builder.CreateTrunc(nva, T_int32); diff --git a/src/module.c b/src/module.c index 328024264535e..5f8ed958d4e14 100644 --- a/src/module.c +++ b/src/module.c @@ -452,7 +452,7 @@ jl_function_t *jl_module_call_func(jl_module_t *m) if (m->call_func == NULL) { jl_function_t *cf = (jl_function_t*)jl_get_global(m, call_sym); if (cf == NULL || !jl_is_function(cf)) - return jl_bottom_func; + cf = jl_bottom_func; m->call_func = cf; } return m->call_func; From 5b03766bf728692fdb1563447dab5601b06b78a0 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 9 Oct 2014 23:44:25 -0400 Subject: [PATCH 10/44] temporarily restore inference/startup performance --- base/inference.jl | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index 81588a8603b6d..65d318fdd034e 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -840,26 +840,19 @@ function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e) if isa(af,Function) || isa(af,DataType) aargtypes = map(to_tuple_of_Types, argtypes[3:end]) return abstract_apply(af, aargtypes, vtypes, sv, e) - else - call_func = isconstantfunc(fargs[1]) - if !is(call_func,false) - aargtypes = map(to_tuple_of_Types, argtypes[2:end]) - aargtypes[1] = (aargtypes[1],) # don't splat "function" - return abstract_apply(_ieval(call_func), aargtypes, vtypes, sv, e) - end - end - else - # non-constant function - if !(Function <: a2type) && typeintersect(DataType, a2type)==Bottom - # would definitely use call() - call_func = isconstantfunc(fargs[1]) - if !is(call_func,false) - aargtypes = map(to_tuple_of_Types, argtypes[2:end]) - aargtypes[1] = (aargtypes[1],) # don't splat "function" - return abstract_apply(_ieval(call_func), aargtypes, vtypes, sv, e) - end end end + # TODO: this slows down inference a lot + # if !(a2type===Function || a2type===DataType) && isleaftype(a2type) + # # would definitely use call() + # call_func = isconstantfunc(fargs[1]) + # if !is(call_func,false) + # aargtypes = Any[ to_tuple_of_Types(argtypes[i]) for i=2:length(argtypes) ] + # aargtypes[1] = (aargtypes[1],) # don't splat "function" + # return abstract_apply(_ieval(call_func), tuple(aargtypes...), vtypes, sv, e) + # end + # end + return Any end if isgeneric(f) return abstract_call_gf(f, fargs, argtypes, e) @@ -904,11 +897,9 @@ function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e) # TODO: call() case return Any end - if !isa(f,Function) && !isa(f,DataType) && !isa(f,IntrinsicFunction) - call_func = isconstantfunc(:call, sv) - if !is(call_func,false) - return abstract_call(_ieval(call_func), e.args, tuple(typeof(f),argtypes...), vtypes, sv, e) - end + if !isa(f,Function) && !isa(f,DataType) && !isa(f,IntrinsicFunction) && _iisdefined(:call) + call_func = _ieval(:call) + return abstract_call(call_func, e.args, tuple(Any[typeof(f),argtypes...]...), vtypes, sv, e) end rt = builtin_tfunction(f, fargs, argtypes) #print("=> ", rt, "\n") @@ -956,11 +947,9 @@ function abstract_eval_call(e, vtypes, sv::StaticVarInfo) return st end end - if !(Function <: ft) && typeintersect(DataType, ft)==Bottom - call_func = isconstantfunc(:call, sv) - if !is(call_func,false) - return abstract_call(_ieval(call_func), e.args, tuple(ft,argtypes...), vtypes, sv, e) - end + if !(Function <: ft) && typeintersect(DataType, ft)==Bottom && _iisdefined(:call) + call_func = _ieval(:call) + return abstract_call(call_func, e.args, tuple(Any[ft,argtypes...]...), vtypes, sv, e) end return Any end From 51a30691c50a86542ac9b0ba052017bb66df9d77 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sat, 11 Oct 2014 13:51:59 -0400 Subject: [PATCH 11/44] fully redesign constructors to use `call` overloading this does not work yet, but gets past the first bootstrap stage. so far this is a significant net simplification. --- base/array.jl | 8 +++ base/boot.jl | 31 +++++++++++ base/inference.jl | 79 ++++++++++---------------- base/linalg/cholmod.jl | 2 +- base/reflection.jl | 6 +- base/subarray.jl | 60 ++++++++++---------- src/alloc.c | 111 ++----------------------------------- src/builtin_proto.h | 5 -- src/builtins.c | 42 +------------- src/codegen.cpp | 20 +++---- src/dump.c | 21 ++----- src/gf.c | 27 +-------- src/interpreter.c | 16 +++--- src/jltypes.c | 87 +++++++++-------------------- src/julia-syntax.scm | 122 ++++++++++++++++++++++++++++------------- src/julia.h | 20 +++---- src/julia_internal.h | 3 - src/module.c | 11 +--- src/task.c | 27 +-------- src/toplevel.c | 37 +++++++++++-- 20 files changed, 280 insertions(+), 455 deletions(-) diff --git a/base/array.jl b/base/array.jl index cd27de4944ce6..6d64b508e5629 100644 --- a/base/array.jl +++ b/base/array.jl @@ -123,6 +123,14 @@ function getindex(T::NonTupleType, vals...) return a end +function getindex(::Type{Any}, vals::ANY...) + a = Array(Any,length(vals)) + for i = 1:length(vals) + a[i] = vals[i] + end + return a +end + getindex(T::(Type...)) = Array(T,0) # T[a:b] and T[a:s:b] also construct typed ranges diff --git a/base/boot.jl b/base/boot.jl index ffe6e6d3cb353..7e3cf56cd9994 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -245,3 +245,34 @@ end typealias ByteString Union(ASCIIString,UTF8String) include(fname::ByteString) = ccall(:jl_load_, Any, (Any,), fname) + +# constructors for built-in types + +TypeVar(n::Symbol) = + ccall(:jl_new_typevar, Any, (Any, Any, Any), n, Union(), Any)::TypeVar +TypeVar(n::Symbol, ub::ANY) = + ccall(:jl_new_typevar, Any, (Any, Any, Any), n, Union(), ub::Type)::TypeVar +TypeVar(n::Symbol, lb::ANY, ub::ANY) = + ccall(:jl_new_typevar, Any, (Any, Any, Any), n, lb::Type, ub::Type)::TypeVar +TypeVar(n::Symbol, b::Bool) = + ccall(:jl_new_typevar_, Any, (Any, Any, Any, Any), n, Union(), Any, b)::TypeVar +TypeVar(n::Symbol, ub::ANY, b::Bool) = + ccall(:jl_new_typevar_, Any, (Any, Any, Any, Any), n, Union(), ub::Type, b)::TypeVar +TypeVar(n::Symbol, lb::ANY, ub::ANY, b::Bool) = + ccall(:jl_new_typevar_, Any, (Any, Any, Any, Any), n, lb::Type, ub::Type, b)::TypeVar + +TypeConstructor(p::ANY, t::ANY) = ccall(:jl_new_type_constructor, Any, (Any, Any), p::Tuple, t::Type) + +Expr(hd::Symbol, args::ANY...) = ccall(:jl_new_expr, Any, (Any, Any), hd, args)::Expr + +LineNumberNode(n::Int) = ccall(:jl_new_struct, Any, (Any,Any...), LineNumberNode, n)::LineNumberNode +LabelNode(n::Int) = ccall(:jl_new_struct, Any, (Any,Any...), LabelNode, n)::LabelNode +GotoNode(n::Int) = ccall(:jl_new_struct, Any, (Any,Any...), GotoNode, n)::GotoNode +QuoteNode(x::ANY) = ccall(:jl_new_struct, Any, (Any,Any...), QuoteNode, x)::QuoteNode +NewvarNode(s::Symbol) = ccall(:jl_new_struct, Any, (Any,Any...), NewvarNode, s)::NewvarNode +TopNode(s::Symbol) = ccall(:jl_new_struct, Any, (Any,Any...), TopNode, s)::TopNode + +Module(name::Symbol) = ccall(:jl_f_new_module, Any, (Any,), name)::Module +Module() = Module(:anonymous) + +Task(f::ANY) = ccall(:jl_new_task, Any, (Any, Int), f::Function, 0)::Task diff --git a/base/inference.jl b/base/inference.jl index 65d318fdd034e..22db441361663 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -29,7 +29,7 @@ type CallStack prev::Union(EmptyCallStack,CallStack) sv::StaticVarInfo - CallStack(ast, mod, types, prev) = new(ast, mod, types, false, 0, Bottom, prev) + CallStack(ast, mod, types::ANY, prev) = new(ast, mod, types, false, 0, Bottom, prev) end inference_stack = EmptyCallStack() @@ -516,10 +516,6 @@ function builtin_tfunction(f::ANY, args::ANY, argtypes::ANY) end tf = get(t_func::ObjectIdDict, f, false) if is(tf,false) - # struct constructor - if isstructtype(f) - return f - end # unknown/unhandled builtin return Any end @@ -828,30 +824,25 @@ end function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e) if is(f,_apply) && length(fargs)>1 a2type = argtypes[2] - if isType(a2type) && isleaftype(a2type.parameters[1]) - af = a2type.parameters[1] - _methods(af,(),0) - else - af = isconstantfunc(fargs[2], sv) - end + af = isconstantfunc(fargs[2], sv) if !is(af,false) af = _ieval(af) - if isa(af,Function) || isa(af,DataType) + if isa(af,Function) aargtypes = map(to_tuple_of_Types, argtypes[3:end]) return abstract_apply(af, aargtypes, vtypes, sv, e) end end # TODO: this slows down inference a lot - # if !(a2type===Function || a2type===DataType) && isleaftype(a2type) - # # would definitely use call() - # call_func = isconstantfunc(fargs[1]) - # if !is(call_func,false) - # aargtypes = Any[ to_tuple_of_Types(argtypes[i]) for i=2:length(argtypes) ] - # aargtypes[1] = (aargtypes[1],) # don't splat "function" - # return abstract_apply(_ieval(call_func), tuple(aargtypes...), vtypes, sv, e) - # end - # end + if !(a2type===Function) && isleaftype(a2type) + # would definitely use call() + call_func = isconstantfunc(fargs[1], sv) + if !is(call_func,false) + aargtypes = Any[ to_tuple_of_Types(argtypes[i]) for i=2:length(argtypes) ] + aargtypes[1] = (aargtypes[1],) # don't splat "function" + return abstract_apply(_ieval(call_func), tuple(aargtypes...), vtypes, sv, e) + end + end return Any end if isgeneric(f) @@ -897,9 +888,9 @@ function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e) # TODO: call() case return Any end - if !isa(f,Function) && !isa(f,DataType) && !isa(f,IntrinsicFunction) && _iisdefined(:call) + if !isa(f,Function) && !isa(f,IntrinsicFunction) && _iisdefined(:call) call_func = _ieval(:call) - return abstract_call(call_func, e.args, tuple(Any[typeof(f),argtypes...]...), vtypes, sv, e) + return abstract_call(call_func, e.args, tuple(Any[abstract_eval_constant(f),argtypes...]...), vtypes, sv, e) end rt = builtin_tfunction(f, fargs, argtypes) #print("=> ", rt, "\n") @@ -933,21 +924,7 @@ function abstract_eval_call(e, vtypes, sv::StaticVarInfo) return result end ft = abstract_eval(called, vtypes, sv) - if isType(ft) - st = ft.parameters[1] - if isa(st,TypeVar) - st = st.ub - end - if isa(st,DataType) - _methods(st,(),0) - if isgeneric(st) && isleaftype(st) - return abstract_call_gf(st, fargs, argtypes, e) - end - # struct constructor - return st - end - end - if !(Function <: ft) && typeintersect(DataType, ft)==Bottom && _iisdefined(:call) + if !(Function <: ft) && _iisdefined(:call) call_func = _ieval(:call) return abstract_call(call_func, e.args, tuple(Any[ft,argtypes...]...), vtypes, sv, e) end @@ -1300,6 +1277,10 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop) end end end + # TODO: typeinf currently gets stuck without this + if linfo.name === :abstract_interpret || linfo.name === :tuple_elim_pass || linfo.name === :abstract_call_gf + return (linfo.ast, Any) + end ast0 = def.ast @@ -1621,6 +1602,7 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop) # just the return type in place of it. tfarr[idx+1] = rec ? frame.result : fulltree tfarr[idx+2] = rec + #tfunc_idx = idx+1 else def.tfunc[tfunc_idx] = rec ? frame.result : fulltree def.tfunc[tfunc_idx+1] = rec @@ -2063,7 +2045,7 @@ end # static parameters are ok if all the static parameter values are leaf types, # meaning they are fully known. function inlineable(f, e::Expr, atypes, sv, enclosing_ast) - if !(isa(f,Function) || isstructtype(f) || isa(f,IntrinsicFunction)) + if !(isa(f,Function) || isa(f,IntrinsicFunction)) return NF end argexprs = e.args[2:end] @@ -2675,18 +2657,13 @@ function inlining_pass(e::Expr, sv, ast) end if is(e.head,:call1) e.head = :call - ET = exprtype(arg1) - if isType(ET) - f = ET.parameters[1] - else - f1 = f = isconstantfunc(arg1, sv) - if !is(f,false) - f = _ieval(f) - end - if f1===false || !(isa(f,Function) || isa(f,Type) || isa(f,IntrinsicFunction)) - f = _ieval(:call) - e.args = Any[f, e.args...] - end + f1 = f = isconstantfunc(arg1, sv) + if !is(f,false) + f = _ieval(f) + end + if f1===false || !(isa(f,Function) || isa(f,IntrinsicFunction)) + f = _ieval(:call) + e.args = Any[f, e.args...] end if is(f, ^) || is(f, .^) diff --git a/base/linalg/cholmod.jl b/base/linalg/cholmod.jl index 7ac19eba71ba7..47464c6784c6e 100644 --- a/base/linalg/cholmod.jl +++ b/base/linalg/cholmod.jl @@ -294,7 +294,7 @@ type c_CholmodTriplet{Tv<:CHMVTypes,Ti<:CHMITypes} j::Ptr{Ti} x::Ptr{Tv} z::Ptr{Void} - stype:Cint + stype::Cint itype::Cint xtype::Cint dtype::Cint diff --git a/base/reflection.jl b/base/reflection.jl index d3aef01b41008..ac61eb44226ea 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -87,7 +87,7 @@ subtypes(x::DataType) = subtypes(Main, x) subtypetree(x::DataType, level=-1) = (level == 0 ? (x, []) : (x, Any[subtypetree(y, level-1) for y in subtypes(x)])) # function reflection -isgeneric(f::ANY) = (isa(f,Function)||isa(f,DataType)) && isa(f.env,MethodTable) +isgeneric(f::ANY) = (isa(f,Function) && isa(f.env,MethodTable)) function_name(f::Function) = isgeneric(f) ? f.env.name : (:anonymous) @@ -126,8 +126,8 @@ function methods(f::Function) f.env end -methods(t::DataType) = (_methods(t,Tuple,0); # force constructor creation - t.env) +#methods(t::DataType) = (_methods(t,Tuple,0); # force constructor creation +# t.env) function length(mt::MethodTable) n = 0 diff --git a/base/subarray.jl b/base/subarray.jl index 139ffb18850b7..a0d621fb43713 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -11,39 +11,39 @@ type SubArray{T,N,A<:AbstractArray,I<:(RangeIndex...,)} <: AbstractArray{T,N} first_index::Int # Note: no bounds-checking on construction. See issue #4044 + #linear indexing constructor (scalar) - if N == 0 && length(I) == 1 && A <: Array - function SubArray(p::A, i::(Int,)) - new(p, i, (), Int[], i[1]) - end - #linear indexing constructor (ranges) - elseif N == 1 && length(I) == 1 && A <: Array - function SubArray(p::A, i::(UnitRange{Int},)) - new(p, i, (length(i[1]),), [1], first(i[1])) - end - function SubArray(p::A, i::(Range{Int},)) - new(p, i, (length(i[1]),), [step(i[1])], first(i[1])) - end - else - function SubArray(p::A, i::I) - newdims = Array(Int, 0) - newstrides = Array(Int, 0) - newfirst = 1 - pstride = 1 - for j = 1:length(i) - if isa(i[j], Int) - newfirst += (i[j]-1)*pstride - else - push!(newdims, length(i[j])) - #may want to return error if step(i[j]) <= 0 - push!(newstrides, isa(i[j],UnitRange) ? pstride : - pstride * step(i[j])) - newfirst += (first(i[j])-1)*pstride - end - pstride *= size(p,j) + global call + function call{T,A<:Array,I<:(Any,)}(::Type{SubArray{T,0,A,I}}, p::A, i::(Int,)) + new(p, i, (), Int[], i[1]) + end + + function call{T,A<:Array,I<:(Any,)}(::Type{SubArray{T,1,A,I}}, p::A, i::(UnitRange{Int},)) + new(p, i, (length(i[1]),), [1], first(i[1])) + end + + function call{T,A<:Array,I<:(Any,)}(::Type{SubArray{T,1,A,I}}, p::A, i::(Range{Int},)) + new(p, i, (length(i[1]),), [step(i[1])], first(i[1])) + end + + function SubArray(p::A, i::I) + newdims = Array(Int, 0) + newstrides = Array(Int, 0) + newfirst = 1 + pstride = 1 + for j = 1:length(i) + if isa(i[j], Int) + newfirst += (i[j]-1)*pstride + else + push!(newdims, length(i[j])) + #may want to return error if step(i[j]) <= 0 + push!(newstrides, isa(i[j],UnitRange) ? pstride : + pstride * step(i[j])) + newfirst += (first(i[j])-1)*pstride end - new(p, i, tuple(newdims...), newstrides, newfirst) + pstride *= size(p,j) end + new(p, i, tuple(newdims...), newstrides, newfirst) end end diff --git a/src/alloc.c b/src/alloc.c index daaa3f64ac007..d203198bd4644 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -578,8 +578,6 @@ jl_typename_t *jl_new_typename(jl_sym_t *name) tn->module = jl_current_module; tn->primary = NULL; tn->cache = (jl_value_t*)jl_null; - tn->ctor_factory = (jl_value_t*)jl_null; - tn->static_ctor_factory = NULL; return tn; } @@ -593,65 +591,6 @@ jl_datatype_t *jl_new_abstracttype(jl_value_t *name, jl_datatype_t *super, jl_function_t *jl_instantiate_method(jl_function_t *f, jl_tuple_t *sp); -void jl_add_constructors(jl_datatype_t *t) -{ - if (t->name == jl_array_typename) { - t->fptr = jl_f_no_function; - return; - } - - jl_initialize_generic_function((jl_function_t*)t, t->name->name); - - if (t->name->ctor_factory == (jl_value_t*)jl_nothing || - t->name->ctor_factory == (jl_value_t*)jl_null) { - } - else { - assert(jl_tuple_len(t->parameters) > 0); - if (t == (jl_datatype_t*)t->name->primary) - return; - jl_function_t *cfactory = NULL; - jl_tuple_t *env = NULL; - JL_GC_PUSH2(&cfactory, &env); - if (jl_compileropts.compile_enabled) { - // instantiating - assert(jl_is_function(t->name->ctor_factory)); - // add type's static parameters to the ctor factory - size_t np = jl_tuple_len(t->parameters); - env = jl_alloc_tuple_uninit(np*2); - for(size_t i=0; i < np; i++) { - jl_tupleset(env, i*2+0, - jl_tupleref(((jl_datatype_t*)t->name->primary)->parameters, i)); - jl_tupleset(env, i*2+1, - jl_tupleref(t->parameters, i)); - } - cfactory = jl_instantiate_method((jl_function_t*)t->name->ctor_factory, env); - cfactory->linfo->ast = jl_prepare_ast(cfactory->linfo, - cfactory->linfo->sparams); - } - else { - cfactory = ((jl_datatype_t*)t)->name->static_ctor_factory; - if (cfactory == NULL) { - JL_PRINTF(JL_STDERR,"code missing for type %s\n", t->name->name); - exit(1); - } - // in generically-compiled case, pass static parameters via closure - // environment. - env = jl_tuple_append((jl_tuple_t*)cfactory->env, t->parameters); - cfactory = jl_new_closure(cfactory->fptr, (jl_value_t*)env, cfactory->linfo); - } - // call user-defined constructor factory on (type,) - jl_value_t *cfargs[1] = { (jl_value_t*)t }; - jl_apply(cfactory, cfargs, 1); - JL_GC_POP(); - } -} - -JL_CALLABLE(jl_f_ctor_trampoline) -{ - jl_add_constructors((jl_datatype_t*)F); - return jl_apply((jl_function_t*)F, args, nargs); -} - jl_datatype_t *jl_new_uninitialized_datatype(size_t nfields) { return (jl_datatype_t*) @@ -732,9 +671,6 @@ jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super, t->abstract = abstract; t->mutabl = mutabl; t->pointerfree = 0; - t->fptr = jl_f_no_function; - t->env = (jl_value_t*)t; - t->linfo = NULL; t->instance = NULL; t->struct_decl = NULL; t->size = 0; @@ -956,57 +892,22 @@ jl_expr_t *jl_exprn(jl_sym_t *head, size_t n) return ex; } -// this constructor has to be built-in for bootstrapping, because we can't -// do anything without being able to make Exprs. -JL_CALLABLE(jl_f_new_expr) +DLLEXPORT jl_value_t *jl_new_expr(jl_sym_t *head, jl_tuple_t *args) { - JL_NARGSV(Expr, 1); - JL_TYPECHK(Expr, symbol, args[0]); - jl_array_t *ar = jl_alloc_cell_1d(nargs-1); + size_t nargs = jl_tuple_len(args); + jl_array_t *ar = jl_alloc_cell_1d(nargs); JL_GC_PUSH1(&ar); - for(size_t i=1; i < nargs; i++) - jl_cellset(ar, i-1, args[i]); + for(size_t i=0; i < nargs; i++) + jl_cellset(ar, i, jl_tupleref(args,i)); jl_expr_t *ex = (jl_expr_t*)alloc_4w(); ex->type = (jl_value_t*)jl_expr_type; - ex->head = (jl_sym_t*)args[0]; + ex->head = head; ex->args = ar; ex->etype = (jl_value_t*)jl_any_type; JL_GC_POP(); return (jl_value_t*)ex; } -JL_CALLABLE(jl_f_new_box) -{ - JL_NARGS(Box, 1, 1); - jl_value_t *box = (jl_value_t*)alloc_2w(); - box->type = jl_box_any_type; - ((jl_value_t**)box)[1] = args[0]; - return box; -} - -JL_CALLABLE(jl_f_default_ctor_1) -{ - if (nargs != 1) - jl_error("wrong number of arguments (expected 1)"); - jl_value_t *ft = jl_t0(((jl_datatype_t*)F)->types); - if (!jl_subtype(args[0], ft, 1)) - jl_type_error(((jl_datatype_t*)F)->name->name->name, ft, args[0]); - return jl_new_struct((jl_datatype_t*)F, args[0]); -} - -JL_CALLABLE(jl_f_default_ctor_2) -{ - if (nargs != 2) - jl_error("wrong number of arguments (expected 2)"); - jl_value_t *ft = jl_t0(((jl_datatype_t*)F)->types); - if (!jl_subtype(args[0], ft, 1)) - jl_type_error(((jl_datatype_t*)F)->name->name->name, ft, args[0]); - ft = jl_t1(((jl_datatype_t*)F)->types); - if (!jl_subtype(args[1], ft, 1)) - jl_type_error(((jl_datatype_t*)F)->name->name->name, ft, args[1]); - return jl_new_struct((jl_datatype_t*)F, args[0], args[1]); -} - #ifdef __cplusplus } #endif diff --git a/src/builtin_proto.h b/src/builtin_proto.h index d2e361d89b1f8..76d25d6acbc25 100644 --- a/src/builtin_proto.h +++ b/src/builtin_proto.h @@ -7,9 +7,6 @@ extern "C" { // declarations for julia-callable builtin functions -JL_CALLABLE(jl_f_new_expr); -JL_CALLABLE(jl_f_new_box); -JL_CALLABLE(jl_f_new_module); JL_CALLABLE(jl_f_throw); JL_CALLABLE(jl_f_is); JL_CALLABLE(jl_f_typeof); @@ -33,13 +30,11 @@ JL_CALLABLE(jl_f_arrayset); JL_CALLABLE(jl_f_arraysize); JL_CALLABLE(jl_f_instantiate_type); JL_CALLABLE(jl_f_convert_default); -JL_CALLABLE(jl_f_new_type_constructor); JL_CALLABLE(jl_f_typevar); JL_CALLABLE(jl_f_union); JL_CALLABLE(jl_f_methodexists); JL_CALLABLE(jl_f_applicable); JL_CALLABLE(jl_f_invoke); -JL_CALLABLE(jl_f_task); JL_CALLABLE(jl_f_yieldto); #ifdef __cplusplus diff --git a/src/builtins.c b/src/builtins.c index 4adb71c505160..3d7a5be00b6e4 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -373,8 +373,6 @@ JL_CALLABLE(jl_f_apply) return result; } -void jl_add_constructors(jl_datatype_t *t); - JL_CALLABLE(jl_f_kwcall) { if (nargs < 4) @@ -399,8 +397,6 @@ JL_CALLABLE(jl_f_kwcall) args[pa-2] = (jl_value_t*)f; } - if (f->fptr == jl_f_ctor_trampoline) - jl_add_constructors((jl_datatype_t*)f); if (!jl_is_gf(f)) jl_error("function does not accept keyword arguments"); jl_function_t *sorter = ((jl_methtable_t*)f->env)->kwsorter; @@ -856,49 +852,15 @@ JL_CALLABLE(jl_f_instantiate_type) return jl_apply_type_(args[0], &args[1], nargs-1); } -JL_CALLABLE(jl_f_new_type_constructor) +DLLEXPORT jl_value_t *jl_new_type_constructor(jl_tuple_t *p, jl_value_t *t) { - JL_NARGS(new_type_constructor, 2, 2); - JL_TYPECHK(new_type_constructor, tuple, args[0]); - if (!jl_is_type(args[1])) - jl_type_error("typealias", (jl_value_t*)jl_type_type, args[1]); - jl_tuple_t *p = (jl_tuple_t*)args[0]; - jl_value_t *tc = (jl_value_t*)jl_new_type_ctor(p, args[1]); + jl_value_t *tc = (jl_value_t*)jl_new_type_ctor(p, t); int i; for(i=0; i < jl_tuple_len(p); i++) ((jl_tvar_t*)jl_tupleref(p,i))->bound = 0; return tc; } -JL_CALLABLE(jl_f_typevar) -{ - if (nargs < 1 || nargs > 3) { - JL_NARGS(TypeVar, 1, 1); - } - JL_TYPECHK(TypeVar, symbol, args[0]); - jl_value_t *lb = (jl_value_t*)jl_bottom_type; - jl_value_t *ub = (jl_value_t*)jl_any_type; - int b = 0; - if (args[nargs-1] == jl_true) { - b = 1; - nargs--; - } - if (nargs > 1) { - JL_TYPECHK(TypeVar, type, args[1]); - if (nargs > 2) { - JL_TYPECHK(TypeVar, type, args[2]); - lb = args[1]; - ub = args[2]; - } - else { - ub = args[1]; - } - } - jl_tvar_t *tv = jl_new_typevar((jl_sym_t*)args[0], lb, ub); - tv->bound = b; - return (jl_value_t*)tv; -} - JL_CALLABLE(jl_f_union) { if (nargs == 0) return (jl_value_t*)jl_bottom_type; diff --git a/src/codegen.cpp b/src/codegen.cpp index 84ff537beae60..485d581e1efe9 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2324,13 +2324,7 @@ static Value *emit_is_function(Value *x, jl_codectx_t *ctx) { Value *xty = emit_typeof(x); Value *isfunc = - builder. - CreateOr(builder. - CreateICmpEQ(xty, - literal_pointer_val((jl_value_t*)jl_function_type)), - builder. - CreateICmpEQ(xty, - literal_pointer_val((jl_value_t*)jl_datatype_type))); + builder.CreateICmpEQ(xty, literal_pointer_val((jl_value_t*)jl_function_type)); return isfunc; } @@ -2364,10 +2358,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, jl_ } hdtype = expr_type(a0, ctx); - definitely_function |= (hdtype == (jl_value_t*)jl_function_type || - hdtype == (jl_value_t*)jl_datatype_type || - (jl_is_type_type(hdtype) && - jl_is_datatype(jl_tparam0(hdtype)))); + definitely_function |= (hdtype == (jl_value_t*)jl_function_type); definitely_not_function |= (jl_is_leaf_type(hdtype) && !definitely_function); assert(!(definitely_function && definitely_not_function)); @@ -2894,9 +2885,11 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, make_gcroot(a1, ctx); Value *a2 = boxed(emit_expr(args[2], ctx),ctx); make_gcroot(a2, ctx); - Value *mdargs[6] = { name, bp, literal_pointer_val(bnd), a1, a2, literal_pointer_val(args[3]) }; + Value *mdargs[7] = + { name, bp, literal_pointer_val(bnd), a1, a2, literal_pointer_val(args[3]), + literal_pointer_val((jl_value_t*)jl_module_call_func(ctx->module)) }; ctx->argDepth = last_depth; - return builder.CreateCall(prepare_call(jlmethod_func), ArrayRef(&mdargs[0], 6)); + return builder.CreateCall(prepare_call(jlmethod_func), ArrayRef(&mdargs[0], 7)); } else if (head == const_sym) { jl_sym_t *sym = (jl_sym_t*)args[0]; @@ -4464,6 +4457,7 @@ static void init_julia_llvm_env(Module *m) mdargs.push_back(jl_pvalue_llvmt); mdargs.push_back(jl_pvalue_llvmt); mdargs.push_back(jl_pvalue_llvmt); + mdargs.push_back(jl_pvalue_llvmt); jlmethod_func = Function::Create(FunctionType::get(jl_pvalue_llvmt, mdargs, false), Function::ExternalLinkage, diff --git a/src/dump.c b/src/dump.c index 50c8f57e9c6c2..7cec6dc7966f3 100644 --- a/src/dump.c +++ b/src/dump.c @@ -302,9 +302,6 @@ static void jl_serialize_datatype(ios_t *s, jl_datatype_t *dt) jl_serialize_value(s, dt->parameters); jl_serialize_value(s, dt->name); jl_serialize_value(s, dt->super); - jl_serialize_value(s, dt->env); - jl_serialize_value(s, dt->linfo); - jl_serialize_fptr(s, (void*)dt->fptr); } static void jl_serialize_module(ios_t *s, jl_module_t *m) @@ -650,9 +647,6 @@ static jl_value_t *jl_deserialize_datatype(ios_t *s, int pos) dt->parameters = (jl_tuple_t*)jl_deserialize_value(s); dt->name = (jl_typename_t*)jl_deserialize_value(s); dt->super = (jl_datatype_t*)jl_deserialize_value(s); - dt->env = jl_deserialize_value(s); - dt->linfo = (jl_lambda_info_t*)jl_deserialize_value(s); - dt->fptr = jl_deserialize_fptr(s); if (dt->name == jl_array_type->name || dt->name == jl_pointer_type->name || dt->name == jl_type_type->name || dt->name == jl_vararg_type->name || dt->name == jl_abstractarray_type->name || @@ -969,8 +963,6 @@ void jl_save_system_image(char *fname) jl_idtable_type = jl_get_global(jl_base_module, jl_symbol("ObjectIdDict")); - jl_serialize_value(&f, jl_array_type->env); - jl_serialize_value(&f, jl_main_module); // deser_tag is an array indexed from 2 until HT_NOTFOUND @@ -1040,8 +1032,6 @@ void jl_restore_system_image(char *fname) datatype_list = jl_alloc_cell_1d(0); - jl_array_type->env = jl_deserialize_value(&f); - jl_main_module = (jl_module_t*)jl_deserialize_value(&f); jl_internal_main_module = jl_main_module; jl_core_module = (jl_module_t*)jl_get_global(jl_main_module, @@ -1314,8 +1304,7 @@ void jl_init_serializer(void) assert(i <= Null_tag); VALUE_TAGS = (ptrint_t)ptrhash_get(&ser_tag, jl_null); - jl_fptr_t fptrs[] = { jl_f_new_expr, jl_f_new_box, - jl_f_throw, jl_f_is, + jl_fptr_t fptrs[] = { jl_f_throw, jl_f_is, jl_f_no_function, jl_f_typeof, jl_f_subtype, jl_f_isa, jl_f_typeassert, jl_f_apply, @@ -1327,13 +1316,11 @@ void jl_init_serializer(void) jl_f_arrayset, jl_f_arraysize, jl_f_instantiate_type, jl_f_kwcall, jl_f_convert_default, - jl_trampoline, jl_f_new_type_constructor, - jl_f_typevar, jl_f_union, + jl_trampoline, jl_f_union, jl_f_methodexists, jl_f_applicable, jl_f_invoke, jl_apply_generic, - jl_unprotect_stack, jl_f_task, - jl_f_yieldto, jl_f_ctor_trampoline, - jl_f_new_module, jl_f_sizeof, + jl_unprotect_stack, + jl_f_yieldto, jl_f_sizeof, NULL }; i=2; while (fptrs[i-2] != NULL) { diff --git a/src/gf.c b/src/gf.c index 9efc13e8c87bb..1737c9672090e 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1194,10 +1194,7 @@ jl_methlist_t *jl_method_list_insert(jl_methlist_t **pml, jl_tuple_t *type, sigs_eq((jl_value_t*)type, (jl_value_t*)l->sig, 1)) { // method overwritten if (check_amb && l->func->linfo && method->linfo && - (l->func->linfo->module != method->linfo->module) && - // special case: allow adding Array() methods in Base - (pml != &((jl_methtable_t*)jl_array_type->env)->defs || - method->linfo->module != jl_base_module)) { + (l->func->linfo->module != method->linfo->module)) { jl_module_t *newmod = method->linfo->module; jl_value_t *errstream = jl_stderr_obj(); JL_STREAM *s = JL_STDERR; @@ -1335,8 +1332,8 @@ jl_value_t *jl_no_method_error(jl_function_t *f, jl_value_t **args, size_t na) { jl_value_t *argtup = jl_f_tuple(NULL, args, na); JL_GC_PUSH1(&argtup); - jl_value_t *fargs[2] = { (jl_value_t*)f, argtup }; - jl_throw(jl_apply((jl_function_t*)jl_methoderror_type, fargs, 2)); + jl_value_t *fargs[3] = { (jl_value_t*)jl_methoderror_type, (jl_value_t*)f, argtup }; + jl_throw(jl_apply(jl_module_call_func(jl_base_module), fargs, 3)); // not reached return jl_nothing; } @@ -1386,7 +1383,6 @@ jl_function_t *jl_method_lookup(jl_methtable_t *mt, jl_value_t **args, size_t na return sf; } -void jl_add_constructors(jl_datatype_t *t); DLLEXPORT jl_value_t *jl_matching_methods(jl_function_t *gf, jl_value_t *type, int lim); // compile-time method lookup @@ -1394,8 +1390,6 @@ jl_function_t *jl_get_specialization(jl_function_t *f, jl_tuple_t *types) { if (!jl_is_leaf_type((jl_value_t*)types)) return NULL; - if (f->fptr == jl_f_ctor_trampoline) - jl_add_constructors((jl_datatype_t*)f); assert(jl_is_gf(f)); // make sure exactly 1 method matches (issue #7302). @@ -1518,19 +1512,6 @@ static void _compile_all(jl_module_t *m, htable_t *h) jl_binding_t *b = (jl_binding_t*)table[i]; if (b->value != NULL) { jl_value_t *v = b->value; - if (jl_is_datatype(v)) { - jl_datatype_t *dt = (jl_datatype_t*)v; - if (dt->fptr == jl_f_ctor_trampoline) { - jl_add_constructors(dt); - jl_compile_all_defs((jl_function_t*)dt); - } - if (v == dt->name->primary && dt->parameters != jl_null && - jl_is_function(dt->name->ctor_factory) && - dt->name->static_ctor_factory == NULL) { - dt->name->static_ctor_factory = jl_instantiate_method((jl_function_t*)dt->name->ctor_factory, jl_null); - precompile_unspecialized(dt->name->static_ctor_factory, NULL, dt->parameters); - } - } if (jl_is_gf(v)) { jl_compile_all_defs((jl_function_t*)v); } @@ -1920,8 +1901,6 @@ jl_value_t *jl_matching_methods(jl_function_t *gf, jl_value_t *type, int lim) assert(jl_is_func(gf)); if (gf->fptr == jl_f_no_function) return (jl_value_t*)jl_an_empty_cell; - if (gf->fptr == jl_f_ctor_trampoline) - jl_add_constructors((jl_datatype_t*)gf); if (!jl_is_gf(gf)) { return (jl_value_t*)jl_an_empty_cell; } diff --git a/src/interpreter.c b/src/interpreter.c index 6bfdf341f731b..7c8248709fe5a 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -263,14 +263,17 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) fname = (jl_sym_t*)jl_exprarg(fname, 0); } gf = eval((jl_value_t*)fname, locals, nl); - assert(jl_is_function(gf)); - assert(jl_is_gf(gf)); + jl_value_t *bp_f = gf; + if (jl_is_datatype(bp_f)) + bp_f = jl_module_call_func(jl_current_module); + assert(jl_is_function(bp_f)); // TODO: type check for this + assert(jl_is_gf(bp_f)); if (jl_is_expr(fname)) fname = (jl_sym_t*)jl_fieldref(jl_exprarg(fname, 2), 0); if (!kw) bp = &gf; else - bp = (jl_value_t**)&((jl_methtable_t*)((jl_function_t*)gf)->env)->kwsorter; + bp = (jl_value_t**)&((jl_methtable_t*)((jl_function_t*)bp_f)->env)->kwsorter; assert(jl_is_symbol(fname)); } else { @@ -292,7 +295,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) jl_check_static_parameter_conflicts((jl_lambda_info_t*)args[2], (jl_tuple_t*)jl_t1(atypes), fname); } meth = eval(args[2], locals, nl); - jl_method_def(fname, bp, b, (jl_tuple_t*)atypes, (jl_function_t*)meth, args[3]); + jl_method_def(fname, bp, b, (jl_tuple_t*)atypes, (jl_function_t*)meth, args[3], NULL); JL_GC_POP(); return *bp; } @@ -373,7 +376,6 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) return (jl_value_t*)jl_nothing; } else if (ex->head == compositetype_sym) { - void jl_add_constructors(jl_datatype_t *t); jl_value_t *name = args[0]; assert(jl_is_symbol(name)); jl_value_t *para = eval(args[1], locals, nl); @@ -386,8 +388,6 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) dt = jl_new_datatype((jl_sym_t*)name, jl_any_type, (jl_tuple_t*)para, (jl_tuple_t*)temp, NULL, 0, args[6]==jl_true ? 1 : 0); - dt->fptr = jl_f_ctor_trampoline; - dt->name->ctor_factory = eval(args[3], locals, nl); jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)name); temp = b->value; // save old value @@ -418,8 +418,6 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) b->value = temp; if (temp==NULL || !equiv_type(dt, (jl_datatype_t*)temp)) { jl_checked_assignment(b, (jl_value_t*)dt); - - jl_add_constructors(dt); } else { // TODO: remove all old ctors and set temp->name->ctor_factory = dt->name->ctor_factory diff --git a/src/jltypes.c b/src/jltypes.c index 745d18e865098..ab256f65f557f 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -55,8 +55,6 @@ jl_datatype_t *jl_number_type; jl_tuple_t *jl_null; jl_value_t *jl_nothing; -void jl_add_constructors(jl_datatype_t *t); - // --- type properties and predicates --- int jl_is_type(jl_value_t *v) @@ -1931,14 +1929,8 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_value_t **env, size_t n, ndt->parameters = iparams_tuple; ndt->names = dt->names; ndt->types = jl_null; // to be filled in below - if (isabstract || !jl_is_function(tn->ctor_factory)) - ndt->fptr = jl_f_no_function; - else - ndt->fptr = jl_f_ctor_trampoline; ndt->mutabl = dt->mutabl; ndt->abstract = dt->abstract; - ndt->env = (jl_value_t*)ndt; - ndt->linfo = NULL; ndt->instance = NULL; ndt->uid = 0; ndt->struct_decl = NULL; @@ -2822,16 +2814,21 @@ jl_value_t *jl_type_match_morespecific(jl_value_t *a, jl_value_t *b) // initialization ------------------------------------------------------------- -jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub) +DLLEXPORT jl_tvar_t *jl_new_typevar_(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub, jl_value_t *b) { jl_tvar_t *tv = (jl_tvar_t*)newobj((jl_value_t*)jl_tvar_type, 4); tv->name = name; tv->lb = lb; tv->ub = ub; - tv->bound = 0; + tv->bound = (b != jl_false); return tv; } +jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub) +{ + return jl_new_typevar_(name, lb, ub, jl_false); +} + static jl_tvar_t *tvar(const char *name) { return jl_new_typevar(jl_symbol(name), (jl_value_t*)jl_bottom_type, @@ -2843,9 +2840,9 @@ extern void jl_init_int32_int64_cache(void); void jl_init_types(void) { // create base objects - jl_datatype_type = jl_new_uninitialized_datatype(13); + jl_datatype_type = jl_new_uninitialized_datatype(10); jl_datatype_type->type = (jl_value_t*)jl_datatype_type; - jl_typename_type = jl_new_uninitialized_datatype(6); + jl_typename_type = jl_new_uninitialized_datatype(4); jl_sym_type = jl_new_uninitialized_datatype(0); jl_symbol_type = jl_sym_type; @@ -2867,10 +2864,7 @@ void jl_init_types(void) jl_datatype_type->name->primary = (jl_value_t*)jl_datatype_type; jl_datatype_type->super = jl_type_type; jl_datatype_type->parameters = jl_null; - jl_datatype_type->names = jl_tuple(13, jl_symbol("fptr"), - jl_symbol("env"), - jl_symbol("code"), - jl_symbol("name"), + jl_datatype_type->names = jl_tuple(10, jl_symbol("name"), jl_symbol("super"), jl_symbol("parameters"), jl_symbol("names"), @@ -2880,15 +2874,11 @@ void jl_init_types(void) jl_symbol("abstract"), jl_symbol("mutable"), jl_symbol("pointerfree")); - jl_datatype_type->types = jl_tuple(13, jl_any_type,jl_any_type,jl_any_type, - jl_typename_type, jl_type_type, + jl_datatype_type->types = jl_tuple(10, jl_typename_type, jl_type_type, jl_tuple_type, jl_tuple_type, jl_tuple_type, jl_any_type, jl_any_type, //types will be fixed later jl_any_type, jl_any_type, jl_any_type); - jl_datatype_type->fptr = jl_f_no_function; - jl_datatype_type->env = (jl_value_t*)jl_null; - jl_datatype_type->linfo = NULL; jl_datatype_type->instance = NULL; jl_datatype_type->uid = jl_assign_type_uid(); jl_datatype_type->struct_decl = NULL; @@ -2902,16 +2892,11 @@ void jl_init_types(void) jl_typename_type->name->primary = (jl_value_t*)jl_typename_type; jl_typename_type->super = jl_any_type; jl_typename_type->parameters = jl_null; - jl_typename_type->names = jl_tuple(6, jl_symbol("name"), jl_symbol("module"), - jl_symbol("primary"), jl_symbol("cache"), - jl_symbol("ctor_factory"), jl_symbol("static_ctor_factory")); - jl_typename_type->types = jl_tuple(6, jl_sym_type, jl_any_type, - jl_type_type, jl_any_type, - jl_any_type, jl_any_type); + jl_typename_type->names = jl_tuple(4, jl_symbol("name"), jl_symbol("module"), + jl_symbol("primary"), jl_symbol("cache")); + jl_typename_type->types = jl_tuple(4, jl_sym_type, jl_any_type, + jl_type_type, jl_any_type); jl_typename_type->uid = jl_assign_type_uid(); - jl_typename_type->fptr = jl_f_no_function; - jl_typename_type->env = (jl_value_t*)jl_null; - jl_typename_type->linfo = NULL; jl_typename_type->instance = NULL; jl_typename_type->struct_decl = NULL; jl_typename_type->abstract = 0; @@ -2924,9 +2909,6 @@ void jl_init_types(void) jl_sym_type->parameters = jl_null; jl_sym_type->names = jl_null; jl_sym_type->types = jl_null; - jl_sym_type->fptr = jl_f_no_function; - jl_sym_type->env = (jl_value_t*)jl_null; - jl_sym_type->linfo = NULL; jl_sym_type->instance = NULL; jl_sym_type->uid = jl_assign_type_uid(); jl_sym_type->struct_decl = NULL; @@ -2946,19 +2928,17 @@ void jl_init_types(void) jl_tuple(1, jl_symbol("types")), jl_tuple(1, jl_tuple_type), 0, 0); - jl_uniontype_type->fptr = jl_f_no_function; jl_bottom_type = (jl_value_t*)jl_new_struct(jl_uniontype_type, jl_null); jl_tvar_type = jl_new_datatype(jl_symbol("TypeVar"), jl_any_type, jl_null, - jl_tuple(3, jl_symbol("name"), - jl_symbol("lb"), - jl_symbol("ub")), - jl_tuple(3, jl_sym_type, jl_type_type, - jl_type_type), + jl_tuple(4, jl_symbol("name"), + jl_symbol("lb"), jl_symbol("ub"), + jl_symbol("bound")), + jl_tuple(4, jl_sym_type, jl_type_type, + jl_type_type, jl_any_type), 0, 0); - jl_tvar_type->fptr = jl_f_typevar; jl_undef_type = jl_new_abstracttype((jl_value_t*)jl_symbol("Undef"), jl_any_type, jl_null); @@ -3012,7 +2992,6 @@ void jl_init_types(void) jl_tuple_type, jl_any_type, jl_any_type, jl_any_type), 0, 1); - jl_method_type->fptr = jl_f_no_function; jl_methtable_type = jl_new_datatype(jl_symbol("MethodTable"), jl_any_type, jl_null, @@ -3024,7 +3003,6 @@ void jl_init_types(void) jl_any_type, jl_any_type, jl_long_type, jl_any_type), 0, 1); - jl_methtable_type->fptr = jl_f_no_function; tv = jl_tuple2(tvar("T"), tvar("N")); jl_abstractarray_type = @@ -3047,10 +3025,7 @@ void jl_init_types(void) tv, jl_null, jl_null, 0, 1); jl_array_typename = jl_array_type->name; - jl_array_type->linfo = NULL; jl_array_type->pointerfree = 0; - jl_initialize_generic_function((jl_function_t*)jl_array_type, - jl_array_typename->name); jl_array_any_type = (jl_value_t*)jl_apply_type((jl_value_t*)jl_array_type, @@ -3070,49 +3045,41 @@ void jl_init_types(void) jl_tuple(3, jl_sym_type, jl_array_any_type, jl_any_type), 0, 1); - jl_expr_type->fptr = jl_f_new_expr; jl_linenumbernode_type = jl_new_datatype(jl_symbol("LineNumberNode"), jl_any_type, jl_null, jl_tuple(1, jl_symbol("line")), jl_tuple(1, jl_long_type), 0, 0); - jl_linenumbernode_type->fptr = jl_f_default_ctor_1; jl_labelnode_type = jl_new_datatype(jl_symbol("LabelNode"), jl_any_type, jl_null, jl_tuple(1, jl_symbol("label")), jl_tuple(1, jl_long_type), 0, 0); - jl_labelnode_type->fptr = jl_f_default_ctor_1; jl_gotonode_type = jl_new_datatype(jl_symbol("GotoNode"), jl_any_type, jl_null, jl_tuple(1, jl_symbol("label")), jl_tuple(1, jl_long_type), 0, 0); - jl_gotonode_type->fptr = jl_f_default_ctor_1; jl_quotenode_type = jl_new_datatype(jl_symbol("QuoteNode"), jl_any_type, jl_null, jl_tuple(1, jl_symbol("value")), jl_tuple(1, jl_any_type), 0, 0); - jl_quotenode_type->fptr = jl_f_default_ctor_1; jl_newvarnode_type = jl_new_datatype(jl_symbol("NewvarNode"), jl_any_type, jl_null, jl_tuple(1, jl_symbol("name")), jl_tuple(1, jl_sym_type), 0, 0); - jl_newvarnode_type->fptr = jl_f_default_ctor_1; jl_topnode_type = jl_new_datatype(jl_symbol("TopNode"), jl_any_type, jl_null, jl_tuple(1, jl_symbol("name")), jl_tuple(1, jl_sym_type), 0, 0); - jl_topnode_type->fptr = jl_f_default_ctor_1; jl_module_type = jl_new_datatype(jl_symbol("Module"), jl_any_type, jl_null, jl_tuple(2, jl_symbol("name"), jl_symbol("parent")), jl_tuple(2, jl_sym_type, jl_any_type), 0, 1); - jl_module_type->fptr = jl_f_new_module; jl_tupleset(jl_typename_type->types, 1, jl_module_type); @@ -3139,14 +3106,12 @@ void jl_init_types(void) jl_sym_type, jl_int32_type, jl_bool_type), 0, 1); - jl_lambda_info_type->fptr = jl_f_no_function; jl_box_type = jl_new_datatype(jl_symbol("Box"), jl_any_type, jl_null, jl_tuple(1, jl_symbol("contents")), jl_tuple(1, jl_any_type), 0, 1); - jl_box_type->fptr = jl_f_new_box; jl_box_typename = jl_box_type->name; jl_box_any_type = (jl_value_t*)jl_box_type; @@ -3157,7 +3122,6 @@ void jl_init_types(void) jl_symbol("body")), jl_tuple(2, jl_tuple_type, jl_any_type), 0, 0); - jl_typector_type->fptr = jl_f_new_type_constructor; jl_function_type = jl_new_datatype(jl_symbol("Function"), jl_any_type, jl_null, @@ -3166,7 +3130,6 @@ void jl_init_types(void) jl_tuple(3, jl_any_type, jl_any_type, jl_lambda_info_type), 0, 1); - jl_function_type->fptr = jl_f_no_function; jl_tupleset(jl_method_type->types, 3, jl_function_type); jl_tupleset(jl_lambda_info_type->types, 6, jl_function_type); @@ -3193,12 +3156,12 @@ void jl_init_types(void) jl_value_t *pointer_void = jl_apply_type((jl_value_t*)jl_pointer_type, jl_tuple(1,jl_void_type)); jl_voidpointer_type = (jl_datatype_t*)pointer_void; - jl_tupleset(jl_datatype_type->types, 0, pointer_void); - jl_tupleset(jl_datatype_type->types, 9, jl_int32_type); - jl_tupleset(jl_datatype_type->types, 10, (jl_value_t*)jl_bool_type); - jl_tupleset(jl_datatype_type->types, 11, (jl_value_t*)jl_bool_type); - jl_tupleset(jl_datatype_type->types, 12, (jl_value_t*)jl_bool_type); + jl_tupleset(jl_datatype_type->types, 6, jl_int32_type); + jl_tupleset(jl_datatype_type->types, 7, (jl_value_t*)jl_bool_type); + jl_tupleset(jl_datatype_type->types, 8, (jl_value_t*)jl_bool_type); + jl_tupleset(jl_datatype_type->types, 9, (jl_value_t*)jl_bool_type); jl_tupleset(jl_function_type->types, 0, pointer_void); + jl_tupleset(jl_tvar_type->types, 3, (jl_value_t*)jl_bool_type); jl_compute_field_offsets(jl_datatype_type); jl_compute_field_offsets(jl_typename_type); diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index da54ef8fd3c3e..4258c8c9dfaa3 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -732,7 +732,7 @@ `(function (call ,name ,@field-names) (block (call new ,@field-names))))) - (if gen-specific? + (if (and gen-specific? (any (lambda (t) (not (eq? t 'Any))) field-types)) (list ;; definition with field types for all arguments `(function (call ,name @@ -775,8 +775,42 @@ `(block ,stmt ,@(cdr body)))) body)) +;; insert item at start of arglist +(define (arglist-unshift sig item) + (if (and (pair? sig) (pair? (car sig)) (eq? (caar sig) 'parameters)) + `(,(car sig) ,item ,@(cdr sig)) + `(,item ,@sig))) + +(define (ctor-signature name params method-params sig) + (if (null? params) + (if (null? method-params) + (cons `(call call + ,@(arglist-unshift sig `(|::| ,(gensy) (curly Type ,name)))) + params) + (cons `(call (curly call ,@method-params) + ,@(arglist-unshift sig `(|::| ,(gensy) (curly Type ,name)))) + params)) + (if (null? method-params) + (cons `(call (curly call ,@params) + ,@(arglist-unshift sig `(|::| ,(gensy) (curly Type (curly ,name ,@params))))) + params) + ;; rename parameters that conflict with user-written method parameters + (let ((new-params (map (lambda (p) (if (memq p method-params) + (gensy) + p)) + params))) + (cons `(call (curly call ,@new-params ,@method-params) + ,@(arglist-unshift sig `(|::| ,(gensy) (curly Type (curly ,name ,@new-params))))) + new-params))))) + +(define (ctor-def keyword name params method-params sig ctor-body body) + (let* ((temp (ctor-signature name params method-params sig)) + (sig (car temp)) + (params (cdr temp))) + `(,keyword ,sig ,(ctor-body body params)))) + (define (rewrite-ctor ctor Tname params field-names field-types mutabl iname) - (define (ctor-body body) + (define (ctor-body body params) (pattern-replace (pattern-set (pattern-lambda (call (-/ new) . args) @@ -791,29 +825,39 @@ field-types mutabl))) body)) - (let ((ctor2 - (pattern-replace - (pattern-set - (pattern-lambda (function (call (curly name . p) . sig) body) - `(function (call (curly ,(if (eq? name Tname) iname name) ,@p) ,@sig) - ,(ctor-body body))) - (pattern-lambda (stagedfunction (call (curly name . p) . sig) body) - `(stagedfunction (call (curly ,(if (eq? name Tname) iname name) ,@p) ,@sig) - ,(ctor-body body))) - (pattern-lambda (function (call name . sig) body) - `(function (call ,(if (eq? name Tname) iname name) ,@sig) - ,(ctor-body body))) - (pattern-lambda (stagedfunction (call name . sig) body) - `(stagedfunction (call ,(if (eq? name Tname) iname name) ,@sig) - ,(ctor-body body))) - (pattern-lambda (= (call (curly name . p) . sig) body) - `(= (call (curly ,(if (eq? name Tname) iname name) ,@p) ,@sig) - ,(ctor-body body))) - (pattern-lambda (= (call name . sig) body) - `(= (call ,(if (eq? name Tname) iname name) ,@sig) - ,(ctor-body body)))) - ctor))) - ctor2)) + (pattern-replace + (pattern-set + (pattern-lambda (function (call (curly name . p) . sig) body) + (if (eq? name Tname) + (ctor-def 'function name params p sig ctor-body body) + `(function (call (curly ,name ,@p) ,@sig) + ,(ctor-body body params)))) + (pattern-lambda (stagedfunction (call (curly name . p) . sig) body) + (if (eq? name Tname) + (ctor-def 'stagedfunction name params p sig ctor-body body) + `(stagedfunction (call (curly ,name ,@p) ,@sig) + ,(ctor-body body params)))) + (pattern-lambda (function (call name . sig) body) + (if (eq? name Tname) + (ctor-def 'function name params '() sig ctor-body body) + `(function (call ,name ,@sig) + ,(ctor-body body params)))) + (pattern-lambda (stagedfunction (call name . sig) body) + (if (eq? name Tname) + (ctor-def 'stagedfunction name params '() sig ctor-body body) + `(stagedfunction (call ,name ,@sig) + ,(ctor-body body params)))) + (pattern-lambda (= (call (curly name . p) . sig) body) + (if (eq? name Tname) + (ctor-def 'function name params p sig ctor-body body) + `(function (call (curly ,name ,@p) ,@sig) + ,(ctor-body body params)))) + (pattern-lambda (= (call name . sig) body) + (if (eq? name Tname) + (ctor-def 'function name params '() sig ctor-body body) + `(function (call ,name ,@sig) + ,(ctor-body body params))))) + ctor)) ;; remove line numbers and nested blocks (define (flatten-blocks e) @@ -854,6 +898,7 @@ (scope-block (block (global ,name) + (global call) ,@(map (lambda (c) (rewrite-ctor c name '() field-names field-types mut name)) defs2))))) @@ -868,25 +913,24 @@ ,@(map make-assignment params (symbols->typevars params bounds #t)) (composite_type ,name (tuple ,@params) (tuple ,@(map (lambda (x) `',x) field-names)) - ,(let ((instantiation-name (gensy))) - `(lambda (,instantiation-name) - (scope-block - ;; don't capture params; in here they are static - ;; parameters - (block - (global ,@params) - ,@(map - (lambda (c) - (rewrite-ctor c name params field-names - field-types mut instantiation-name)) - defs2) - ,name)))) + (null) ,super (tuple ,@field-types) ,mut))) + ;; "inner" constructors + (call + (lambda () + (scope-block + (block + (global ,name) + (global call) + ,@(map (lambda (c) + (rewrite-ctor c name params field-names + field-types mut name)) + defs2))))) + ;; "outer" constructors (scope-block (block (global ,name) - (global ,@params) ,@(if (and (null? defs) ;; don't generate an outer constructor if the type has ;; parameters not mentioned in the field types. such a diff --git a/src/julia.h b/src/julia.h index 2952851f27df2..ae0a3633da63e 100644 --- a/src/julia.h +++ b/src/julia.h @@ -162,14 +162,11 @@ typedef struct _jl_lambda_info_t { #define LAMBDA_INFO_NW (NWORDS(sizeof(jl_lambda_info_t))-1) -#define JL_FUNC_FIELDS \ - jl_fptr_t fptr; \ - jl_value_t *env; \ - jl_lambda_info_t *linfo; - typedef struct _jl_function_t { JL_DATA_TYPE - JL_FUNC_FIELDS + jl_fptr_t fptr; + jl_value_t *env; + jl_lambda_info_t *linfo; } jl_function_t; typedef struct { @@ -188,9 +185,6 @@ typedef struct { // not the original. jl_value_t *primary; jl_value_t *cache; - // to create a set of constructors for this sort of type - jl_value_t *ctor_factory; - jl_function_t *static_ctor_factory; } jl_typename_t; typedef struct { @@ -206,7 +200,6 @@ typedef struct { typedef struct _jl_datatype_t { JL_DATA_TYPE - JL_FUNC_FIELDS jl_typename_t *name; struct _jl_datatype_t *super; jl_tuple_t *parameters; @@ -229,7 +222,7 @@ typedef struct { jl_sym_t *name; jl_value_t *lb; // lower bound jl_value_t *ub; // upper bound - uptrint_t bound; // part of a constraint environment + uint8_t bound; // part of a constraint environment } jl_tvar_t; typedef struct { @@ -526,7 +519,7 @@ extern jl_sym_t *arrow_sym; extern jl_sym_t *ldots_sym; #define jl_is_module(v) jl_typeis(v,jl_module_type) #define jl_is_mtable(v) jl_typeis(v,jl_methtable_type) #define jl_is_task(v) jl_typeis(v,jl_task_type) -#define jl_is_func(v) (jl_typeis(v,jl_function_type) || jl_is_datatype(v)) +#define jl_is_func(v) jl_typeis(v,jl_function_type) #define jl_is_function(v) jl_is_func(v) #define jl_is_ascii_string(v) jl_typeis(v,jl_ascii_string_type) #define jl_is_utf8_string(v) jl_typeis(v,jl_utf8_string_type) @@ -677,7 +670,8 @@ jl_function_t *jl_new_generic_function(jl_sym_t *name); void jl_add_method(jl_function_t *gf, jl_tuple_t *types, jl_function_t *meth, jl_tuple_t *tvars, int8_t isstaged); DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, - jl_tuple_t *argtypes, jl_function_t *f, jl_value_t *isstaged); + jl_tuple_t *argtypes, jl_function_t *f, jl_value_t *isstaged, + jl_value_t *call_func); DLLEXPORT jl_value_t *jl_box_bool(int8_t x); DLLEXPORT jl_value_t *jl_box_int8(int32_t x); DLLEXPORT jl_value_t *jl_box_uint8(uint32_t x); diff --git a/src/julia_internal.h b/src/julia_internal.h index 157740f37f110..c8c55a03a6bff 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -33,13 +33,10 @@ void jl_set_gs_ctr(uint32_t ctr); DLLEXPORT jl_value_t *name(jl_value_t *F, jl_value_t **args, uint32_t nargs) JL_CALLABLE(jl_trampoline); -JL_CALLABLE(jl_f_ctor_trampoline); JL_CALLABLE(jl_apply_generic); JL_CALLABLE(jl_unprotect_stack); JL_CALLABLE(jl_f_no_function); JL_CALLABLE(jl_f_tuple); -JL_CALLABLE(jl_f_default_ctor_1); -JL_CALLABLE(jl_f_default_ctor_2); extern jl_function_t *jl_unprotect_stack_func; extern jl_function_t *jl_bottom_func; diff --git a/src/module.c b/src/module.c index 5f8ed958d4e14..ce9a4685416eb 100644 --- a/src/module.c +++ b/src/module.c @@ -35,17 +35,8 @@ jl_module_t *jl_new_module(jl_sym_t *name) return m; } -JL_CALLABLE(jl_f_new_module) +DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name) { - jl_sym_t *name; - if (nargs == 0) { - name = anonymous_sym; - } - else { - JL_NARGS(Module, 1, 1); - JL_TYPECHK(Module, symbol, args[0]); - name = (jl_sym_t*)args[0]; - } jl_module_t *m = jl_new_module(name); m->parent = jl_main_module; jl_add_standard_imports(m); diff --git a/src/task.c b/src/task.c index 4af206a582d64..025aa0f0218d2 100644 --- a/src/task.c +++ b/src/task.c @@ -714,7 +714,8 @@ DLLEXPORT void gdblookup(ptrint_t ip) DLLEXPORT void jlbacktrace() { - for(size_t i=0; i < bt_size; i++) + size_t n = bt_size; //bt_size > 40 ? 40 : bt_size; + for(size_t i=0; i < n; i++) gdblookup(bt_data[i]); } @@ -770,7 +771,7 @@ DLLEXPORT void jl_throw_with_superfluous_argument(jl_value_t *e, int line) jl_throw(e); } -jl_task_t *jl_new_task(jl_function_t *start, size_t ssize) +DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, size_t ssize) { size_t pagesz = jl_page_size; jl_task_t *t = (jl_task_t*)allocobj(sizeof(jl_task_t)); @@ -827,27 +828,6 @@ JL_CALLABLE(jl_unprotect_stack) return (jl_value_t*)jl_null; } -#define JL_MIN_STACK (4096*sizeof(void*)) -#define JL_DEFAULT_STACK (2*12288*sizeof(void*)) - -JL_CALLABLE(jl_f_task) -{ - JL_NARGS(Task, 1, 2); - JL_TYPECHK(Task, function, args[0]); - /* - we need a somewhat large stack, because execution can trigger - compilation, which uses perhaps too much stack space. - */ - size_t ssize = JL_DEFAULT_STACK; - if (nargs == 2) { - JL_TYPECHK(Task, long, args[1]); - ssize = jl_unbox_long(args[1]); - if (ssize < JL_MIN_STACK) - jl_error("Task: stack size too small"); - } - return (jl_value_t*)jl_new_task((jl_function_t*)args[0], ssize); -} - JL_CALLABLE(jl_f_yieldto) { JL_NARGSV(yieldto, 1); @@ -894,7 +874,6 @@ void jl_init_tasks(void *stack, size_t ssize) jl_any_type, jl_any_type, jl_function_type), 0, 1); jl_tupleset(jl_task_type->types, 0, (jl_value_t*)jl_task_type); - jl_task_type->fptr = jl_f_task; done_sym = jl_symbol("done"); failed_sym = jl_symbol("failed"); diff --git a/src/toplevel.c b/src/toplevel.c index c7753a2d500d0..8c966a4a057e0 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -624,7 +624,6 @@ void jl_set_datatype_super(jl_datatype_t *tt, jl_value_t *super) // method definition ---------------------------------------------------------- extern int jl_boot_file_loaded; -void jl_add_constructors(jl_datatype_t *t); static int type_contains(jl_value_t *ty, jl_value_t *x) { @@ -647,12 +646,14 @@ static int type_contains(jl_value_t *ty, jl_value_t *x) void print_func_loc(JL_STREAM *s, jl_lambda_info_t *li); DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, - jl_tuple_t *argtypes, jl_function_t *f, jl_value_t *isstaged) + jl_tuple_t *argtypes, jl_function_t *f, jl_value_t *isstaged, + jl_value_t *call_func) { // argtypes is a tuple ((types...), (typevars...)) jl_tuple_t *t = (jl_tuple_t*)jl_t1(argtypes); argtypes = (jl_tuple_t*)jl_t0(argtypes); jl_value_t *gf=NULL; + JL_GC_PUSH3(&gf, &argtypes, &t); if (bnd && bnd->value != NULL && !bnd->constp) { jl_errorf("cannot define function %s; it already has a value", @@ -662,9 +663,34 @@ DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_ if (*bp != NULL) { gf = *bp; if (!jl_is_gf(gf)) { - if (jl_is_datatype(gf) && - ((jl_function_t*)gf)->fptr == jl_f_ctor_trampoline) { - jl_add_constructors((jl_datatype_t*)gf); + if (jl_is_datatype(gf)) { + // DataType: define `call`, for backwards compat with outer constructors + // TODO: this does not yet handle keyword sorters correctly + if (call_func == NULL) + call_func = (jl_value_t*)jl_module_call_func(jl_current_module); + size_t na = jl_tuple_len(argtypes); + jl_tuple_t *newargtypes = jl_alloc_tuple(1 + na); + JL_GC_PUSH1(&newargtypes); + jl_tupleset(newargtypes, 0, jl_wrap_Type(gf)); + size_t i; + for(i=0; i < na; i++) { + jl_tupleset(newargtypes, i+1, jl_tupleref(argtypes, i)); + } + argtypes = newargtypes; + JL_GC_POP(); + gf = call_func; + // TODO: edit args, insert type first + if (!jl_is_expr(f->linfo->ast)) + f->linfo->ast = jl_uncompress_ast(f->linfo, f->linfo->ast); + jl_array_t *al = jl_lam_args((jl_expr_t*)f->linfo->ast); + if (jl_array_len(al) == 0) { + al = jl_alloc_cell_1d(1); + jl_exprarg(f->linfo->ast, 0) = (jl_value_t*)al; + } + else { + jl_array_grow_beg(al, 1); + } + jl_cellset(al, 0, (jl_value_t*)jl_gensym()); } if (!jl_is_gf(gf)) { jl_error("invalid method definition: not a generic function"); @@ -702,7 +728,6 @@ DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_ gf = (jl_value_t*)jl_new_generic_function(name); *bp = gf; } - JL_GC_PUSH1(&gf); assert(jl_is_function(f)); assert(jl_is_tuple(argtypes)); assert(jl_is_tuple(t)); From 2604610c578292c83c685d2076905366cb46847b Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sat, 11 Oct 2014 16:59:45 -0400 Subject: [PATCH 12/44] fix keyword args in constructors-via-`call` REPL now works with sys0.ji --- base/inference.jl | 2 +- src/builtins.c | 10 ++-------- src/codegen.cpp | 16 ++++++---------- src/interpreter.c | 12 ++---------- src/julia-syntax.scm | 6 +++--- src/julia.h | 2 +- src/toplevel.c | 10 +++++++--- 7 files changed, 22 insertions(+), 36 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index 22db441361663..57979aa9eac80 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -875,7 +875,7 @@ function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e) return Any end kwcount = fargs[2] - ff = isconstantfunc(fargs[4 + 2*kwcount], sv) + ff = isconstantfunc(fargs[3 + 2*kwcount], sv) if !(ff===false) ff = _ieval(ff) if isgeneric(ff) && isdefined(ff.env,:kwsorter) diff --git a/src/builtins.c b/src/builtins.c index 3d7a5be00b6e4..8ea5f237229a3 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -382,20 +382,14 @@ JL_CALLABLE(jl_f_kwcall) assert(jl_is_function(call_func)); size_t nkeys = jl_unbox_long(args[1]); size_t pa = 4 + 2*nkeys; - jl_array_t *container = (jl_array_t*)args[pa-2]; + jl_array_t *container = (jl_array_t*)args[pa-1]; assert(jl_array_len(container) > 0); - f = (jl_function_t*)args[pa-1]; + f = (jl_function_t*)args[pa-2]; if (!jl_is_function(f)) { // do generic call(args...; kws...) instead f = call_func; pa--; } - else { - // switch (container f pa...) to (f container pa...) - // TODO: this is not as legitimate as it could be. - args[pa-1] = args[pa-2]; - args[pa-2] = (jl_value_t*)f; - } if (!jl_is_gf(f)) jl_error("function does not accept keyword arguments"); diff --git a/src/codegen.cpp b/src/codegen.cpp index 485d581e1efe9..65cf319406e5e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2863,13 +2863,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, Value *name = literal_pointer_val(mn); jl_binding_t *bnd = NULL; Value *bp; - if (iskw) { - // fenv = theF->env - Value *fenv = emit_nthptr(theF, 2, tbaa_func); - // bp = &((jl_methtable_t*)fenv)->kwsorter - bp = emit_nthptr_addr(fenv, 7); - } - else if (theF != NULL) { + if (theF != NULL) { bp = make_gcroot(theF, ctx); } else { @@ -2885,11 +2879,12 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, make_gcroot(a1, ctx); Value *a2 = boxed(emit_expr(args[2], ctx),ctx); make_gcroot(a2, ctx); - Value *mdargs[7] = + Value *mdargs[8] = { name, bp, literal_pointer_val(bnd), a1, a2, literal_pointer_val(args[3]), - literal_pointer_val((jl_value_t*)jl_module_call_func(ctx->module)) }; + literal_pointer_val((jl_value_t*)jl_module_call_func(ctx->module)), + ConstantInt::get(T_int32, (int)iskw) }; ctx->argDepth = last_depth; - return builder.CreateCall(prepare_call(jlmethod_func), ArrayRef(&mdargs[0], 7)); + return builder.CreateCall(prepare_call(jlmethod_func), ArrayRef(&mdargs[0], 8)); } else if (head == const_sym) { jl_sym_t *sym = (jl_sym_t*)args[0]; @@ -4458,6 +4453,7 @@ static void init_julia_llvm_env(Module *m) mdargs.push_back(jl_pvalue_llvmt); mdargs.push_back(jl_pvalue_llvmt); mdargs.push_back(jl_pvalue_llvmt); + mdargs.push_back(T_int32); jlmethod_func = Function::Create(FunctionType::get(jl_pvalue_llvmt, mdargs, false), Function::ExternalLinkage, diff --git a/src/interpreter.c b/src/interpreter.c index 7c8248709fe5a..4a16ac9b454dc 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -263,17 +263,9 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) fname = (jl_sym_t*)jl_exprarg(fname, 0); } gf = eval((jl_value_t*)fname, locals, nl); - jl_value_t *bp_f = gf; - if (jl_is_datatype(bp_f)) - bp_f = jl_module_call_func(jl_current_module); - assert(jl_is_function(bp_f)); // TODO: type check for this - assert(jl_is_gf(bp_f)); if (jl_is_expr(fname)) fname = (jl_sym_t*)jl_fieldref(jl_exprarg(fname, 2), 0); - if (!kw) - bp = &gf; - else - bp = (jl_value_t**)&((jl_methtable_t*)((jl_function_t*)bp_f)->env)->kwsorter; + bp = &gf; assert(jl_is_symbol(fname)); } else { @@ -295,7 +287,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) jl_check_static_parameter_conflicts((jl_lambda_info_t*)args[2], (jl_tuple_t*)jl_t1(atypes), fname); } meth = eval(args[2], locals, nl); - jl_method_def(fname, bp, b, (jl_tuple_t*)atypes, (jl_function_t*)meth, args[3], NULL); + jl_method_def(fname, bp, b, (jl_tuple_t*)atypes, (jl_function_t*)meth, args[3], NULL, kw); JL_GC_POP(); return *bp; } diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 4258c8c9dfaa3..5289adb50cdc0 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1514,8 +1514,8 @@ keys)))) (if (null? restkeys) `(call (top kwcall) call ,(length keys) ,@keyargs - (call (top Array) (top Any) ,(* 2 (length keys))) - ,f ,@pa) + ,f (call (top Array) (top Any) ,(* 2 (length keys))) + ,@pa) (let ((container (gensy))) `(block (= ,container (call (top Array) (top Any) ,(* 2 (length keys)))) @@ -1536,7 +1536,7 @@ (if (call (top isempty) ,container) (call ,f ,@pa) (call (top kwcall) call ,(length keys) ,@keyargs - ,container ,f ,@pa)))))))) + ,f ,container ,@pa)))))))) (define (expand-transposed-op e ops) (let ((a (caddr e)) diff --git a/src/julia.h b/src/julia.h index ae0a3633da63e..32242899dc77d 100644 --- a/src/julia.h +++ b/src/julia.h @@ -671,7 +671,7 @@ void jl_add_method(jl_function_t *gf, jl_tuple_t *types, jl_function_t *meth, jl_tuple_t *tvars, int8_t isstaged); DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, jl_tuple_t *argtypes, jl_function_t *f, jl_value_t *isstaged, - jl_value_t *call_func); + jl_value_t *call_func, int iskw); DLLEXPORT jl_value_t *jl_box_bool(int8_t x); DLLEXPORT jl_value_t *jl_box_int8(int32_t x); DLLEXPORT jl_value_t *jl_box_uint8(uint32_t x); diff --git a/src/toplevel.c b/src/toplevel.c index 8c966a4a057e0..36cb93f7560f4 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -647,7 +647,7 @@ void print_func_loc(JL_STREAM *s, jl_lambda_info_t *li); DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_t *bnd, jl_tuple_t *argtypes, jl_function_t *f, jl_value_t *isstaged, - jl_value_t *call_func) + jl_value_t *call_func, int iskw) { // argtypes is a tuple ((types...), (typevars...)) jl_tuple_t *t = (jl_tuple_t*)jl_t1(argtypes); @@ -665,7 +665,6 @@ DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_ if (!jl_is_gf(gf)) { if (jl_is_datatype(gf)) { // DataType: define `call`, for backwards compat with outer constructors - // TODO: this does not yet handle keyword sorters correctly if (call_func == NULL) call_func = (jl_value_t*)jl_module_call_func(jl_current_module); size_t na = jl_tuple_len(argtypes); @@ -679,7 +678,8 @@ DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_ argtypes = newargtypes; JL_GC_POP(); gf = call_func; - // TODO: edit args, insert type first + name = call_sym; + // edit args, insert type first if (!jl_is_expr(f->linfo->ast)) f->linfo->ast = jl_uncompress_ast(f->linfo, f->linfo->ast); jl_array_t *al = jl_lam_args((jl_expr_t*)f->linfo->ast); @@ -696,6 +696,10 @@ DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_ jl_error("invalid method definition: not a generic function"); } } + if (iskw) { + bp = (jl_value_t**)&((jl_methtable_t*)((jl_function_t*)gf)->env)->kwsorter; + gf = *bp; + } } size_t na = jl_tuple_len(argtypes); From 79e006b97205ee418d44833456836bcdc6d85d8e Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sat, 11 Oct 2014 18:58:21 -0400 Subject: [PATCH 13/44] carefully arrange `call` methods in Core not to get specialized on types in Base this allows the full build to go through --- base/boot.jl | 14 ++++++-------- base/inference.jl | 3 +++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 7e3cf56cd9994..b8859cb546b29 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -171,8 +171,6 @@ const (===) = is # simple convert for use by constructors of types in Core convert(T, x) = convert_default(T, x, convert) -call(T::Type, arg) = convert(T, arg) - abstract Number abstract Real <: Number abstract FloatingPoint <: Real @@ -251,13 +249,13 @@ include(fname::ByteString) = ccall(:jl_load_, Any, (Any,), fname) TypeVar(n::Symbol) = ccall(:jl_new_typevar, Any, (Any, Any, Any), n, Union(), Any)::TypeVar TypeVar(n::Symbol, ub::ANY) = - ccall(:jl_new_typevar, Any, (Any, Any, Any), n, Union(), ub::Type)::TypeVar + (isa(ub,Bool) ? + ccall(:jl_new_typevar_, Any, (Any, Any, Any, Any), n, Union(), Any, ub)::TypeVar : + ccall(:jl_new_typevar, Any, (Any, Any, Any), n, Union(), ub::Type)::TypeVar) TypeVar(n::Symbol, lb::ANY, ub::ANY) = - ccall(:jl_new_typevar, Any, (Any, Any, Any), n, lb::Type, ub::Type)::TypeVar -TypeVar(n::Symbol, b::Bool) = - ccall(:jl_new_typevar_, Any, (Any, Any, Any, Any), n, Union(), Any, b)::TypeVar -TypeVar(n::Symbol, ub::ANY, b::Bool) = - ccall(:jl_new_typevar_, Any, (Any, Any, Any, Any), n, Union(), ub::Type, b)::TypeVar + (isa(ub,Bool) ? + ccall(:jl_new_typevar_, Any, (Any, Any, Any, Any), n, Union(), lb::Type, ub)::TypeVar : + ccall(:jl_new_typevar, Any, (Any, Any, Any), n, lb::Type, ub::Type)::TypeVar) TypeVar(n::Symbol, lb::ANY, ub::ANY, b::Bool) = ccall(:jl_new_typevar_, Any, (Any, Any, Any, Any), n, lb::Type, ub::Type, b)::TypeVar diff --git a/base/inference.jl b/base/inference.jl index 57979aa9eac80..e0f6862a54026 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -1254,6 +1254,9 @@ CYCLE_ID = 1 # def is the original unspecialized version of a method. we aggregate all # saved type inference data there. function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop) + if linfo.module === Core + atypes = Tuple + end #dbg = #dotrace = true local ast::Expr, tfunc_idx From 2e46b1bbfd7957918d9a9b772b2d9a907c2e25a9 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sun, 12 Oct 2014 12:57:42 -0400 Subject: [PATCH 14/44] remove unsupported use of chained type parameters --- base/linalg/cholesky.jl | 2 +- base/linalg/ldlt.jl | 2 +- base/linalg/lu.jl | 2 +- base/linalg/symmetric.jl | 4 ++-- base/linalg/triangular.jl | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/base/linalg/cholesky.jl b/base/linalg/cholesky.jl index 69e0b756c459b..8920c0a66a873 100644 --- a/base/linalg/cholesky.jl +++ b/base/linalg/cholesky.jl @@ -1,7 +1,7 @@ ########################## # Cholesky Factorization # ########################## -immutable Cholesky{T,S<:AbstractMatrix{T},UpLo} <: Factorization{T} +immutable Cholesky{T,S<:AbstractMatrix,UpLo} <: Factorization{T} UL::S end immutable CholeskyPivoted{T} <: Factorization{T} diff --git a/base/linalg/ldlt.jl b/base/linalg/ldlt.jl index 2d5016c82bd2f..624ba87363d18 100644 --- a/base/linalg/ldlt.jl +++ b/base/linalg/ldlt.jl @@ -1,4 +1,4 @@ -immutable LDLt{T,S<:AbstractMatrix{T}} <: Factorization{T} +immutable LDLt{T,S<:AbstractMatrix} <: Factorization{T} data::S end diff --git a/base/linalg/lu.jl b/base/linalg/lu.jl index 14755187f1c48..121e20882cad4 100644 --- a/base/linalg/lu.jl +++ b/base/linalg/lu.jl @@ -1,7 +1,7 @@ #################### # LU Factorization # #################### -immutable LU{T,S<:AbstractMatrix{T}} <: Factorization{T} +immutable LU{T,S<:AbstractMatrix} <: Factorization{T} factors::S ipiv::Vector{BlasInt} info::BlasInt diff --git a/base/linalg/symmetric.jl b/base/linalg/symmetric.jl index b562a0e3fba58..bfde6693d3405 100644 --- a/base/linalg/symmetric.jl +++ b/base/linalg/symmetric.jl @@ -1,10 +1,10 @@ #Symmetric and Hermitian matrices -immutable Symmetric{T,S<:AbstractMatrix{T}} <: AbstractMatrix{T} +immutable Symmetric{T,S<:AbstractMatrix} <: AbstractMatrix{T} data::S uplo::Char end Symmetric(A::AbstractMatrix, uplo::Symbol=:U) = (chksquare(A);Symmetric{eltype(A),typeof(A)}(A, char_uplo(uplo))) -immutable Hermitian{T,S<:AbstractMatrix{T}} <: AbstractMatrix{T} +immutable Hermitian{T,S<:AbstractMatrix} <: AbstractMatrix{T} data::S uplo::Char end diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index 1448449f63430..6920a524abc43 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -1,5 +1,5 @@ ## Triangular -immutable Triangular{T,S<:AbstractMatrix{T},UpLo,IsUnit} <: AbstractMatrix{T} +immutable Triangular{T,S<:AbstractMatrix,UpLo,IsUnit} <: AbstractMatrix{T} data::S end function Triangular{T}(A::AbstractMatrix{T}, uplo::Symbol, isunit::Bool=false) From 1888e850b82a7aa193153b7942689fe2c761a638 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sun, 12 Oct 2014 13:27:11 -0400 Subject: [PATCH 15/44] fix constructor method sort order by preserving typevar bounds in the generated `call` methods --- src/interpreter.c | 6 +-- src/julia-syntax.scm | 91 ++++++++++++++++++-------------------------- 2 files changed, 40 insertions(+), 57 deletions(-) diff --git a/src/interpreter.c b/src/interpreter.c index 4a16ac9b454dc..86814306301c2 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -379,7 +379,7 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) temp = eval(args[2], locals, nl); // field names dt = jl_new_datatype((jl_sym_t*)name, jl_any_type, (jl_tuple_t*)para, (jl_tuple_t*)temp, NULL, - 0, args[6]==jl_true ? 1 : 0); + 0, args[5]==jl_true ? 1 : 0); jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)name); temp = b->value; // save old value @@ -390,10 +390,10 @@ static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl) JL_TRY { // operations that can fail inside_typedef = 1; - dt->types = (jl_tuple_t*)eval(args[5], locals, nl); + dt->types = (jl_tuple_t*)eval(args[4], locals, nl); inside_typedef = 0; jl_check_type_tuple(dt->types, dt->name->name, "type definition"); - super = eval(args[4], locals, nl); + super = eval(args[3], locals, nl); jl_set_datatype_super(dt, super); } JL_CATCH { diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 5289adb50cdc0..2b3e020fc7131 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -781,7 +781,7 @@ `(,(car sig) ,item ,@(cdr sig)) `(,item ,@sig))) -(define (ctor-signature name params method-params sig) +(define (ctor-signature name params bounds method-params sig) (if (null? params) (if (null? method-params) (cons `(call call @@ -791,7 +791,7 @@ ,@(arglist-unshift sig `(|::| ,(gensy) (curly Type ,name)))) params)) (if (null? method-params) - (cons `(call (curly call ,@params) + (cons `(call (curly call ,@(map (lambda (p b) `(<: ,p ,b)) params bounds)) ,@(arglist-unshift sig `(|::| ,(gensy) (curly Type (curly ,name ,@params))))) params) ;; rename parameters that conflict with user-written method parameters @@ -799,17 +799,22 @@ (gensy) p)) params))) - (cons `(call (curly call ,@new-params ,@method-params) + (cons `(call (curly call + ,@(map (lambda (p b) `(<: ,p ,b)) new-params bounds) + ,@method-params) ,@(arglist-unshift sig `(|::| ,(gensy) (curly Type (curly ,name ,@new-params))))) new-params))))) -(define (ctor-def keyword name params method-params sig ctor-body body) - (let* ((temp (ctor-signature name params method-params sig)) - (sig (car temp)) - (params (cdr temp))) - `(,keyword ,sig ,(ctor-body body params)))) +(define (ctor-def keyword name Tname params bounds method-params sig ctor-body body) + (if (eq? name Tname) + (let* ((temp (ctor-signature name params bounds method-params sig)) + (sig (car temp)) + (params (cdr temp))) + `(,keyword ,sig ,(ctor-body body params))) + `(,keyword (call (curly ,name ,@method-params) ,@sig) + ,(ctor-body body params)))) -(define (rewrite-ctor ctor Tname params field-names field-types mutabl iname) +(define (rewrite-ctor ctor Tname params bounds field-names field-types mutabl) (define (ctor-body body params) (pattern-replace (pattern-set (pattern-lambda @@ -828,35 +833,17 @@ (pattern-replace (pattern-set (pattern-lambda (function (call (curly name . p) . sig) body) - (if (eq? name Tname) - (ctor-def 'function name params p sig ctor-body body) - `(function (call (curly ,name ,@p) ,@sig) - ,(ctor-body body params)))) + (ctor-def 'function name Tname params bounds p sig ctor-body body)) (pattern-lambda (stagedfunction (call (curly name . p) . sig) body) - (if (eq? name Tname) - (ctor-def 'stagedfunction name params p sig ctor-body body) - `(stagedfunction (call (curly ,name ,@p) ,@sig) - ,(ctor-body body params)))) + (ctor-def 'stagedfunction name Tname params bounds p sig ctor-body body)) (pattern-lambda (function (call name . sig) body) - (if (eq? name Tname) - (ctor-def 'function name params '() sig ctor-body body) - `(function (call ,name ,@sig) - ,(ctor-body body params)))) + (ctor-def 'function name Tname params bounds '() sig ctor-body body)) (pattern-lambda (stagedfunction (call name . sig) body) - (if (eq? name Tname) - (ctor-def 'stagedfunction name params '() sig ctor-body body) - `(stagedfunction (call ,name ,@sig) - ,(ctor-body body params)))) + (ctor-def 'stagedfunction name Tname params bounds '() sig ctor-body body)) (pattern-lambda (= (call (curly name . p) . sig) body) - (if (eq? name Tname) - (ctor-def 'function name params p sig ctor-body body) - `(function (call (curly ,name ,@p) ,@sig) - ,(ctor-body body params)))) + (ctor-def 'function name Tname params bounds p sig ctor-body body)) (pattern-lambda (= (call name . sig) body) - (if (eq? name Tname) - (ctor-def 'function name params '() sig ctor-body body) - `(function (call ,name ,@sig) - ,(ctor-body body params))))) + (ctor-def 'function name Tname params bounds '() sig ctor-body body))) ctor)) ;; remove line numbers and nested blocks @@ -891,8 +878,7 @@ (const ,name) (composite_type ,name (tuple ,@params) (tuple ,@(map (lambda (x) `',x) field-names)) - (null) ,super (tuple ,@field-types) - ,mut) + ,super (tuple ,@field-types) ,mut) (call (lambda () (scope-block @@ -900,7 +886,7 @@ (global ,name) (global call) ,@(map (lambda (c) - (rewrite-ctor c name '() field-names field-types mut name)) + (rewrite-ctor c name '() '() field-names field-types mut)) defs2))))) (null)) ;; parametric case @@ -913,9 +899,7 @@ ,@(map make-assignment params (symbols->typevars params bounds #t)) (composite_type ,name (tuple ,@params) (tuple ,@(map (lambda (x) `',x) field-names)) - (null) - ,super (tuple ,@field-types) - ,mut))) + ,super (tuple ,@field-types) ,mut))) ;; "inner" constructors (call (lambda () @@ -924,23 +908,22 @@ (global ,name) (global call) ,@(map (lambda (c) - (rewrite-ctor c name params field-names - field-types mut name)) + (rewrite-ctor c name params bounds field-names field-types mut)) defs2))))) ;; "outer" constructors - (scope-block - (block - (global ,name) - ,@(if (and (null? defs) - ;; don't generate an outer constructor if the type has - ;; parameters not mentioned in the field types. such a - ;; constructor would not be callable anyway. - (every (lambda (sp) - (expr-contains-eq sp (cons 'list field-types))) - params)) - `(,(default-outer-ctor name field-names field-types - params bounds)) - '()))) + ,@(if (and (null? defs) + ;; don't generate an outer constructor if the type has + ;; parameters not mentioned in the field types. such a + ;; constructor would not be callable anyway. + (every (lambda (sp) + (expr-contains-eq sp (cons 'list field-types))) + params)) + `((scope-block + (block + (global ,name) + ,(default-outer-ctor name field-names field-types + params bounds)))) + '()) (null)))))) (define (abstract-type-def-expr name params super) From b2bfd5290b48f348800a83f0660229489a83ac9c Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sun, 12 Oct 2014 14:19:38 -0400 Subject: [PATCH 16/44] my last trick for constructor+call+keywordargs didn't quite work; fix it --- src/builtins.c | 3 +++ src/toplevel.c | 23 ++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index 8ea5f237229a3..c8575aa274712 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -387,6 +387,9 @@ JL_CALLABLE(jl_f_kwcall) f = (jl_function_t*)args[pa-2]; if (!jl_is_function(f)) { // do generic call(args...; kws...) instead + // switch (f container pa...) to (container f pa...) + args[pa-2] = args[pa-1]; // TODO: this might not be safe + args[pa-1] = (jl_value_t*)f; f = call_func; pa--; } diff --git a/src/toplevel.c b/src/toplevel.c index 36cb93f7560f4..1551001941751 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -670,10 +670,17 @@ DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_ size_t na = jl_tuple_len(argtypes); jl_tuple_t *newargtypes = jl_alloc_tuple(1 + na); JL_GC_PUSH1(&newargtypes); - jl_tupleset(newargtypes, 0, jl_wrap_Type(gf)); - size_t i; - for(i=0; i < na; i++) { - jl_tupleset(newargtypes, i+1, jl_tupleref(argtypes, i)); + size_t i=0; + if (iskw) { + assert(na > 0); + // for kw sorter, keep container argument first + jl_tupleset(newargtypes, 0, jl_tupleref(argtypes, 0)); + i++; + } + jl_tupleset(newargtypes, i, jl_wrap_Type(gf)); + i++; + for(; i < na+1; i++) { + jl_tupleset(newargtypes, i, jl_tupleref(argtypes, i-1)); } argtypes = newargtypes; JL_GC_POP(); @@ -690,7 +697,13 @@ DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_binding_ else { jl_array_grow_beg(al, 1); } - jl_cellset(al, 0, (jl_value_t*)jl_gensym()); + if (iskw) { + jl_cellset(al, 0, jl_cellref(al, 1)); + jl_cellset(al, 1, (jl_value_t*)jl_gensym()); + } + else { + jl_cellset(al, 0, (jl_value_t*)jl_gensym()); + } } if (!jl_is_gf(gf)) { jl_error("invalid method definition: not a generic function"); From 208b2cd40a7edc31172e0d85dc9c4062ff68aa21 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 13 Oct 2014 14:40:12 -0400 Subject: [PATCH 17/44] fix a memory bug in codegen of getfield on a 0-size struct --- src/codegen.cpp | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 65cf319406e5e..efa66b40dcf1b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2164,19 +2164,26 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, assert(llvm_st->isStructTy()); // TODO: move these allocas to the first basic block instead of // frobbing the stack - Instruction *stacksave = - CallInst::Create(Intrinsic::getDeclaration(jl_Module, - Intrinsic::stacksave)); - builder.Insert(stacksave); - Value *tempSpace = builder.CreateAlloca(llvm_st); - builder.CreateStore(strct, tempSpace); - jl_value_t *jt = jl_t0(stt->types); - idx = emit_bounds_check(idx, ConstantInt::get(T_size, nfields), ctx); - Value *ptr = builder.CreateGEP(tempSpace, ConstantInt::get(T_size, 0)); - Value *fld = typed_load(ptr, idx, jt, ctx); - builder.CreateCall(Intrinsic::getDeclaration(jl_Module, - Intrinsic::stackrestore), - stacksave); + Value *fld; + if (nfields == 0) { + emit_bounds_check(idx, ConstantInt::get(T_size, nfields), ctx); + fld = UndefValue::get(jl_pvalue_llvmt); + } + else { + Instruction *stacksave = + CallInst::Create(Intrinsic::getDeclaration(jl_Module, + Intrinsic::stacksave)); + builder.Insert(stacksave); + Value *tempSpace = builder.CreateAlloca(llvm_st); + builder.CreateStore(strct, tempSpace); + jl_value_t *jt = jl_t0(stt->types); + idx = emit_bounds_check(idx, ConstantInt::get(T_size, nfields), ctx); + Value *ptr = builder.CreateGEP(tempSpace, ConstantInt::get(T_size, 0)); + fld = typed_load(ptr, idx, jt, ctx); + builder.CreateCall(Intrinsic::getDeclaration(jl_Module, + Intrinsic::stackrestore), + stacksave); + } JL_GC_POP(); return fld; } From 70683906eb73e83cca99f144bac10c6a65f6114c Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 13 Oct 2014 15:35:18 -0400 Subject: [PATCH 18/44] type system improvements needed for constructors-via-call - make typeintersect((Rational{T},T),(Rational{Integer},Int)) == (Rational{Integer},Int) This used to be Bottom, since the T's had to match exactly. Now if T appears in covariant position, subtypes can also match. This is a good change anyway, but turns out to be necessary for the new constructor design. We have a constructor `Rational{T}(x::T, y::T)` which now gets lowered to `call{T}(::Type{Rational{T}}, x::T, y::T)`, so obviously we must allow x and y to be any subtypes of T. This also allows convert_default to be replaced with `convert{T}(::Type{T}, x::T) = x` (to be done next). - making that work required an improved constraint solving algorithm in type intersection. the new algorithm should be much more robust, but it yields more typevars in its answers, for example `typeintersect((T,AbstractArray{T}),(Any,Array{Number,1}))` gives `(_<:Number,Array{Number,1})`. Hopefully this will not cause problems. But I can imagine doing a post-processing step to replace `_<:T` in covariant position with just `T`. In the meantime, to further legitimize such results I also made the next change: - make TypeVar a subtype of Type --- src/jltypes.c | 235 +++++++++++++++++++++++++++++--------------------- test/core.jl | 6 +- 2 files changed, 141 insertions(+), 100 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index ab256f65f557f..dc24f7c5529b7 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -64,13 +64,14 @@ int jl_is_type(jl_value_t *v) size_t i, l = jl_tuple_len(t); for(i=0; i < l; i++) { jl_value_t *vv = jl_tupleref(t, i); - if (!jl_is_typevar(vv) && !jl_is_type(vv)) + if (!jl_is_type(vv)) return 0; if (i < l-1 && jl_is_vararg_type(vv)) return 0; } return 1; } + if (jl_is_typevar(v)) return 1; return jl_is_nontuple_type(v); } @@ -720,11 +721,19 @@ static jl_value_t *intersect_typevar(jl_tvar_t *a, jl_value_t *b, jl_value_t *ti = jl_type_intersection(b, penv->data[i+1]); if (ti == (jl_value_t*)jl_bottom_type) return ti; - penv->data[i+1] = ti; - return (jl_value_t*)a; + break; } } extend((jl_value_t*)a, b, penv); + if (jl_is_typevar(b)) { + return (jl_value_t*)a; + } + else { + jl_tvar_t *new_b = jl_new_typevar(underscore_sym, jl_bottom_type, b); + extend((jl_value_t*)new_b, b, penv); + extend((jl_value_t*)new_b, (jl_value_t*)a, penv); + return (jl_value_t*)new_b; + } } return (jl_value_t*)a; } @@ -1215,6 +1224,11 @@ static jl_value_t *meet(jl_value_t *X, jl_value_t *Y, variance_t var) if (var==invariant) { return (jl_types_equal(X,Y) ? X : NULL); } + else { + if (jl_subtype(X,Y,0)) return X; + if (jl_subtype(Y,X,0)) return Y; + return NULL; + } } return (jl_subtype(X,Y,0) ? X : NULL); } @@ -1225,120 +1239,145 @@ static jl_value_t *meet(jl_value_t *X, jl_value_t *Y, variance_t var) return (v == (jl_value_t*)jl_bottom_type ? NULL : v); } +/* +void print_env(cenv_t *soln) +{ + for(int i=0; i < soln->n; i+=2) { + jl_value_t *T, *S; + T = soln->data[i]; S = soln->data[i+1]; + JL_PRINTF(JL_STDOUT, "%s@%x=", ((jl_tvar_t*)T)->name->name, T); + jl_static_show(JL_STDOUT, S); + JL_PRINTF(JL_STDOUT, " "); + } + JL_PRINTF(JL_STDOUT, "\n"); +} +*/ + static int solve_tvar_constraints(cenv_t *env, cenv_t *soln) { - //JL_PRINTF(JL_STDOUT, "\n"); - jl_value_t *v=NULL; - for(int i=0; i < env->n; i+=2) { - jl_value_t *T = env->data[i]; - jl_value_t *S = env->data[i+1]; - jl_value_t **pT; - pT = tvar_lookup(soln, &T); - if (pT != &T) { - // T=U is in the results - jl_value_t **pU = pT; - //jl_value_t *U = *pU; - if (is_btv(S)) { - // S is a typevar - jl_value_t **pS; - pS = tvar_lookup(soln, &S); - if (pS != &S) { - // S=R is in the results - jl_value_t **pR = pS; - *pR = meet(*pR, *pU, invariant); - if (*pR == NULL) { - return 0; - } + while (1) { + int old_n = soln->n; + + // 1. replace each T=S with T=find(S) + for(int i=0; i < soln->n; i+=2) { + jl_value_t **pS = &soln->data[i+1]; + if (jl_is_typevar(*pS)) + *pS = *tvar_lookup(soln, pS); + } + + // 2. instantiate all RHSes using soln + if (soln->n > 0) { + for(int i=0; i < env->n; i+=2) { + jl_value_t **pS = &env->data[i+1]; + JL_TRY { + *pS = jl_instantiate_type_with(*pS, &soln->data[0], soln->n/2); } - else { - v = meet(*pU, S, covariant); - if (v == NULL) { - return 0; - } - extend(S, v, soln); + JL_CATCH { } - if (pS != pU) - *pU = S; } - else { - if (jl_is_long(*pU) && jl_is_long(S)) { - int bot = 0; - long mv = meet_tuple_lengths(~jl_unbox_long(S), - jl_unbox_long(*pU), &bot); - if (bot) - return 0; - v = jl_box_long(mv); + } + + // 3. given T, let S´ = intersect(all S s.t. (T=S) or (S=T) ∈ env). add (T=S´) to soln. + for(int i=0; i < env->n; i+=2) { + jl_value_t *T = env->data[i]; + jl_value_t **pS = &env->data[i+1]; + jl_value_t *S = *pS; + if (!jl_is_typevar(S)) { + for(int j=i+2; j < env->n; j+=2) { + jl_value_t *TT = env->data[j]; + jl_value_t *SS = env->data[j+1]; + if (TT == T) { + // found T=SS in env + if (!jl_is_typevar(SS)) { + jl_value_t *m = meet(S, SS, covariant); + if (m == NULL) return 0; + S = m; + } + } + else if (SS == T) { + // found TT=T in env; meet with TT + jl_value_t **pTT = tvar_lookup(soln, &TT); + if (pTT != &TT) { + jl_value_t *m = meet(S, *pTT, covariant); + if (m == NULL) return 0; + S = m; + } + } } - else if (!jl_is_type(S) && jl_is_typevar(*pU)) { - // combine T<:2 with T==N => T==N - v = *pU; + + if (!(jl_is_leaf_type(S) || S == (jl_value_t*)jl_bottom_type)) { + goto next_in_env; } - else { - if (!jl_subtype(*pU, S, 0)) { - // T<:S and T=U and !(U<:S) - return 0; + + jl_value_t **pT = tvar_lookup(soln, &T); + if (pT != &T) { + if (jl_is_long(S) && jl_is_long(*pT)) { + int bot = 0; + long mv = meet_tuple_lengths(~jl_unbox_long(S), jl_unbox_long(*pT), &bot); + if (bot) + return 0; + // NOTE: this is unused. can we do anything with it? + (void)mv; + //S = jl_box_long(mv); + } + else { + if (meet(*pT,S,covariant) == NULL) + return 0; } - v = meet(*pU, S, covariant); - if (v == NULL) - return 0; - } - if (is_btv(*pU)) { - extend(*pU, v, soln); } else { - *pU = v; - } - } - } - else { - if (jl_is_typevar(S)) { - if (*tvar_lookup(soln, &S) != T) extend(T, S, soln); - } - else if (jl_is_type(S)) { - // ints in the <: env are not definite - if (jl_is_leaf_type(S) || S == (jl_value_t*)jl_bottom_type) { - v = S; } - else { - assert(jl_is_typevar(T)); - v = meet(S, T, covariant); - if (v == NULL) - return 0; - if (!jl_is_typevar(v)) { - v = (jl_value_t*) - jl_new_typevar(underscore_sym, - (jl_value_t*)jl_bottom_type, v); + } + else { + jl_value_t **pT = tvar_lookup(soln, &T); + if (pT != &T) { + if (tvar_lookup(soln, &S) == &S) { + jl_value_t *v = meet(S, *pT, covariant); + if (v == NULL) return 0; + extend(S, v, soln); + *pT = S; } } - extend(T, v, soln); } + next_in_env: + ; } + if (soln->n == old_n) + break; } - return 1; -} -/* -char *type_summary(jl_value_t *t) -{ - if (jl_is_tuple(t)) return "Tuple"; - if (jl_is_datatype(t)) - return ((jl_datatype_t*)t)->name->name->name; - return "?"; -} -void print_env(cenv_t *soln) -{ - for(int i=0; i < soln->n; i+=2) { - jl_value_t *T, *S; - T = soln->data[i]; S = soln->data[i+1]; - JL_PRINTF(JL_STDOUT, - "%s@%x=%s ", - ((jl_tvar_t*)T)->name->name, T, - type_summary(S)); + for(int i=0; i < env->n; i+=2) { + jl_value_t *T = env->data[i]; + jl_value_t **pS = &env->data[i+1]; + jl_value_t *S = *pS; + if (tvar_lookup(soln, &T) == &T) { + for(int j=i+2; j < env->n; j+=2) { + jl_value_t *TT = env->data[j]; + jl_value_t *SS = env->data[j+1]; + if (TT == T) { + jl_value_t *m = meet(S, SS, covariant); + if (m == NULL) return 0; + S = m; + } + else if (SS == T) { + jl_value_t *m = meet(S, *tvar_lookup(soln, &TT), covariant); + if (m == NULL) return 0; + S = m; + } + } + if (jl_is_type(S)) { + if (!jl_is_typevar(S) && !jl_is_leaf_type(S) && S != jl_bottom_type) { + S = (jl_value_t*)jl_new_typevar(underscore_sym, + (jl_value_t*)jl_bottom_type, S); + } + extend(T, S, soln); + } + } } - JL_PRINTF(JL_STDOUT, "\n"); + + return 1; } -*/ jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, jl_tuple_t **penv, jl_tuple_t *tvars) @@ -2932,7 +2971,7 @@ void jl_init_types(void) jl_bottom_type = (jl_value_t*)jl_new_struct(jl_uniontype_type, jl_null); jl_tvar_type = jl_new_datatype(jl_symbol("TypeVar"), - jl_any_type, jl_null, + jl_type_type, jl_null, jl_tuple(4, jl_symbol("name"), jl_symbol("lb"), jl_symbol("ub"), jl_symbol("bound")), diff --git a/test/core.jl b/test/core.jl index 16048d465535c..a6649742f76e8 100644 --- a/test/core.jl +++ b/test/core.jl @@ -41,7 +41,7 @@ let T = TypeVar(:T,true) (Int, Array{Int,1})) @test isequal(typeintersect((T, AbstractArray{T}),(Int, Array{Number,1})), - Bottom) + (Int, Array{Number,1})) @test isequal(typeintersect((T, AbstractArray{T}),(Any, Array{Number,1})), (Number, Array{Number,1})) @@ -68,6 +68,8 @@ let T = TypeVar(:T,true) @test typeintersect(Type{(Bool,Int...)}, Type{(T...)}) === Bottom @test typeintersect(Type{(Bool,Int...)}, Type{(T,T...)}) === Bottom + + @test typeintersect((Rational{T},T), (Rational{Integer},Int)) === (Rational{Integer},Int) end let N = TypeVar(:N,true) @test isequal(typeintersect((NTuple{N,Integer},NTuple{N,Integer}), @@ -651,7 +653,7 @@ begin c = Vector[a] @test my_func(c,c)==0 - @test_throws MethodError my_func(a,c) + @test my_func(a,c)==1 end begin From d5aebc7bd869327297a91fabdb42b920b3307706 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 14 Oct 2014 00:19:25 -0400 Subject: [PATCH 19/44] a couple tweaks to type intersection that were helpful when eliminating convert_default --- src/jltypes.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index dc24f7c5529b7..e9d8caed5b11a 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -1219,22 +1219,8 @@ static jl_value_t *meet(jl_value_t *X, jl_value_t *Y, variance_t var) return NULL; return tv; } - if (!jl_has_typevars_(X,1)) { - if (!jl_has_typevars_(Y,1)) { - if (var==invariant) { - return (jl_types_equal(X,Y) ? X : NULL); - } - else { - if (jl_subtype(X,Y,0)) return X; - if (jl_subtype(Y,X,0)) return Y; - return NULL; - } - } - return (jl_subtype(X,Y,0) ? X : NULL); - } - if (!jl_has_typevars_(Y,1)) { - return (jl_subtype(Y,X,0) ? Y : NULL); - } + if (jl_subtype(X,Y,0)) return X; + if (jl_subtype(Y,X,0)) return Y; jl_value_t *v = jl_type_intersection(X, Y); return (v == (jl_value_t*)jl_bottom_type ? NULL : v); } @@ -1513,6 +1499,8 @@ jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, } JL_GC_POP(); + if (jl_is_typevar(*pti) && !(jl_is_typevar(a) && jl_is_typevar(b))) + return ((jl_tvar_t*)*pti)->ub; return *pti; } From c62c8f0cb955e825115c44e5d805778c04a12aa0 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 14 Oct 2014 00:23:30 -0400 Subject: [PATCH 20/44] remove convert_default builtin --- base/base.jl | 11 +++++++---- base/boot.jl | 8 ++++---- base/inference.jl | 23 ----------------------- base/sysimg.jl | 3 +-- src/builtin_proto.h | 1 - src/builtins.c | 20 ++++++-------------- src/dump.c | 1 - src/gf.c | 6 +++++- 8 files changed, 23 insertions(+), 50 deletions(-) diff --git a/base/base.jl b/base/base.jl index 21518918faebd..b77fad819ab3f 100644 --- a/base/base.jl +++ b/base/base.jl @@ -6,20 +6,23 @@ typealias Callable Union(Function,DataType) const Bottom = Union() -convert(T, x) = convert_default(T, x, convert) +# fall back to Core.call +call(args...) = Core.call(args...) + +convert{T}(::Type{T}, x::T) = x convert(::(), ::()) = () convert(::Type{Tuple}, x::Tuple) = x -# fall back to Core.call -call(args...) = Core.call(args...) - # allow convert to be called as if it were a single-argument constructor # call(T::Type, x) = convert(T, x) argtail(x, rest...) = rest tupletail(x::Tuple) = argtail(x...) +convert(T::(Type, Type...), x::(Any, Any...)) = + tuple(convert(T[1],x[1]), convert(tupletail(T), tupletail(x))...) + convert(T::(Any, Any...), x::(Any, Any...)) = tuple(convert(T[1],x[1]), convert(tupletail(T), tupletail(x))...) diff --git a/base/boot.jl b/base/boot.jl index b8859cb546b29..1d1ffcec29589 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -138,7 +138,7 @@ export GetfieldNode, NewvarNode, # object model functions fieldtype, getfield, setfield!, yieldto, throw, tuple, is, ===, isdefined, - # arraylen, arrayref, arrayset, arraysize, tuplelen, tupleref, convert_default, + # arraylen, arrayref, arrayset, arraysize, tuplelen, tupleref, # _apply, kwcall, # sizeof # not exported, to avoid conflicting with Base.sizeof # type reflection @@ -168,9 +168,6 @@ export const (===) = is -# simple convert for use by constructors of types in Core -convert(T, x) = convert_default(T, x, convert) - abstract Number abstract Real <: Number abstract FloatingPoint <: Real @@ -274,3 +271,6 @@ Module(name::Symbol) = ccall(:jl_f_new_module, Any, (Any,), name)::Module Module() = Module(:anonymous) Task(f::ANY) = ccall(:jl_new_task, Any, (Any, Int), f::Function, 0)::Task + +# simple convert for use by constructors of types in Core +convert{T}(::Type{T}, x::T) = x diff --git a/base/inference.jl b/base/inference.jl index e0f6862a54026..11ed4e6bf5c00 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -159,21 +159,6 @@ t_func[arraysize] = (1, 2, arraysize_tfunc) t_func[pointerref] = (2,2,(a,i)->(isa(a,DataType) && a<:Ptr ? a.parameters[1] : Any)) 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] - - if isa(to,TypeVar) - return to - end - if from <: to - return from - end - return typeintersect(from,to) -end -t_func[convert_default] = (3, 3, convert_default_tfunc) - const typeof_tfunc = function (t) if isType(t) t = t.parameters[1] @@ -2053,14 +2038,6 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast) end argexprs = e.args[2:end] - if is(f, convert_default) && length(atypes)==3 - # builtin case of convert. convert(T,x::S) => x, when S<:T - if isType(atypes[1]) && isleaftype(atypes[1]) && - atypes[2] <: atypes[1].parameters[1] - # todo: if T expression has side effects??! - return (e.args[3],()) - end - end if is(f, typeassert) && length(atypes)==2 # typeassert(x::S, T) => x, when S<:T if isType(atypes[2]) && isleaftype(atypes[2]) && diff --git a/base/sysimg.jl b/base/sysimg.jl index 4f8d4fd44ca26..a41e78f19dfde 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -9,8 +9,7 @@ eval(m,x) = Core.eval(m,x) include = Core.include using Core: Intrinsics, arraylen, arrayref, arrayset, arraysize, - tuplelen, tupleref, convert_default, kwcall, _apply, - typeassert, apply_type + tuplelen, tupleref, kwcall, _apply, typeassert, apply_type include("exports.jl") diff --git a/src/builtin_proto.h b/src/builtin_proto.h index 76d25d6acbc25..59c3a5c4ab131 100644 --- a/src/builtin_proto.h +++ b/src/builtin_proto.h @@ -29,7 +29,6 @@ JL_CALLABLE(jl_f_arrayref); JL_CALLABLE(jl_f_arrayset); JL_CALLABLE(jl_f_arraysize); JL_CALLABLE(jl_f_instantiate_type); -JL_CALLABLE(jl_f_convert_default); JL_CALLABLE(jl_f_typevar); JL_CALLABLE(jl_f_union); JL_CALLABLE(jl_f_methodexists); diff --git a/src/builtins.c b/src/builtins.c index c8575aa274712..fb1fcc195be5f 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -628,16 +628,6 @@ JL_CALLABLE(jl_f_field_type) // conversion ----------------------------------------------------------------- -JL_CALLABLE(jl_f_convert_default) -{ - jl_value_t *to = args[0]; - jl_value_t *x = args[1]; - if (!jl_subtype(x, (jl_value_t*)to, 1)) { - jl_no_method_error((jl_function_t*)args[2], args, 2); - } - return x; -} - DLLEXPORT void *jl_symbol_name(jl_sym_t *s) { return s->name; @@ -1029,7 +1019,6 @@ void jl_init_primitives(void) add_builtin_func("yieldto", jl_f_yieldto); // functions for internal use - add_builtin_func("convert_default", jl_f_convert_default); add_builtin_func("tupleref", jl_f_tupleref); add_builtin_func("tuplelen", jl_f_tuplelen); add_builtin_func("getfield", jl_f_get_field); @@ -1142,7 +1131,7 @@ DLLEXPORT size_t jl_static_show(JL_STREAM *out, jl_value_t *v) JL_PUTS(".", out); n += 1; } n += JL_PRINTF(out, "%s", dv->name->name->name); - if (dv->parameters) { + if (dv->parameters && (jl_value_t*)dv != dv->name->primary) { size_t j, tlen = jl_tuple_len(dv->parameters); if (tlen > 0) { n += JL_PRINTF(out, "{"); @@ -1224,8 +1213,11 @@ DLLEXPORT size_t jl_static_show(JL_STREAM *out, jl_value_t *v) n += jl_static_show(out, ((jl_typector_t*)v)->body); } else if (jl_is_typevar(v)) { - n += jl_static_show(out, ((jl_tvar_t*)v)->lb); - n += JL_PRINTF(out, "<:%s<:", ((jl_tvar_t*)v)->name->name); + if (((jl_tvar_t*)v)->lb != jl_bottom_type) { + n += jl_static_show(out, ((jl_tvar_t*)v)->lb); + n += JL_PRINTF(out, "<:"); + } + n += JL_PRINTF(out, "%s<:", ((jl_tvar_t*)v)->name->name); n += jl_static_show(out, ((jl_tvar_t*)v)->ub); } else if (jl_is_module(v)) { diff --git a/src/dump.c b/src/dump.c index 7cec6dc7966f3..0cb96de2f74f1 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1315,7 +1315,6 @@ void jl_init_serializer(void) jl_f_arraylen, jl_f_arrayref, jl_f_arrayset, jl_f_arraysize, jl_f_instantiate_type, jl_f_kwcall, - jl_f_convert_default, jl_trampoline, jl_f_union, jl_f_methodexists, jl_f_applicable, jl_f_invoke, jl_apply_generic, diff --git a/src/gf.c b/src/gf.c index 1737c9672090e..3ec8e40ea6ff1 100644 --- a/src/gf.c +++ b/src/gf.c @@ -593,7 +593,9 @@ static jl_function_t *cache_method(jl_methtable_t *mt, jl_tuple_t *type, } } else if (jl_is_type_type(elt) && jl_is_type_type(jl_tparam0(elt)) && - (decl_i==NULL || !jl_has_typevars(decl_i))) { + // give up on specializing static parameters for Type{Type{Type{...}}} + (jl_is_type_type(jl_tparam0(jl_tparam0(elt))) || + decl_i==NULL || !jl_has_typevars(decl_i))) { /* actual argument was Type{...}, we computed its type as Type{Type{...}}. we must avoid unbounded nesting here, so @@ -608,6 +610,8 @@ static jl_function_t *cache_method(jl_methtable_t *mt, jl_tuple_t *type, declt = jl_tparam0(declt); jl_tupleset(type, i, jl_type_intersection(declt, (jl_value_t*)jl_typetype_type)); + // TODO: recompute static parameter values, so in extreme cases we + // can give `T=Type` instead of `T=Type{Type{Type{...`. } else { jl_tupleset(type, i, (jl_value_t*)jl_typetype_type); From 4e0dd590aaee2263964dec44ebcdcbfc41fd4e74 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 14 Oct 2014 00:51:23 -0400 Subject: [PATCH 21/44] code cleanup, fix error displaying types, change Callable --- base/base.jl | 3 +-- base/deprecated.jl | 2 +- base/inference.jl | 3 --- base/interactiveutil.jl | 3 --- base/reflection.jl | 3 --- base/replutil.jl | 7 +------ src/builtins.c | 6 ++---- src/codegen.cpp | 12 ++++-------- src/interpreter.c | 10 ++++------ src/julia-syntax.scm | 18 ++++++------------ 10 files changed, 19 insertions(+), 48 deletions(-) diff --git a/base/base.jl b/base/base.jl index b77fad819ab3f..2afd6df0d4330 100644 --- a/base/base.jl +++ b/base/base.jl @@ -2,7 +2,7 @@ import Core.Array # to add methods const NonTupleType = Union(DataType,UnionType,TypeConstructor) -typealias Callable Union(Function,DataType) +typealias Callable Function const Bottom = Union() @@ -22,7 +22,6 @@ tupletail(x::Tuple) = argtail(x...) convert(T::(Type, Type...), x::(Any, Any...)) = tuple(convert(T[1],x[1]), convert(tupletail(T), tupletail(x))...) - convert(T::(Any, Any...), x::(Any, Any...)) = tuple(convert(T[1],x[1]), convert(tupletail(T), tupletail(x))...) diff --git a/base/deprecated.jl b/base/deprecated.jl index 726767442f7ca..3b3938bf1b3e6 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -188,7 +188,7 @@ const None = Union() export apply function apply(f, args...) - depwarn("apply() is deprecated, use `...` instead", :apply) + depwarn("apply(f, x) is deprecated, use `f(x...)` instead", :apply) return Core._apply(call, f, args...) end diff --git a/base/inference.jl b/base/inference.jl index 11ed4e6bf5c00..c6ee0ca1f3941 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -1309,8 +1309,6 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop) end #if dbg print("typeinf ", linfo.name, " ", atypes, "\n") end - #ccall(:jl_,Void,(Any,),linfo.name) - #ccall(:jl_,Void,(Any,),atypes) if cop sparams = tuple(sparams..., linfo.sparams...) @@ -1590,7 +1588,6 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop) # just the return type in place of it. tfarr[idx+1] = rec ? frame.result : fulltree tfarr[idx+2] = rec - #tfunc_idx = idx+1 else def.tfunc[tfunc_idx] = rec ? frame.result : fulltree def.tfunc[tfunc_idx+1] = rec diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index a11f498c16c13..20516089662f4 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -265,9 +265,6 @@ function type_close_enough(x::ANY, t::ANY) end function methodswith(t::Type, f::Callable, showparents::Bool=false, meths = Method[]) - if isa(f,DataType) - methods(f) # force constructor creation - end if !isa(f.env, MethodTable) return meths end diff --git a/base/reflection.jl b/base/reflection.jl index ac61eb44226ea..b723b8f70a351 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -126,9 +126,6 @@ function methods(f::Function) f.env end -#methods(t::DataType) = (_methods(t,Tuple,0); # force constructor creation -# t.env) - function length(mt::MethodTable) n = 0 d = mt.defs diff --git a/base/replutil.jl b/base/replutil.jl index b41e556ff86c8..5cd68b99afc9d 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -28,12 +28,7 @@ writemime(io::IO, ::MIME"text/plain", v::AbstractArray) = function writemime(io::IO, ::MIME"text/plain", v::DataType) show(io, v) - methods(v) # force constructor creation - if isgeneric(v) - n = length(v.env) - m = n==1 ? "method" : "methods" - print(io, " (constructor with $n $m)") - end + # TODO: maybe show constructor info? end writemime(io::IO, ::MIME"text/plain", t::Associative) = diff --git a/src/builtins.c b/src/builtins.c index fb1fcc195be5f..21aef3181512b 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -313,8 +313,7 @@ JL_CALLABLE(jl_f_apply) } } if (jl_is_tuple(args[1])) { - return jl_apply(f, &jl_tupleref(args[1],0), - jl_tuple_len(args[1])); + return jl_apply(f, &jl_tupleref(args[1],0), jl_tuple_len(args[1])); } } jl_value_t *argarr = NULL; @@ -332,8 +331,7 @@ JL_CALLABLE(jl_f_apply) else { if (jl_append_any_func == NULL) { jl_append_any_func = - (jl_function_t*)jl_get_global(jl_base_module, - jl_symbol("append_any")); + (jl_function_t*)jl_get_global(jl_base_module, jl_symbol("append_any")); if (jl_append_any_func == NULL) { // error if append_any not available JL_TYPECHK(apply, tuple, args[i]); diff --git a/src/codegen.cpp b/src/codegen.cpp index efa66b40dcf1b..9a40b11da396f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2171,8 +2171,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, } else { Instruction *stacksave = - CallInst::Create(Intrinsic::getDeclaration(jl_Module, - Intrinsic::stacksave)); + CallInst::Create(Intrinsic::getDeclaration(jl_Module,Intrinsic::stacksave)); builder.Insert(stacksave); Value *tempSpace = builder.CreateAlloca(llvm_st); builder.CreateStore(strct, tempSpace); @@ -2180,8 +2179,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, idx = emit_bounds_check(idx, ConstantInt::get(T_size, nfields), ctx); Value *ptr = builder.CreateGEP(tempSpace, ConstantInt::get(T_size, 0)); fld = typed_load(ptr, idx, jt, ctx); - builder.CreateCall(Intrinsic::getDeclaration(jl_Module, - Intrinsic::stackrestore), + builder.CreateCall(Intrinsic::getDeclaration(jl_Module,Intrinsic::stackrestore), stacksave); } JL_GC_POP(); @@ -2353,8 +2351,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, jl_ definitely_function = jl_is_func(f); definitely_not_function = !definitely_function; if (jl_typeis(f, jl_intrinsic_type) || jl_is_func(f)) { - result = emit_known_call((jl_value_t*)f, args, nargs, ctx, - &theFptr, &f, expr); + result = emit_known_call((jl_value_t*)f, args, nargs, ctx, &theFptr, &f, expr); assert(!jl_typeis(f,jl_intrinsic_type) || result!=NULL); } else { @@ -2376,8 +2373,7 @@ static Value *emit_call(jl_value_t **args, size_t arglen, jl_codectx_t *ctx, jl_ if (definitely_not_function) { if (f == NULL) { f = jl_module_call_func(ctx->module); - Value *r = emit_known_call((jl_value_t*)f, - args-1, nargs+1, ctx, &theFptr, &f, expr); + Value *r = emit_known_call((jl_value_t*)f, args-1, nargs+1, ctx, &theFptr, &f, expr); assert(r == NULL); assert(theFptr != NULL); } diff --git a/src/interpreter.c b/src/interpreter.c index 86814306301c2..55e25bd49602b 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -60,14 +60,12 @@ static jl_value_t *do_call(jl_function_t *f, jl_value_t **args, size_t nargs, size_t i; argv[0] = (jl_value_t*)f; for(i=1; i < nargs+1; i++) argv[i] = NULL; + i = 0; if (eval0) { /* 0-th argument has already been evaluated */ - argv[1] = eval0; - for(i=1; i < nargs; i++) - argv[i+1] = eval(args[i], locals, nl); + argv[1] = eval0; i++; } - else { - for(i=0; i < nargs; i++) - argv[i+1] = eval(args[i], locals, nl); + for(; i < nargs; i++) { + argv[i+1] = eval(args[i], locals, nl); } jl_value_t *result = jl_apply(f, &argv[1], nargs); JL_GC_POP(); diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 2b3e020fc7131..f2f7d5093453b 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -784,8 +784,7 @@ (define (ctor-signature name params bounds method-params sig) (if (null? params) (if (null? method-params) - (cons `(call call - ,@(arglist-unshift sig `(|::| ,(gensy) (curly Type ,name)))) + (cons `(call call ,@(arglist-unshift sig `(|::| ,(gensy) (curly Type ,name)))) params) (cons `(call (curly call ,@method-params) ,@(arglist-unshift sig `(|::| ,(gensy) (curly Type ,name)))) @@ -799,8 +798,7 @@ (gensy) p)) params))) - (cons `(call (curly call - ,@(map (lambda (p b) `(<: ,p ,b)) new-params bounds) + (cons `(call (curly call ,@(map (lambda (p b) `(<: ,p ,b)) new-params bounds) ,@method-params) ,@(arglist-unshift sig `(|::| ,(gensy) (curly Type (curly ,name ,@new-params))))) new-params))))) @@ -874,8 +872,7 @@ field-names) (if (null? params) `(block - (global ,name) - (const ,name) + (global ,name) (const ,name) (composite_type ,name (tuple ,@params) (tuple ,@(map (lambda (x) `',x) field-names)) ,super (tuple ,@field-types) ,mut) @@ -883,8 +880,7 @@ (lambda () (scope-block (block - (global ,name) - (global call) + (global ,name) (global call) ,@(map (lambda (c) (rewrite-ctor c name '() '() field-names field-types mut)) defs2))))) @@ -893,8 +889,7 @@ `(block (scope-block (block - (global ,name) - (const ,name) + (global ,name) (const ,name) ,@(map (lambda (v) `(local ,v)) params) ,@(map make-assignment params (symbols->typevars params bounds #t)) (composite_type ,name (tuple ,@params) @@ -905,8 +900,7 @@ (lambda () (scope-block (block - (global ,name) - (global call) + (global ,name) (global call) ,@(map (lambda (c) (rewrite-ctor c name params bounds field-names field-types mut)) defs2))))) From 0f67c6925ddb21c86733e855d38d77870e386b6c Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 14 Oct 2014 18:38:05 -0400 Subject: [PATCH 22/44] remove old ASCIIString constructor code from dump.c --- src/dump.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/dump.c b/src/dump.c index 0cb96de2f74f1..d74b3f4a86588 100644 --- a/src/dump.c +++ b/src/dump.c @@ -933,8 +933,7 @@ static jl_value_t *jl_deserialize_value(ios_t *s) extern jl_array_t *jl_module_init_order; -DLLEXPORT -void jl_save_system_image(char *fname) +DLLEXPORT void jl_save_system_image(char *fname) { jl_gc_collect(); jl_gc_collect(); @@ -950,17 +949,6 @@ void jl_save_system_image(char *fname) // orphan old Base module if present jl_base_module = (jl_module_t*)jl_get_global(jl_main_module, jl_symbol("Base")); - // delete cached slow ASCIIString constructor if present - jl_methtable_t *mt = jl_gf_mtable((jl_function_t*)jl_ascii_string_type); - jl_array_t *spec = mt->defs->func->linfo->specializations; - if (spec != NULL && jl_array_len(spec) > 0 && - ((jl_lambda_info_t*)jl_cellref(spec,0))->inferred == 0) { - mt->cache = (jl_methlist_t*)JL_NULL; - mt->cache_arg1 = (jl_array_t*)JL_NULL; - mt->defs->func->linfo->tfunc = (jl_value_t*)jl_null; - mt->defs->func->linfo->specializations = NULL; - } - jl_idtable_type = jl_get_global(jl_base_module, jl_symbol("ObjectIdDict")); jl_serialize_value(&f, jl_main_module); From bec065f10879bbf67327fe2d06c7cc01e8c52b76 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 14 Oct 2014 18:42:01 -0400 Subject: [PATCH 23/44] faster Expr constructor (large impact on sysimg build time) another Core.convert method to prevent types from old Base from leaking in --- base/boot.jl | 3 ++- base/inference.jl | 1 + base/sysimg.jl | 2 +- src/alloc.c | 14 ++++++++------ src/array.c | 2 ++ src/builtin_proto.h | 1 + src/builtins.c | 1 + src/dump.c | 2 +- src/julia-syntax.scm | 2 +- src/support/libsupport.h | 1 + 10 files changed, 19 insertions(+), 10 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 1d1ffcec29589..f56c48257226f 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -258,7 +258,7 @@ TypeVar(n::Symbol, lb::ANY, ub::ANY, b::Bool) = TypeConstructor(p::ANY, t::ANY) = ccall(:jl_new_type_constructor, Any, (Any, Any), p::Tuple, t::Type) -Expr(hd::Symbol, args::ANY...) = ccall(:jl_new_expr, Any, (Any, Any), hd, args)::Expr +Expr(args::ANY...) = _expr(args...) LineNumberNode(n::Int) = ccall(:jl_new_struct, Any, (Any,Any...), LineNumberNode, n)::LineNumberNode LabelNode(n::Int) = ccall(:jl_new_struct, Any, (Any,Any...), LabelNode, n)::LabelNode @@ -273,4 +273,5 @@ Module() = Module(:anonymous) Task(f::ANY) = ccall(:jl_new_task, Any, (Any, Int), f::Function, 0)::Task # simple convert for use by constructors of types in Core +convert(::Type{Any}, x::ANY) = x convert{T}(::Type{T}, x::T) = x diff --git a/base/inference.jl b/base/inference.jl index c6ee0ca1f3941..88bebe1007322 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -136,6 +136,7 @@ t_func[Union] = (0, Inf, else Type end)) +t_func[_expr] = (1, Inf, (args...)->Expr) t_func[method_exists] = (2, 2, cmp_tfunc) t_func[applicable] = (1, Inf, (f, args...)->Bool) t_func[tuplelen] = (1, 1, x->Int) diff --git a/base/sysimg.jl b/base/sysimg.jl index a41e78f19dfde..8c4e5e99f5752 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -8,7 +8,7 @@ eval(m,x) = Core.eval(m,x) include = Core.include -using Core: Intrinsics, arraylen, arrayref, arrayset, arraysize, +using Core: Intrinsics, arraylen, arrayref, arrayset, arraysize, _expr, tuplelen, tupleref, kwcall, _apply, typeassert, apply_type include("exports.jl") diff --git a/src/alloc.c b/src/alloc.c index d203198bd4644..640574c176703 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -221,6 +221,7 @@ int jl_field_index(jl_datatype_t *t, jl_sym_t *fld, int err) jl_value_t *jl_get_nth_field(jl_value_t *v, size_t i) { jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v); + assert(i < jl_tuple_len(st->names)); size_t offs = jl_field_offset(st,i) + sizeof(void*); if (st->fields[i].isptr) { return *(jl_value_t**)((char*)v + offs); @@ -892,16 +893,17 @@ jl_expr_t *jl_exprn(jl_sym_t *head, size_t n) return ex; } -DLLEXPORT jl_value_t *jl_new_expr(jl_sym_t *head, jl_tuple_t *args) +JL_CALLABLE(jl_f_new_expr) { - size_t nargs = jl_tuple_len(args); - jl_array_t *ar = jl_alloc_cell_1d(nargs); + JL_NARGSV(Expr, 1); + JL_TYPECHK(Expr, symbol, args[0]); + jl_array_t *ar = jl_alloc_cell_1d(nargs-1); JL_GC_PUSH1(&ar); - for(size_t i=0; i < nargs; i++) - jl_cellset(ar, i, jl_tupleref(args,i)); + for(size_t i=0; i < nargs-1; i++) + jl_cellset(ar, i, args[i+1]); jl_expr_t *ex = (jl_expr_t*)alloc_4w(); ex->type = (jl_value_t*)jl_expr_type; - ex->head = head; + ex->head = (jl_sym_t*)args[0]; ex->args = ar; ex->etype = (jl_value_t*)jl_any_type; JL_GC_POP(); diff --git a/src/array.c b/src/array.c index e09798cdf5ee1..ad661ab80dc15 100644 --- a/src/array.c +++ b/src/array.c @@ -413,6 +413,7 @@ JL_CALLABLE(jl_f_arraysize) jl_value_t *jl_arrayref(jl_array_t *a, size_t i) { + assert(i < jl_array_len(a)); jl_value_t *el_type = (jl_value_t*)jl_tparam0(jl_typeof(a)); jl_value_t *elt; if (!a->ptrarray) { @@ -490,6 +491,7 @@ int jl_array_isdefined(jl_value_t **args0, int nargs) void jl_arrayset(jl_array_t *a, jl_value_t *rhs, size_t i) { + assert(i < jl_array_len(a)); jl_value_t *el_type = jl_tparam0(jl_typeof(a)); if (el_type != (jl_value_t*)jl_any_type) { if (!jl_subtype(rhs, el_type, 1)) diff --git a/src/builtin_proto.h b/src/builtin_proto.h index 59c3a5c4ab131..c77b4008acb26 100644 --- a/src/builtin_proto.h +++ b/src/builtin_proto.h @@ -35,6 +35,7 @@ JL_CALLABLE(jl_f_methodexists); JL_CALLABLE(jl_f_applicable); JL_CALLABLE(jl_f_invoke); JL_CALLABLE(jl_f_yieldto); +JL_CALLABLE(jl_f_new_expr); #ifdef __cplusplus } diff --git a/src/builtins.c b/src/builtins.c index 21aef3181512b..32410b8d2785c 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1022,6 +1022,7 @@ void jl_init_primitives(void) add_builtin_func("getfield", jl_f_get_field); add_builtin_func("setfield!", jl_f_set_field); add_builtin_func("fieldtype", jl_f_field_type); + add_builtin_func("_expr", jl_f_new_expr); add_builtin_func("arraylen", jl_f_arraylen); add_builtin_func("arrayref", jl_f_arrayref); diff --git a/src/dump.c b/src/dump.c index d74b3f4a86588..9e68462fdbe12 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1307,7 +1307,7 @@ void jl_init_serializer(void) jl_f_methodexists, jl_f_applicable, jl_f_invoke, jl_apply_generic, jl_unprotect_stack, - jl_f_yieldto, jl_f_sizeof, + jl_f_yieldto, jl_f_sizeof, jl_f_new_expr, NULL }; i=2; while (fptrs[i-2] != NULL) { diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index f2f7d5093453b..c67eed1a07ff2 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -3213,7 +3213,7 @@ So far only the second case can actually occur. ((not (contains (lambda (e) (and (pair? e) (eq? (car e) '$))) e)) `(copyast (inert ,e))) ((not (any splice-expr? e)) - `(call (top Expr) ,.(map expand-backquote e))) + `(call (top _expr) ,.(map expand-backquote e))) (else (let loop ((p (cdr e)) (q '())) (if (null? p) diff --git a/src/support/libsupport.h b/src/support/libsupport.h index aecb596c4ec8c..80446ca993625 100644 --- a/src/support/libsupport.h +++ b/src/support/libsupport.h @@ -5,6 +5,7 @@ #include #include +#include #include "dtypes.h" #include "utils.h" #include "utf8.h" From 2bfa247225d1cd3beef20c2c03e96c1d9e9ae699 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 16 Oct 2014 09:24:35 -0400 Subject: [PATCH 24/44] handle apply_type in static_eval --- base/inference.jl | 2 +- base/string.jl | 4 ++-- src/codegen.cpp | 11 ++++------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index 88bebe1007322..d108a3cda5ad0 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -1602,7 +1602,7 @@ function record_var_type(e::Symbol, t::ANY, decls) otherTy = get(decls::ObjectIdDict, e, false) # keep track of whether a variable is always the same type if !is(otherTy,false) - if !is(otherTy, t) + if !typeseq(otherTy, t) decls[e] = Any end else diff --git a/base/string.jl b/base/string.jl index f2478e5363001..f9a9babf8fe6a 100644 --- a/base/string.jl +++ b/base/string.jl @@ -1072,8 +1072,8 @@ function shell_parse(raw::String, interp::Bool) in_single_quotes = false in_double_quotes = false - args = [] - arg = [] + args::Vector{Any} = [] + arg::Vector{Any} = [] i = start(s) j = i diff --git a/src/codegen.cpp b/src/codegen.cpp index 9a40b11da396f..9a8adf0a85bc1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1011,10 +1011,10 @@ jl_value_t *jl_static_eval(jl_value_t *ex, void *ctx_, jl_module_t *mod, return b->value; } } - else if (fptr == &jl_f_tuple) { + else if (fptr == &jl_f_tuple || fptr == &jl_f_instantiate_type) { size_t i; size_t n = jl_array_dim0(e->args)-1; - if (n==0) return (jl_value_t*)jl_null; + if (n==0 && fptr == &jl_f_tuple) return (jl_value_t*)jl_null; if (!allow_alloc) return NULL; jl_value_t **v; @@ -1027,12 +1027,9 @@ jl_value_t *jl_static_eval(jl_value_t *ex, void *ctx_, jl_module_t *mod, return NULL; } } - jl_tuple_t *tup = jl_alloc_tuple_uninit(n); - for(i=0; i < n; i++) { - jl_tupleset(tup, i, v[i]); - } + jl_value_t *result = fptr(f, v, n); JL_GC_POP(); - return (jl_value_t*)tup; + return result; } } // The next part is probably valid, but it is untested From 6a2032ed5390e8e2aab3d803ddef44d3655cb2ce Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 16 Oct 2014 09:25:36 -0400 Subject: [PATCH 25/44] add DataType back to Callable for now --- base/base.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/base.jl b/base/base.jl index 2afd6df0d4330..d420733781641 100644 --- a/base/base.jl +++ b/base/base.jl @@ -2,7 +2,7 @@ import Core.Array # to add methods const NonTupleType = Union(DataType,UnionType,TypeConstructor) -typealias Callable Function +typealias Callable Union(Function,DataType) const Bottom = Union() From ab61bd9cb9415350ead5d0288c5d58186f5e7839 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 16 Oct 2014 18:11:10 -0400 Subject: [PATCH 26/44] fix a missing gc root in codegen --- src/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 9a8adf0a85bc1..893e844a0807d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2221,7 +2221,7 @@ static Value *emit_known_call(jl_value_t *ff, jl_value_t **args, size_t nargs, if (i > nargs) { jl_value_t *ty = static_eval(expr, ctx, true, true); if (ty!=NULL && jl_is_leaf_type(ty)) { - if (jl_has_typevars(ty)) { + if (jl_has_typevars(ty) || jl_is_tuple(ty)) { // add root for types not cached. issue #7065 jl_add_linfo_root(ctx->linfo, ty); } From 95c0ecf8eadcc64c832f9eca77bdcfcc2d621e84 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 16 Oct 2014 18:11:30 -0400 Subject: [PATCH 27/44] fix 2 ambiguity warnings fix `TypeVar` dispatch --- base/linalg/symmetric.jl | 8 ++++---- src/gf.c | 11 ++++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/base/linalg/symmetric.jl b/base/linalg/symmetric.jl index bfde6693d3405..f40bf9482660e 100644 --- a/base/linalg/symmetric.jl +++ b/base/linalg/symmetric.jl @@ -17,11 +17,11 @@ getindex(A::Symmetric, i::Integer, j::Integer) = (A.uplo == 'U') == (i < j) ? ge getindex(A::Hermitian, i::Integer, j::Integer) = (A.uplo == 'U') == (i < j) ? getindex(A.data, i, j) : conj(getindex(A.data, j, i)) full(A::Symmetric) = copytri!(copy(A.data), A.uplo) full(A::Hermitian) = copytri!(copy(A.data), A.uplo, true) -convert{T,S}(::Type{Symmetric{T,S}},A::Symmetric{T,S}) = A -convert{T,S}(::Type{Symmetric{T,S}},A::Symmetric) = Symmetric{T,S}(convert(S,A.data),A.uplo) +convert{T,S<:AbstractMatrix}(::Type{Symmetric{T,S}},A::Symmetric{T,S}) = A +convert{T,S<:AbstractMatrix}(::Type{Symmetric{T,S}},A::Symmetric) = Symmetric{T,S}(convert(S,A.data),A.uplo) convert{T}(::Type{AbstractMatrix{T}}, A::Symmetric) = Symmetric(convert(AbstractMatrix{T}, A.data), symbol(A.uplo)) -convert{T,S}(::Type{Hermitian{T,S}},A::Hermitian{T,S}) = A -convert{T,S}(::Type{Hermitian{T,S}},A::Hermitian) = Hermitian{T,S}(convert(S,A.data),A.uplo) +convert{T,S<:AbstractMatrix}(::Type{Hermitian{T,S}},A::Hermitian{T,S}) = A +convert{T,S<:AbstractMatrix}(::Type{Hermitian{T,S}},A::Hermitian) = Hermitian{T,S}(convert(S,A.data),A.uplo) convert{T}(::Type{AbstractMatrix{T}}, A::Hermitian) = Hermitian(convert(AbstractMatrix{T}, A.data), symbol(A.uplo)) copy{T,S}(A::Symmetric{T,S}) = Symmetric{T,S}(copy(A.data),A.uplo) copy{T,S}(A::Hermitian{T,S}) = Hermitian{T,S}(copy(A.data),A.uplo) diff --git a/src/gf.c b/src/gf.c index 3ec8e40ea6ff1..6c7180ddb1013 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1348,15 +1348,16 @@ static jl_tuple_t *arg_type_tuple(jl_value_t **args, size_t nargs) JL_GC_PUSH1(&tt); size_t i; for(i=0; i < nargs; i++) { + jl_value_t *ai = args[i]; jl_value_t *a; - if (jl_is_type(args[i])) { - a = (jl_value_t*)jl_wrap_Type(args[i]); + if (!jl_is_typevar(ai) && jl_is_type(ai)) { + a = (jl_value_t*)jl_wrap_Type(ai); } - else if (!jl_is_tuple(args[i])) { - a = jl_typeof(args[i]); + else if (!jl_is_tuple(ai)) { + a = jl_typeof(ai); } else { - a = (jl_value_t*)arg_type_tuple(&jl_tupleref(args[i],0), jl_tuple_len(args[i])); + a = (jl_value_t*)arg_type_tuple(&jl_tupleref(ai,0), jl_tuple_len(ai)); } jl_tupleset(tt, i, a); } From 0d60213e36c67823d9524a9df036ee8ae943e319 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 17 Oct 2014 13:59:16 -0400 Subject: [PATCH 28/44] remove no-longer-needed deserialize method for TypeVar --- base/serialize.jl | 7 ------- 1 file changed, 7 deletions(-) diff --git a/base/serialize.jl b/base/serialize.jl index b8b3bf1a35cd9..af1b2fa0fe2b6 100644 --- a/base/serialize.jl +++ b/base/serialize.jl @@ -488,13 +488,6 @@ function deserialize_expr(s, len) e end -function deserialize(s, ::Type{TypeVar}) - name = deserialize(s) - lb = deserialize(s) - ub = deserialize(s) - TypeVar(name, lb, ub) -end - function deserialize(s, ::Type{UnionType}) types = deserialize(s) Union(types...) From a1a656384add8f4c2309130d27ebc0cbd9258b15 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 17 Oct 2014 14:44:41 -0400 Subject: [PATCH 29/44] allow passing type parameters to `new` with `new{ ... }` also *require* it for `new` calls inside non-constructors --- base/subarray.jl | 6 +++--- src/julia-syntax.scm | 44 ++++++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/base/subarray.jl b/base/subarray.jl index a0d621fb43713..10eeddc3b8b3d 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -15,15 +15,15 @@ type SubArray{T,N,A<:AbstractArray,I<:(RangeIndex...,)} <: AbstractArray{T,N} #linear indexing constructor (scalar) global call function call{T,A<:Array,I<:(Any,)}(::Type{SubArray{T,0,A,I}}, p::A, i::(Int,)) - new(p, i, (), Int[], i[1]) + new{T,0,A,I}(p, i, (), Int[], i[1]) end function call{T,A<:Array,I<:(Any,)}(::Type{SubArray{T,1,A,I}}, p::A, i::(UnitRange{Int},)) - new(p, i, (length(i[1]),), [1], first(i[1])) + new{T,1,A,I}(p, i, (length(i[1]),), [1], first(i[1])) end function call{T,A<:Array,I<:(Any,)}(::Type{SubArray{T,1,A,I}}, p::A, i::(Range{Int},)) - new(p, i, (length(i[1]),), [step(i[1])], first(i[1])) + new{T,1,A,I}(p, i, (length(i[1]),), [step(i[1])], first(i[1])) end function SubArray(p::A, i::I) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index c67eed1a07ff2..c27a6400d249e 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -751,18 +751,24 @@ (block (call (curly ,name ,@params) ,@field-names))))) -(define (new-call Texpr args field-names field-types mutabl) +(define (new-call Tname type-params params args field-names field-types mutabl) (if (any vararg? args) (error "... is not supported inside \"new\"")) (if (any kwarg? args) (error "\"new\" does not accept keyword arguments")) - (cond ((length> args (length field-names)) - `(call (top error) "new: too many arguments")) - (else - `(new ,Texpr - ,@(map (lambda (fty val) - `(call (top convert) ,fty ,val)) - (list-head field-types (length args)) args))))) + (if (length> params (length type-params)) + (error "too few type parameters specified in \"new{...}\"")) + (let ((Texpr (if (null? type-params) + `(|.| ,(current-julia-module) ',Tname) + `(curly (|.| ,(current-julia-module) ',Tname) + ,@type-params)))) + (cond ((length> args (length field-names)) + `(call (top error) "new: too many arguments")) + (else + `(new ,Texpr + ,@(map (lambda (fty val) + `(call (top convert) ,fty ,val)) + (list-head field-types (length args)) args)))))) ;; insert a statement after line number node (define (prepend-stmt stmt body) @@ -810,23 +816,21 @@ (params (cdr temp))) `(,keyword ,sig ,(ctor-body body params))) `(,keyword (call (curly ,name ,@method-params) ,@sig) - ,(ctor-body body params)))) + ;; pass '() in order to require user-specified parameters with + ;; new{...} inside a non-ctor inner definition. + ,(ctor-body body '())))) (define (rewrite-ctor ctor Tname params bounds field-names field-types mutabl) - (define (ctor-body body params) + (define (ctor-body body type-params) (pattern-replace (pattern-set (pattern-lambda (call (-/ new) . args) - (new-call (if (null? params) - ;; be careful to avoid possible conflicts - ;; with local & arg names - `(|.| ,(current-julia-module) ',Tname) - `(curly (|.| ,(current-julia-module) ',Tname) - ,@params)) - args - field-names - field-types - mutabl))) + (new-call Tname type-params params + args field-names field-types mutabl)) + (pattern-lambda + (call (curly (-/ new) . p) . args) + (new-call Tname p params + args field-names field-types mutabl))) body)) (pattern-replace (pattern-set From e5cbd8f1d7eb82632417a5d4efd9c5eb0ba9c204 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 17 Oct 2014 15:53:31 -0400 Subject: [PATCH 30/44] fix some incorrect uses of alloc_tuple_uninit (memory bug) --- src/cgutils.cpp | 4 ++-- src/jltypes.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 46edf3e0381d7..4fd6c2e4ca415 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1441,7 +1441,7 @@ static jl_value_t *static_void_instance(jl_value_t *jt) if (jl_tuple_len(jt) == 0) return (jl_value_t*)jl_null; size_t nargs = jl_tuple_len(jt); - jl_value_t *tpl = (jl_value_t*)jl_alloc_tuple_uninit(nargs); + jl_value_t *tpl = (jl_value_t*)jl_alloc_tuple(nargs); JL_GC_PUSH1(&tpl); for(size_t i=0; i < nargs; i++) { jl_tupleset(tpl, i, static_void_instance(jl_tupleref(jt,i))); @@ -1498,7 +1498,7 @@ static jl_value_t *static_constant_instance(Constant *constant, jl_value_t *jt) else assert(false && "Cannot process this type of constant"); - jl_value_t *tpl = (jl_value_t*)jl_alloc_tuple_uninit(nargs); + jl_value_t *tpl = (jl_value_t*)jl_alloc_tuple(nargs); JL_GC_PUSH1(&tpl); for(size_t i=0; i < nargs; i++) { jl_tupleset(tpl, i, static_constant_instance( diff --git a/src/jltypes.c b/src/jltypes.c index e9d8caed5b11a..08e56100b2b00 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -742,7 +742,7 @@ static jl_value_t *intersect_typevar(jl_tvar_t *a, jl_value_t *b, static int tuple_to_Type(jl_tuple_t *a, jl_tuple_t **ptemp) { int alen = jl_tuple_len(a); - *ptemp = jl_alloc_tuple_uninit(alen); + *ptemp = jl_alloc_tuple(alen); int i; for(i=0; i < alen; i++) { jl_value_t *el = jl_tupleref(a, i); From 4ee2b41552a6bc95465c12ca66146d69b354317b Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 17 Oct 2014 17:08:02 -0400 Subject: [PATCH 31/44] sharpen the result of tmerge() for Tuple types change a comprehension in Pkg.Reqs.Requirement that depended on type inference. due to `call` constructors we simply cannot get its type anymore, although the other change in this commit helps a lot. --- base/inference.jl | 5 ++++- base/pkg/reqs.jl | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index d108a3cda5ad0..7e56e5b565e90 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -1154,7 +1154,10 @@ function tmerge(typea::ANY, typeb::ANY) if typeb <: typea return typea end - if typea <: Tuple && typeb <: Tuple + if isa(typea, Tuple) && isa(typeb, Tuple) + if length(typea) == length(typeb) && !isvatuple(typea) && !isvatuple(typeb) + return typejoin(typea, typeb) + end return Tuple end u = Union(typea, typeb) diff --git a/base/pkg/reqs.jl b/base/pkg/reqs.jl index abcd861364fcd..e901adc3e721d 100644 --- a/base/pkg/reqs.jl +++ b/base/pkg/reqs.jl @@ -24,7 +24,7 @@ immutable Requirement <: Line package = shift!(fields) all(field->ismatch(Base.VERSION_REGEX, field), fields) || error("invalid requires entry for $package: $content") - versions = [VersionNumber(field) for field in fields] + versions = VersionNumber[fields...] issorted(versions) || error("invalid requires entry for $package: $content") new(content, package, VersionSet(versions), system) end From 36c5ad6337482c967dffd490b5b964cde9cbce77 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sat, 18 Oct 2014 14:30:43 -0400 Subject: [PATCH 32/44] make `methods` and `functionloc` work with `call` definitions --- base/reflection.jl | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/base/reflection.jl b/base/reflection.jl index b723b8f70a351..9312dc9b29c5a 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -91,8 +91,9 @@ isgeneric(f::ANY) = (isa(f,Function) && isa(f.env,MethodTable)) function_name(f::Function) = isgeneric(f) ? f.env.name : (:anonymous) -code_lowered(f::Callable,t::(Type...)) = map(m->uncompressed_ast(m.func.code), methods(f,t)) -methods(f::ANY,t::ANY) = Any[m[3] for m in _methods(f,t,-1)] +code_lowered(f::Function,t::(Type...)) = map(m->uncompressed_ast(m.func.code), methods(f,t)) +methods(f::Function,t::ANY) = Any[m[3] for m in _methods(f,t,-1)] +methods(f::ANY,t::ANY) = methods(call, tuple(isa(f,Type) ? Type{f} : typeof(f), t...)) _methods(f::ANY,t::ANY,lim) = _methods(f, Any[(t::Tuple)...], length(t::Tuple), lim, []) function _methods(f::ANY,t::Array,i,lim::Integer,matching::Array{Any,1}) if i == 0 @@ -126,6 +127,8 @@ function methods(f::Function) f.env end +methods(x::ANY) = methods(call, (isa(x,Type) ? Type{x} : typeof(x), Any...)) + function length(mt::MethodTable) n = 0 d = mt.defs @@ -152,10 +155,10 @@ function _dump_function(f, t::ANY, native, wrapper) str end -code_llvm (f::Callable, types::(Type...)) = print(_dump_function(f, types, false, false)) -code_native(f::Callable, types::(Type...)) = print(_dump_function(f, types, true, false)) +code_llvm (f::Function, types::(Type...)) = print(_dump_function(f, types, false, false)) +code_native(f::Function, types::(Type...)) = print(_dump_function(f, types, true, false)) -function functionlocs(f::Callable, types=(Type...)) +function functionlocs(f::ANY, types=(Type...)) locs = Any[] for m in methods(f, types) lsd = m.func.code::LambdaStaticData @@ -170,9 +173,9 @@ function functionlocs(f::Callable, types=(Type...)) locs end -functionloc(f::Callable, types=(Any...)) = functionlocs(f, types)[1] +functionloc(f::ANY, types=(Any...)) = functionlocs(f, types)[1] -function function_module(f::Function, types=(Any...)) +function function_module(f, types=(Any...)) m = methods(f, types) if isempty(m) error("no matching methods") From a3d637fbdfd820f6982cb1b5181626eb39f6188b Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sat, 18 Oct 2014 16:08:00 -0400 Subject: [PATCH 33/44] remove error for failing to import a non-function used in a method definition, since the method will actually be added to `call` --- src/module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module.c b/src/module.c index ce9a4685416eb..9bbc245de74a3 100644 --- a/src/module.c +++ b/src/module.c @@ -97,7 +97,7 @@ jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_t *var) jl_binding_t *b2 = jl_get_binding(b->owner, var); if (b2 == NULL) jl_errorf("invalid method definition: imported function %s.%s does not exist", b->owner->name->name, var->name); - if (!b->imported) + if (!b->imported && b->value!=NULL && jl_is_function(b->value)) jl_errorf("error in method definition: function %s.%s must be explicitly imported to be extended", b->owner->name->name, var->name); return b2; } From 12ecc25666f2aceb0794a45dc23cd4786a5072fd Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sat, 18 Oct 2014 19:13:57 -0400 Subject: [PATCH 34/44] more surgical approach to importing Core.call this is not ideal but will give us more flexibility for now --- base/base.jl | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/base/base.jl b/base/base.jl index d420733781641..3874b0c6c96bd 100644 --- a/base/base.jl +++ b/base/base.jl @@ -1,13 +1,35 @@ -import Core.Array # to add methods - const NonTupleType = Union(DataType,UnionType,TypeConstructor) typealias Callable Union(Function,DataType) const Bottom = Union() -# fall back to Core.call -call(args...) = Core.call(args...) +# constructors for Core types in boot.jl +call(T::Type{BoundsError}) = Core.call(T) +call(T::Type{DivideError}) = Core.call(T) +call(T::Type{DomainError}) = Core.call(T) +call(T::Type{OverflowError}) = Core.call(T) +call(T::Type{InexactError}) = Core.call(T) +call(T::Type{MemoryError}) = Core.call(T) +call(T::Type{StackOverflowError}) = Core.call(T) +call(T::Type{UndefRefError}) = Core.call(T) +call(T::Type{UndefVarError}, var::Symbol) = Core.call(T, var) +call(T::Type{InterruptException}) = Core.call(T) +call(T::Type{SymbolNode}, name::Symbol, t::ANY) = Core.call(T, name, t) +call(T::Type{GetfieldNode}, value, name::Symbol, typ) = Core.call(T, value, name, typ) +call(T::Type{ASCIIString}, d::Array{Uint8,1}) = Core.call(T, d) +call(T::Type{UTF8String}, d::Array{Uint8,1}) = Core.call(T, d) +call(T::Type{TypeVar}, args...) = Core.call(T, args...) +call(T::Type{TypeConstructor}, args...) = Core.call(T, args...) +call(T::Type{Expr}, args::ANY...) = _expr(args...) +call(T::Type{LineNumberNode}, n::Int) = Core.call(T, n) +call(T::Type{LabelNode}, n::Int) = Core.call(T, n) +call(T::Type{GotoNode}, n::Int) = Core.call(T, n) +call(T::Type{QuoteNode}, x::ANY) = Core.call(T, x) +call(T::Type{NewvarNode}, s::Symbol) = Core.call(T, s) +call(T::Type{TopNode}, s::Symbol) = Core.call(T, s) +call(T::Type{Module}, args...) = Core.call(T, args...) +call(T::Type{Task}, f::ANY) = Core.call(T, f) convert{T}(::Type{T}, x::T) = x @@ -215,8 +237,6 @@ macro goto(name::Symbol) Expr(:symbolicgoto, name) end -# NOTE: Base shares Array with Core so we can add definitions to it - Array{T,N}(::Type{T}, d::NTuple{N,Int}) = ccall(:jl_new_array, Array{T,N}, (Any,Any), Array{T,N}, d) From d382a4656ce1a2e852770e5939adaa46582d396e Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sun, 19 Oct 2014 15:12:53 -0400 Subject: [PATCH 35/44] fix order of initialization in jl_new_datatype (memory bug) --- src/alloc.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 640574c176703..48d4d12ca333e 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -654,17 +654,12 @@ jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super, else if (!strcmp(((jl_sym_t*)name)->name, "Bool")) t = jl_bool_type; } - if (t == NULL) { + if (t == NULL) t = jl_new_uninitialized_datatype(jl_tuple_len(fnames)); - if (jl_is_typename(name)) - tn = (jl_typename_t*)name; - else - tn = jl_new_typename((jl_sym_t*)name); - t->name = tn; - } + else + tn = t->name; - if (t->name->primary == NULL) - t->name->primary = (jl_value_t*)t; + // init before possibly calling jl_new_typename t->super = super; t->parameters = parameters; t->names = fnames; @@ -676,6 +671,19 @@ jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super, t->struct_decl = NULL; t->size = 0; t->alignment = 0; + + if (tn == NULL) { + t->name = NULL; + if (jl_is_typename(name)) + tn = (jl_typename_t*)name; + else + tn = jl_new_typename((jl_sym_t*)name); + t->name = tn; + } + + if (t->name->primary == NULL) + t->name->primary = (jl_value_t*)t; + if (abstract || jl_tuple_len(parameters) > 0) { t->uid = 0; } From 5b9ec88f68ba58e732e9ec8697a3a6b53f441d6e Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sun, 19 Oct 2014 15:49:43 -0400 Subject: [PATCH 36/44] fix a missing GC root in codegen --- src/codegen.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 893e844a0807d..3866101d7f87c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1347,6 +1347,7 @@ static Value *emit_boxed_rooted(jl_value_t *e, jl_codectx_t *ctx) static void jl_add_linfo_root(jl_lambda_info_t *li, jl_value_t *val) { + JL_GC_PUSH1(&val); li = li->def; if (li->roots == NULL) { li->roots = jl_alloc_cell_1d(1); @@ -1355,11 +1356,14 @@ static void jl_add_linfo_root(jl_lambda_info_t *li, jl_value_t *val) else { size_t rlen = jl_array_dim0(li->roots); for(size_t i=0; i < rlen; i++) { - if (jl_arrayref(li->roots,i) == val) + if (jl_arrayref(li->roots,i) == val) { + JL_GC_POP(); return; + } } jl_cell_1d_push(li->roots, val); } + JL_GC_POP(); } static Value *emit_lambda_closure(jl_value_t *expr, jl_codectx_t *ctx) From d2dd9f175843666d7d9b75272ed17c1b6b50903c Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 20 Oct 2014 00:45:27 -0400 Subject: [PATCH 37/44] fix crash in sortrows the subtype check in gf.c:ml_matches (line 1834) was causing an extra matching method to be missed, when we have both call(::Type{Perm},...) and call(::Type{Perm{O,V}},...) --- src/jltypes.c | 5 ++++- test/core.jl | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/jltypes.c b/src/jltypes.c index 08e56100b2b00..8750dccb786ed 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2213,8 +2213,11 @@ static int jl_subtype_le(jl_value_t *a, jl_value_t *b, int ta, int invariant) if (jl_subtype_le(a, jl_tparam0(b), 0, 1)) return 1; } + if (invariant && ttb == (jl_datatype_t*)ttb->name->primary) + return 0; assert(jl_tuple_len(tta->parameters) == jl_tuple_len(ttb->parameters)); - for(i=0; i < jl_tuple_len(tta->parameters); i++) { + size_t l = jl_tuple_len(tta->parameters); + for(i=0; i < l; i++) { jl_value_t *apara = jl_tupleref(tta->parameters,i); jl_value_t *bpara = jl_tupleref(ttb->parameters,i); if (invariant && jl_is_typevar(bpara) && diff --git a/test/core.jl b/test/core.jl index a6649742f76e8..41b732114a533 100644 --- a/test/core.jl +++ b/test/core.jl @@ -128,6 +128,8 @@ end @test !isa((Int,), Type{(Int...,)}) @test !isa((Int,), Type{(Any...,)}) +@test !issubtype(Type{Array{TypeVar(:T,true)}}, Type{Array}) + # issue #6561 @test issubtype(Array{Tuple}, Array{NTuple}) @test issubtype(Array{(Any...)}, Array{NTuple}) From 4fdf20076dfa2e556a13c6b750ff49ba237b3ceb Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 20 Oct 2014 00:59:26 -0400 Subject: [PATCH 38/44] slightly cut down lowered code for kwcall --- src/julia-syntax.scm | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index c27a6400d249e..9343d1c523a43 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1514,10 +1514,13 @@ `(block (= (tuple ,k ,v) ,rk) ,push-expr)))) restkeys)) - (if (call (top isempty) ,container) - (call ,f ,@pa) - (call (top kwcall) call ,(length keys) ,@keyargs - ,f ,container ,@pa)))))))) + ,(let ((kw-call `(call (top kwcall) call ,(length keys) ,@keyargs + ,f ,container ,@pa))) + (if (not (null? keys)) + kw-call + `(if (call (top isempty) ,container) + (call ,f ,@pa) + ,kw-call))))))))) (define (expand-transposed-op e ops) (let ((a (caddr e)) From adb53bb80668a4b65abf9f6bd90debd82fb1c4b7 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 20 Oct 2014 13:40:44 -0400 Subject: [PATCH 39/44] fix a method specificity problem --- base/expr.jl | 2 +- src/gf.c | 2 +- src/jltypes.c | 3 +++ test/core.jl | 7 +++++++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/base/expr.jl b/base/expr.jl index 6b2c80c816365..3edfc531ce873 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -47,7 +47,7 @@ function show(io::IO, tv::TypeVar) show(io, tv.lb) print(io, "<:") end - print(io, tv.name) + write(io, tv.name) if !is(tv.ub, Any) print(io, "<:") show(io, tv.ub) diff --git a/src/gf.c b/src/gf.c index 955b518e6add2..f2f42eb86bb56 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1065,7 +1065,7 @@ static int sigs_eq(jl_value_t *a, jl_value_t *b, int useenv) return jl_subtype(a, b, 0) && jl_subtype(b, a, 0); } -int jl_args_morespecific(jl_value_t *a, jl_value_t *b) +DLLEXPORT int jl_args_morespecific(jl_value_t *a, jl_value_t *b) { int msp = jl_type_morespecific(a,b); int btv = jl_has_typevars(b); diff --git a/src/jltypes.c b/src/jltypes.c index 8750dccb786ed..d8589fc2be6f2 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2627,6 +2627,9 @@ static jl_value_t *type_match_(jl_value_t *child, jl_value_t *parent, if (jl_type_morespecific_(child, pv, 0)) { return jl_true; } + else if (!jl_is_typevar(child) && !jl_type_morespecific_(pv, child, 0)) { + return jl_true; + } else if (jl_subtype(pv, child, 0)) { env->data[i+1] = (jl_value_t*)child; return jl_true; diff --git a/test/core.jl b/test/core.jl index 41b732114a533..2c580de77bc1d 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1903,3 +1903,10 @@ let x = Issue2403(20) @test x(3) == 26 @test issue2403func(x) == 34 end + +# a method specificity issue +c99991{T}(::Type{T},x::T) = 0 +c99991{T}(::Type{UnitRange{T}},x::FloatRange{T}) = 1 +c99991{T}(::Type{UnitRange{T}},x::Range{T}) = 2 +@test c99991(UnitRange{Float64}, 1.0:2.0) == 1 +@test c99991(UnitRange{Int}, 1:2) == 2 From 8569cd5be1886ca41ae3737296a18253962c4293 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 20 Oct 2014 14:17:56 -0400 Subject: [PATCH 40/44] fix uses of `Callable` --- base/c.jl | 4 ++-- base/deprecated.jl | 2 +- base/inference.jl | 6 ++++-- base/interactiveutil.jl | 9 +++------ 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/base/c.jl b/base/c.jl index c07e3526340a5..0ebbf053ee5ed 100644 --- a/base/c.jl +++ b/base/c.jl @@ -112,11 +112,11 @@ function find_library{T<:ByteString, S<:ByteString}(libnames::Array{T,1}, extrap return "" end -function ccallable(f::Callable, rt::Type, argt::(Type...), name::Union(String,Symbol)=string(f)) +function ccallable(f::Function, rt::Type, argt::(Type...), name::Union(String,Symbol)=string(f)) ccall(:jl_extern_c, Void, (Any, Any, Any, Ptr{Uint8}), f, rt, argt, name) end -function ccallable(f::Callable, argt::(Type...), name::Union(String,Symbol)=string(f)) +function ccallable(f::Function, argt::(Type...), name::Union(String,Symbol)=string(f)) ccall(:jl_extern_c, Void, (Any, Ptr{Void}, Any, Ptr{Uint8}), f, C_NULL, argt, name) end diff --git a/base/deprecated.jl b/base/deprecated.jl index c2833926cbef0..432da85b6deaf 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -157,7 +157,7 @@ end scale!{T<:Base.LinAlg.BlasReal}(X::Array{T}, s::Complex) = error("scale!: Cannot scale a real array by a complex value in-place. Use scale(X::Array{Real}, s::Complex) instead.") -@deprecate which(f::Callable, args...) @which f(args...) +@deprecate which(f, args...) @which f(args...) @deprecate rmdir rm # 0.4 deprecations diff --git a/base/inference.jl b/base/inference.jl index 7e56e5b565e90..7fff4948ddd84 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -3051,7 +3051,8 @@ function replace_tupleref!(ast, e::ANY, tupname, vals, sv, i0) end end -function code_typed(f::Callable, types::(Type...)) +code_typed(f, types) = code_typed(call, tuple(isa(f,Type)?Type{f}:typeof(f), types...)) +function code_typed(f::Function, types::(Type...)) asts = [] for x in _methods(f,types,-1) linfo = func_for_method(x[3],types) @@ -3065,7 +3066,8 @@ function code_typed(f::Callable, types::(Type...)) asts end -function return_types(f::Callable, types) +return_types(f, types) = return_types(call, tuple(isa(f,Type)?Type{f}:typeof(f), types...)) +function return_types(f::Function, types) rt = [] for x in _methods(f,types,-1) linfo = func_for_method(x[3],types) diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index 22bb612bf50d0..782ff957b3697 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -198,10 +198,7 @@ versioninfo(verbose::Bool) = versioninfo(STDOUT,verbose) # searching definitions -function which(f::Callable, t::(Type...)) - if !isgeneric(f) - throw(ErrorException("not a generic function, no methods available")) - end +function which(f, t::(Type...)) ms = methods(f, t) isempty(ms) && error("no method found for the specified argument types") ms[1] @@ -268,7 +265,7 @@ function type_close_enough(x::ANY, t::ANY) !isleaftype(t) && x <: t) end -function methodswith(t::Type, f::Callable, showparents::Bool=false, meths = Method[]) +function methodswith(t::Type, f::Function, showparents::Bool=false, meths = Method[]) if !isa(f.env, MethodTable) return meths end @@ -291,7 +288,7 @@ function methodswith(t::Type, m::Module, showparents::Bool=false) for nm in names(m) if isdefined(m, nm) f = eval(m, nm) - if isa(f, Callable) + if isa(f, Function) methodswith(t, f, showparents, meths) end end From bcbb53c7db236940b0fd4450dbcda3298bd3f7bc Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 20 Oct 2014 16:22:41 -0400 Subject: [PATCH 41/44] update `precompile` for `call` overloading --- base/base.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/base/base.jl b/base/base.jl index 3874b0c6c96bd..e14db016331ec 100644 --- a/base/base.jl +++ b/base/base.jl @@ -210,7 +210,11 @@ map(f::Callable, a::Array{Any,1}) = Any[ f(a[i]) for i=1:length(a) ] macro thunk(ex); :(()->$(esc(ex))); end macro L_str(s); s; end -function precompile(f, args::Tuple) +function precompile(f::ANY, args::Tuple) + if isa(f,DataType) + args = tuple(Type{f}, args...) + f = f.name.module.call + end if isgeneric(f) ccall(:jl_compile_hint, Void, (Any, Any), f, args) end From 39dfd9282baf4b0402001149ce759c2db6c660cc Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 20 Oct 2014 16:23:10 -0400 Subject: [PATCH 42/44] add the long-awaited call=>convert fallback I put `::T` on there for now; we'll see how that goes. --- base/base.jl | 2 ++ test/core.jl | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/base/base.jl b/base/base.jl index e14db016331ec..dfbdc38ec01c8 100644 --- a/base/base.jl +++ b/base/base.jl @@ -31,6 +31,8 @@ call(T::Type{TopNode}, s::Symbol) = Core.call(T, s) call(T::Type{Module}, args...) = Core.call(T, args...) call(T::Type{Task}, f::ANY) = Core.call(T, f) +call{T}(::Type{T}, args...) = convert(T, args...)::T + convert{T}(::Type{T}, x::T) = x convert(::(), ::()) = () diff --git a/test/core.jl b/test/core.jl index 2c580de77bc1d..56fb730b4f7bb 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1144,7 +1144,6 @@ type Foo4376{T} end @test isa(Foo4376{Float32}(Foo4376{Int}(2)), Foo4376{Float32}) -@test_throws MethodError Foo4376{Float32}(Foo4376{Float32}(2.0f0)) type _0_test_ctor_syntax_ _0_test_ctor_syntax_{T<:String}(files::Vector{T},step) = 0 From ff88a00c04ec003b74605cc395b76ed385c39b59 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 20 Oct 2014 17:49:03 -0400 Subject: [PATCH 43/44] avoid overflowing environment in type intersection when a typevar meets the same type repeatedly --- src/jltypes.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jltypes.c b/src/jltypes.c index d8589fc2be6f2..1b45eca53fa81 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -718,6 +718,8 @@ static jl_value_t *intersect_typevar(jl_tvar_t *a, jl_value_t *b, int i; for(i=0; i < penv->n; i+=2) { if (penv->data[i] == (jl_value_t*)a && !jl_is_typevar(penv->data[i+1])) { + if (jl_types_equal(b, penv->data[i+1])) + return (jl_value_t*)a; jl_value_t *ti = jl_type_intersection(b, penv->data[i+1]); if (ti == (jl_value_t*)jl_bottom_type) return ti; From b73cf129f245157291f9278e9dd6cdbb942d68f5 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 21 Oct 2014 11:02:44 -0400 Subject: [PATCH 44/44] update serializer changes for call_constructors branch --- src/dump.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/dump.c b/src/dump.c index 6776c705769d1..0c91636873f96 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1227,13 +1227,7 @@ void jl_deserialize_lambdas_from_mod(ios_t *s) jl_sym_t *name = (jl_sym_t*)jl_deserialize_value(s, NULL); jl_function_t *gf = (jl_function_t*)jl_get_global(mod, name); int8_t iskw = read_int8(s); - if (!jl_is_gf(gf)) { - if (jl_is_datatype(gf) && - ((jl_function_t*)gf)->fptr == jl_f_ctor_trampoline) { - jl_add_constructors((jl_datatype_t*)gf); - } - assert(jl_is_gf(gf)); - } + assert(jl_is_gf(gf)); if (iskw) { if (!jl_gf_mtable(gf)->kwsorter) { jl_gf_mtable(gf)->kwsorter = jl_new_generic_function(jl_gf_name(gf)); @@ -1580,9 +1574,6 @@ jl_module_t *jl_restore_new_module(char *fname) if (offs) ptrhash_put(&backref_table, offs, t); } } - else if (!t->fptr) { - jl_add_constructors(t); - } if (t->instance != v) { jl_typeof(v) = (jl_value_t*)(ptrint_t)1; // invalidate the old value to help catch errors if (v == o) {