# HG changeset patch # User Bram Moolenaar # Date 1590357604 -7200 # Node ID cb4831fa7e25b3f74412f0c3a01ad8a9bea91290 # Parent 6eb8347bcf1a4ce52498d5e5203a182710979a10 patch 8.2.0820: Vim9: function type isn't set until compiled Commit: https://github.com/vim/vim/commit/6ff71d8b7fbdf667a2f119a2487302e240961816 Author: Bram Moolenaar Date: Sun May 24 23:45:24 2020 +0200 patch 8.2.0820: Vim9: function type isn't set until compiled Problem: Vim9: function type isn't set until compiled. Solution: Set function type early. diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -10,6 +10,7 @@ char_u *to_name_const_end(char_u *arg); int assignment_len(char_u *p, int *heredoc); int check_vim9_unlet(char_u *name); int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx); +void set_function_type(ufunc_T *ufunc); void delete_instr(isn_T *isn); void delete_def_function(ufunc_T *ufunc); void free_def_functions(void); diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -560,8 +560,7 @@ def Test_func_type_part() RefVoid = FuncNoArgNoRet RefVoid = FuncOneArgNoRet CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number') -" TODO: these should fail -" CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string') + CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string') let RefAny: func(): any RefAny = FuncNoArgRetNumber @@ -573,8 +572,7 @@ def Test_func_type_part() RefNr = FuncNoArgRetNumber RefNr = FuncOneArgRetNumber CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()') -" TODO: should fail -" CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string') + CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string') let RefStr: func: string RefStr = FuncNoArgRetString @@ -589,10 +587,9 @@ def Test_func_type_fails() CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number') CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)') CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): number') -" TODO: these don't fail -" CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)') -" CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)') -" CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)') + CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)') + CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)') + CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)') call CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:') call CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:') diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3284,6 +3284,9 @@ def_function(exarg_T *eap, char_u *name_ is_export = FALSE; } + if (eap->cmdidx == CMD_def) + set_function_type(fp); + goto ret_free; erret: diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 820, +/**/ 819, /**/ 818, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -6763,54 +6763,6 @@ compile_def_function(ufunc_T *ufunc, int ufunc->uf_flags |= FC_CLOSURE; } - { - int varargs = ufunc->uf_va_name != NULL; - int argcount = ufunc->uf_args.ga_len; - - // Create a type for the function, with the return type and any - // argument types. - // A vararg is included in uf_args.ga_len but not in uf_arg_types. - // The type is included in "tt_args". - if (argcount > 0 || varargs) - { - ufunc->uf_func_type = alloc_func_type(ufunc->uf_ret_type, - argcount, &ufunc->uf_type_list); - // Add argument types to the function type. - if (func_type_add_arg_types(ufunc->uf_func_type, - argcount + varargs, - &ufunc->uf_type_list) == FAIL) - { - ret = FAIL; - goto erret; - } - ufunc->uf_func_type->tt_argcount = argcount + varargs; - ufunc->uf_func_type->tt_min_argcount = - argcount - ufunc->uf_def_args.ga_len; - if (ufunc->uf_arg_types == NULL) - { - int i; - - // lambda does not have argument types. - for (i = 0; i < argcount; ++i) - ufunc->uf_func_type->tt_args[i] = &t_any; - } - else - mch_memmove(ufunc->uf_func_type->tt_args, - ufunc->uf_arg_types, sizeof(type_T *) * argcount); - if (varargs) - { - ufunc->uf_func_type->tt_args[argcount] = - ufunc->uf_va_type == NULL ? &t_any : ufunc->uf_va_type; - ufunc->uf_func_type->tt_flags = TTFLAG_VARARGS; - } - } - else - // No arguments, can use a predefined type. - ufunc->uf_func_type = get_func_type(ufunc->uf_ret_type, - argcount, &ufunc->uf_type_list); - - } - ret = OK; erret: @@ -6847,6 +6799,53 @@ erret: return ret; } + void +set_function_type(ufunc_T *ufunc) +{ + int varargs = ufunc->uf_va_name != NULL; + int argcount = ufunc->uf_args.ga_len; + + // Create a type for the function, with the return type and any + // argument types. + // A vararg is included in uf_args.ga_len but not in uf_arg_types. + // The type is included in "tt_args". + if (argcount > 0 || varargs) + { + ufunc->uf_func_type = alloc_func_type(ufunc->uf_ret_type, + argcount, &ufunc->uf_type_list); + // Add argument types to the function type. + if (func_type_add_arg_types(ufunc->uf_func_type, + argcount + varargs, + &ufunc->uf_type_list) == FAIL) + return; + ufunc->uf_func_type->tt_argcount = argcount + varargs; + ufunc->uf_func_type->tt_min_argcount = + argcount - ufunc->uf_def_args.ga_len; + if (ufunc->uf_arg_types == NULL) + { + int i; + + // lambda does not have argument types. + for (i = 0; i < argcount; ++i) + ufunc->uf_func_type->tt_args[i] = &t_any; + } + else + mch_memmove(ufunc->uf_func_type->tt_args, + ufunc->uf_arg_types, sizeof(type_T *) * argcount); + if (varargs) + { + ufunc->uf_func_type->tt_args[argcount] = + ufunc->uf_va_type == NULL ? &t_any : ufunc->uf_va_type; + ufunc->uf_func_type->tt_flags = TTFLAG_VARARGS; + } + } + else + // No arguments, can use a predefined type. + ufunc->uf_func_type = get_func_type(ufunc->uf_ret_type, + argcount, &ufunc->uf_type_list); +} + + /* * Delete an instruction, free what it contains. */