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_tuple_t *t) { jl_value_t *gf; if (bnd) { //jl_declare_constant(bnd); if (bnd->value != NULL && !bnd->constp) { jl_errorf("cannot define function %s; it already has a value", bnd->name->name); } bnd->constp = 1; } if (*bp == NULL) { gf = (jl_value_t*)jl_new_generic_function(name); *bp = gf; } else { 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_gf(gf)) { jl_error("invalid method definition: not a generic function"); } } } JL_GC_PUSH1(&gf); assert(jl_is_function(f)); assert(jl_is_tuple(argtypes)); assert(jl_is_tuple(t)); for(size_t i=0; i < jl_tuple_len(argtypes); i++) { jl_value_t *elt = jl_tupleref(argtypes,i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_lambda_info_t *li = f->linfo; jl_errorf("invalid type for argument %s in method definition for %s at %s:%d", jl_is_expr(li->ast) ? ((jl_sym_t*)jl_arrayref(jl_lam_args((jl_expr_t*)li->ast),i))->name : "?", name->name, li->file->name, li->line); } } for(size_t i=0; i < jl_tuple_len(t); i++) { if (!jl_is_typevar(jl_tupleref(t,i))) jl_type_error_rt(name->name, "method definition", (jl_value_t*)jl_tvar_type, jl_tupleref(t,i)); } jl_add_method((jl_function_t*)gf, argtypes, f, t); if (jl_boot_file_loaded && f->linfo && f->linfo->ast && jl_is_expr(f->linfo->ast)) { jl_lambda_info_t *li = f->linfo; li->ast = jl_compress_ast(li, li->ast); } JL_GC_POP(); return gf; }
static int sig_match_by_type_simple(jl_value_t **types, size_t n, jl_tupletype_t *sig, size_t lensig, int va) { size_t i; if (va) lensig -= 1; for (i = 0; i < lensig; i++) { jl_value_t *decl = jl_field_type(sig, i); jl_value_t *a = types[i]; if (jl_is_type_type(decl)) { jl_value_t *tp0 = jl_tparam0(decl); if (jl_is_type_type(a)) { if (tp0 == (jl_value_t*)jl_typetype_tvar) { // in the case of Type{T}, the types don't have // to match exactly either. this is cached as Type{T}. // analogous to the situation with tuples. } else if (jl_is_typevar(tp0)) { if (!jl_subtype(jl_tparam0(a), ((jl_tvar_t*)tp0)->ub, 0)) return 0; } else { if (!jl_types_equal(jl_tparam0(a), tp0)) return 0; } } else if (!is_kind(a) || !jl_is_typevar(tp0) || ((jl_tvar_t*)tp0)->ub != (jl_value_t*)jl_any_type) { // manually unroll jl_subtype(a, decl) // where `a` can be a subtype like TypeConstructor // and decl is Type{T} return 0; } } else if (decl == (jl_value_t*)jl_any_type) { } else { if (jl_is_type_type(a)) // decl is not Type, because it would be caught above a = jl_typeof(jl_tparam0(a)); if (!jl_types_equal(a, decl)) return 0; } } if (va) { jl_value_t *decl = jl_field_type(sig, i); if (jl_vararg_kind(decl) == JL_VARARG_INT) { if (n-i != jl_unbox_long(jl_tparam1(decl))) return 0; } jl_value_t *t = jl_tparam0(decl); for(; i < n; i++) { if (!jl_subtype(types[i], t, 0)) return 0; } return 1; } return 1; }
static int sig_match_by_type_simple(jl_value_t **types, size_t n, jl_tupletype_t *sig, size_t lensig, int va) { size_t i; if (va) lensig -= 1; for (i = 0; i < lensig; i++) { jl_value_t *decl = jl_field_type(sig, i); jl_value_t *a = types[i]; jl_value_t *unw = jl_is_unionall(decl) ? ((jl_unionall_t*)decl)->body : decl; if (jl_is_type_type(unw)) { jl_value_t *tp0 = jl_tparam0(unw); if (jl_is_type_type(a)) { if (jl_is_typevar(tp0)) { // in the case of Type{_}, the types don't have to match exactly. // this is cached as `Type{T} where T`. if (((jl_tvar_t*)tp0)->ub != (jl_value_t*)jl_any_type && !jl_subtype(jl_tparam0(a), ((jl_tvar_t*)tp0)->ub)) return 0; } else { if (!(jl_typeof(jl_tparam0(a)) == jl_typeof(tp0) && jl_types_equal(jl_tparam0(a), tp0))) return 0; } } else if (!jl_is_kind(a) || !jl_is_typevar(tp0) || ((jl_tvar_t*)tp0)->ub != (jl_value_t*)jl_any_type) { // manually unroll jl_subtype(a, decl) // where `a` can be a subtype and decl is Type{T} return 0; } } else if (decl == (jl_value_t*)jl_any_type) { } else { if (jl_is_type_type(a)) // decl is not Type, because it would be caught above a = jl_typeof(jl_tparam0(a)); if (!jl_types_equal(a, decl)) return 0; } } if (va) { jl_value_t *decl = jl_unwrap_unionall(jl_field_type(sig, i)); if (jl_vararg_kind(decl) == JL_VARARG_INT) { if (n-i != jl_unbox_long(jl_tparam1(decl))) return 0; } jl_value_t *t = jl_tparam0(decl); if (jl_is_typevar(t)) t = ((jl_tvar_t*)t)->ub; for(; i < n; i++) { if (!jl_subtype(types[i], t)) return 0; } return 1; } return 1; }
void jl_check_static_parameter_conflicts(jl_lambda_info_t *li, jl_svec_t *t, jl_sym_t *fname) { jl_array_t *vinfo; size_t nvars; if (li->ast && jl_is_expr(li->ast)) { vinfo = jl_lam_vinfo((jl_expr_t*)li->ast); nvars = jl_array_len(vinfo); for(size_t i=0; i < jl_svec_len(t); i++) { for(size_t j=0; j < nvars; j++) { jl_value_t *tv = jl_svecref(t,i); if (jl_is_typevar(tv)) { if ((jl_sym_t*)jl_cellref((jl_array_t*)jl_cellref(vinfo,j),0) == ((jl_tvar_t*)tv)->name) { jl_printf(JL_STDERR, "WARNING: local variable %s conflicts with a static parameter in %s", ((jl_tvar_t*)tv)->name->name, fname->name); print_func_loc(JL_STDERR, li); jl_printf(JL_STDERR, ".\n"); } } } } } }
static int jl_typemap_intersection_array_visitor(struct jl_ordereddict_t *a, jl_value_t *ty, int tparam, int offs, struct typemap_intersection_env *closure) { size_t i, l = jl_array_len(a->values); union jl_typemap_t *data = (union jl_typemap_t*)jl_array_data(a->values); for (i = 0; i < l; i++) { union jl_typemap_t ml = data[i]; if (ml.unknown == jl_nothing) continue; jl_value_t *t; if (jl_typeof(ml.unknown) == (jl_value_t*)jl_typemap_level_type) { t = ml.node->key; } else { t = jl_field_type(ml.leaf->sig, offs); if (tparam) t = jl_tparam0(t); } if (ty == (jl_value_t*)jl_any_type || // easy case: Any always matches (tparam ? // need to compute `ty <: Type{t}` (jl_is_uniontype(ty) || // punt on Union{...} right now jl_typeof(t) == ty || // deal with kinds (e.g. ty == DataType && t == Type{t}) (jl_is_type_type(ty) && (jl_is_typevar(jl_tparam0(ty)) ? jl_subtype(t, ((jl_tvar_t*)jl_tparam0(ty))->ub, 0) : // deal with ty == Type{<:T} jl_subtype(t, jl_tparam0(ty), 0)))) // deal with ty == Type{T{#<:T}} : jl_subtype(t, ty, 0))) // `t` is a leaftype, so intersection test becomes subtype if (!jl_typemap_intersection_visitor(ml, offs+1, closure)) return 0; } return 1; }
static inline int sig_match_simple(jl_value_t **args, size_t n, jl_value_t **sig, int va, size_t lensig) { // NOTE: This function is a performance hot spot!! size_t i; if (va) lensig -= 1; for (i = 0; i < lensig; i++) { jl_value_t *decl = sig[i]; jl_value_t *a = args[i]; if (decl == (jl_value_t*)jl_any_type || ((jl_value_t*)jl_typeof(a) == decl)) { /* we are only matching concrete types here, and those types are hash-consed, so pointer comparison should work. */ continue; } jl_value_t *unw = jl_is_unionall(decl) ? ((jl_unionall_t*)decl)->body : decl; if (jl_is_type_type(unw) && jl_is_type(a)) { jl_value_t *tp0 = jl_tparam0(unw); if (jl_is_typevar(tp0)) { // in the case of Type{_}, the types don't have to match exactly. // this is cached as `Type{T} where T`. if (((jl_tvar_t*)tp0)->ub != (jl_value_t*)jl_any_type && !jl_subtype(a, ((jl_tvar_t*)tp0)->ub)) return 0; } else { if (a != tp0) { if (jl_typeof(a) != jl_typeof(tp0)) return 0; jl_datatype_t *da = (jl_datatype_t*)a; jl_datatype_t *dt = (jl_datatype_t*)tp0; while (jl_is_unionall(da)) da = (jl_datatype_t*)((jl_unionall_t*)da)->body; while (jl_is_unionall(dt)) dt = (jl_datatype_t*)((jl_unionall_t*)dt)->body; if (jl_is_datatype(da) && jl_is_datatype(dt) && da->name != dt->name) return 0; if (!jl_types_equal(a, tp0)) return 0; } } } else { return 0; } } if (va) { jl_value_t *decl = sig[i]; if (jl_vararg_kind(decl) == JL_VARARG_INT) { if (n-i != jl_unbox_long(jl_tparam1(decl))) return 0; } jl_value_t *t = jl_unwrap_vararg(decl); for(; i < n; i++) { if (!jl_isa(args[i], t)) return 0; } return 1; } return 1; }
// compute whether the specificity of this type is equivalent to Any in the sort order static int jl_is_any(jl_value_t *t1) { return (t1 == (jl_value_t*)jl_any_type || (jl_is_typevar(t1) && ((jl_tvar_t*)t1)->ub == (jl_value_t*)jl_any_type && !((jl_tvar_t*)t1)->bound)); }
static jl_value_t *copy_ast(jl_value_t *expr, jl_tuple_t *sp, int do_sp) { if (jl_is_symbol(expr)) { if (!do_sp) return expr; // pre-evaluate certain static parameters to help type inference for(int i=0; i < jl_tuple_len(sp); i+=2) { assert(jl_is_typevar(jl_tupleref(sp,i))); if ((jl_sym_t*)expr == ((jl_tvar_t*)jl_tupleref(sp,i))->name) { jl_value_t *spval = jl_tupleref(sp,i+1); if (jl_is_long(spval)) return spval; } } } else if (jl_is_lambda_info(expr)) { jl_lambda_info_t *li = (jl_lambda_info_t*)expr; /* if (sp == jl_null && li->ast && jl_lam_capt((jl_expr_t*)li->ast)->length == 0) return expr; */ // TODO: avoid if above condition is true and decls have already // been evaluated. JL_GC_PUSH(&li); li = jl_add_static_parameters(li, sp); li->ast = jl_prepare_ast(li, li->sparams); JL_GC_POP(); return (jl_value_t*)li; } else if (jl_typeis(expr,jl_array_any_type)) { jl_array_t *a = (jl_array_t*)expr; jl_array_t *na = jl_alloc_cell_1d(jl_array_len(a)); JL_GC_PUSH(&na); size_t i; for(i=0; i < jl_array_len(a); i++) jl_cellset(na, i, copy_ast(jl_cellref(a,i), sp, do_sp)); JL_GC_POP(); return (jl_value_t*)na; } else if (jl_is_expr(expr)) { jl_expr_t *e = (jl_expr_t*)expr; jl_expr_t *ne = jl_exprn(e->head, jl_array_len(e->args)); JL_GC_PUSH(&ne); size_t i; if (e->head == lambda_sym) { jl_exprarg(ne, 0) = copy_ast(jl_exprarg(e,0), sp, 0); jl_exprarg(ne, 1) = copy_ast(jl_exprarg(e,1), sp, 0); jl_exprarg(ne, 2) = copy_ast(jl_exprarg(e,2), sp, 1); } else { for(i=0; i < jl_array_len(e->args); i++) jl_exprarg(ne, i) = copy_ast(jl_exprarg(e,i), sp, 1); } JL_GC_POP(); return (jl_value_t*)ne; } return expr; }
void jl_check_type_tuple(jl_tuple_t *t, jl_sym_t *name, const char *ctx) { for(size_t i=0; i < jl_tuple_len(t); i++) { jl_value_t *elt = jl_tupleref(t,i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_type_error_rt(name->name, ctx, (jl_value_t*)jl_type_type, elt); } } }
static int all_typevars(jl_tuple_t *p) { size_t i; for(i=0; i < p->length; i++) { if (!jl_is_typevar(jl_tupleref(p,i))) return 0; } return 1; }
static void unbind_tvars(jl_tuple_t *parameters) { size_t i; for(i=0; i < parameters->length; i++) { jl_tvar_t *tv = (jl_tvar_t*)jl_tupleref(parameters, i); if (jl_is_typevar(tv)) tv->bound = 0; } }
static int is_ast_node(jl_value_t *v) { return jl_is_symbol(v) || jl_is_expr(v) || jl_typeis(v, jl_array_any_type) || jl_is_tuple(v) || jl_is_union_type(v) || jl_is_int32(v) || jl_is_int64(v) || jl_is_symbolnode(v) || jl_is_bool(v) || jl_is_typevar(v) || jl_is_topnode(v) || jl_is_quotenode(v) || jl_is_gotonode(v) || jl_is_labelnode(v) || jl_is_linenode(v); }
static void check_type_tuple(jl_tuple_t *t, jl_sym_t *name, const char *ctx) { size_t i; for(i=0; i < t->length; i++) { jl_value_t *elt = jl_tupleref(t,i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_type_error_rt(name->name, ctx, (jl_value_t*)jl_type_type, elt); } } }
jl_tuple_t *jl_tuple_tvars_to_symbols(jl_tuple_t *t) { jl_tuple_t *s = jl_alloc_tuple_uninit(jl_tuple_len(t)); size_t i; for(i=0; i < jl_tuple_len(s); i+=2) { assert(jl_is_typevar(jl_tupleref(t,i))); jl_tupleset(s, i, (jl_value_t*)((jl_tvar_t*)jl_tupleref(t,i))->name); jl_tupleset(s, i+1, jl_tupleref(t,i+1)); } return s; }
static inline int sig_match_simple(jl_value_t **args, size_t n, jl_value_t **sig, int va, size_t lensig) { // NOTE: This function is a performance hot spot!! size_t i; if (va) lensig -= 1; for (i = 0; i < lensig; i++) { jl_value_t *decl = sig[i]; jl_value_t *a = args[i]; if (decl == (jl_value_t*)jl_any_type) { } else if ((jl_value_t*)jl_typeof(a) == decl) { /* we are only matching concrete types here, and those types are hash-consed, so pointer comparison should work. */ } else if (jl_is_type_type(decl) && jl_is_type(a)) { jl_value_t *tp0 = jl_tparam0(decl); if (tp0 == (jl_value_t*)jl_typetype_tvar) { // in the case of Type{T}, the types don't have // to match exactly either. this is cached as Type{T}. // analogous to the situation with tuples. } else if (jl_is_typevar(tp0)) { if (!jl_subtype(a, ((jl_tvar_t*)tp0)->ub, 0)) return 0; } else { if (a!=tp0 && !jl_types_equal(a,tp0)) return 0; } } else { return 0; } } if (va) { jl_value_t *decl = sig[i]; if (jl_vararg_kind(decl) == JL_VARARG_INT) { if (n-i != jl_unbox_long(jl_tparam1(decl))) return 0; } jl_value_t *t = jl_tparam0(decl); for(; i < n; i++) { if (!jl_subtype(args[i], t, 1)) return 0; } return 1; } return 1; }
JL_DLLEXPORT jl_value_t *jl_new_type_constructor(jl_svec_t *p, jl_value_t *body) { #ifndef NDEBUG size_t i, np = jl_svec_len(p); for (i = 0; i < np; i++) { jl_tvar_t *tv = (jl_tvar_t*)jl_svecref(p, i); assert(jl_is_typevar(tv) && !tv->bound); } #endif jl_typector_t *tc = (jl_typector_t*)newobj((jl_value_t*)jl_typector_type, NWORDS(sizeof(jl_typector_t))); tc->parameters = p; tc->body = body; return (jl_value_t*)tc; }
static int is_ast_node(jl_value_t *v) { if (jl_is_lambda_info(v)) { jl_lambda_info_t *li = (jl_lambda_info_t*)v; if (jl_is_expr(li->ast)) li->ast = jl_compress_ast(li, li->ast); return 0; } return jl_is_symbol(v) || jl_is_expr(v) || jl_typeis(v, jl_array_any_type) || jl_is_tuple(v) || jl_is_union_type(v) || jl_is_int32(v) || jl_is_int64(v) || jl_is_symbolnode(v) || jl_is_bool(v) || jl_is_typevar(v) || jl_is_topnode(v) || jl_is_quotenode(v) || jl_is_gotonode(v) || jl_is_labelnode(v) || jl_is_linenode(v) || jl_is_getfieldnode(v); }
// this is a heuristic for allowing "redefining" a type to something identical static int equiv_svec_dt(jl_svec_t *sa, jl_svec_t *sb) { size_t i, l = jl_svec_len(sa); if (l != jl_svec_len(sb)) return 0; for (i = 0; i < l; i++) { jl_value_t *a = jl_svecref(sa, i); jl_value_t *b = jl_svecref(sb, i); if (jl_typeof(a) != jl_typeof(b)) return 0; if (jl_is_typevar(a) && ((jl_tvar_t*)a)->name != ((jl_tvar_t*)b)->name) return 0; if (!jl_subtype(a, b, 0) || !jl_subtype(b, a, 0)) return 0; } return 1; }
// TODO: eval decl types for arguments of non-generic functions static void eval_decl_types(jl_array_t *vi, jl_value_t *ast, jl_tuple_t *spenv) { size_t i, l = jl_array_len(vi); for(i=0; i < l; i++) { jl_array_t *v = (jl_array_t*)jl_cellref(vi, i); assert(jl_array_len(v) > 1); jl_value_t *ty = jl_static_eval(jl_cellref(v,1), NULL, jl_current_module, (jl_value_t*)spenv, (jl_expr_t*)ast, 1, 1); if (ty != NULL && (jl_is_type(ty) || jl_is_typevar(ty))) { jl_cellref(v, 1) = ty; } else { jl_cellref(v, 1) = (jl_value_t*)jl_any_type; } } }
JL_DLLEXPORT jl_value_t *jl_new_type_constructor(jl_svec_t *p, jl_value_t *body) { jl_ptls_t ptls = jl_get_ptls_states(); #ifndef NDEBUG size_t i, np = jl_svec_len(p); for (i = 0; i < np; i++) { jl_tvar_t *tv = (jl_tvar_t*)jl_svecref(p, i); assert(jl_is_typevar(tv) && !tv->bound); } #endif jl_typector_t *tc = (jl_typector_t*)jl_gc_alloc(ptls, sizeof(jl_typector_t), jl_typector_type); tc->parameters = p; tc->body = body; return (jl_value_t*)tc; }
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_tuple_t *t) { jl_value_t *gf; if (bnd) { jl_declare_constant(bnd); } if (*bp == NULL) { gf = (jl_value_t*)jl_new_generic_function(name); *bp = gf; } else { gf = *bp; if (!jl_is_gf(gf)) { if (jl_is_struct_type(gf) && ((jl_function_t*)gf)->fptr == jl_f_ctor_trampoline) { jl_add_constructors((jl_struct_type_t*)gf); } if (!jl_is_gf(gf)) { jl_error("invalid method definition: not a generic function"); } } } JL_GC_PUSH(&gf); assert(jl_is_function(f)); assert(jl_is_tuple(argtypes)); assert(jl_is_tuple(t)); jl_check_type_tuple(argtypes, name, "method definition"); for(size_t i=0; i < t->length; i++) { if (!jl_is_typevar(jl_tupleref(t,i))) jl_type_error_rt(name->name, "method definition", (jl_value_t*)jl_tvar_type, jl_tupleref(t,i)); } jl_add_method((jl_function_t*)gf, argtypes, f, t); if (jl_boot_file_loaded && f->linfo && f->linfo->ast && jl_is_expr(f->linfo->ast)) { jl_lambda_info_t *li = f->linfo; li->ast = jl_compress_ast(li, li->ast); } JL_GC_POP(); return gf; }
static int references_name(jl_value_t *p, jl_typename_t *name) { if (jl_is_uniontype(p)) return references_name(((jl_uniontype_t*)p)->a, name) || references_name(((jl_uniontype_t*)p)->b, name); if (jl_is_unionall(p)) return references_name((jl_value_t*)((jl_unionall_t*)p)->var, name) || references_name(((jl_unionall_t*)p)->body, name); if (jl_is_typevar(p)) return references_name(((jl_tvar_t*)p)->ub, name) || references_name(((jl_tvar_t*)p)->lb, name); if (jl_is_datatype(p)) { if (((jl_datatype_t*)p)->name == name) return 1; size_t i, l = jl_nparams(p); for (i = 0; i < l; i++) { if (references_name(jl_tparam(p, i), name)) return 1; } } return 0; }
static jl_value_t *eval(jl_value_t *e, jl_value_t **locals, size_t nl, size_t ngensym) { if (jl_is_symbol(e)) { jl_value_t *v; size_t i; for(i=0; i < nl; i++) { if (locals[i*2] == e) { v = locals[i*2+1]; break; } } if (i >= nl) { v = jl_get_global(jl_current_module, (jl_sym_t*)e); } if (v == NULL) { jl_undefined_var_error((jl_sym_t*)e); } return v; } if (jl_is_symbolnode(e)) { return eval((jl_value_t*)jl_symbolnode_sym(e), locals, nl, ngensym); } if (jl_is_gensym(e)) { ssize_t genid = ((jl_gensym_t*)e)->id; if (genid >= ngensym || genid < 0) jl_error("access to invalid GenSym location"); else return locals[nl*2 + genid]; } if (jl_is_quotenode(e)) { return jl_fieldref(e,0); } if (jl_is_topnode(e)) { jl_sym_t *s = (jl_sym_t*)jl_fieldref(e,0); jl_value_t *v = jl_get_global(jl_base_relative_to(jl_current_module),s); if (v == NULL) jl_undefined_var_error(s); return v; } if (!jl_is_expr(e)) { if (jl_is_globalref(e)) { jl_value_t *gfargs[2] = {(jl_value_t*)jl_globalref_mod(e), (jl_value_t*)jl_globalref_name(e)}; return jl_f_get_field(NULL, gfargs, 2); } if (jl_is_lambda_info(e)) { jl_lambda_info_t *li = (jl_lambda_info_t*)e; if (jl_boot_file_loaded && li->ast && jl_is_expr(li->ast)) { li->ast = jl_compress_ast(li, li->ast); jl_gc_wb(li, li->ast); } return (jl_value_t*)jl_new_closure(NULL, (jl_value_t*)jl_emptysvec, li); } if (jl_is_linenode(e)) { jl_lineno = jl_linenode_line(e); } if (jl_is_newvarnode(e)) { jl_value_t *var = jl_fieldref(e,0); assert(!jl_is_gensym(var)); assert(jl_is_symbol(var)); for(size_t i=0; i < nl; i++) { if (locals[i*2] == var) { locals[i*2+1] = NULL; break; } } return (jl_value_t*)jl_nothing; } return e; } jl_expr_t *ex = (jl_expr_t*)e; jl_value_t **args = (jl_value_t**)jl_array_data(ex->args); size_t nargs = jl_array_len(ex->args); if (ex->head == call_sym) { if (jl_is_lambda_info(args[0])) { // directly calling an inner function ("let") jl_lambda_info_t *li = (jl_lambda_info_t*)args[0]; if (jl_is_expr(li->ast) && !jl_lam_vars_captured((jl_expr_t*)li->ast) && !jl_has_intrinsics((jl_expr_t*)li->ast, (jl_expr_t*)li->ast, jl_current_module)) { size_t na = nargs-1; if (na == 0) return jl_interpret_toplevel_thunk(li); jl_array_t *formals = jl_lam_args((jl_expr_t*)li->ast); size_t nreq = jl_array_len(formals); if (nreq==0 || !jl_is_rest_arg(jl_cellref(formals,nreq-1))) { jl_value_t **ar; JL_GC_PUSHARGS(ar, na*2); for(int i=0; i < na; i++) { ar[i*2+1] = eval(args[i+1], locals, nl, ngensym); jl_gc_wb(ex->args, ar[i*2+1]); } if (na != nreq) { jl_error("wrong number of arguments"); } for(int i=0; i < na; i++) { jl_value_t *v = jl_cellref(formals, i); ar[i*2] = (jl_is_gensym(v)) ? v : (jl_value_t*)jl_decl_var(v); } jl_value_t *ret = jl_interpret_toplevel_thunk_with(li, ar, na); JL_GC_POP(); return ret; } } } jl_function_t *f = (jl_function_t*)eval(args[0], locals, nl, ngensym); if (jl_is_func(f)) return do_call(f, &args[1], nargs-1, NULL, locals, nl, ngensym); else return do_call(jl_module_call_func(jl_current_module), args, nargs, (jl_value_t*)f, locals, nl, ngensym); } else if (ex->head == assign_sym) { jl_value_t *sym = args[0]; jl_value_t *rhs = eval(args[1], locals, nl, ngensym); if (jl_is_gensym(sym)) { ssize_t genid = ((jl_gensym_t*)sym)->id; if (genid >= ngensym || genid < 0) jl_error("assignment to invalid GenSym location"); locals[nl*2 + genid] = rhs; return rhs; } if (jl_is_symbol(sym)) { size_t i; for (i=0; i < nl; i++) { if (locals[i*2] == sym) { locals[i*2+1] = rhs; return rhs; } } } jl_module_t *m = jl_current_module; if (jl_is_globalref(sym)) { m = jl_globalref_mod(sym); sym = (jl_value_t*)jl_globalref_name(sym); } assert(jl_is_symbol(sym)); JL_GC_PUSH1(&rhs); jl_binding_t *b = jl_get_binding_wr(m, (jl_sym_t*)sym); jl_checked_assignment(b, rhs); JL_GC_POP(); return rhs; } else if (ex->head == new_sym) { jl_value_t *thetype = eval(args[0], locals, nl, ngensym); jl_value_t *v=NULL; JL_GC_PUSH2(&thetype, &v); assert(jl_is_structtype(thetype)); v = jl_new_struct_uninit((jl_datatype_t*)thetype); for(size_t i=1; i < nargs; i++) { jl_set_nth_field(v, i-1, eval(args[i], locals, nl, ngensym)); } JL_GC_POP(); return v; } else if (ex->head == null_sym) { return (jl_value_t*)jl_nothing; } else if (ex->head == body_sym) { return eval_body(ex->args, locals, nl, ngensym, 0, 0); } else if (ex->head == exc_sym) { return jl_exception_in_transit; } else if (ex->head == static_typeof_sym) { return (jl_value_t*)jl_any_type; } else if (ex->head == method_sym) { jl_sym_t *fname = (jl_sym_t*)args[0]; jl_value_t **bp=NULL; jl_value_t *bp_owner=NULL; jl_binding_t *b=NULL; jl_value_t *gf=NULL; int kw=0; if (jl_is_expr(fname) || jl_is_globalref(fname)) { if (jl_is_expr(fname) && ((jl_expr_t*)fname)->head == kw_sym) { kw = 1; fname = (jl_sym_t*)jl_exprarg(fname, 0); } gf = eval((jl_value_t*)fname, locals, nl, ngensym); if (jl_is_expr(fname)) fname = (jl_sym_t*)jl_fieldref(jl_exprarg(fname, 2), 0); bp = &gf; assert(jl_is_symbol(fname)); } else { for (size_t i=0; i < nl; i++) { if (locals[i*2] == (jl_value_t*)fname) { bp = &locals[i*2+1]; break; } } if (bp == NULL) { b = jl_get_binding_for_method_def(jl_current_module, fname); bp = &b->value; bp_owner = (jl_value_t*)jl_current_module; } } if (jl_expr_nargs(ex) == 1) return jl_generic_function_def(fname, bp, bp_owner, b); jl_value_t *atypes=NULL, *meth=NULL; JL_GC_PUSH2(&atypes, &meth); atypes = eval(args[1], locals, nl, ngensym); if (jl_is_lambda_info(args[2])) { jl_check_static_parameter_conflicts((jl_lambda_info_t*)args[2], (jl_svec_t*)jl_svecref(atypes,1), fname); } meth = eval(args[2], locals, nl, ngensym); jl_method_def(fname, bp, bp_owner, b, (jl_svec_t*)atypes, (jl_function_t*)meth, args[3], NULL, kw); JL_GC_POP(); return *bp; } else if (ex->head == copyast_sym) { return jl_copy_ast(eval(args[0], locals, nl, ngensym)); } else if (ex->head == const_sym) { jl_value_t *sym = args[0]; assert(jl_is_symbol(sym)); for (size_t i=0; i < nl; i++) { if (locals[i*2] == sym) { return (jl_value_t*)jl_nothing; } } jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)sym); jl_declare_constant(b); return (jl_value_t*)jl_nothing; } else if (ex->head == global_sym) { // create uninitialized mutable binding for "global x" decl // TODO: handle type decls for (size_t i=0; i < jl_array_len(ex->args); i++) { assert(jl_is_symbol(args[i])); jl_get_binding_wr(jl_current_module, (jl_sym_t*)args[i]); } return (jl_value_t*)jl_nothing; } else if (ex->head == abstracttype_sym) { jl_value_t *name = args[0]; jl_value_t *para = eval(args[1], locals, nl, ngensym); jl_value_t *super = NULL; jl_value_t *temp = NULL; jl_datatype_t *dt = NULL; JL_GC_PUSH4(¶, &super, &temp, &dt); assert(jl_is_svec(para)); assert(jl_is_symbol(name)); dt = jl_new_abstracttype(name, jl_any_type, (jl_svec_t*)para); jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)name); temp = b->value; check_can_assign_type(b); b->value = (jl_value_t*)dt; jl_gc_wb_binding(b, dt); super = eval(args[2], locals, nl, ngensym); jl_set_datatype_super(dt, super); b->value = temp; if (temp==NULL || !equiv_type(dt, (jl_datatype_t*)temp)) { jl_checked_assignment(b, (jl_value_t*)dt); } JL_GC_POP(); return (jl_value_t*)jl_nothing; } else if (ex->head == bitstype_sym) { jl_value_t *name = args[0]; jl_value_t *super = NULL, *para = NULL, *vnb = NULL, *temp = NULL; jl_datatype_t *dt = NULL; JL_GC_PUSH4(¶, &super, &temp, &dt); assert(jl_is_symbol(name)); para = eval(args[1], locals, nl, ngensym); assert(jl_is_svec(para)); vnb = eval(args[2], locals, nl, ngensym); if (!jl_is_long(vnb)) jl_errorf("invalid declaration of bits type %s", ((jl_sym_t*)name)->name); ssize_t nb = jl_unbox_long(vnb); if (nb < 1 || nb>=(1<<23) || (nb&7) != 0) jl_errorf("invalid number of bits in type %s", ((jl_sym_t*)name)->name); dt = jl_new_bitstype(name, jl_any_type, (jl_svec_t*)para, nb); jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)name); temp = b->value; check_can_assign_type(b); b->value = (jl_value_t*)dt; jl_gc_wb_binding(b, dt); super = eval(args[3], locals, nl, ngensym); jl_set_datatype_super(dt, super); b->value = temp; if (temp==NULL || !equiv_type(dt, (jl_datatype_t*)temp)) { jl_checked_assignment(b, (jl_value_t*)dt); } JL_GC_POP(); return (jl_value_t*)jl_nothing; } else if (ex->head == compositetype_sym) { jl_value_t *name = args[0]; assert(jl_is_symbol(name)); jl_value_t *para = eval(args[1], locals, nl, ngensym); assert(jl_is_svec(para)); jl_value_t *temp = NULL; jl_value_t *super = NULL; jl_datatype_t *dt = NULL; JL_GC_PUSH4(¶, &super, &temp, &dt); temp = eval(args[2], locals, nl, ngensym); // field names dt = jl_new_datatype((jl_sym_t*)name, jl_any_type, (jl_svec_t*)para, (jl_svec_t*)temp, NULL, 0, args[5]==jl_true ? 1 : 0, jl_unbox_long(args[6])); jl_binding_t *b = jl_get_binding_wr(jl_current_module, (jl_sym_t*)name); temp = b->value; // save old value // temporarily assign so binding is available for field types check_can_assign_type(b); b->value = (jl_value_t*)dt; jl_gc_wb_binding(b,dt); JL_TRY { // operations that can fail inside_typedef = 1; dt->types = (jl_svec_t*)eval(args[4], locals, nl, ngensym); jl_gc_wb(dt, dt->types); inside_typedef = 0; for(size_t i=0; i < jl_svec_len(dt->types); i++) { jl_value_t *elt = jl_svecref(dt->types, i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) jl_type_error_rt(dt->name->name->name, "type definition", (jl_value_t*)jl_type_type, elt); } super = eval(args[3], locals, nl, ngensym); jl_set_datatype_super(dt, super); } JL_CATCH { b->value = temp; jl_rethrow(); } for(size_t i=0; i < jl_svec_len(para); i++) { ((jl_tvar_t*)jl_svecref(para,i))->bound = 0; } jl_compute_field_offsets(dt); if (para == (jl_value_t*)jl_emptysvec && jl_is_datatype_singleton(dt)) { dt->instance = newstruct(dt); jl_gc_wb(dt, dt->instance); } b->value = temp; if (temp==NULL || !equiv_type(dt, (jl_datatype_t*)temp)) { jl_checked_assignment(b, (jl_value_t*)dt); } else { // TODO: remove all old ctors and set temp->name->ctor_factory = dt->name->ctor_factory } JL_GC_POP(); return (jl_value_t*)jl_nothing; }
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, int iskw) { // 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", bnd->name->name); } if (*bp != NULL) { gf = *bp; if (!jl_is_gf(gf)) { if (jl_is_datatype(gf)) { // DataType: define `call`, for backwards compat with outer constructors 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); 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(); gf = call_func; 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); 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); } 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"); } } if (iskw) { bp = (jl_value_t**)&((jl_methtable_t*)((jl_function_t*)gf)->env)->kwsorter; gf = *bp; } } size_t na = jl_tuple_len(argtypes); for(size_t i=0; i < na; i++) { jl_value_t *elt = jl_tupleref(argtypes,i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_lambda_info_t *li = f->linfo; jl_errorf("invalid type for argument %s in method definition for %s at %s:%d", jl_lam_argname(li,i)->name, name->name, li->file->name, li->line); } } int ishidden = !!strchr(name->name, '#'); for(size_t i=0; i < jl_tuple_len(t); i++) { jl_value_t *tv = jl_tupleref(t,i); if (!jl_is_typevar(tv)) jl_type_error_rt(name->name, "method definition", (jl_value_t*)jl_tvar_type, tv); if (!ishidden && !type_contains((jl_value_t*)argtypes, tv)) { JL_PRINTF(JL_STDERR, "Warning: static parameter %s does not occur in signature for %s", ((jl_tvar_t*)tv)->name->name, name->name); print_func_loc(JL_STDERR, f->linfo); JL_PRINTF(JL_STDERR, ".\nThe method will not be callable.\n"); } } if (bnd) { bnd->constp = 1; } if (*bp == NULL) { gf = (jl_value_t*)jl_new_generic_function(name); *bp = gf; } assert(jl_is_function(f)); assert(jl_is_tuple(argtypes)); assert(jl_is_tuple(t)); jl_add_method((jl_function_t*)gf, argtypes, f, t, isstaged == jl_true); if (jl_boot_file_loaded && f->linfo && f->linfo->ast && jl_is_expr(f->linfo->ast)) { jl_lambda_info_t *li = f->linfo; li->ast = jl_compress_ast(li, li->ast); } JL_GC_POP(); return gf; }
static jl_value_t *copy_ast(jl_value_t *expr, jl_tuple_t *sp, int do_sp) { if (jl_is_symbol(expr)) { if (!do_sp) return expr; // pre-evaluate certain static parameters to help type inference for(int i=0; i < jl_tuple_len(sp); i+=2) { assert(jl_is_typevar(jl_tupleref(sp,i))); if ((jl_sym_t*)expr == ((jl_tvar_t*)jl_tupleref(sp,i))->name) { jl_value_t *spval = jl_tupleref(sp,i+1); if (jl_is_long(spval)) return spval; } } } else if (jl_is_lambda_info(expr)) { jl_lambda_info_t *li = (jl_lambda_info_t*)expr; /* if (sp == jl_null && li->ast && jl_array_len(jl_lam_capt((jl_expr_t*)li->ast)) == 0) return expr; */ // TODO: avoid if above condition is true and decls have already // been evaluated. JL_GC_PUSH1(&li); li = jl_add_static_parameters(li, sp); // inner lambda does not need the "def" link. it leads to excess object // retention, for example pointing to the original uncompressed AST // of a top-level thunk that gets type inferred. li->def = li; li->ast = jl_prepare_ast(li, li->sparams); JL_GC_POP(); return (jl_value_t*)li; } else if (jl_typeis(expr,jl_array_any_type)) { jl_array_t *a = (jl_array_t*)expr; jl_array_t *na = jl_alloc_cell_1d(jl_array_len(a)); JL_GC_PUSH1(&na); size_t i; for(i=0; i < jl_array_len(a); i++) jl_cellset(na, i, copy_ast(jl_cellref(a,i), sp, do_sp)); JL_GC_POP(); return (jl_value_t*)na; } else if (jl_is_expr(expr)) { jl_expr_t *e = (jl_expr_t*)expr; jl_expr_t *ne = jl_exprn(e->head, jl_array_len(e->args)); JL_GC_PUSH1(&ne); if (e->head == lambda_sym) { jl_exprarg(ne, 0) = copy_ast(jl_exprarg(e,0), sp, 0); jl_exprarg(ne, 1) = copy_ast(jl_exprarg(e,1), sp, 0); jl_exprarg(ne, 2) = copy_ast(jl_exprarg(e,2), sp, 1); } else { for(size_t i=0; i < jl_array_len(e->args); i++) jl_exprarg(ne, i) = copy_ast(jl_exprarg(e,i), sp, 1); } JL_GC_POP(); return (jl_value_t*)ne; } return expr; }
static jl_value_t *eval(jl_value_t *e, interpreter_state *s) { jl_ptls_t ptls = jl_get_ptls_states(); jl_code_info_t *src = s==NULL ? NULL : s->src; if (jl_is_ssavalue(e)) { ssize_t id = ((jl_ssavalue_t*)e)->id; if (id >= jl_source_nssavalues(src) || id < 0 || s->locals == NULL) jl_error("access to invalid SSAValue"); else return s->locals[jl_source_nslots(src) + id]; } if (jl_is_slot(e)) { ssize_t n = jl_slot_number(e); if (n > jl_source_nslots(src) || n < 1 || s->locals == NULL) jl_error("access to invalid slot number"); jl_value_t *v = s->locals[n-1]; if (v == NULL) jl_undefined_var_error((jl_sym_t*)jl_array_ptr_ref(src->slotnames, n - 1)); return v; } if (jl_is_globalref(e)) { jl_sym_t *s = jl_globalref_name(e); jl_value_t *v = jl_get_global(jl_globalref_mod(e), s); if (v == NULL) jl_undefined_var_error(s); return v; } if (jl_is_quotenode(e)) return jl_fieldref(e,0); jl_module_t *modu = (s == NULL ? ptls->current_module : s->module); if (jl_is_symbol(e)) { // bare symbols appear in toplevel exprs not wrapped in `thunk` jl_value_t *v = jl_get_global(modu, (jl_sym_t*)e); if (v == NULL) jl_undefined_var_error((jl_sym_t*)e); return v; } if (!jl_is_expr(e)) return e; jl_expr_t *ex = (jl_expr_t*)e; jl_value_t **args = (jl_value_t**)jl_array_data(ex->args); size_t nargs = jl_array_len(ex->args); if (ex->head == call_sym) { return do_call(args, nargs, s); } else if (ex->head == invoke_sym) { return do_invoke(args, nargs, s); } else if (ex->head == new_sym) { jl_value_t *thetype = eval(args[0], s); jl_value_t *v=NULL; JL_GC_PUSH2(&thetype, &v); assert(jl_is_structtype(thetype)); v = jl_new_struct_uninit((jl_datatype_t*)thetype); for(size_t i=1; i < nargs; i++) { jl_set_nth_field(v, i-1, eval(args[i], s)); } JL_GC_POP(); return v; } else if (ex->head == static_parameter_sym) { ssize_t n = jl_unbox_long(args[0]); assert(n > 0); if (s->sparam_vals && n <= jl_svec_len(s->sparam_vals)) { jl_value_t *sp = jl_svecref(s->sparam_vals, n - 1); if (!jl_is_typevar(sp)) return sp; } // static parameter val unknown needs to be an error for ccall jl_error("could not determine static parameter value"); } else if (ex->head == inert_sym) { return args[0]; } else if (ex->head == copyast_sym) { return jl_copy_ast(eval(args[0], s)); } else if (ex->head == exc_sym) { return ptls->exception_in_transit; } else if (ex->head == method_sym) { jl_sym_t *fname = (jl_sym_t*)args[0]; if (jl_is_globalref(fname)) { modu = jl_globalref_mod(fname); fname = jl_globalref_name(fname); } assert(jl_expr_nargs(ex) != 1 || jl_is_symbol(fname)); if (jl_is_symbol(fname)) { jl_value_t **bp=NULL; jl_value_t *bp_owner=NULL; jl_binding_t *b=NULL; if (bp == NULL) { b = jl_get_binding_for_method_def(modu, fname); bp = &b->value; bp_owner = (jl_value_t*)modu; } jl_value_t *gf = jl_generic_function_def(fname, bp, bp_owner, b); if (jl_expr_nargs(ex) == 1) return gf; } jl_value_t *atypes=NULL, *meth=NULL; JL_GC_PUSH2(&atypes, &meth); atypes = eval(args[1], s); meth = eval(args[2], s); jl_method_def((jl_svec_t*)atypes, (jl_code_info_t*)meth, args[3]); JL_GC_POP(); return jl_nothing; } else if (ex->head == const_sym) { jl_sym_t *sym = (jl_sym_t*)args[0]; if (jl_is_globalref(sym)) { modu = jl_globalref_mod(sym); sym = jl_globalref_name(sym); } assert(jl_is_symbol(sym)); jl_binding_t *b = jl_get_binding_wr(modu, sym); jl_declare_constant(b); return (jl_value_t*)jl_nothing; } else if (ex->head == global_sym) { // create uninitialized mutable binding for "global x" decl // TODO: handle type decls size_t i, l = jl_array_len(ex->args); for (i = 0; i < l; i++) { jl_sym_t *gsym = (jl_sym_t*)args[i]; jl_module_t *gmodu = modu; if (jl_is_globalref(gsym)) { gmodu = jl_globalref_mod(gsym); gsym = jl_globalref_name(gsym); } assert(jl_is_symbol(gsym)); jl_get_binding_wr(gmodu, gsym); } return (jl_value_t*)jl_nothing; } else if (ex->head == abstracttype_sym) { if (inside_typedef) jl_error("cannot eval a new abstract type definition while defining another type"); jl_value_t *name = args[0]; jl_value_t *para = eval(args[1], s); jl_value_t *super = NULL; jl_value_t *temp = NULL; jl_datatype_t *dt = NULL; JL_GC_PUSH4(¶, &super, &temp, &dt); assert(jl_is_svec(para)); if (jl_is_globalref(name)) { modu = jl_globalref_mod(name); name = (jl_value_t*)jl_globalref_name(name); } assert(jl_is_symbol(name)); dt = jl_new_abstracttype(name, NULL, (jl_svec_t*)para); jl_binding_t *b = jl_get_binding_wr(modu, (jl_sym_t*)name); temp = b->value; check_can_assign_type(b); b->value = (jl_value_t*)dt; jl_gc_wb_binding(b, dt); JL_TRY { inside_typedef = 1; super = eval(args[2], s); jl_set_datatype_super(dt, super); jl_reinstantiate_inner_types(dt); } JL_CATCH { jl_reset_instantiate_inner_types(dt); b->value = temp; jl_rethrow(); } b->value = temp; if (temp == NULL || !equiv_type(dt, (jl_datatype_t*)temp)) { jl_checked_assignment(b, (jl_value_t*)dt); } JL_GC_POP(); return (jl_value_t*)jl_nothing; } else if (ex->head == bitstype_sym) {
static void jl_serialize_value_(ios_t *s, jl_value_t *v) { if (v == NULL) { write_uint8(s, Null_tag); return; } void **bp = ptrhash_bp(&ser_tag, v); if (*bp != HT_NOTFOUND) { write_as_tag(s, (uint8_t)(ptrint_t)*bp); return; } if (tree_literal_values) { // compressing tree if (!is_ast_node(v)) { writetag(s, (jl_value_t*)LiteralVal_tag); write_uint16(s, literal_val_id(v)); return; } } else { bp = ptrhash_bp(&backref_table, v); if (*bp != HT_NOTFOUND) { write_uint8(s, BackRef_tag); write_int32(s, (ptrint_t)*bp); return; } ptrhash_put(&backref_table, v, (void*)(ptrint_t)ios_pos(s)); } size_t i; if (jl_is_tuple(v)) { size_t l = ((jl_tuple_t*)v)->length; if (l <= 255) { writetag(s, jl_tuple_type); write_uint8(s, (uint8_t)l); } else { writetag(s, (jl_value_t*)LongTuple_tag); write_int32(s, l); } for(i=0; i < l; i++) { jl_serialize_value(s, jl_tupleref(v, i)); } } else if (jl_is_symbol(v)) { size_t l = strlen(((jl_sym_t*)v)->name); if (l <= 255) { writetag(s, jl_symbol_type); write_uint8(s, (uint8_t)l); } else { writetag(s, (jl_value_t*)LongSymbol_tag); write_int32(s, l); } ios_write(s, ((jl_sym_t*)v)->name, l); } else if (jl_is_array(v)) { jl_array_t *ar = (jl_array_t*)v; writetag(s, (jl_value_t*)jl_array_type); jl_serialize_value(s, ar->type); jl_value_t *elty = jl_tparam0(ar->type); for (i=0; i < ar->ndims; i++) jl_serialize_value(s, jl_box_long(jl_array_dim(ar,i))); if (jl_is_bits_type(elty)) { size_t tot = ar->length * ar->elsize; ios_write(s, ar->data, tot); } else { for(i=0; i < ar->length; i++) { jl_serialize_value(s, jl_cellref(v, i)); } } } else if (jl_is_expr(v)) { jl_expr_t *e = (jl_expr_t*)v; size_t l = e->args->length; if (l <= 255) { writetag(s, jl_expr_type); write_uint8(s, (uint8_t)l); } else { writetag(s, (jl_value_t*)LongExpr_tag); write_int32(s, l); } jl_serialize_value(s, e->head); jl_serialize_value(s, e->etype); for(i=0; i < l; i++) { jl_serialize_value(s, jl_exprarg(e, i)); } } else if (jl_is_some_tag_type(v)) { jl_serialize_tag_type(s, v); } else if (jl_is_typevar(v)) { writetag(s, jl_tvar_type); jl_serialize_value(s, ((jl_tvar_t*)v)->name); jl_serialize_value(s, ((jl_tvar_t*)v)->lb); jl_serialize_value(s, ((jl_tvar_t*)v)->ub); write_int8(s, ((jl_tvar_t*)v)->bound); } else if (jl_is_function(v)) { writetag(s, jl_func_kind); jl_serialize_value(s, v->type); jl_function_t *f = (jl_function_t*)v; jl_serialize_value(s, (jl_value_t*)f->linfo); jl_serialize_value(s, f->env); if (f->linfo && f->linfo->ast && (jl_is_expr(f->linfo->ast) || jl_is_tuple(f->linfo->ast)) && f->fptr != &jl_trampoline) { write_int32(s, 0); } else { jl_serialize_fptr(s, f->fptr); } } else if (jl_is_lambda_info(v)) { writetag(s, jl_lambda_info_type); jl_lambda_info_t *li = (jl_lambda_info_t*)v; jl_serialize_value(s, li->ast); jl_serialize_value(s, (jl_value_t*)li->sparams); // don't save cached type info for code in the Base module, because // it might reference types in the old System module. if (li->module == jl_base_module) jl_serialize_value(s, (jl_value_t*)jl_null); else jl_serialize_value(s, (jl_value_t*)li->tfunc); jl_serialize_value(s, (jl_value_t*)li->name); jl_serialize_value(s, (jl_value_t*)li->specTypes); jl_serialize_value(s, (jl_value_t*)li->specializations); jl_serialize_value(s, (jl_value_t*)li->inferred); jl_serialize_value(s, (jl_value_t*)li->file); jl_serialize_value(s, (jl_value_t*)li->line); jl_serialize_value(s, (jl_value_t*)li->module); } else if (jl_typeis(v, jl_module_type)) { jl_serialize_module(s, (jl_module_t*)v); } else if (jl_typeis(v, jl_methtable_type)) { writetag(s, jl_methtable_type); jl_methtable_t *mt = (jl_methtable_t*)v; jl_serialize_methlist(s, mt->defs); jl_serialize_methlist(s, mt->cache); jl_serialize_value(s, mt->cache_1arg); write_int32(s, mt->max_args); } else if (jl_typeis(v, jl_task_type)) { jl_error("Task cannot be serialized"); } else { jl_value_t *t = (jl_value_t*)jl_typeof(v); if (jl_is_bits_type(t)) { void *data = jl_bits_data(v); if (t == (jl_value_t*)jl_int64_type && *(int64_t*)data >= S32_MIN && *(int64_t*)data <= S32_MAX) { writetag(s, (jl_value_t*)SmallInt64_tag); write_int32(s, (int32_t)*(int64_t*)data); } else { int nb = ((jl_bits_type_t*)t)->nbits; writetag(s, jl_bits_kind); jl_serialize_value(s, t); ios_write(s, data, nb/8); } } else if (jl_is_struct_type(t)) { writetag(s, jl_struct_kind); jl_serialize_value(s, t); size_t nf = ((jl_struct_type_t*)t)->names->length; size_t i; for(i=0; i < nf; i++) { jl_value_t *fld = ((jl_value_t**)v)[i+1]; jl_serialize_value(s, fld); } if (t == jl_idtable_type) { jl_cell_1d_push(idtable_list, v); } } else { assert(0); } } }
DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_value_t *bp_owner, jl_binding_t *bnd, jl_svec_t *argdata, jl_function_t *f, jl_value_t *isstaged, jl_value_t *call_func, int iskw) { jl_module_t *module = (bnd ? bnd->owner : NULL); // argdata is svec({types...}, svec(typevars...)) jl_tupletype_t *argtypes = (jl_tupletype_t*)jl_svecref(argdata,0); jl_svec_t *tvars = (jl_svec_t*)jl_svecref(argdata,1); jl_value_t *gf = NULL; JL_GC_PUSH4(&gf, &tvars, &argtypes, &f); if (bnd && bnd->value != NULL && !bnd->constp) { jl_errorf("cannot define function %s; it already has a value", bnd->name->name); } if (*bp != NULL) { gf = *bp; if (!jl_is_gf(gf)) { if (jl_is_datatype(gf)) { // DataType: define `call`, for backwards compat with outer constructors if (call_func == NULL) call_func = (jl_value_t*)jl_module_call_func(jl_current_module); size_t na = jl_nparams(argtypes); jl_svec_t *newargtypes = jl_alloc_svec(1 + na); jl_lambda_info_t *new_linfo = NULL; JL_GC_PUSH2(&newargtypes, &new_linfo); new_linfo = jl_copy_lambda_info(f->linfo); f = jl_new_closure(f->fptr, f->env, new_linfo); size_t i=0; if (iskw) { assert(na > 0); // for kw sorter, keep container argument first jl_svecset(newargtypes, 0, jl_tparam(argtypes, 0)); i++; } jl_svecset(newargtypes, i, jl_wrap_Type(gf)); i++; for(; i < na+1; i++) { jl_svecset(newargtypes, i, jl_tparam(argtypes, i-1)); } argtypes = jl_apply_tuple_type(newargtypes); JL_GC_POP(); gf = call_func; 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_gc_wb(f->linfo, f->linfo->ast); } else { // Do not mutate the original ast since it might // be reused somewhere else f->linfo->ast = jl_copy_ast(f->linfo->ast); jl_gc_wb(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_exprargset(f->linfo->ast, 0, (jl_value_t*)al); } else { jl_array_grow_beg(al, 1); } 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_errorf("cannot define function %s; it already has a value", name->name); } } if (iskw) { jl_methtable_t *mt = jl_gf_mtable(gf); assert(!module); module = mt->module; bp = (jl_value_t**)&mt->kwsorter; bp_owner = (jl_value_t*)mt; gf = *bp; } } // TODO size_t na = jl_nparams(argtypes); for(size_t i=0; i < na; i++) { jl_value_t *elt = jl_tparam(argtypes,i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_lambda_info_t *li = f->linfo; jl_exceptionf(jl_argumenterror_type, "invalid type for argument %s in method definition for %s at %s:%d", jl_lam_argname(li,i)->name, name->name, li->file->name, li->line); } } int ishidden = !!strchr(name->name, '#'); for(size_t i=0; i < jl_svec_len(tvars); i++) { jl_value_t *tv = jl_svecref(tvars,i); if (!jl_is_typevar(tv)) jl_type_error_rt(name->name, "method definition", (jl_value_t*)jl_tvar_type, tv); if (!ishidden && !type_contains((jl_value_t*)argtypes, tv)) { jl_printf(JL_STDERR, "WARNING: static parameter %s does not occur in signature for %s", ((jl_tvar_t*)tv)->name->name, name->name); print_func_loc(JL_STDERR, f->linfo); jl_printf(JL_STDERR, ".\nThe method will not be callable.\n"); } } if (bnd) { bnd->constp = 1; } if (*bp == NULL) { gf = (jl_value_t*)jl_new_generic_function(name, module); *bp = gf; if (bp_owner) jl_gc_wb(bp_owner, gf); } assert(jl_is_function(f)); assert(jl_is_tuple_type(argtypes)); assert(jl_is_svec(tvars)); jl_add_method((jl_function_t*)gf, argtypes, f, tvars, isstaged == jl_true); if (jl_boot_file_loaded && f->linfo && f->linfo->ast && jl_is_expr(f->linfo->ast)) { jl_lambda_info_t *li = f->linfo; li->ast = jl_compress_ast(li, li->ast); jl_gc_wb(li, li->ast); } JL_GC_POP(); return gf; }
/* Method caches are divided into three parts: one for signatures where the first argument is a singleton kind (Type{Foo}), one indexed by the UID of the first argument's type in normal cases, and a fallback table of everything else. Note that the "primary key" is the type of the first *argument*, since there tends to be lots of variation there. The type of the 0th argument (the function) is always the same for most functions. */ static jl_typemap_entry_t *jl_typemap_assoc_by_type_(jl_typemap_entry_t *ml, jl_tupletype_t *types, int8_t inexact, jl_svec_t **penv) { size_t n = jl_field_count(types); while (ml != (void*)jl_nothing) { size_t lensig = jl_field_count(ml->sig); if (lensig == n || (ml->va && lensig <= n+1)) { int resetenv = 0, ismatch = 1; if (ml->simplesig != (void*)jl_nothing) { size_t lensimplesig = jl_field_count(ml->simplesig); int isva = lensimplesig > 0 && jl_is_vararg_type(jl_tparam(ml->simplesig, lensimplesig - 1)); if (lensig == n || (isva && lensimplesig <= n + 1)) ismatch = sig_match_by_type_simple(jl_svec_data(types->parameters), n, ml->simplesig, lensimplesig, isva); else ismatch = 0; } if (ismatch == 0) ; // nothing else if (ml->isleafsig) ismatch = sig_match_by_type_leaf(jl_svec_data(types->parameters), ml->sig, lensig); else if (ml->issimplesig) ismatch = sig_match_by_type_simple(jl_svec_data(types->parameters), n, ml->sig, lensig, ml->va); else if (ml->tvars == jl_emptysvec) ismatch = jl_tuple_subtype(jl_svec_data(types->parameters), n, ml->sig, 0); else if (penv == NULL) { ismatch = jl_type_match((jl_value_t*)types, (jl_value_t*)ml->sig) != (jl_value_t*)jl_false; } else { // TODO: this is missing the actual subtype test, // which works currently because types is typically a leaf tt, // or inexact is set (which then does a sort of subtype test via jl_types_equal) // but this isn't entirely general jl_value_t *ti = jl_lookup_match((jl_value_t*)types, (jl_value_t*)ml->sig, penv, ml->tvars); resetenv = 1; ismatch = (ti != (jl_value_t*)jl_bottom_type); if (ismatch) { // parametric methods only match if all typevars are matched by // non-typevars. size_t i, l; for (i = 0, l = jl_svec_len(*penv); i < l; i++) { if (jl_is_typevar(jl_svecref(*penv, i))) { if (inexact) { // "inexact" means the given type is compile-time, // where a failure to determine the value of a // static parameter is inconclusive. // this is issue #3182, see test/core.jl return INEXACT_ENTRY; } ismatch = 0; break; } } if (inexact) { // the compiler might attempt jl_get_specialization on e.g. // convert(::Type{Type{Int}}, ::DataType), which is concrete but might not // equal the run time type. in this case ti would be {Type{Type{Int}}, Type{Int}} // but tt would be {Type{Type{Int}}, DataType}. JL_GC_PUSH1(&ti); ismatch = jl_types_equal(ti, (jl_value_t*)types); JL_GC_POP(); if (!ismatch) return INEXACT_ENTRY; } } } if (ismatch) { size_t i, l; for (i = 0, l = jl_svec_len(ml->guardsigs); i < l; i++) { // see corresponding code in jl_typemap_assoc_exact if (jl_subtype((jl_value_t*)types, jl_svecref(ml->guardsigs, i), 0)) { ismatch = 0; break; } } if (ismatch) return ml; } if (resetenv) *penv = jl_emptysvec; } ml = ml->next; } return NULL; }
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_tuple_t *t) { jl_value_t *gf; if (bnd) { //jl_declare_constant(bnd); if (bnd->value != NULL && !bnd->constp) { jl_errorf("cannot define function %s; it already has a value", bnd->name->name); } bnd->constp = 1; } if (*bp == NULL) { gf = (jl_value_t*)jl_new_generic_function(name); *bp = gf; } else { 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_gf(gf)) { jl_error("invalid method definition: not a generic function"); } } } JL_GC_PUSH1(&gf); assert(jl_is_function(f)); assert(jl_is_tuple(argtypes)); assert(jl_is_tuple(t)); for(size_t i=0; i < jl_tuple_len(argtypes); i++) { jl_value_t *elt = jl_tupleref(argtypes,i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_lambda_info_t *li = f->linfo; jl_errorf("invalid type for argument %s in method definition for %s at %s:%d", jl_is_expr(li->ast) ? ((jl_sym_t*)jl_arrayref(jl_lam_args((jl_expr_t*)li->ast),i))->name : "?", name->name, li->file->name, li->line); } } int ishidden = !!strchr(name->name, '#'); for(size_t i=0; i < jl_tuple_len(t); i++) { jl_value_t *tv = jl_tupleref(t,i); if (!jl_is_typevar(tv)) jl_type_error_rt(name->name, "method definition", (jl_value_t*)jl_tvar_type, tv); if (!ishidden && !type_contains((jl_value_t*)argtypes, tv)) { JL_PRINTF(JL_STDERR, "Warning: static parameter %s does not occur in signature for %s", ((jl_tvar_t*)tv)->name->name, name->name); print_func_loc(JL_STDERR, f->linfo); JL_PRINTF(JL_STDERR, ".\nThe method will not be callable.\n"); } } jl_add_method((jl_function_t*)gf, argtypes, f, t); if (jl_boot_file_loaded && f->linfo && f->linfo->ast && jl_is_expr(f->linfo->ast)) { jl_lambda_info_t *li = f->linfo; li->ast = jl_compress_ast(li, li->ast); } JL_GC_POP(); return gf; }