mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
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 <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
44831e4bea
commit
b5f463ce4f
@ -3059,27 +3059,6 @@ def Test_class_extends()
|
|||||||
END
|
END
|
||||||
v9.CheckSourceFailure(lines, 'E1354: Cannot extend SomeVar', 5)
|
v9.CheckSourceFailure(lines, 'E1354: Cannot extend SomeVar', 5)
|
||||||
|
|
||||||
lines =<< trim END
|
|
||||||
vim9script
|
|
||||||
class Base
|
|
||||||
var name: string
|
|
||||||
def ToString(): string
|
|
||||||
return this.name
|
|
||||||
enddef
|
|
||||||
endclass
|
|
||||||
|
|
||||||
class Child extends Base
|
|
||||||
var age: number
|
|
||||||
def ToString(): string
|
|
||||||
return super.ToString() .. ': ' .. this.age
|
|
||||||
enddef
|
|
||||||
endclass
|
|
||||||
|
|
||||||
var o = Child.new('John', 42)
|
|
||||||
assert_equal('John: 42', o.ToString())
|
|
||||||
END
|
|
||||||
v9.CheckSourceSuccess(lines)
|
|
||||||
|
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
class Child
|
class Child
|
||||||
@ -3094,49 +3073,6 @@ def Test_class_extends()
|
|||||||
END
|
END
|
||||||
v9.CheckSourceFailure(lines, 'E1355: Duplicate function: ToString', 9)
|
v9.CheckSourceFailure(lines, 'E1355: Duplicate function: ToString', 9)
|
||||||
|
|
||||||
lines =<< trim END
|
|
||||||
vim9script
|
|
||||||
class Child
|
|
||||||
var age: number
|
|
||||||
def ToString(): string
|
|
||||||
return super .ToString() .. ': ' .. this.age
|
|
||||||
enddef
|
|
||||||
endclass
|
|
||||||
var o = Child.new(42)
|
|
||||||
echo o.ToString()
|
|
||||||
END
|
|
||||||
v9.CheckSourceFailure(lines, 'E1356: "super" must be followed by a dot', 1)
|
|
||||||
|
|
||||||
lines =<< trim END
|
|
||||||
vim9script
|
|
||||||
class Base
|
|
||||||
var name: string
|
|
||||||
def ToString(): string
|
|
||||||
return this.name
|
|
||||||
enddef
|
|
||||||
endclass
|
|
||||||
|
|
||||||
var age = 42
|
|
||||||
def ToString(): string
|
|
||||||
return super.ToString() .. ': ' .. age
|
|
||||||
enddef
|
|
||||||
echo ToString()
|
|
||||||
END
|
|
||||||
v9.CheckSourceFailure(lines, 'E1357: Using "super" not in a class method', 1)
|
|
||||||
|
|
||||||
lines =<< trim END
|
|
||||||
vim9script
|
|
||||||
class Child
|
|
||||||
var age: number
|
|
||||||
def ToString(): string
|
|
||||||
return super.ToString() .. ': ' .. this.age
|
|
||||||
enddef
|
|
||||||
endclass
|
|
||||||
var o = Child.new(42)
|
|
||||||
echo o.ToString()
|
|
||||||
END
|
|
||||||
v9.CheckSourceFailure(lines, 'E1358: Using "super" not in a child class', 1)
|
|
||||||
|
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
class Base
|
class Base
|
||||||
@ -3244,28 +3180,6 @@ def Test_using_base_class()
|
|||||||
END
|
END
|
||||||
v9.CheckSourceSuccess(lines)
|
v9.CheckSourceSuccess(lines)
|
||||||
unlet g:result
|
unlet g:result
|
||||||
|
|
||||||
# Using super, Child invokes Base method which has optional arg. #12471
|
|
||||||
lines =<< trim END
|
|
||||||
vim9script
|
|
||||||
|
|
||||||
class Base
|
|
||||||
var success: bool = false
|
|
||||||
def Method(arg = 0)
|
|
||||||
this.success = true
|
|
||||||
enddef
|
|
||||||
endclass
|
|
||||||
|
|
||||||
class Child extends Base
|
|
||||||
def new()
|
|
||||||
super.Method()
|
|
||||||
enddef
|
|
||||||
endclass
|
|
||||||
|
|
||||||
var obj = Child.new()
|
|
||||||
assert_equal(true, obj.success)
|
|
||||||
END
|
|
||||||
v9.CheckSourceSuccess(lines)
|
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
" Test for using a method from the super class
|
" Test for using a method from the super class
|
||||||
@ -12409,4 +12323,162 @@ def Test_protected_new_method()
|
|||||||
v9.CheckSourceSuccess(lines)
|
v9.CheckSourceSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
" Test for using 'super' in a closure function inside an object method
|
||||||
|
def Test_super_in_closure()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class A
|
||||||
|
const _value: number
|
||||||
|
|
||||||
|
def Fn(): func(any): number
|
||||||
|
return (_: any) => this._value
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class B extends A
|
||||||
|
def Fn(): func(any): number
|
||||||
|
return (_: any) => super._value
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
assert_equal(100, A.new(100).Fn()(null))
|
||||||
|
assert_equal(200, B.new(200).Fn()(null))
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
" Test for using 'super' to access methods and variables
|
||||||
|
def Test_super_keyword()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class Base
|
||||||
|
var name: string
|
||||||
|
def ToString(): string
|
||||||
|
return this.name
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Child extends Base
|
||||||
|
var age: number
|
||||||
|
def ToString(): string
|
||||||
|
return super.ToString() .. ': ' .. this.age
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var o = Child.new('John', 42)
|
||||||
|
assert_equal('John: 42', o.ToString())
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class Child
|
||||||
|
var age: number
|
||||||
|
def ToString(): string
|
||||||
|
return super .ToString() .. ': ' .. this.age
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
var o = Child.new(42)
|
||||||
|
echo o.ToString()
|
||||||
|
END
|
||||||
|
v9.CheckSourceFailure(lines, 'E1356: "super" must be followed by a dot', 1)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class Base
|
||||||
|
var name: string
|
||||||
|
def ToString(): string
|
||||||
|
return this.name
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var age = 42
|
||||||
|
def ToString(): string
|
||||||
|
return super.ToString() .. ': ' .. age
|
||||||
|
enddef
|
||||||
|
echo ToString()
|
||||||
|
END
|
||||||
|
v9.CheckSourceFailure(lines, 'E1357: Using "super" not in a class method', 1)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
class Child
|
||||||
|
var age: number
|
||||||
|
def ToString(): string
|
||||||
|
return super.ToString() .. ': ' .. this.age
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
var o = Child.new(42)
|
||||||
|
echo o.ToString()
|
||||||
|
END
|
||||||
|
v9.CheckSourceFailure(lines, 'E1358: Using "super" not in a child class', 1)
|
||||||
|
|
||||||
|
# Using super, Child invokes Base method which has optional arg. #12471
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class Base
|
||||||
|
var success: bool = false
|
||||||
|
def Method(arg = 0)
|
||||||
|
this.success = true
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Child extends Base
|
||||||
|
def new()
|
||||||
|
super.Method()
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var obj = Child.new()
|
||||||
|
assert_equal(true, obj.success)
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
|
||||||
|
# Using 'super' to access an object variable in the parent
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class A
|
||||||
|
var foo: string = 'xxx'
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class B extends A
|
||||||
|
def GetString(): string
|
||||||
|
return super.foo
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var b: B = B.new()
|
||||||
|
echo b.GetString()
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
|
||||||
|
# Using super to access an overriden method in the parent class
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class A
|
||||||
|
def Foo(): string
|
||||||
|
return 'A.Foo'
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class B extends A
|
||||||
|
def Foo(): string
|
||||||
|
return 'B.Foo'
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Bar(): string
|
||||||
|
return $'{super.Foo()} {this.Foo()}'
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var b = B.new()
|
||||||
|
assert_equal('A.Foo B.Foo', b.Bar())
|
||||||
|
END
|
||||||
|
v9.CheckSourceSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1116,
|
||||||
/**/
|
/**/
|
||||||
1115,
|
1115,
|
||||||
/**/
|
/**/
|
||||||
|
@ -843,27 +843,21 @@ find_imported(char_u *name, size_t len, int load)
|
|||||||
imported_T *
|
imported_T *
|
||||||
find_imported_from_extends(cctx_T *cctx, char_u *name, size_t len, int load)
|
find_imported_from_extends(cctx_T *cctx, char_u *name, size_t len, int load)
|
||||||
{
|
{
|
||||||
imported_T *ret = NULL;
|
|
||||||
class_T *cl_extends;
|
|
||||||
|
|
||||||
if (cctx == NULL || cctx->ctx_ufunc == NULL
|
if (cctx == NULL || cctx->ctx_ufunc == NULL
|
||||||
|| cctx->ctx_ufunc->uf_class == NULL)
|
|| cctx->ctx_ufunc->uf_class == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
cl_extends = cctx->ctx_ufunc->uf_class->class_extends;
|
class_T *cl_extends = cctx->ctx_ufunc->uf_class->class_extends;
|
||||||
|
if (cl_extends == NULL
|
||||||
if (cl_extends == NULL || cl_extends->class_class_function_count_child <= 0)
|
|| cl_extends->class_class_function_count_child <= 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
|
||||||
{
|
|
||||||
sctx_T current_sctx_save = current_sctx;
|
|
||||||
|
|
||||||
|
sctx_T current_sctx_save = current_sctx;
|
||||||
current_sctx = cl_extends->class_class_functions[0]->uf_script_ctx;
|
current_sctx = cl_extends->class_class_functions[0]->uf_script_ctx;
|
||||||
ret = find_imported(name, len, load);
|
imported_T *ret = find_imported(name, len, load);
|
||||||
current_sctx = current_sctx_save;
|
current_sctx = current_sctx_save;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -291,7 +291,7 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
class_T *cl = type->tt_class;
|
class_T *cl = type->tt_class;
|
||||||
int is_super = type->tt_flags & TTFLAG_SUPER;
|
int is_super = ((type->tt_flags & TTFLAG_SUPER) == TTFLAG_SUPER);
|
||||||
if (type == &t_super)
|
if (type == &t_super)
|
||||||
{
|
{
|
||||||
if (cctx->ctx_ufunc == NULL || cctx->ctx_ufunc->uf_class == NULL)
|
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)
|
|||||||
return generate_PUSHFUNC(cctx, ufunc->uf_name, ufunc->uf_func_type, TRUE);
|
return generate_PUSHFUNC(cctx, ufunc->uf_name, ufunc->uf_func_type, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns TRUE if compiling a class method.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
compiling_a_class_method(cctx_T *cctx)
|
||||||
|
{
|
||||||
|
// For an object method, the FC_OBJECT flag will be set.
|
||||||
|
// For a constructor method, the FC_NEW flag will be set.
|
||||||
|
// Excluding these methods, the others are class methods.
|
||||||
|
// When compiling a closure function inside an object method,
|
||||||
|
// cctx->ctx_outer->ctx_func will point to the object method.
|
||||||
|
return cctx->ctx_ufunc != NULL
|
||||||
|
&& (cctx->ctx_ufunc->uf_flags & (FC_OBJECT|FC_NEW)) == 0
|
||||||
|
&& (cctx->ctx_outer == NULL
|
||||||
|
|| cctx->ctx_outer->ctx_ufunc == NULL
|
||||||
|
|| cctx->ctx_outer->ctx_ufunc->uf_class == NULL
|
||||||
|
|| (cctx->ctx_outer->ctx_ufunc->uf_flags
|
||||||
|
& (FC_OBJECT|FC_NEW)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compile a variable name into a load instruction.
|
* Compile a variable name into a load instruction.
|
||||||
* "end" points to just after the name.
|
* "end" points to just after the name.
|
||||||
@ -807,9 +827,7 @@ compile_load(
|
|||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
if (STRCMP(name, "super") == 0
|
if (STRCMP(name, "super") == 0 && compiling_a_class_method(cctx))
|
||||||
&& cctx->ctx_ufunc != NULL
|
|
||||||
&& (cctx->ctx_ufunc->uf_flags & (FC_OBJECT|FC_NEW)) == 0)
|
|
||||||
{
|
{
|
||||||
// super.SomeFunc() in a class function: push &t_super type, this
|
// super.SomeFunc() in a class function: push &t_super type, this
|
||||||
// is recognized in compile_subscript().
|
// is recognized in compile_subscript().
|
||||||
|
Loading…
x
Reference in New Issue
Block a user