From: Jérémie Astor Date: Wed, 20 Apr 2022 11:57:53 +0000 (+0200) Subject: Dev (#246) X-Git-Tag: nightly~283^2 X-Git-Url: http://10.10.0.4:5575/?a=commitdiff_plain;h=0516c5033164001c89cf1c874b45944718a1e5a6;p=gwion.git Dev (#246) * :art: Locales :smile: * :bug: Update fmt * :art: Fully implement partial application * :art: LGTM * :art: Improve partial non used checking * :wrench: install submodules if not present * :art: Update README * :art: test partial application --- diff --git a/Makefile b/Makefile index 12d81b4f..b2f29edc 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,10 @@ CFLAGS += -Wno-pedantic CFLAGS += -DGWION_BUILTIN -all: options-show ${PRG} +all: deps options-show ${PRG} + +deps: + [ "$(shell ls util | wc -l)" = "0" ] && git submodule update --init --recursive || true ${PRG}: ${GWLIBS} src/main.o @$(info link ${PRG}) diff --git a/README.md b/README.md index 697f3771..a62c41b8 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,6 @@ [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/2417/badge)](https://bestpractices.coreinfrastructure.org/projects/2417) [![Coverage](https://raw.githubusercontent.com/Gwion/gwion-coverage-report/master/badge.svg?sanitize=true)](https://fennecdjay.github.io/gwion-coverage-report/master) [![Line Count](https://tokei.rs/b1/github/Gwion/Gwion)](https://github.com/fennecdjay/Gwion) - -[![All Contributors](https://img.shields.io/badge/all_contributors-16-orange.svg)](#contributors) - ![Linux](https://github.com/Gwion/Gwion/workflows/Linux/badge.svg) ![MacOs](https://github.com/Gwion/Gwion/workflows/MacOs/badge.svg) ![Windows](https://github.com/Gwion/Gwion/workflows/Windows/badge.svg) @@ -162,41 +159,4 @@ If there's anything you see that can make Gwion better, please let us know! ## Acknowledgements. The whole [Chuck](http://chuck.cs.princeton.edu/) team, for inspiration. [Paul Batchelor](https://github.com/PaulBatchelor) and the awesome [soundpipe](https://github.com/PaulBatchelor/Soundpipe) library, that got me started. - -## Contributors - -Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)): - - - - - - - - - - - - - - - - - - - - - - - - - - -

Paul Batchelor

💬 🐛 💻 🤔

Benny

💬 🐛 💻

Andrew Prentice

💬 🐛 💻 🤔

aleserche

💻

Pranav Joglekar

📓 📖

Amber

💬 📖 🤔

Chase

💻

Nithin Pankaj

💻

Enrico Gruner

💻

Muhammad Umer Farooq

💻

Harsh Jain

📖

ry-v1

📖

deekts

💻

Forrest Cahoon

🤔

Connor Hewett

💻

Ethan Uppal

🤔
- - - - -This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! - -> NOTE: if you should be on the list of contributors but we forgot you, don't be shy and let us know! +not to forget these wonderful people ([emoji key](https://gwion.github.io/Gwion/Contributing/Contributors.html)): diff --git a/ast b/ast index c13d5da0..27fba9f6 160000 --- a/ast +++ b/ast @@ -1 +1 @@ -Subproject commit c13d5da0476a1409d2f501e7e014a58f55be9fd8 +Subproject commit 27fba9f6ef3faf79695c95d57afdb4267bc751b5 diff --git a/fmt b/fmt index 3bb27f71..cf352393 160000 --- a/fmt +++ b/fmt @@ -1 +1 @@ -Subproject commit 3bb27f71298a13e4d31b3dda1b67c854086298be +Subproject commit cf3523938d57ae658952b1104f8b91dbd3dd8ea2 diff --git a/highlighters/gwion.kak b/highlighters/gwion.kak index c342e51f..e79652f9 100644 --- a/highlighters/gwion.kak +++ b/highlighters/gwion.kak @@ -22,10 +22,10 @@ provide-module -override gwion %{ where when case varloop defer try perform handle retry fun function typedef distinct funptr - new spork fork' + new spork fork locale' attributes='const var static private public protect variadic template samp ms second minute delay' - types='auto int float bool dur void Object Shred Event' + types='auto int float bool dur time void Object Shred Event' values='true false none this now me adc dac maybe' builtins='__file__ __line__ __func__' entities='class struct trait union enum' diff --git a/highlighters/gwion.nanorc b/highlighters/gwion.nanorc index b6ed677b..52729fa1 100644 --- a/highlighters/gwion.nanorc +++ b/highlighters/gwion.nanorc @@ -37,14 +37,14 @@ color mauve "\" color mauve "\" comment "#!" -color italic,red start="#\<(pragma|include|define|ifdef|ifndef|undef|endif|import)\>" end="$" - color brightred "\<(typeof|spork|fork)\>" color lightred "\<(second|ms|day|samp|minute|hour)\>" color brightcyan "\<(maybe)\>" color cyan "\<(adc|blackhole)\>" -color brightgreen "\<(try|handle|perform|retry|class|struct|trait|union|enum|fun|operator|funptr|typedef|distinct|new)\>" +color brightgreen "\<(try|handle|perform|retry|class|struct|trait|union|enum|fun|locale|operator|funptr|typedef|distinct|new)\>" +color italic,red start="#\<(pragma|include|define|ifdef|ifndef|undef|endif|import|locale)\>" end="$" +color italic,red "#locale" color italic,yellow "extends" color italic,brightgreen "\<(final|abstract)\>" color lightgreen "@[a-zA-Z]+[a-zA-Z0-9_]*|&[a-zA-Z]+[a-zA-Z0-9_]*" diff --git a/include/emit.h b/include/emit.h index 808879e1..a5928716 100644 --- a/include/emit.h +++ b/include/emit.h @@ -52,6 +52,7 @@ struct Emitter_ { struct Gwion_ * gwion; struct EmitterInfo_ *info; struct Vector_ stack; + Func locale; uint16_t this_offset; // reset uint16_t vararg_offset; // reset }; diff --git a/include/env/context.h b/include/env/context.h index 77b4bb2e..af191283 100644 --- a/include/env/context.h +++ b/include/env/context.h @@ -5,7 +5,6 @@ struct Context_ { Nspc nspc; m_str name; Ast tree; - Func locale; uint16_t ref; uint16_t weight; bool error; diff --git a/include/env/type.h b/include/env/type.h index 23938edf..6a3e1a3a 100644 --- a/include/env/type.h +++ b/include/env/type.h @@ -140,7 +140,6 @@ typedef enum { et_union, et_auto, et_none, - et_apms, et_dict, MAX_TYPE } type_enum; diff --git a/include/lang_private.h b/include/lang_private.h index 825edae1..c60954a6 100644 --- a/include/lang_private.h +++ b/include/lang_private.h @@ -19,5 +19,4 @@ ANN m_bool import_ref(const Gwi gwi); ANN m_bool import_deep_equal(const Gwi gwi); ANN m_bool import_dict(const Gwi gwi); ANN m_bool import_gack(const Gwi gwi); -ANN m_bool import_curry(const Gwi gwi); #endif diff --git a/include/partial.h b/include/partial.h new file mode 100644 index 00000000..0a6603e3 --- /dev/null +++ b/include/partial.h @@ -0,0 +1,18 @@ +#ifndef __PARTIAL_APPLICATION +#define __PARTIAL_APPLICATION + +ANN Type partial_type(const Env, Exp_Call *const); +ANN void print_signature(const Func f); + +ANN static inline bool func_match_inner(const Env env, const Exp e, + const Type t, const bool implicit, + const bool specific) { + if (specific ? e->type == t : isa(e->type, t) > 0) // match + return true; + return !implicit ? false : check_implicit(env, e, t) > 0; +} + +ANN static inline bool is_typed_hole(const Env env, const Exp exp) { + return exp->exp_type == ae_exp_cast && is_hole(env, exp->d.exp_cast.exp); +} +#endif diff --git a/plug b/plug index 49a4be94..52469434 160000 --- a/plug +++ b/plug @@ -1 +1 @@ -Subproject commit 49a4be94f9c4042f854dc82c8c6e598ec9d4df29 +Subproject commit 524694345a2e9ed7b257bf6ff8a3d70940e5aa61 diff --git a/src/compile.c b/src/compile.c index 5a0e380d..2974fdef 100644 --- a/src/compile.c +++ b/src/compile.c @@ -103,7 +103,6 @@ ANN static inline m_bool _passes(struct Gwion_ *gwion, struct Compiler *c) { ANN static inline m_bool passes(struct Gwion_ *gwion, struct Compiler *c) { const Env env = gwion->env; const Context ctx = new_context(env->gwion->mp, c->ast, env->name); -//ctx->locale = nspc_lookup_value1(gwion->env->global_nspc, insert_symbol(gwion->st, "@DefaultLocale"))->d.func_ref; env_reset(env); load_context(ctx, env); const m_bool ret = _passes(gwion, c); diff --git a/src/emit/emit.c b/src/emit/emit.c index 0b6acd14..5d5ce858 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -18,6 +18,7 @@ #include "specialid.h" #include "vararg.h" #include "looper.h" +#include "shreduler_private.h" #undef insert_symbol #define insert_symbol(a) insert_symbol(emit->gwion->st, (a)) @@ -912,7 +913,7 @@ ANN static m_bool emit_prim_interp(const Emitter emit, const Exp *exp) { emit_localx(emit, emit->gwion->type[et_string]); return GW_OK; } -#include "shreduler_private.h" + ANN static m_bool emit_ensure_func(const Emitter emit, const Func f) { const struct ValueFrom_ *from = f->value_ref->from; if(from->owner_class) @@ -925,32 +926,26 @@ ANN static m_bool emit_ensure_func(const Emitter emit, const Func f) { } ANN static m_bool emit_prim_locale(const Emitter emit, const Symbol *id) { - CHECK_BB(emit_ensure_func(emit, emit->env->context->locale)); + if(emit->locale->def->d.code) { + const Stmt stmt = mp_vector_at((emit->locale->def->d.code->d.stmt_code.stmt_list), struct Stmt_, 0); + const Func f = stmt->d.stmt_exp.val->d.exp_call.func->type->info->func; + CHECK_OB(emit_ensure_func(emit, f)); + } + CHECK_OB(emit_ensure_func(emit, emit->locale)); emit_push_code(emit, "locale"); // new code { - - // push args const M_Object string = new_string(emit->gwion, s_name(*id)); regpushi(emit, (m_uint)string); - - regpushi(emit, (m_uint)emit->env->context->locale->code); - emit_exp_call1(emit, emit->env->context->locale, true); - - regpop(emit, emit->env->context->locale->def->base->ret_type->size); + regpushi(emit, (m_uint)emit->locale->code); + emit_exp_call1(emit, emit->locale, true); + regpop(emit, emit->locale->def->base->ret_type->size); const VM_Code code = finalyze(emit, EOC); const VM_Shred shred = new_vm_shred(emit->gwion->mp, code); vm_add_shred(emit->gwion->vm, shred); shred->info->me->ref++; vm_run(emit->gwion->vm); emit->gwion->vm->bbq->is_running = true; - if(tflag(emit->env->context->locale->def->base->ret_type, tflag_float)) { - const Instr instr = emit_add_instr(emit, RegPushImm2); - instr->f = *(m_float*)shred->reg; - } else if(emit->env->context->locale->def->base->ret_type->size == SZ_INT) - regpushi(emit, *(m_uint*)shred->reg); - else { - // here we would need to deallocate - ERR_B(prim_pos(id), "not implemented atm"); - } + const Instr instr = emit_add_instr(emit, RegPushImm2); + instr->f = *(m_float*)shred->reg; return GW_OK; } @@ -1990,12 +1985,12 @@ ANN2(1,2) static Instr _flow(const Emitter emit, const Exp e, Instr *const instr // CHECK_BO(emit_exp_pop_next(emit, e)); CHECK_BO(emit_exp(emit, e)); { - const Instr instr = (Instr)vector_back(&emit->code->instr); - if(instr->execute == fast_except) { + const Instr ex = (Instr)vector_back(&emit->code->instr); + if(ex->execute == fast_except) { vector_rem(&emit->code->instr, vector_size(&emit->code->instr) - 1); - if(instr->m_val2) - mp_free2(emit->gwion->mp, sizeof(struct FastExceptInfo), (struct FastExceptInfo*)instr->m_val2); - free_instr(emit->gwion, instr); + if(ex->m_val2) + mp_free2(emit->gwion->mp, sizeof(struct FastExceptInfo), (struct FastExceptInfo*)ex->m_val2); + free_instr(emit->gwion, ex); } } if(instr) @@ -2837,11 +2832,14 @@ ANN static m_bool emit_stmt_match(const Emitter emit, ANN static m_bool emit_stmt_pp(const Emitter emit, const struct Stmt_PP_ *stmt) { - if (stmt->pp_type == ae_pp_pragma) { + if (stmt->pp_type == ae_pp_include) + emit->env->name = stmt->data; + else if (stmt->pp_type == ae_pp_locale) + emit->locale = stmt->exp->d.exp_lambda.def->base->func; + else if (stmt->pp_type == ae_pp_pragma) { if (!strncmp(stmt->data, "unroll", strlen("unroll"))) emit->info->unroll = strtol(stmt->data + 6, NULL, 10); - } else if (stmt->pp_type == ae_pp_include) - emit->env->name = stmt->data; + } return GW_OK; } @@ -3078,7 +3076,9 @@ ANN m_bool _emit_func_def(const Emitter emit, const Func_Def f) { ANN m_bool emit_func_def(const Emitter emit, const Func_Def fdef) { const uint16_t depth = emit->env->scope->depth; emit->env->scope->depth = 0; + const Func locale = emit->locale; const m_bool ret = _emit_func_def(emit, fdef); + emit->locale = locale; emit->env->scope->depth = depth; return ret; } @@ -3131,10 +3131,8 @@ ANN static m_bool cdef_parent(const Emitter emit, const Class_Def cdef) { return ret; } -ANN static m_bool emit_class_def(const Emitter emit, const Class_Def cdef) { - if (tmpl_base(cdef->base.tmpl)) return GW_OK; +ANN static m_bool _emit_class_def(const Emitter emit, const Class_Def cdef) { const Type t = cdef->base.type; - if (tflag(t, tflag_emit)) return GW_OK; set_tflag(t, tflag_emit); const Class_Def c = t->info->cdef; if (c->base.ext && t->info->parent->info->cdef && @@ -3153,6 +3151,15 @@ ANN static m_bool emit_class_def(const Emitter emit, const Class_Def cdef) { return GW_OK; } +ANN static m_bool emit_class_def(const Emitter emit, const Class_Def cdef) { + if (tmpl_base(cdef->base.tmpl)) return GW_OK; + if (tflag(cdef->base.type, tflag_emit)) return GW_OK; + const Func locale = emit->locale; + const m_bool ret = _emit_class_def(emit, cdef); + emit->locale = locale; + return ret; +} + ANN static inline void emit_free_code(const Emitter emit, Code *code) { if (vector_size(&code->instr)) free_code_instr(&code->instr, emit->gwion); free_code(emit->gwion->mp, code); @@ -3177,6 +3184,7 @@ ANN static inline void emit_clear(const Emitter emit) { ANN m_bool emit_ast(const Env env, Ast *ast) { const Emitter emit = env->gwion->emit; + const Func locale = emit->locale; emit_clear(emit); emit->code = new_code(emit, emit->env->name); emit_push_scope(emit); @@ -3187,5 +3195,6 @@ ANN m_bool emit_ast(const Env env, Ast *ast) { else emit_free_stack(emit); emit_clear(emit); + emit->locale = locale; return ret; } diff --git a/src/gwion.c b/src/gwion.c index 9fca9311..0f7f94e8 100644 --- a/src/gwion.c +++ b/src/gwion.c @@ -68,6 +68,14 @@ ANN static void gwion_core(const Gwion gwion) { gwion->vm->gwion = gwion->emit->gwion = gwion->env->gwion = gwion; } + +ANN static Func gwion_locale(const Gwion gwion) { + const Nspc nspc = gwion->env->curr; + const Symbol sym = insert_symbol(gwion->st, "BasicLocale"); + const Value v = nspc_lookup_value1(nspc, sym); + return v->d.func_ref; +} + ANN static m_bool gwion_ok(const Gwion gwion, CliArg *arg) { CHECK_BB(plug_ini(gwion, &arg->lib)); shreduler_set_loop(gwion->vm->shreduler, arg->loop); @@ -75,6 +83,7 @@ ANN static m_bool gwion_ok(const Gwion gwion, CliArg *arg) { plug_run(gwion, &arg->mod); if (type_engine_init(gwion)) { gwion->vm->cleaner_shred = gwion_cleaner(gwion); + gwion->emit->locale = gwion_locale(gwion); (void)arg_compile(gwion, arg); return GW_OK; } diff --git a/src/lib/curry.c b/src/lib/curry.c deleted file mode 100644 index 75e84fda..00000000 --- a/src/lib/curry.c +++ /dev/null @@ -1,107 +0,0 @@ -#include "gwion_util.h" -#include "gwion_ast.h" -#include "gwion_env.h" -#include "vm.h" -#include "instr.h" -#include "emit.h" -#include "gwion.h" -#include "object.h" -#include "operator.h" -#include "import.h" -#include "gwi.h" -#include "traverse.h" -#include "parse.h" - -ANN static Arg_List curry_arg_list(const Env env, const Arg_List base, const Exp e) { - Arg_List args = new_mp_vector(env->gwion->mp, sizeof(Arg), 0); - Exp next = e; - uint32_t i = 0; - while(next) { - if(is_hole(env, next)) { - char c[256]; - sprintf(c, "@%u\n", args->len); - Type_Decl *td = cpy_type_decl(env->gwion->mp, mp_vector_at(base, Arg, i)->td); - Arg arg = { .td = td, .var_decl = { .xid = insert_symbol(c) }}; - mp_vector_add(env->gwion->mp, &args, Arg, arg); - } - i++; - next = next->next; - } - return args; -} - -ANN2(1) static Func_Base *curry_base(const Env env, const Func_Base *base, Exp earg, const loc_t loc) { - Arg_List args = earg ? curry_arg_list(env, base->args, earg) : NULL; - Func_Base *fb = new_func_base(env->gwion->mp, cpy_type_decl(env->gwion->mp, base->td), lambda_name(env->gwion->st, loc.first), args, ae_flag_none, loc); - fb->fbflag |= fbflag_lambda; - return fb; -} - -ANN static Exp curry_call(const Env env, Exp e) { - Exp base = NULL, arg; - uint32_t i = 0; - while(e) { - if(is_hole(env, e)) { - char c[256]; - sprintf(c, "@%u\n", i++); - const Exp next = new_prim_id(env->gwion->mp, insert_symbol(c), e->pos); - if(base) arg = arg->next = next; - else arg = base = next; - } else { - const Exp next = cpy_exp(env->gwion->mp, e); - if(base) arg = arg->next = next; - else arg = base = next; - } - e = e->next; - } - return base; -} - -ANN static Stmt curry_code(const Env env, const Exp efun, const Exp earg) { - Stmt_List slist = new_mp_vector(env->gwion->mp, sizeof(struct Stmt_), 1); - const Exp arg = curry_call(env, earg); - const Exp exp = new_exp_call(env->gwion->mp, efun, arg, efun->pos); - Stmt stmt = mp_vector_at(slist, struct Stmt_, 0); - stmt->stmt_type = ae_stmt_return; - stmt->d.stmt_exp.val = exp; - return new_stmt_code(env->gwion->mp, slist, efun->pos); -} - -ANN static Type curry_type(const Env env, const Exp exp, const Exp efun, const Exp earg) { - Func_Base *base = curry_base(env, efun->type->info->func->def->base, earg, exp->pos); - Stmt code = curry_code(env, efun, earg); - exp->d.exp_lambda.def = new_func_def(env->gwion->mp, base, code); - exp->exp_type = ae_exp_lambda; - return check_exp(env, exp); -} - -static OP_CHECK(opck_curry) { - Exp_Call *call = (Exp_Call*)data; - if(!call->args) - ERR_N(exp_self(call)->pos, _("`curry` requires a function as first argument")); - const Exp efun = call->args; - const Exp earg = efun->next; - efun->next = NULL; - const Type ret = check_exp(env, efun) - ? curry_type(env, exp_self(call), efun, earg) - : env->gwion->type[et_error]; - mp_free(env->gwion->mp, Exp, earg); - return ret; -} - -GWION_IMPORT(curry) { - GWI_BB(gwi_func_ini(gwi, "@function", "curry")); - GWI_BB(gwi_func_end(gwi, (f_xfun)1, ae_flag_none)); - - const Env env = gwi->gwion->env; // no need - const Func f = (Func)map_at(&env->curr->info->func->map, map_size(&env->curr->info->func->map) - 1); - const struct Op_Func opfunc = {.ck = opck_curry}; - const struct Op_Import opi = { - .rhs = f->value_ref->type, - .func = &opfunc, - .data = (uintptr_t)f, - .op = insert_symbol("@func_check")}; - CHECK_BB(add_op(gwi->gwion, &opi)); - return GW_OK; -} - diff --git a/src/lib/dict.c b/src/lib/dict.c index 0e85c398..98d4f121 100644 --- a/src/lib/dict.c +++ b/src/lib/dict.c @@ -488,8 +488,8 @@ static OP_EMIT(opem_dict_remove) { CHECK_BB(emit_dict_iter(emit, hinfo, &opi, &call, bin->lhs)); if(hinfo->keyk || hinfo->valk) { clear_fn *const fn = clear[hinfo->keyk][hinfo->valk]; - const Instr clear = emit_add_instr(emit, hmap_remove_clear); - clear->m_val = (m_uint)fn; + const Instr instr = emit_add_instr(emit, hmap_remove_clear); + instr->m_val = (m_uint)fn; } const Instr pushval = emit_add_instr(emit, hmap_remove); diff --git a/src/lib/engine.c b/src/lib/engine.c index c4a607fa..adab057e 100644 --- a/src/lib/engine.c +++ b/src/lib/engine.c @@ -56,6 +56,28 @@ static FREEARG(freearg_release) { vector_release(&v); } +ANN static m_float basic_locale(m_str str) { + const char base = str[0]; + str++; + if(base < 'A' || base > 'G') return -1; + m_int bnote = base - 'A'; + if(*str == '#') { bnote++; str++; } + else if(*str == 'b') { bnote--; str++; } + char *remainder; + const long octave = strtol(str, &remainder, 10); + if(*remainder != '\0') return -1; + const int note = bnote + 12 * octave + 21; + return (pow(2, (note - 69) / 12.0) * 440.0); +} + +static SFUN(BasicLocale) { + const M_Object arg = *(M_Object*)MEM(0); + const m_float ret = basic_locale(STRING(arg)); + if(ret == -1.0) + handle(shred, "invalid value for locale"); + *(m_float*)RETURN = ret; +} + ANN static m_bool import_core_libs(const Gwi gwi) { gwidoc(gwi, "one type to rule them all."); const Type t_class = gwi_mk_type(gwi, "Class", SZ_INT, NULL); @@ -141,10 +163,6 @@ ANN static m_bool import_core_libs(const Gwi gwi) { /*set_tflag(t_lambda, tflag_infer);*/ GWI_BB(gwi_set_global_type(gwi, t_lambda, et_lambda)) - gwidoc(gwi, "Mark function as apms."); - const Type t_apms = gwi_mk_type(gwi, "@apms", 0, NULL); - GWI_BB(gwi_set_global_type(gwi, t_apms, et_apms)) - gwidoc(gwi, "type for internal pointer data."); GWI_BB(gwi_typedef_ini(gwi, "int", "@internal")) GWI_BB(gwi_typedef_end(gwi, ae_flag_none)) @@ -187,7 +205,9 @@ ANN static m_bool import_core_libs(const Gwi gwi) { GWI_BB(import_gack(gwi)); - GWI_BB(import_curry(gwi)); +gwi_func_ini(gwi, "float", "BasicLocale"); +gwi_func_arg(gwi, "string", "str"); +gwi_func_end(gwi, BasicLocale, ae_flag_none); // seemed need at a point to ease liking gwi_enum_ini(gwi, "@hidden_enum"); diff --git a/src/lib/lib_func.c b/src/lib/lib_func.c index d4c29a92..0433c872 100644 --- a/src/lib/lib_func.c +++ b/src/lib/lib_func.c @@ -18,7 +18,6 @@ static OP_CHECK(opck_func_call) { Exp_Call call = {.func = bin->rhs, .args = bin->lhs}; Exp e = exp_self(bin); e->exp_type = ae_exp_call; - call.apms = true; memcpy(&e->d.exp_call, &call, sizeof(Exp_Call)); return check_exp_call1(env, &e->d.exp_call) ?: env->gwion->type[et_error]; } @@ -36,54 +35,6 @@ ANN static inline Exp cpy_nonext(const Env env, const Exp e) { return ret; } -ANN static Exp order_apms(const Env env, Exp fn, const Exp _arg) { - const MemPool mp = env->gwion->mp; - Exp base = NULL; - Exp next = NULL; - Exp arg = _arg; - do { - const bool hole = is_hole(env, fn); - const Exp curr = !hole ? fn : arg; - if (hole) { - if (!arg) { - if (base) free_exp(mp, base); - ERR_O(fn->pos, "not enough arguments for holes"); - } - arg = arg->next; - } - if (!base) - base = next = cpy_nonext(env, curr); - else if(next) { // check me (added after a fuzzing session) - next->next = cpy_nonext(env, curr); - next = next->next; - } - } while ((fn = fn->next)); - assert(base); - if (arg) { - free_exp(mp, base); - ERR_O(arg->pos, "too many arguments for holes"); - } - return base; -} - -static OP_CHECK(opck_apms) { - Exp_Binary *bin = (Exp_Binary *)data; - Exp lhs = bin->lhs; - Exp_Call base = bin->rhs->d.exp_call; - DECL_ON(const Exp, args, = order_apms(env, base.args, lhs)); - Exp_Call call = {.func = base.func, .args = args}; - Exp e = exp_self(bin); - e->exp_type = ae_exp_call; - e->type = NULL; - memcpy(&e->d.exp_call, &call, sizeof(Exp_Call)); - - const MemPool mp = env->gwion->mp; - free_exp(mp, base.args); - free_exp(mp, lhs); - - return check_exp_call1(env, &e->d.exp_call) ?: env->gwion->type[et_error]; -} - static inline void fptr_instr(const Emitter emit, const Func f, const m_uint i) { const Instr set = emit_add_instr(emit, RegSetImm); @@ -354,10 +305,11 @@ ANN static m_bool fptr_do(const Env env, struct FptrInfo *info) { return check_lambda(env, actual_type(env->gwion, info->rhs->value_ref->type), l); } -ANN static Type curry2auto(const Env env, const Exp_Binary *bin) { +ANN static Type partial2auto(const Env env, const Exp_Binary *bin) { const Func_Def fdef = bin->lhs->d.exp_lambda.def; unset_fbflag(fdef->base, fbflag_lambda); CHECK_BN(traverse_func_def(env, fdef)); + set_fbflag(fdef->base, fbflag_lambda); const Type actual = fdef->base->func->value_ref->type; set_fbflag(fdef->base, fbflag_lambda); Var_Decl vd = mp_vector_at(bin->rhs->d.exp_decl.list, struct Var_Decl_, 0); @@ -374,7 +326,7 @@ static OP_CHECK(opck_auto_fptr) { if (bin->lhs->exp_type == ae_exp_td) ERR_N(bin->lhs->pos, "can't use {/}type decl expressions{0} in auto function pointer declarations"); if(!bin->lhs->type->info->func) - return curry2auto(env, bin); + return partial2auto(env, bin); // create a matching signature // TODO: we could check first if there a matching existing one Func_Base *const fbase = @@ -723,18 +675,12 @@ GWION_IMPORT(func) { GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "@function", NULL)) GWI_BB(gwi_oper_add(gwi, opck_func_call)) GWI_BB(gwi_oper_end(gwi, "=>", NULL)) - GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "@apms", NULL)) - GWI_BB(gwi_oper_add(gwi, opck_apms)) - GWI_BB(gwi_oper_end(gwi, "=>", NULL)) GWI_BB(gwi_oper_ini(gwi, NULL, "@func_ptr", "bool")) GWI_BB(gwi_oper_end(gwi, "!", IntNot)) GWI_BB(gwi_oper_ini(gwi, "@function", "@func_ptr", NULL)) GWI_BB(gwi_oper_add(gwi, opck_fptr_at)) GWI_BB(gwi_oper_emi(gwi, opem_func_assign)) GWI_BB(gwi_oper_end(gwi, "@=>", NULL)) - // GWI_BB(gwi_oper_add(gwi, opck_fptr_cast)) - // GWI_BB(gwi_oper_emi(gwi, opem_fptr_cast)) - // GWI_BB(gwi_oper_end(gwi, "$", NULL)) GWI_BB(gwi_oper_add(gwi, opck_fptr_impl)) GWI_BB(gwi_oper_emi(gwi, opem_fptr_impl)) GWI_BB(gwi_oper_end(gwi, "@implicit", NULL)) diff --git a/src/main.c b/src/main.c index 1a0a5f4f..1811e9dc 100644 --- a/src/main.c +++ b/src/main.c @@ -44,7 +44,6 @@ int main(int argc, char **argv) { CliArg arg = {.arg = {.argc = argc, .argv = argv}, .loop = false}; signal(SIGINT, sig); signal(SIGTERM, sig); - struct Gwion_ gwion = {}; const m_bool ini = gwion_ini(&gwion, &arg); arg_release(&arg); if (ini > 0) gwion_run(&gwion); diff --git a/src/parse/check.c b/src/parse/check.c index 76697b57..46a713a6 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -14,6 +14,7 @@ #include "match.h" #include "specialid.h" #include "tmp_resolve.h" +#include "partial.h" ANN static m_bool check_stmt_list(const Env env, Stmt_List list); ANN m_bool check_class_def(const Env env, const Class_Def class_def); @@ -310,6 +311,9 @@ ANN static Value check_non_res_value(const Env env, const Symbol *data) { ERR_O(prim_pos(data), _("non-global variable '%s' used from global function/class."), s_name(var)) + } else if(env->func && fbflag(env->func->def->base, fbflag_locale)) { + if(!is_func(env->gwion, value->type) && value->from->owner && !from_global_nspc(env, value->from->owner)) + ERR_O(prim_pos(data), _("invalid variable access from locale definition")); } return value; } @@ -422,7 +426,7 @@ ANN static Type check_prim_hack(const Env env, const Exp *data) { } ANN static Type check_prim_locale(const Env env, const Symbol *data NUSED) { - return env->context->locale->def->base->ret_type; + return env->gwion->type[et_float]; } #define describe_prim_xxx(name, type) \ @@ -494,14 +498,6 @@ ANN static Type_Decl* mk_td(const Env env, const Arg *arg, return type2td(env->gwion, t, pos); } -ANN static inline bool func_match_inner(const Env env, const Exp e, - const Type t, const bool implicit, - const bool specific) { - if (specific ? e->type == t : isa(e->type, t) > 0) // match - return true; - return !implicit ? false : check_implicit(env, e, t) > 0; -} - ANN2(1, 2) static Func find_func_match_actual(const Env env, Func func, const Exp exp, const bool implicit, const bool specific) { @@ -514,7 +510,6 @@ static Func find_func_match_actual(const Env env, Func func, const Exp exp, e->cast_to = NULL; if (!e->type) // investigate return NULL; -// rewrite Arg *arg = i < args_len ? mp_vector_at(args, Arg, i++) : NULL; if (!arg) { if (fbflag(func->def->base, fbflag_variadic)) return func; @@ -621,16 +616,6 @@ ANN static void print_current_args(Exp e) { gw_err("\n"); } -ANN static void print_arg(Arg_List args) { - for(uint32_t i = 0; i < args->len; i++) { - Arg *arg = mp_vector_at(args, Arg, i); - gw_err("{G}%s{0} {/}%s{0}", arg->type ? arg->type->name : NULL, - arg->var_decl.xid ? s_name(arg->var_decl.xid) : ""); - if(i < args->len - 1) gw_err(", "); - } -// while ((e = next_arg_Arg_List(e))); -} - ANN2(1) static void function_alternative(const Env env, const Type f, const Exp args, const loc_t pos) { @@ -639,15 +624,8 @@ static void function_alternative(const Env env, const Type f, const Exp args, gwerr_basic("Argument type mismatch", "call site", "valid alternatives:", env->name, pos, 0); Func up = f->info->func; - do { - gw_err(" {-}(%s){0} ", up->name); - const Arg_List e = up->def->base->args; - if (e) - print_arg(e); - else - gw_err("{G}void{0}"); - gw_err("\n"); - } while ((up = up->next)); + do print_signature(up); + while ((up = up->next)); if (args) print_current_args(args); else @@ -765,17 +743,6 @@ ANN static Type check_lambda_call(const Env env, const Exp_Call *exp) { } if(e) ERR_O(exp_self(exp)->pos, _("argument number does not match for lambda")) -/* - while (arg && e) { - arg->type = e->type; - if(is_class(env->gwion, arg->type)) - type_addref(arg->type); - arg = arg->next; - e = e->next; - } - if (arg || e) - ERR_O(exp_self(exp)->pos, _("argument number does not match for lambda")) -*/ l->def->base->values = env->curr->info->value; const m_bool ret = traverse_func_def(env, l->def); if (l->def->base->func) { @@ -867,10 +834,13 @@ ANN Type check_exp_call1(const Env env, Exp_Call *const exp) { } exp->func->type = func->value_ref->type; call_add_effect(env, func, exp->func->pos); -// if (func == env->func) set_fflag(env->func, fflag_recurs); return func->def->base->ret_type != env->gwion->type[et_auto] ? func->def->base->ret_type : exp->func->d.exp_dot.base->type; } + if(exp->func->exp_type == ae_exp_lambda) { + const Type tt = partial_type(env, exp); + if(tt) return tt; + } function_alternative(env, exp->func->type, exp->args, exp->func->pos); return NULL; } @@ -884,7 +854,6 @@ ANN static Type check_exp_binary(const Env env, const Exp_Binary *bin) { CHECK_OO(check_exp(env, bin->rhs)); if (is_auto) { assert(bin->rhs->type == bin->lhs->type); -// bin->rhs->type = bin->lhs->type; set_vflag(mp_vector_at(bin->rhs->d.exp_decl.list, struct Var_Decl_, 0)->value, vflag_assigned); } struct Op_Import opi = {.op = bin->op, @@ -938,9 +907,9 @@ ANN static m_bool predefined_call(const Env env, const Type t, return GW_ERROR; } -ANN2(1) static inline bool apms(const Env env, Exp exp) { +ANN2(1) static inline bool is_partial(const Env env, Exp exp) { while (exp) { - if (is_hole(env, exp)) + if (is_hole(env, exp) || is_typed_hole(env, exp)) return true; exp = exp->next; } @@ -968,8 +937,10 @@ ANN static Type check_exp_call_tmpl(const Env env, Exp_Call *exp, const Type t) } ANN static Type check_exp_call(const Env env, Exp_Call *exp) { - if (exp->apms && apms(env, exp->args)) - return env->gwion->type[et_apms]; + if (is_partial(env, exp->args)) { + CHECK_OO(check_exp(env, exp->func)); + return partial_type(env, exp); + } if (exp->tmpl) { DECL_BO(const m_bool, ret, = func_check(env, exp)); if (!ret) return exp_self(exp)->type; @@ -1345,6 +1316,13 @@ ANN m_bool check_union_def(const Env env NUSED, const Union_Def udef) { } ANN static m_bool check_stmt_exp(const Env env, const Stmt_Exp stmt) { + if(stmt->val) { + CHECK_OB(check_exp(env, stmt->val)); + if(stmt->val->exp_type == ae_exp_lambda) { + const loc_t loc = stmt->val->d.exp_lambda.def->base->pos; + env_warn(env, loc, _("Partial application not used")); + } + } return stmt->val ? check_exp(env, stmt->val) ? 1 : -1 : 1; } @@ -1500,9 +1478,19 @@ ANN static m_bool check_stmt_match(const Env env, const Stmt_Match stmt) { ANN static m_bool check_stmt_pp(const Env env, const Stmt_PP stmt) { if (stmt->pp_type == ae_pp_include) env->name = stmt->data; // check for memoization - if (env->func && stmt->pp_type == ae_pp_pragma && + else if (env->func && stmt->pp_type == ae_pp_pragma && !strncmp(stmt->data, "memoize", strlen("memoize"))) env->func->memoize = strtol(stmt->data + 7, NULL, 10); + else if(stmt->pp_type == ae_pp_locale) { + const loc_t loc = stmt_self(stmt)->pos; + const Exp id = new_prim_id(env->gwion->mp, stmt->xid, loc); + const Exp arg = new_prim_id(env->gwion->mp, insert_symbol("_"), loc); + arg->next = stmt->exp; + const Exp call = new_exp_call(env->gwion->mp, id, arg, loc); + stmt->exp = call; + CHECK_BB(traverse_exp(env, id)); + CHECK_OB(partial_type(env, &call->d.exp_call)); + } return GW_OK; } @@ -1673,7 +1661,7 @@ ANN m_bool _check_func_def(const Env env, const Func_Def f) { if(fflag(func, fflag_valid))return GW_OK; set_fflag(func, fflag_valid); assert(func == fdef->base->func); - if (env->class_def && !strstr(func->name, "lambda:")) + if (env->class_def && !fbflag(func->def->base, fbflag_lambda)) CHECK_BB(check_parent_match(env, fdef)); if (tmpl_base(fdef->base->tmpl)) return GW_OK; Value override = NULL; diff --git a/src/parse/partial.c b/src/parse/partial.c new file mode 100644 index 00000000..85aab198 --- /dev/null +++ b/src/parse/partial.c @@ -0,0 +1,211 @@ +#include "gwion_util.h" +#include "gwion_ast.h" +#include "gwion_env.h" +#include "vm.h" +#include "instr.h" +#include "emit.h" +#include "gwion.h" +#include "object.h" +#include "operator.h" +#include "import.h" +#include "gwi.h" +#include "traverse.h" +#include "parse.h" +#include "partial.h" + +ANN static Arg_List partial_arg_list(const Env env, const Arg_List base, const Exp e) { + Arg_List args = new_mp_vector(env->gwion->mp, sizeof(Arg), 0); + Exp next = e; + uint32_t i = 0; + while(next) { + if(is_hole(env, next) || is_typed_hole(env, next)) { + char c[256]; + sprintf(c, "@%u", args->len); + const Arg *src = mp_vector_at(base, Arg, i); + Type_Decl *td = src->td ? cpy_type_decl(env->gwion->mp, src->td) : NULL; + Arg arg = { .td = td, .var_decl = { .xid = insert_symbol(c) }}; + mp_vector_add(env->gwion->mp, &args, Arg, arg); + } + i++; + next = next->next; + } + return args; +} + +ANN static inline Symbol partial_name(const Env env, const pos_t pos) { + char c[7 + 1 + num_digit(pos.line) + num_digit(pos.column) + 2]; + sprintf(c, "partial:%u:%u", pos.line, pos.column); + return insert_symbol(c); +} + +ANN2(1, 2) static inline Func_Base *partial_base(const Env env, const Func_Base *base, Exp earg, const loc_t loc) { + Arg_List args = earg ? partial_arg_list(env, base->args, earg) : NULL; + Func_Base *fb = new_func_base(env->gwion->mp, cpy_type_decl(env->gwion->mp, base->td), partial_name(env, loc.first), args, ae_flag_none, loc); + return fb; +} + +ANN static Exp partial_call(const Env env, Exp e) { + Exp base = NULL, arg; + uint32_t i = 0; + while(e) { + if(is_hole(env, e) || is_typed_hole(env, e)) { + char c[256]; + sprintf(c, "@%u", i++); + const Exp next = new_prim_id(env->gwion->mp, insert_symbol(c), e->pos); + if(base) arg = arg->next = next; + else arg = base = next; + } else { + const Exp next = cpy_exp(env->gwion->mp, e); + if(base) arg = arg->next = next; + else arg = base = next; + } + e = e->next; + } + return base; +} + + +ANN Func find_match(const Env env, Func func, const Exp exp, const bool implicit, + const bool specific) { + do { + Exp e = exp; + uint32_t i = 0; + Arg_List args = func->def->base->args; + uint32_t len = args ? args->len : 0; + while(e) { + if (i >= len) break; + const Arg *arg = mp_vector_at(args, Arg, i++); + if(!is_hole(env, e)) { + if(!is_typed_hole(env, e)) { + const Exp next = e->next; + e->next = NULL; + check_exp(env, e); + e->next = next; + } else + CHECK_OO((e->type = known_type(env, e->d.exp_cast.td))); + if (!func_match_inner(env, e, arg->type, implicit, specific)) break; + } + e = e->next; + } + if (!e && len == i) return func; + } while ((func = func->next)); + return NULL; +} + +ANN Func find_match_actual(const Env env, const Func up, const Exp args) { + Func func; + if ((func = find_match(env, up, args, false, true)) || + (func = find_match(env, up, args, true, true)) || + (func = find_match(env, up, args, false, true)) || + (func = find_match(env, up, args, true, false))) + return func; + return NULL; +} + +ANN static Func partial_match(const Env env, const Func up, const Exp args, const loc_t loc); + +ANN static void print_arg(Arg_List args) { + for(uint32_t i = 0; i < args->len; i++) { + Arg *arg = mp_vector_at(args, Arg, i); + gw_err("{G}%s{0} {/}%s{0}", arg->type ? arg->type->name : NULL, + arg->var_decl.xid ? s_name(arg->var_decl.xid) : ""); + if(i < args->len - 1) gw_err(", "); + } +} + +ANN void print_signature(const Func f) { + gw_err(" {-}(%s){0} ", f->name); + const Arg_List args = f->def->base->args; + if (args) + print_arg(args); + else + gw_err("{G}void{0}"); + gw_err("\n"); +} + +ANN void ambiguity(const Env env, Func f, const Exp args, const loc_t loc) { + print_signature(f); + while(f->next) { + const Func next = partial_match(env, f->next, args, loc); + if(next) print_signature(next); + f = f->next; + } +} + +ANN static Func partial_match(const Env env, const Func up, const Exp args, const loc_t loc) { + const Func f = find_match_actual(env, up, args); + if(f) { + if(f->next) { + const Func next = partial_match(env, f->next, args, loc); + if(next) { + gwerr_basic(_("can't resolve ambiguity"), _("in this partial application"), _("use typed holes: _ $ type"), env->name, loc, 0); + gw_err(_("\nthose functions could match:\n")); + print_signature(f); + ambiguity(env, next, args, loc); + env->context->error = true; + return NULL; + } + } + return f; + } + return NULL; +} + +ANN static Stmt partial_code(const Env env, const Exp efun, const Exp earg) { + Stmt_List slist = new_mp_vector(env->gwion->mp, sizeof(struct Stmt_), 1); + const Exp arg = partial_call(env, earg); + const Exp exp = new_exp_call(env->gwion->mp, efun, arg, efun->pos); + Stmt stmt = mp_vector_at(slist, struct Stmt_, 0); + stmt->stmt_type = ae_stmt_return; + stmt->d.stmt_exp.val = exp; + return new_stmt_code(env->gwion->mp, slist, efun->pos); +} + +ANN static uint32_t count_args_exp(Exp args) { + uint32_t i = 0; + while(args && ++i) args = args->next; + return i; +} + +ANN static uint32_t count_args_func(Func f, const uint32_t i) { + uint32_t max = 0; + while(f) { + const uint32_t len = f->def->base->args ? f->def->base->args->len : 0; + if(len > i && len > max) max = len; + f = f->next; + } + return max; +} + +ANN static Exp expand(const Env env, const Func func, const Exp e, const loc_t loc) { + const uint32_t i = count_args_exp(e); + const uint32_t max = count_args_func(func, i); + if(max > i) { + Exp args = e; + if(args) { + while(args->next) args = args->next; + args->next = new_prim_id(env->gwion->mp, insert_symbol("_"), loc); + return e; + } else return new_prim_id(env->gwion->mp, insert_symbol("_"), loc); + } + return NULL; +} + +ANN Type partial_type(const Env env, Exp_Call *const call) { + const Func f = partial_match(env, call->func->type->info->func, call->args, call->func->pos); + if(!f) { + const Exp e = expand(env, call->func->type->info->func, call->args, call->func->pos); + if(e) { + call->args = e; + return partial_type(env, call); + } + ERR_O(call->func->pos, _("no match found for partial application")); + } + Func_Base *const base = partial_base(env, f->def->base, call->args, call->func->pos); + const Stmt code = partial_code(env, call->func, call->args); + const Exp exp = exp_self(call); + exp->d.exp_lambda.def = new_func_def(env->gwion->mp, base, code); + exp->exp_type = ae_exp_lambda; + CHECK_OO(traverse_func_def(env, exp->d.exp_lambda.def)); + return exp->d.exp_lambda.def->base->func->value_ref->type; +} diff --git a/src/parse/scan2.c b/src/parse/scan2.c index b8a9f047..ff31b001 100644 --- a/src/parse/scan2.c +++ b/src/parse/scan2.c @@ -54,7 +54,8 @@ ANN static m_bool scan2_args(const Func_Def f) { Arg *arg = mp_vector_at(args, Arg, i); const Value v = arg->var_decl.value; v->from->offset = f->stack_depth; - f->stack_depth += v->type->size; + //f->stack_depth += v->type->size; + f->stack_depth += v->type ? v->type->size : SZ_INT; if (global) SET_FLAG(v, global); } return GW_OK; @@ -146,7 +147,6 @@ ANN static inline m_bool scan2_exp_binary(const Env env, const Exp_Binary *bin) { CHECK_BB(scan2_exp(env, bin->lhs)); CHECK_BB(scan2_exp(env, bin->rhs)); - if(bin->rhs->exp_type == ae_exp_call)bin->rhs->d.exp_call.apms = true; CHECK_BB(multi_decl(env, bin->lhs, bin->op)); return multi_decl(env, bin->rhs, bin->op); } diff --git a/src/parse/template.c b/src/parse/template.c index 69d3d53c..3cb6fcd1 100644 --- a/src/parse/template.c +++ b/src/parse/template.c @@ -132,8 +132,8 @@ ANN static Type _scan_type(const Env env, const Type t, Type_Decl *td) { Specialized_List sl = t->info->cdef->base.tmpl ? t->info->cdef->base.tmpl->list : NULL; for(uint32_t i = 0; i < tl->len; i++) { - Type_Decl *td = *mp_vector_at(tl, Type_Decl*, i); - DECL_OO(const Type, t, = known_type(env, td)); + Type_Decl *tmp = *mp_vector_at(tl, Type_Decl*, i); + DECL_OO(const Type, t, = known_type(env, tmp)); Specialized *spec = mp_vector_at(sl, Specialized, i); if(spec->traits) { Symbol missing = miss_traits(t, spec); diff --git a/tests/locale/locale.basic.gw b/tests/locale/locale.basic.gw new file mode 100644 index 00000000..4d4b4ee5 --- /dev/null +++ b/tests/locale/locale.basic.gw @@ -0,0 +1,3 @@ +#! [contains] 440 + +<<< `A4` >>>; diff --git a/tests/locale/locale_default_args.gw b/tests/locale/locale_default_args.gw new file mode 100644 index 00000000..2272ce05 --- /dev/null +++ b/tests/locale/locale_default_args.gw @@ -0,0 +1,5 @@ +#! [contains] 432 +locale Test(float base : 432) { return base; } + +#locale Test +<<< `foo` >>>; diff --git a/tests/locale/locale_with_args.gw b/tests/locale/locale_with_args.gw new file mode 100644 index 00000000..3977e718 --- /dev/null +++ b/tests/locale/locale_with_args.gw @@ -0,0 +1,5 @@ +#! [contains] 440 +locale Test(float base : 432) { return base; } + +#locale Test 440 +<<< `foo` >>>; diff --git a/tests/apms/apms1.gw b/tests/partial/apms1.gw similarity index 100% rename from tests/apms/apms1.gw rename to tests/partial/apms1.gw diff --git a/tests/apms/apms2.gw b/tests/partial/apms2.gw similarity index 100% rename from tests/apms/apms2.gw rename to tests/partial/apms2.gw diff --git a/tests/apms/apms3.gw b/tests/partial/apms3.gw similarity index 100% rename from tests/apms/apms3.gw rename to tests/partial/apms3.gw diff --git a/tests/partial/partial_ambiguous.gw b/tests/partial/partial_ambiguous.gw new file mode 100644 index 00000000..3a273dd1 --- /dev/null +++ b/tests/partial/partial_ambiguous.gw @@ -0,0 +1,4 @@ +#! [contains] can't resolve ambiguity +fun void test(int i, int j) {} +fun void test(int i, string s) {} +test(_, _); diff --git a/tests/partial/partial_no_match.gw b/tests/partial/partial_no_match.gw new file mode 100644 index 00000000..8daa922e --- /dev/null +++ b/tests/partial/partial_no_match.gw @@ -0,0 +1,3 @@ +#! [contains] no match found for partial application +fun void test(int i) {} +test(_, _); diff --git a/tests/partial/partial_not_used.gw b/tests/partial/partial_not_used.gw new file mode 100644 index 00000000..936be2b4 --- /dev/null +++ b/tests/partial/partial_not_used.gw @@ -0,0 +1,2 @@ +#! [contains] Partial application not used +me.arg(_); diff --git a/util b/util index 34744e73..2b55ce35 160000 --- a/util +++ b/util @@ -1 +1 @@ -Subproject commit 34744e7349965d104709563bba8861fadf544bd1 +Subproject commit 2b55ce354595c33d5cee4a90085feb2a31be1572