Skip to content

Commit b5f463c

Browse files
yegappanchrisbra
authored andcommitted
patch 9.1.1116: Vim9: super not supported in lambda expressions
Problem: Vim9: super not supported in lambda expressions (Aliaksei Budavei) Solution: Support using the super keyword in a closure in an instance method (Yegappan Lakshmanan) fixes: #16586 closes: #16647 Signed-off-by: Yegappan Lakshmanan <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent 44831e4 commit b5f463c

4 files changed

Lines changed: 190 additions & 104 deletions

File tree

src/testdir/test_vim9_class.vim

Lines changed: 158 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -3059,27 +3059,6 @@ def Test_class_extends()
30593059
END
30603060
v9.CheckSourceFailure(lines, 'E1354: Cannot extend SomeVar', 5)
30613061

3062-
lines =<< trim END
3063-
vim9script
3064-
class Base
3065-
var name: string
3066-
def ToString(): string
3067-
return this.name
3068-
enddef
3069-
endclass
3070-
3071-
class Child extends Base
3072-
var age: number
3073-
def ToString(): string
3074-
return super.ToString() .. ': ' .. this.age
3075-
enddef
3076-
endclass
3077-
3078-
var o = Child.new('John', 42)
3079-
assert_equal('John: 42', o.ToString())
3080-
END
3081-
v9.CheckSourceSuccess(lines)
3082-
30833062
lines =<< trim END
30843063
vim9script
30853064
class Child
@@ -3094,49 +3073,6 @@ def Test_class_extends()
30943073
END
30953074
v9.CheckSourceFailure(lines, 'E1355: Duplicate function: ToString', 9)
30963075

3097-
lines =<< trim END
3098-
vim9script
3099-
class Child
3100-
var age: number
3101-
def ToString(): string
3102-
return super .ToString() .. ': ' .. this.age
3103-
enddef
3104-
endclass
3105-
var o = Child.new(42)
3106-
echo o.ToString()
3107-
END
3108-
v9.CheckSourceFailure(lines, 'E1356: "super" must be followed by a dot', 1)
3109-
3110-
lines =<< trim END
3111-
vim9script
3112-
class Base
3113-
var name: string
3114-
def ToString(): string
3115-
return this.name
3116-
enddef
3117-
endclass
3118-
3119-
var age = 42
3120-
def ToString(): string
3121-
return super.ToString() .. ': ' .. age
3122-
enddef
3123-
echo ToString()
3124-
END
3125-
v9.CheckSourceFailure(lines, 'E1357: Using "super" not in a class method', 1)
3126-
3127-
lines =<< trim END
3128-
vim9script
3129-
class Child
3130-
var age: number
3131-
def ToString(): string
3132-
return super.ToString() .. ': ' .. this.age
3133-
enddef
3134-
endclass
3135-
var o = Child.new(42)
3136-
echo o.ToString()
3137-
END
3138-
v9.CheckSourceFailure(lines, 'E1358: Using "super" not in a child class', 1)
3139-
31403076
lines =<< trim END
31413077
vim9script
31423078
class Base
@@ -3244,28 +3180,6 @@ def Test_using_base_class()
32443180
END
32453181
v9.CheckSourceSuccess(lines)
32463182
unlet g:result
3247-
3248-
# Using super, Child invokes Base method which has optional arg. #12471
3249-
lines =<< trim END
3250-
vim9script
3251-
3252-
class Base
3253-
var success: bool = false
3254-
def Method(arg = 0)
3255-
this.success = true
3256-
enddef
3257-
endclass
3258-
3259-
class Child extends Base
3260-
def new()
3261-
super.Method()
3262-
enddef
3263-
endclass
3264-
3265-
var obj = Child.new()
3266-
assert_equal(true, obj.success)
3267-
END
3268-
v9.CheckSourceSuccess(lines)
32693183
enddef
32703184

32713185
" Test for using a method from the super class
@@ -12409,4 +12323,162 @@ def Test_protected_new_method()
1240912323
v9.CheckSourceSuccess(lines)
1241012324
enddef
1241112325

12326+
" Test for using 'super' in a closure function inside an object method
12327+
def Test_super_in_closure()
12328+
var lines =<< trim END
12329+
vim9script
12330+
12331+
class A
12332+
const _value: number
12333+
12334+
def Fn(): func(any): number
12335+
return (_: any) => this._value
12336+
enddef
12337+
endclass
12338+
12339+
class B extends A
12340+
def Fn(): func(any): number
12341+
return (_: any) => super._value
12342+
enddef
12343+
endclass
12344+
12345+
assert_equal(100, A.new(100).Fn()(null))
12346+
assert_equal(200, B.new(200).Fn()(null))
12347+
END
12348+
v9.CheckSourceSuccess(lines)
12349+
enddef
12350+
12351+
" Test for using 'super' to access methods and variables
12352+
def Test_super_keyword()
12353+
var lines =<< trim END
12354+
vim9script
12355+
class Base
12356+
var name: string
12357+
def ToString(): string
12358+
return this.name
12359+
enddef
12360+
endclass
12361+
12362+
class Child extends Base
12363+
var age: number
12364+
def ToString(): string
12365+
return super.ToString() .. ': ' .. this.age
12366+
enddef
12367+
endclass
12368+
12369+
var o = Child.new('John', 42)
12370+
assert_equal('John: 42', o.ToString())
12371+
END
12372+
v9.CheckSourceSuccess(lines)
12373+
12374+
lines =<< trim END
12375+
vim9script
12376+
class Child
12377+
var age: number
12378+
def ToString(): string
12379+
return super .ToString() .. ': ' .. this.age
12380+
enddef
12381+
endclass
12382+
var o = Child.new(42)
12383+
echo o.ToString()
12384+
END
12385+
v9.CheckSourceFailure(lines, 'E1356: "super" must be followed by a dot', 1)
12386+
12387+
lines =<< trim END
12388+
vim9script
12389+
class Base
12390+
var name: string
12391+
def ToString(): string
12392+
return this.name
12393+
enddef
12394+
endclass
12395+
12396+
var age = 42
12397+
def ToString(): string
12398+
return super.ToString() .. ': ' .. age
12399+
enddef
12400+
echo ToString()
12401+
END
12402+
v9.CheckSourceFailure(lines, 'E1357: Using "super" not in a class method', 1)
12403+
12404+
lines =<< trim END
12405+
vim9script
12406+
class Child
12407+
var age: number
12408+
def ToString(): string
12409+
return super.ToString() .. ': ' .. this.age
12410+
enddef
12411+
endclass
12412+
var o = Child.new(42)
12413+
echo o.ToString()
12414+
END
12415+
v9.CheckSourceFailure(lines, 'E1358: Using "super" not in a child class', 1)
12416+
12417+
# Using super, Child invokes Base method which has optional arg. #12471
12418+
lines =<< trim END
12419+
vim9script
12420+
12421+
class Base
12422+
var success: bool = false
12423+
def Method(arg = 0)
12424+
this.success = true
12425+
enddef
12426+
endclass
12427+
12428+
class Child extends Base
12429+
def new()
12430+
super.Method()
12431+
enddef
12432+
endclass
12433+
12434+
var obj = Child.new()
12435+
assert_equal(true, obj.success)
12436+
END
12437+
v9.CheckSourceSuccess(lines)
12438+
12439+
# Using 'super' to access an object variable in the parent
12440+
lines =<< trim END
12441+
vim9script
12442+
12443+
class A
12444+
var foo: string = 'xxx'
12445+
endclass
12446+
12447+
class B extends A
12448+
def GetString(): string
12449+
return super.foo
12450+
enddef
12451+
endclass
12452+
12453+
var b: B = B.new()
12454+
echo b.GetString()
12455+
END
12456+
v9.CheckSourceSuccess(lines)
12457+
12458+
# Using super to access an overriden method in the parent class
12459+
lines =<< trim END
12460+
vim9script
12461+
12462+
class A
12463+
def Foo(): string
12464+
return 'A.Foo'
12465+
enddef
12466+
endclass
12467+
12468+
class B extends A
12469+
def Foo(): string
12470+
return 'B.Foo'
12471+
enddef
12472+
12473+
def Bar(): string
12474+
return $'{super.Foo()} {this.Foo()}'
12475+
enddef
12476+
endclass
12477+
12478+
var b = B.new()
12479+
assert_equal('A.Foo B.Foo', b.Bar())
12480+
END
12481+
v9.CheckSourceSuccess(lines)
12482+
enddef
12483+
1241212484
" 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+
1116,
707709
/**/
708710
1115,
709711
/**/

src/vim9compile.c

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -843,27 +843,21 @@ find_imported(char_u *name, size_t len, int load)
843843
imported_T *
844844
find_imported_from_extends(cctx_T *cctx, char_u *name, size_t len, int load)
845845
{
846-
imported_T *ret = NULL;
847-
class_T *cl_extends;
848-
849846
if (cctx == NULL || cctx->ctx_ufunc == NULL
850847
|| cctx->ctx_ufunc->uf_class == NULL)
851848
return NULL;
852849

853-
cl_extends = cctx->ctx_ufunc->uf_class->class_extends;
854-
855-
if (cl_extends == NULL || cl_extends->class_class_function_count_child <= 0)
850+
class_T *cl_extends = cctx->ctx_ufunc->uf_class->class_extends;
851+
if (cl_extends == NULL
852+
|| cl_extends->class_class_function_count_child <= 0)
856853
return NULL;
857-
else
858-
{
859-
sctx_T current_sctx_save = current_sctx;
860854

861-
current_sctx = cl_extends->class_class_functions[0]->uf_script_ctx;
862-
ret = find_imported(name, len, load);
863-
current_sctx = current_sctx_save;
855+
sctx_T current_sctx_save = current_sctx;
856+
current_sctx = cl_extends->class_class_functions[0]->uf_script_ctx;
857+
imported_T *ret = find_imported(name, len, load);
858+
current_sctx = current_sctx_save;
864859

865-
return ret;
866-
}
860+
return ret;
867861
}
868862

869863
/*

src/vim9expr.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
291291
}
292292

293293
class_T *cl = type->tt_class;
294-
int is_super = type->tt_flags & TTFLAG_SUPER;
294+
int is_super = ((type->tt_flags & TTFLAG_SUPER) == TTFLAG_SUPER);
295295
if (type == &t_super)
296296
{
297297
if (cctx->ctx_ufunc == NULL || cctx->ctx_ufunc->uf_class == NULL)
@@ -693,6 +693,26 @@ generate_funcref(cctx_T *cctx, char_u *name, int has_g_prefix)
693693
return generate_PUSHFUNC(cctx, ufunc->uf_name, ufunc->uf_func_type, TRUE);
694694
}
695695

696+
/*
697+
* Returns TRUE if compiling a class method.
698+
*/
699+
static int
700+
compiling_a_class_method(cctx_T *cctx)
701+
{
702+
// For an object method, the FC_OBJECT flag will be set.
703+
// For a constructor method, the FC_NEW flag will be set.
704+
// Excluding these methods, the others are class methods.
705+
// When compiling a closure function inside an object method,
706+
// cctx->ctx_outer->ctx_func will point to the object method.
707+
return cctx->ctx_ufunc != NULL
708+
&& (cctx->ctx_ufunc->uf_flags & (FC_OBJECT|FC_NEW)) == 0
709+
&& (cctx->ctx_outer == NULL
710+
|| cctx->ctx_outer->ctx_ufunc == NULL
711+
|| cctx->ctx_outer->ctx_ufunc->uf_class == NULL
712+
|| (cctx->ctx_outer->ctx_ufunc->uf_flags
713+
& (FC_OBJECT|FC_NEW)) == 0);
714+
}
715+
696716
/*
697717
* Compile a variable name into a load instruction.
698718
* "end" points to just after the name.
@@ -807,9 +827,7 @@ compile_load(
807827
if (name == NULL)
808828
return FAIL;
809829

810-
if (STRCMP(name, "super") == 0
811-
&& cctx->ctx_ufunc != NULL
812-
&& (cctx->ctx_ufunc->uf_flags & (FC_OBJECT|FC_NEW)) == 0)
830+
if (STRCMP(name, "super") == 0 && compiling_a_class_method(cctx))
813831
{
814832
// super.SomeFunc() in a class function: push &t_super type, this
815833
// is recognized in compile_subscript().

0 commit comments

Comments
 (0)