patch 9.1.1116: Vim9: super not supported in lambda expressions

Commit: 
https://github.com/vim/vim/commit/b5f463ce4f2bf17c91f1f5b04f9de9ee27753cf3
Author: Yegappan Lakshmanan <yegap...@yahoo.com>
Date:   Sun Feb 16 16:25:24 2025 +0100

    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 <yegap...@yahoo.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 7a269fc8f..0f692ed9c 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -3059,27 +3059,6 @@ def Test_class_extends()
   END
   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
     vim9script
     class Child
@@ -3094,49 +3073,6 @@ def Test_class_extends()
   END
   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
     vim9script
     class Base
@@ -3244,28 +3180,6 @@ def Test_using_base_class()
   END
   v9.CheckSourceSuccess(lines)
   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
 
 " Test for using a method from the super class
@@ -12409,4 +12323,162 @@ def Test_protected_new_method()
   v9.CheckSourceSuccess(lines)
 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
diff --git a/src/version.c b/src/version.c
index 0c85695b9..19968a66d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1116,
 /**/
     1115,
 /**/
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 42a30b192..3d8921ad8 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -843,27 +843,21 @@ find_imported(char_u *name, size_t len, int load)
     imported_T *
 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
                                        || cctx->ctx_ufunc->uf_class == NULL)
        return NULL;
 
-    cl_extends = cctx->ctx_ufunc->uf_class->class_extends;
-
-    if (cl_extends == NULL || cl_extends->class_class_function_count_child <= 
0)
+    class_T *cl_extends = cctx->ctx_ufunc->uf_class->class_extends;
+    if (cl_extends == NULL
+                       || cl_extends->class_class_function_count_child <= 0)
        return NULL;
-    else
-    {
-       sctx_T current_sctx_save = current_sctx;
 
-       current_sctx = cl_extends->class_class_functions[0]->uf_script_ctx;
-       ret = find_imported(name, len, load);
-       current_sctx = current_sctx_save;
+    sctx_T current_sctx_save = current_sctx;
+    current_sctx = cl_extends->class_class_functions[0]->uf_script_ctx;
+    imported_T *ret = find_imported(name, len, load);
+    current_sctx = current_sctx_save;
 
-       return ret;
-    }
+    return ret;
 }
 
 /*
diff --git a/src/vim9expr.c b/src/vim9expr.c
index fe2be410b..67722d114 100644
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -291,7 +291,7 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, 
type_T *type)
     }
 
     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 (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);
 }
 
+/*
+ * 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.
  * "end" points to just after the name.
@@ -807,9 +827,7 @@ compile_load(
        if (name == NULL)
            return FAIL;
 
-       if (STRCMP(name, "super") == 0
-               && cctx->ctx_ufunc != NULL
-               && (cctx->ctx_ufunc->uf_flags & (FC_OBJECT|FC_NEW)) == 0)
+       if (STRCMP(name, "super") == 0 && compiling_a_class_method(cctx))
        {
            // super.SomeFunc() in a class function: push &t_super type, this
            // is recognized in compile_subscript().

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1tjgpN-00CTWi-4T%40256bit.org.

Raspunde prin e-mail lui