Skip to content

Commit 778ada4

Browse files
yegappanchrisbra
authored andcommitted
patch 9.1.1119: Vim9: Not able to use an autoloaded class from another autoloaded script
Problem: Vim9: Not able to use an autoloaded class from another autoloaded script (Elliot) Solution: make it work (Yegappan Lakshmanan) fixes: #15031 closes: #16652 Signed-off-by: Yegappan Lakshmanan <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent b34a688 commit 778ada4

6 files changed

Lines changed: 131 additions & 33 deletions

File tree

src/errors.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3552,7 +3552,8 @@ EXTERN char e_type_can_only_be_defined_in_vim9_script[]
35523552
INIT(= N_("E1393: Type can only be defined in Vim9 script"));
35533553
EXTERN char e_type_name_must_start_with_uppercase_letter_str[]
35543554
INIT(= N_("E1394: Type name must start with an uppercase letter: %s"));
3555-
// E1395 unused
3555+
EXTERN char e_using_null_class[]
3556+
INIT(= N_("E1395: Using a null class"));
35563557
EXTERN char e_typealias_already_exists_for_str[]
35573558
INIT(= N_("E1396: Type alias \"%s\" already exists"));
35583559
EXTERN char e_missing_typealias_name[]

src/testdir/test_vim9_class.vim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ def Test_using_null_class()
544544
var lines =<< trim END
545545
@_ = null_class.member
546546
END
547-
v9.CheckDefExecAndScriptFailure(lines, ['E715: Dictionary required', 'E1363: Incomplete type'])
547+
v9.CheckDefExecAndScriptFailure(lines, ['E1395: Using a null class', 'E1363: Incomplete type'])
548548

549549
# Test for using a null class as a value
550550
lines =<< trim END

src/testdir/test_vim9_import.vim

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3494,4 +3494,75 @@ def Test_vim9_import_and_class_extends_2()
34943494
&rtp = save_rtp
34953495
enddef
34963496

3497+
" Test for using an autoloaded class from another autoloaded script
3498+
def Test_class_from_auloaded_script()
3499+
mkdir('Xdir', 'R')
3500+
var save_rtp = &rtp
3501+
&rtp = getcwd()
3502+
exe 'set rtp^=' .. getcwd() .. '/Xdir'
3503+
3504+
mkdir('Xdir/autoload/SomeClass/bar', 'p')
3505+
3506+
var lines =<< trim END
3507+
vim9script
3508+
3509+
export class Baz
3510+
static var v1: string = "v1"
3511+
var v2: string = "v2"
3512+
def GetName(): string
3513+
return "baz"
3514+
enddef
3515+
endclass
3516+
END
3517+
writefile(lines, 'Xdir/autoload/SomeClass/bar/baz.vim', 'D')
3518+
3519+
lines =<< trim END
3520+
vim9script
3521+
3522+
import autoload './bar/baz.vim'
3523+
3524+
export def MyTestFoo(): string
3525+
assert_fails('var x = baz.Baz.NonExisting()', 'E1325: Method "NonExisting" not found in class "Baz"')
3526+
assert_fails('var x = baz.Baz.foobar', 'E1337: Class variable "foobar" not found in class "Baz"')
3527+
3528+
const instance = baz.Baz.new()
3529+
return $'{instance.GetName()} {baz.Baz.v1} {instance.v2}'
3530+
enddef
3531+
END
3532+
writefile(lines, 'Xdir/autoload/SomeClass/foo.vim', 'D')
3533+
3534+
lines =<< trim END
3535+
vim9script
3536+
3537+
import autoload 'SomeClass/foo.vim'
3538+
import autoload 'SomeClass/bar/baz.vim'
3539+
3540+
def NotInAutoload()
3541+
# Use non-existing class method and variable
3542+
assert_fails('var x = baz.Baz.NonExisting()', 'E1325: Method "NonExisting" not found in class "Baz"')
3543+
3544+
var caught_exception = false
3545+
try
3546+
var x = baz.Baz.foobar
3547+
catch /E1337: Class variable "foobar" not found in class "Baz"/
3548+
caught_exception = true
3549+
endtry
3550+
assert_true(caught_exception)
3551+
3552+
const instance = baz.Baz.new()
3553+
assert_equal("baz v1 v2", $'{instance.GetName()} {baz.Baz.v1} {instance.v2}')
3554+
enddef
3555+
3556+
def InAutoload()
3557+
assert_equal("baz v1 v2", foo.MyTestFoo())
3558+
enddef
3559+
3560+
NotInAutoload()
3561+
InAutoload()
3562+
END
3563+
v9.CheckScriptSuccess(lines)
3564+
3565+
&rtp = save_rtp
3566+
enddef
3567+
34973568
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ static char *(features[]) =
704704

705705
static int included_patches[] =
706706
{ /* Add new patch number below this line */
707+
/**/
708+
1119,
707709
/**/
708710
1118,
709711
/**/

src/vim9class.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2053,8 +2053,7 @@ ex_class(exarg_T *eap)
20532053
tv.v_type = VAR_CLASS;
20542054
tv.vval.v_class = cl;
20552055
SOURCING_LNUM = start_lnum;
2056-
int rc = set_var_const(cl->class_name, current_sctx.sc_sid,
2057-
NULL, &tv, FALSE, 0, 0);
2056+
int rc = set_var_const(cl->class_name, 0, NULL, &tv, FALSE, 0, 0);
20582057
if (rc == FAIL)
20592058
goto cleanup;
20602059

@@ -2874,7 +2873,7 @@ ex_type(exarg_T *eap)
28742873
tv.vval.v_class = type->tt_class;
28752874
++tv.vval.v_class->class_refcount;
28762875
}
2877-
set_var_const(name_start, current_sctx.sc_sid, NULL, &tv, FALSE,
2876+
set_var_const(name_start, 0, NULL, &tv, FALSE,
28782877
ASSIGN_CONST | ASSIGN_FINAL, 0);
28792878

28802879
done:

src/vim9execute.c

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3162,34 +3162,53 @@ object_required_error(typval_T *tv)
31623162
}
31633163

31643164
/*
3165-
* Accessing the member of an object stored in a variable of type "any".
3165+
* Accessing the variable or method of an object or a class stored in a
3166+
* variable of type "any".
31663167
* Returns OK if the member variable is present.
31673168
* Returns FAIL if the variable is not found.
31683169
*/
31693170
static int
3170-
any_var_get_obj_member(class_T *current_class, isn_T *iptr, typval_T *tv)
3171+
var_any_get_oc_member(class_T *current_class, isn_T *iptr, typval_T *tv)
31713172
{
3172-
object_T *obj = tv->vval.v_object;
3173+
int is_object = tv->v_type == VAR_OBJECT;
3174+
class_T *tv_cl;
3175+
object_T *obj = NULL;
31733176
typval_T mtv;
31743177

3175-
if (obj == NULL)
3178+
if (is_object)
31763179
{
3177-
SOURCING_LNUM = iptr->isn_lnum;
3178-
emsg(_(e_using_null_object));
3179-
return FAIL;
3180+
obj = tv->vval.v_object;
3181+
if (obj == NULL)
3182+
{
3183+
SOURCING_LNUM = iptr->isn_lnum;
3184+
emsg(_(e_using_null_object));
3185+
return FAIL;
3186+
}
3187+
tv_cl = obj->obj_class;
3188+
}
3189+
else
3190+
{
3191+
tv_cl = tv->vval.v_class;
3192+
if (tv_cl == NULL)
3193+
{
3194+
SOURCING_LNUM = iptr->isn_lnum;
3195+
emsg(_(e_using_null_class));
3196+
return FAIL;
3197+
}
31803198
}
31813199

3182-
// get_member_tv() needs the object information in the typval argument.
3183-
// So set the object information.
3200+
// get_member_tv() needs the class/object information in the typval
3201+
// argument. So set the object information.
31843202
copy_tv(tv, &mtv);
31853203

3186-
// 'name' can either be a object variable or a object method
3204+
// 'name' can either be an instance or class variable or method
31873205
int namelen = (int)STRLEN(iptr->isn_arg.string);
31883206
int save_did_emsg = did_emsg;
31893207

3190-
if (get_member_tv(obj->obj_class, TRUE, iptr->isn_arg.string, namelen,
3208+
if (get_member_tv(tv_cl, is_object, iptr->isn_arg.string, namelen,
31913209
current_class, &mtv) == OK)
31923210
{
3211+
// instance or class variable
31933212
copy_tv(&mtv, tv);
31943213
clear_tv(&mtv);
31953214
return OK;
@@ -3198,31 +3217,36 @@ any_var_get_obj_member(class_T *current_class, isn_T *iptr, typval_T *tv)
31983217
if (did_emsg != save_did_emsg)
31993218
return FAIL;
32003219

3201-
// could be a member function
3202-
ufunc_T *obj_method;
3203-
int obj_method_idx;
3220+
// could be a class or instance method
3221+
ufunc_T *oc_method;
3222+
int oc_method_idx;
32043223

3205-
obj_method = method_lookup(obj->obj_class, VAR_OBJECT,
3206-
iptr->isn_arg.string, namelen,
3207-
&obj_method_idx);
3208-
if (obj_method == NULL)
3224+
oc_method = method_lookup(tv_cl, tv->v_type, iptr->isn_arg.string,
3225+
namelen, &oc_method_idx);
3226+
if (oc_method == NULL)
32093227
{
3228+
char *msg;
3229+
32103230
SOURCING_LNUM = iptr->isn_lnum;
3211-
semsg(_(e_variable_not_found_on_object_str_str), iptr->isn_arg.string,
3212-
obj->obj_class->class_name);
3231+
if (is_object)
3232+
msg = e_variable_not_found_on_object_str_str;
3233+
else
3234+
msg = e_class_variable_str_not_found_in_class_str;
3235+
semsg(_(msg), iptr->isn_arg.string, tv_cl->class_name);
32133236
return FAIL;
32143237
}
32153238

32163239
// Protected methods are not accessible outside the class
3217-
if (*obj_method->uf_name == '_'
3218-
&& !class_instance_of(current_class, obj->obj_class))
3240+
if (*oc_method->uf_name == '_'
3241+
&& !class_instance_of(current_class, tv_cl))
32193242
{
3220-
semsg(_(e_cannot_access_protected_method_str), obj_method->uf_name);
3243+
semsg(_(e_cannot_access_protected_method_str), oc_method->uf_name);
32213244
return FAIL;
32223245
}
32233246

3224-
// Create a partial for the member function
3225-
if (obj_method_to_partial_tv(obj, obj_method, tv) == FAIL)
3247+
// Create a partial for the instance or class method
3248+
if (obj_method_to_partial_tv(is_object ? obj : NULL, oc_method, tv)
3249+
== FAIL)
32263250
return FAIL;
32273251

32283252
return OK;
@@ -5671,15 +5695,16 @@ exec_instructions(ectx_T *ectx)
56715695

56725696
tv = STACK_TV_BOT(-1);
56735697

5674-
if (tv->v_type == VAR_OBJECT)
5698+
if (tv->v_type == VAR_OBJECT
5699+
|| tv->v_type == VAR_CLASS)
56755700
{
56765701
if (dict_stack_save(tv) == FAIL)
56775702
goto on_fatal_error;
56785703

56795704
ufunc_T *ufunc = (((dfunc_T *)def_functions.ga_data)
56805705
+ ectx->ec_dfunc_idx)->df_ufunc;
5681-
// Class object (not a Dict)
5682-
if (any_var_get_obj_member(ufunc->uf_class, iptr, tv) == FAIL)
5706+
// Class or an object (not a Dict)
5707+
if (var_any_get_oc_member(ufunc->uf_class, iptr, tv) == FAIL)
56835708
goto on_error;
56845709
}
56855710
else

0 commit comments

Comments
 (0)