#endif
EXTERN char e_class_required[]
INIT(= N_("E614: Class required"));
-EXTERN char e_object_required[]
- INIT(= N_("E615: Object required"));
+// E615 unused
EXTERN char e_object_required_for_argument_nr[]
INIT(= N_("E616: Object required for argument %d"));
#ifdef FEAT_GUI_GTK
INIT(= N_("E1327: Object required, found %s"));
EXTERN char e_constructor_default_value_must_be_vnone_str[]
INIT(= N_("E1328: Constructor default value must be v:none: %s"));
-EXTERN char e_cannot_get_object_member_type_from_initializer_str[]
- INIT(= N_("E1329: Cannot get object member type from initializer: %s"));
+// E1329 unused
EXTERN char e_invalid_type_for_object_member_str[]
INIT(= N_("E1330: Invalid type for object member: %s"));
EXTERN char e_public_must_be_followed_by_this_or_static[]
INIT(= N_("E1332: Public member name cannot start with underscore: %s"));
EXTERN char e_cannot_access_private_member_str[]
INIT(= N_("E1333: Cannot access private member: %s"));
+// E1334 unused
EXTERN char e_member_is_not_writable_str[]
INIT(= N_("E1335: Member is not writable: %s"));
#endif
#ifdef FEAT_EVAL
EXTERN char e_class_member_str_not_found_in_class_str[]
INIT(= N_("E1337: Class member \"%s\" not found in class \"%s\""));
-EXTERN char e_member_not_found_on_class_str_str[]
- INIT(= N_("E1338: Member not found on class \"%s\": %s"));
+EXTERN char e_interface_static_direct_access_str[]
+ INIT(= N_("E1338: Cannot directly access interface \"%s\" static member \"%s\""));
#endif
#ifdef FEAT_PROP_POPUP
EXTERN char e_cannot_add_textprop_with_text_after_using_textprop_with_negative_id[]
EXTERN char e_not_valid_interface_str[]
INIT(= N_("E1347: Not a valid interface: %s"));
EXTERN char e_member_str_of_interface_str_not_implemented[]
- INIT(= N_("E1348: Member \"%s\" of interface \"%s\" not implemented"));
-EXTERN char e_function_str_of_interface_str_not_implemented[]
- INIT(= N_("E1349: Function \"%s\" of interface \"%s\" not implemented"));
+ INIT(= N_("E1348: Member \"%s\" of interface \"%s\" is not implemented"));
+EXTERN char e_method_str_of_interface_str_not_implemented[]
+ INIT(= N_("E1349: Method \"%s\" of interface \"%s\" is not implemented"));
EXTERN char e_duplicate_implements[]
INIT(= N_("E1350: Duplicate \"implements\""));
EXTERN char e_duplicate_interface_after_implements_str[]
#endif
EXTERN char e_warning_pointer_block_corrupted[]
INIT(= N_("E1364: Warning: Pointer block corrupted"));
+#ifdef FEAT_EVAL
EXTERN char e_cannot_use_a_return_type_with_new[]
INIT(= N_("E1365: Cannot use a return type with the \"new\" function"));
EXTERN char e_cannot_access_private_method_str[]
INIT(= N_("E1375: Class member \"%s\" accessible only using class \"%s\""));
EXTERN char e_object_member_str_accessible_only_using_object_str[]
INIT(= N_("E1376: Object member \"%s\" accessible only using class \"%s\" object"));
-EXTERN char e_static_member_not_supported_in_interface[]
- INIT(= N_("E1377: Static member is not supported in an interface"));
EXTERN char e_method_str_of_class_str_has_different_access[]
- INIT(= N_("E1378: Access level of method \"%s\" is different in class \"%s\""));
+ INIT(= N_("E1377: Access level of method \"%s\" is different in class \"%s\""));
+EXTERN char e_static_cannot_be_used_in_interface[]
+ INIT(= N_("E1378: Static cannot be used in an interface"));
+EXTERN char e_private_variable_str_in_interface[]
+ INIT(= N_("E1379: Private variable not supported in an interface"));
+EXTERN char e_private_method_str_in_interface[]
+ INIT(= N_("E1380: Private method not supported in an interface"));
+EXTERN char e_interface_cannot_use_implements[]
+ INIT(= N_("E1381: Interface cannot use \"implements\""));
+EXTERN char e_member_str_type_mismatch_expected_str_but_got_str[]
+ INIT(= N_("E1382: Member \"%s\": type mismatch, expected %s but got %s"));
+EXTERN char e_method_str_type_mismatch_expected_str_but_got_str[]
+ INIT(= N_("E1383: Method \"%s\": type mismatch, expected %s but got %s"));
+#endif
EXTERN char e_cannot_mix_positional_and_non_positional_str[]
INIT(= N_("E1400: Cannot mix positional and non-positional arguments: %s"));
EXTERN char e_fmt_arg_nr_unused_str[]
INIT(= N_("E1404: Positional argument %d type used inconsistently: %s/%s"));
EXTERN char e_invalid_format_specifier_str[]
INIT(= N_("E1405: Invalid format specifier: %s"));
-EXTERN char e_member_str_type_mismatch_expected_str_but_got_str[]
- INIT(= N_("E1406: Member \"%s\": type mismatch, expected %s but got %s"));
-EXTERN char e_method_str_type_mismatch_expected_str_but_got_str[]
- INIT(= N_("E1407: Method \"%s\": type mismatch, expected %s but got %s"));
EXTERN char e_aptypes_is_null_nr_str[]
INIT(= "E1408: Internal error: ap_types or ap_types[idx] is NULL: %d: %s");
-EXTERN char e_interface_static_direct_access_str[]
- INIT(= N_("E1409: Cannot directly access interface \"%s\" static member \"%s\""));
-// E1376 - E1399 unused
+// E1384 - E1399 unused
Bar()
END
v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected class<Unknown> but got number')
+
+ lines =<< trim END
+ vim9script
+ class Foo
+ endclass
+ instanceof(Foo.new(), [{}])
+ END
+ v9.CheckSourceFailure(lines, 'E614: Class required')
+
+ lines =<< trim END
+ vim9script
+ class Foo
+ endclass
+ def Bar()
+ instanceof(Foo.new(), [{}])
+ enddef
+ Bar()
+ END
+ v9.CheckSourceFailure(lines, 'E614: Class required')
enddef
def Test_invert()
END
v9.CheckSourceFailure(lines, 'E1170:')
+ # Test for using class as a bool
+ lines =<< trim END
+ vim9script
+ class A
+ endclass
+ if A
+ endif
+ END
+ v9.CheckSourceFailure(lines, 'E1319: Using a class as a Number')
+
+ # Test for using object as a bool
+ lines =<< trim END
+ vim9script
+ class A
+ endclass
+ var a = A.new()
+ if a
+ endif
+ END
+ v9.CheckSourceFailure(lines, 'E1320: Using an object as a Number')
+
+ # Test for using class as a float
+ lines =<< trim END
+ vim9script
+ class A
+ endclass
+ sort([1.1, A], 'f')
+ END
+ v9.CheckSourceFailure(lines, 'E1321: Using a class as a Float')
+
+ # Test for using object as a float
+ lines =<< trim END
+ vim9script
+ class A
+ endclass
+ var a = A.new()
+ sort([1.1, a], 'f')
+ END
+ v9.CheckSourceFailure(lines, 'E1322: Using an object as a Float')
+
+ # Test for using class as a string
+ lines =<< trim END
+ vim9script
+ class A
+ endclass
+ :exe 'call ' .. A
+ END
+ v9.CheckSourceFailure(lines, 'E1323: Using a class as a String')
+
+ # Test for using object as a string
+ lines =<< trim END
+ vim9script
+ class A
+ endclass
+ var a = A.new()
+ :exe 'call ' .. a
+ END
+ v9.CheckSourceFailure(lines, 'E1324: Using an object as a String')
+
lines =<< trim END
vim9script
var missing = Person.new()
END
v9.CheckSourceFailure(lines, 'E119:')
+
+ # Using a specific value to initialize an instance variable in the new()
+ # method.
+ lines =<< trim END
+ vim9script
+ class A
+ this.val: string
+ def new(this.val = 'a')
+ enddef
+ endclass
+ END
+ v9.CheckSourceFailure(lines, "E1328: Constructor default value must be v:none: = 'a'")
enddef
var a = A.new()
END
v9.CheckSourceFailure(lines, 'E1001:')
+
+ # Test for initializing an object member with an special type
+ lines =<< trim END
+ vim9script
+ class A
+ this.value: void
+ endclass
+ END
+ v9.CheckSourceFailure(lines, 'E1330: Invalid type for object member: void')
enddef
" Test for instance variable access
vim9script
interface I
- static ro_class_var: number
- public static rw_class_var: number
- static _priv_class_var: number
this.ro_obj_var: number
public this.rw_obj_var: number
- this._priv_obj_var: number
- static def ClassFoo(): number
- static def _ClassBar(): number
def ObjFoo(): number
- def _ObjBar(): number
endinterface
class A implements I
var lines =<< trim END
vim9script
interface Something
- this.value: string
- static count: number
+ this.ro_var: string
+ public this.rw_var: list<number>
def GetCount(): number
endinterface
END
END
v9.CheckSourceFailure(lines, 'E1342:')
- lines =<< trim END
- vim9script
-
- interface Some
- static count: number
- def Method(count: number)
- endinterface
- END
- v9.CheckSourceFailure(lines, 'E1340: Argument already declared in the class: count', 5)
-
lines =<< trim END
vim9script
vim9script
interface SomethingWrong
this.value: string
- static count = 7
+ this.count = 7
def GetCount(): number
endinterface
END
vim9script
interface SomethingWrong
this.value: string
- static count: number
+ this.count: number
def GetCount(): number
return 5
enddef
vim9script
interface Some
- static count: number
+ this.count: number
def Method(nr: number)
endinterface
class SomeImpl implements Some
- static count: number
+ this.count: number
def Method(nr: number)
echo nr
enddef
class AnotherImpl implements Some, Another
this.member = 'abc'
- static count: number
+ this.count = 20
def Method(nr: number)
echo nr
enddef
vim9script
interface Some
- static counter: number
+ this.count: number
endinterface
class SomeImpl implements Some implements Some
- static count: number
+ this.count: number
endclass
END
v9.CheckSourceFailure(lines, 'E1350:')
vim9script
interface Some
- static counter: number
+ this.count: number
endinterface
class SomeImpl implements Some, Some
- static count: number
+ this.count: number
endclass
END
v9.CheckSourceFailure(lines, 'E1351: Duplicate interface after "implements": Some')
vim9script
interface Some
- static counter: number
+ this.counter: number
def Method(nr: number)
endinterface
class SomeImpl implements Some
- static count: number
+ this.count: number
def Method(nr: number)
echo nr
enddef
endclass
END
- v9.CheckSourceFailure(lines, 'E1348: Member "counter" of interface "Some" not implemented')
+ v9.CheckSourceFailure(lines, 'E1348: Member "counter" of interface "Some" is not implemented')
lines =<< trim END
vim9script
interface Some
- static count: number
+ this.count: number
def Methods(nr: number)
endinterface
class SomeImpl implements Some
- static count: number
+ this.count: number
def Method(nr: number)
echo nr
enddef
endclass
END
- v9.CheckSourceFailure(lines, 'E1349: Function "Methods" of interface "Some" not implemented')
+ v9.CheckSourceFailure(lines, 'E1349: Method "Methods" of interface "Some" is not implemented')
# Check different order of members in class and interface works.
lines =<< trim END
END
v9.CheckSourceFailure(lines, 'E1347:')
- # all the class methods in an "interface" should be implemented
- lines =<< trim END
- vim9script
- interface A
- static def Foo()
- endinterface
- class B implements A
- endclass
- END
- v9.CheckSourceFailure(lines, 'E1349:')
-
# implements should be followed by a white space
lines =<< trim END
vim9script
END
v9.CheckSourceFailure(lines, 'E1315:')
- lines =<< trim END
- vim9script
-
- interface One
- static matching: bool
- static as_any: any
- static not_matching: number
- endinterface
- class Two implements One
- static not_matching: string
- static as_any: string
- static matching: bool
- endclass
- END
- v9.CheckSourceFailure(lines, 'E1406: Member "not_matching": type mismatch, expected number but got string')
-
lines =<< trim END
vim9script
enddef
endclass
END
- v9.CheckSourceFailure(lines, 'E1407: Method "IsEven": type mismatch, expected func(number): bool but got func(number): string')
+ v9.CheckSourceFailure(lines, 'E1383: Method "IsEven": type mismatch, expected func(number): bool but got func(number): string')
lines =<< trim END
vim9script
enddef
endclass
END
- v9.CheckSourceFailure(lines, 'E1407: Method "IsEven": type mismatch, expected func(number): bool but got func(bool): bool')
+ v9.CheckSourceFailure(lines, 'E1383: Method "IsEven": type mismatch, expected func(number): bool but got func(bool): bool')
lines =<< trim END
vim9script
enddef
endclass
END
- v9.CheckSourceFailure(lines, 'E1407: Method "IsEven": type mismatch, expected func(number): bool but got func(number, ...list<number>): bool')
+ v9.CheckSourceFailure(lines, 'E1383: Method "IsEven": type mismatch, expected func(number): bool but got func(number, ...list<number>): bool')
# access superclass interface members from subclass, mix variable order
lines =<< trim END
vim9script
interface I1
- public static svar1: number
- public static svar2: number
public this.mvar1: number
public this.mvar2: number
endinterface
vim9script
interface I1
- public static svar1: number
- public static svar2: number
public this.mvar1: number
public this.mvar2: number
endinterface
interface I2
- public static svar3: number
- public static svar4: number
public this.mvar3: number
public this.mvar4: number
endinterface
v9.CheckSourceFailure(lines, 'E1325: Method not found on class "C": _Foo')
enddef
-" Test for an interface private object_method
-def Test_interface_private_object_method()
- # Implement an interface private method and use it from a public method
- var lines =<< trim END
- vim9script
- interface Intf
- def _Foo(): number
- endinterface
- class A implements Intf
- def _Foo(): number
- return 1234
- enddef
- def Bar(): number
- return this._Foo()
- enddef
- endclass
- var a = A.new()
- assert_equal(1234, a.Bar())
- END
- v9.CheckSourceSuccess(lines)
-
- # Call an interface private class method (script context)
- lines =<< trim END
- vim9script
- interface Intf
- def _Foo(): number
- endinterface
- class A implements Intf
- def _Foo(): number
- return 1234
- enddef
- endclass
- var a = A.new()
- assert_equal(1234, a._Foo())
- END
- v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()')
-
- # Call an interface private class method (def context)
- lines =<< trim END
- vim9script
- interface Intf
- def _Foo(): number
- endinterface
- class A implements Intf
- def _Foo(): number
- return 1234
- enddef
- endclass
- def T()
- var a = A.new()
- assert_equal(1234, a._Foo())
- enddef
- T()
- END
- v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo()')
-
- # Implement an interface private object method as a private class method
- lines =<< trim END
- vim9script
- interface Intf
- def _Foo(): number
- endinterface
- class A implements Intf
- static def _Foo(): number
- return 1234
- enddef
- endclass
- END
- v9.CheckSourceFailure(lines, 'E1349: Function "_Foo" of interface "Intf" not implemented')
-enddef
-
-" Test for an interface private class method
-def Test_interface_private_class_method()
- # Implement an interface private class method and use it from a public method
- var lines =<< trim END
- vim9script
- interface Intf
- static def _Foo(): number
- endinterface
- class A implements Intf
- static def _Foo(): number
- return 1234
- enddef
- def Bar(): number
- return A._Foo()
- enddef
- endclass
- var a = A.new()
- assert_equal(1234, a.Bar())
- END
- v9.CheckSourceSuccess(lines)
-
- # Call an interface private class method (script context)
- lines =<< trim END
- vim9script
- interface Intf
- static def _Foo(): number
- endinterface
- class A implements Intf
- static def _Foo(): number
- return 1234
- enddef
- endclass
- assert_equal(1234, A._Foo())
- END
- v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo())')
-
- # Call an interface private class method (def context)
- lines =<< trim END
- vim9script
- interface Intf
- static def _Foo(): number
- endinterface
- class A implements Intf
- static def _Foo(): number
- return 1234
- enddef
- endclass
- def T()
- assert_equal(1234, A._Foo())
- enddef
- T()
- END
- v9.CheckSourceFailure(lines, 'E1366: Cannot access private method: _Foo())')
-
- # Implement an interface private class method as a private object method
- lines =<< trim END
- vim9script
- interface Intf
- static def _Foo(): number
- endinterface
- class A implements Intf
- def _Foo(): number
- return 1234
- enddef
- endclass
- END
- v9.CheckSourceFailure(lines, 'E1349: Function "_Foo" of interface "Intf" not implemented')
-enddef
-
" Test for using the return value of a class/object method as a function
" argument.
def Test_objmethod_funcarg()
v9.CheckSourceSuccess(lines)
enddef
-def Test_interface_static_member_access()
- # In a class cannot read from interface static
+" Test for accessing a private member outside a class in a def function
+def Test_private_member_access_outside_class()
+ # private object member variable
var lines =<< trim END
vim9script
- interface I
- public static num: number
- endinterface
- class C implements I
- public static num = 3
- def F()
- var x = I.num
- enddef
+ class A
+ this._val = 10
+ def GetVal(): number
+ return this._val
+ enddef
endclass
- C.new().F()
+ def T()
+ var a = A.new()
+ a._val = 20
+ enddef
+ T()
END
- v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"')
+ v9.CheckSourceFailure(lines, 'E1333: Cannot access private member: _val')
- # In a class cannot write to interface static
+ # access a non-existing private object member variable
lines =<< trim END
vim9script
- interface I
- public static num: number
- endinterface
- class C implements I
- public static num = 3
- def F()
- I.num = 7
- enddef
+ class A
+ this._val = 10
endclass
- C.new().F()
+ def T()
+ var a = A.new()
+ a._a = 1
+ enddef
+ T()
END
- v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"')
+ v9.CheckSourceFailure(lines, 'E1089: Unknown variable: _a')
- # In a def cannot read from interface static
+ # private static member variable
lines =<< trim END
vim9script
- interface I
- public static num: number
- endinterface
- def F()
- var x = I.num
+ class A
+ static _val = 10
+ endclass
+ def T()
+ var a = A.new()
+ var x = a._val
enddef
- F()
+ T()
END
- v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"')
+ v9.CheckSourceFailure(lines, 'E1375: Class member "_val" accessible only using class "A"')
- # In a def cannot write to interface static
- lines =<< trim END
- vim9script
- interface I
- public static num: number
- endinterface
- def F()
- I.num = 7
- enddef
- F()
- END
- v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "num"')
-
- # script level cannot read interface static
- lines =<< trim END
- vim9script
- interface I
- public static s_var1: number
- endinterface
-
- var x = I.s_var1
- END
- v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "s_var1"')
-
- # script level cannot write interface static
- lines =<< trim END
- vim9script
- interface I
- public static s_var1: number
- endinterface
-
- I.s_var1 = 3
- END
- v9.CheckSourceFailure(lines, 'E1409: Cannot directly access interface "I" static member "I.s_var1 = 3"')
-
-enddef
-
-def Test_static_member_access_outside_class()
- # Verify access of statics implemented from interface
- # in a :def (outside of a class)
- # Note the order of the static is different
- # between the interface and the class,
- # since they are allocated in order in each interface/class;
- # so the static index is mapped from interfaced to class as needed.
-
- # Check reading statics
- var lines =<< trim END
- vim9script
-
- interface I
- public static s_var1: number
- public static s_var2: number
- endinterface
-
- class C implements I
- public static s_var2 = 2
- public static x_static = 7
- public static s_var1 = 1
- endclass
-
- def F1(): number
- assert_equal(1, C.s_var1)
- assert_equal(2, C.s_var2)
- assert_equal(7, C.x_static)
- return 11
- enddef
-
- assert_equal(11, F1())
- END
- v9.CheckSourceSuccess(lines)
-enddef
-
-" Test for accessing a private member outside a class in a def function
-def Test_private_member_access_outside_class()
- # private object member variable
- var lines =<< trim END
- vim9script
- class A
- this._val = 10
- def GetVal(): number
- return this._val
- enddef
- endclass
- def T()
- var a = A.new()
- a._val = 20
- enddef
- T()
- END
- v9.CheckSourceFailure(lines, 'E1333: Cannot access private member: _val')
-
- # access a non-existing private object member variable
- lines =<< trim END
- vim9script
- class A
- this._val = 10
- endclass
- def T()
- var a = A.new()
- a._a = 1
- enddef
- T()
- END
- v9.CheckSourceFailure(lines, 'E1089: Unknown variable: _a')
-
- # private static member variable
- lines =<< trim END
- vim9script
- class A
- static _val = 10
- endclass
- def T()
- var a = A.new()
- var x = a._val
- enddef
- T()
- END
- v9.CheckSourceFailure(lines, 'E1375: Class member "_val" accessible only using class "A"')
-
- # private static member variable
+ # private static member variable
lines =<< trim END
vim9script
class A
abstract def Foo()
endinterface
class B implements A
+ def Foo()
+ enddef
endclass
END
- v9.CheckSourceFailure(lines, 'E1372: Abstract method "abstract def Foo()" cannot be defined in a concrete class')
+ v9.CheckSourceSuccess(lines)
# Abbreviate the "abstract" keyword
lines =<< trim END
enddef
endclass
END
- v9.CheckSourceFailure(lines, 'E1407: Method "Foo": type mismatch, expected func(string, number): list<number> but got func(number, string): list<string>')
+ v9.CheckSourceFailure(lines, 'E1383: Method "Foo": type mismatch, expected func(string, number): list<number> but got func(number, string): list<string>')
# Use an abstract class to invoke an abstract method
# FIXME: This should fail
enddef
endclass
END
- v9.CheckSourceFailure(lines, 'E1378: Access level of method "_Foo" is different in class "A"')
+ v9.CheckSourceFailure(lines, 'E1377: Access level of method "_Foo" is different in class "A"')
# Public method in subclass
lines =<< trim END
enddef
endclass
END
- v9.CheckSourceFailure(lines, 'E1378: Access level of method "Foo" is different in class "A"')
+ v9.CheckSourceFailure(lines, 'E1377: Access level of method "Foo" is different in class "A"')
enddef
def Test_extend_empty_class()
v9.CheckSourceSuccess(lines)
enddef
+" A interface cannot have a static variable or a static method or a private
+" variable or a private method
+def Test_interface_with_unsupported_members()
+ var lines =<< trim END
+ vim9script
+ interface A
+ static num: number
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface')
+
+ lines =<< trim END
+ vim9script
+ interface A
+ static _num: number
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface')
+
+ lines =<< trim END
+ vim9script
+ interface A
+ public static num: number
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface')
+
+ lines =<< trim END
+ vim9script
+ interface A
+ public static _num: number
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface')
+
+ lines =<< trim END
+ vim9script
+ interface A
+ static def Foo(d: dict<any>): list<string>
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface')
+
+ lines =<< trim END
+ vim9script
+ interface A
+ static def _Foo(d: dict<any>): list<string>
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1378: Static cannot be used in an interface')
+
+ lines =<< trim END
+ vim9script
+ interface A
+ this._Foo: list<string>
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1379: Private variable not supported in an interface')
+
+ lines =<< trim END
+ vim9script
+ interface A
+ def _Foo(d: dict<any>): list<string>
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1380: Private method not supported in an interface')
+enddef
+
+" Test for extending an interface
+def Test_extend_interface()
+ var lines =<< trim END
+ vim9script
+ interface A
+ this.var1: list<string>
+ def Foo()
+ endinterface
+ interface B extends A
+ public this.var2: dict<string>
+ def Bar()
+ endinterface
+ class C implements A, B
+ this.var1 = [1, 2]
+ def Foo()
+ enddef
+ public this.var2 = {a: '1'}
+ def Bar()
+ enddef
+ endclass
+ END
+ v9.CheckSourceSuccess(lines)
+
+ lines =<< trim END
+ vim9script
+ interface A
+ def Foo()
+ endinterface
+ interface B extends A
+ public this.var2: dict<string>
+ endinterface
+ class C implements A, B
+ public this.var2 = {a: '1'}
+ endclass
+ END
+ v9.CheckSourceFailure(lines, 'E1349: Method "Foo" of interface "A" is not implemented')
+
+ lines =<< trim END
+ vim9script
+ interface A
+ def Foo()
+ endinterface
+ interface B extends A
+ public this.var2: dict<string>
+ endinterface
+ class C implements A, B
+ def Foo()
+ enddef
+ endclass
+ END
+ v9.CheckSourceFailure(lines, 'E1348: Member "var2" of interface "B" is not implemented')
+
+ # interface cannot extend a class
+ lines =<< trim END
+ vim9script
+ class A
+ endclass
+ interface B extends A
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1354: Cannot extend A')
+
+ # class cannot extend an interface
+ lines =<< trim END
+ vim9script
+ interface A
+ endinterface
+ class B extends A
+ endclass
+ END
+ v9.CheckSourceFailure(lines, 'E1354: Cannot extend A')
+
+ # interface cannot implement another interface
+ lines =<< trim END
+ vim9script
+ interface A
+ endinterface
+ interface B implements A
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1381: Interface cannot use "implements"')
+
+ # interface cannot extend multiple interfaces
+ lines =<< trim END
+ vim9script
+ interface A
+ endinterface
+ interface B
+ endinterface
+ interface C extends A, B
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1315: White space required after name: A, B')
+
+ # Variable type in an extended interface is of different type
+ lines =<< trim END
+ vim9script
+ interface A
+ this.val1: number
+ endinterface
+ interface B extends A
+ this.val2: string
+ endinterface
+ interface C extends B
+ this.val1: string
+ this.val2: number
+ endinterface
+ END
+ v9.CheckSourceFailure(lines, 'E1382: Member "val1": type mismatch, expected number but got string')
+enddef
+
+" Test for a child class implementing an interface when some of the methods are
+" defined in the parent class.
+def Test_child_class_implements_interface()
+ var lines =<< trim END
+ vim9script
+
+ interface Intf
+ def F1(): list<list<number>>
+ def F2(): list<list<number>>
+ def F3(): list<list<number>>
+ this.var1: list<dict<number>>
+ this.var2: list<dict<number>>
+ this.var3: list<dict<number>>
+ endinterface
+
+ class A
+ def A1()
+ enddef
+ def F3(): list<list<number>>
+ return [[3]]
+ enddef
+ this.v1: list<list<number>> = [[0]]
+ this.var3 = [{c: 30}]
+ endclass
+
+ class B extends A
+ def B1()
+ enddef
+ def F2(): list<list<number>>
+ return [[2]]
+ enddef
+ this.v2: list<list<number>> = [[0]]
+ this.var2 = [{b: 20}]
+ endclass
+
+ class C extends B implements Intf
+ def C1()
+ enddef
+ def F1(): list<list<number>>
+ return [[1]]
+ enddef
+ this.v3: list<list<number>> = [[0]]
+ this.var1 = [{a: 10}]
+ endclass
+
+ def T(if: Intf)
+ assert_equal([[1]], if.F1())
+ assert_equal([[2]], if.F2())
+ assert_equal([[3]], if.F3())
+ assert_equal([{a: 10}], if.var1)
+ assert_equal([{b: 20}], if.var2)
+ assert_equal([{c: 30}], if.var3)
+ enddef
+
+ var c = C.new()
+ T(c)
+ assert_equal([[1]], c.F1())
+ assert_equal([[2]], c.F2())
+ assert_equal([[3]], c.F3())
+ assert_equal([{a: 10}], c.var1)
+ assert_equal([{b: 20}], c.var2)
+ assert_equal([{c: 30}], c.var3)
+ END
+ v9.CheckSourceSuccess(lines)
+
+ # One of the interface methods is not found
+ lines =<< trim END
+ vim9script
+
+ interface Intf
+ def F1()
+ def F2()
+ def F3()
+ endinterface
+
+ class A
+ def A1()
+ enddef
+ endclass
+
+ class B extends A
+ def B1()
+ enddef
+ def F2()
+ enddef
+ endclass
+
+ class C extends B implements Intf
+ def C1()
+ enddef
+ def F1()
+ enddef
+ endclass
+ END
+ v9.CheckSourceFailure(lines, 'E1349: Method "F3" of interface "Intf" is not implemented')
+
+ # One of the interface methods is of different type
+ lines =<< trim END
+ vim9script
+
+ interface Intf
+ def F1()
+ def F2()
+ def F3()
+ endinterface
+
+ class A
+ def F3(): number
+ return 0
+ enddef
+ def A1()
+ enddef
+ endclass
+
+ class B extends A
+ def B1()
+ enddef
+ def F2()
+ enddef
+ endclass
+
+ class C extends B implements Intf
+ def C1()
+ enddef
+ def F1()
+ enddef
+ endclass
+ END
+ v9.CheckSourceFailure(lines, 'E1383: Method "F3": type mismatch, expected func() but got func(): number')
+
+ # One of the interface variables is not present
+ lines =<< trim END
+ vim9script
+
+ interface Intf
+ this.var1: list<dict<number>>
+ this.var2: list<dict<number>>
+ this.var3: list<dict<number>>
+ endinterface
+
+ class A
+ this.v1: list<list<number>> = [[0]]
+ endclass
+
+ class B extends A
+ this.v2: list<list<number>> = [[0]]
+ this.var2 = [{b: 20}]
+ endclass
+
+ class C extends B implements Intf
+ this.v3: list<list<number>> = [[0]]
+ this.var1 = [{a: 10}]
+ endclass
+ END
+ v9.CheckSourceFailure(lines, 'E1348: Member "var3" of interface "Intf" is not implemented')
+
+ # One of the interface variables is of different type
+ lines =<< trim END
+ vim9script
+
+ interface Intf
+ this.var1: list<dict<number>>
+ this.var2: list<dict<number>>
+ this.var3: list<dict<number>>
+ endinterface
+
+ class A
+ this.v1: list<list<number>> = [[0]]
+ this.var3: list<dict<string>>
+ endclass
+
+ class B extends A
+ this.v2: list<list<number>> = [[0]]
+ this.var2 = [{b: 20}]
+ endclass
+
+ class C extends B implements Intf
+ this.v3: list<list<number>> = [[0]]
+ this.var1 = [{a: 10}]
+ endclass
+ END
+ v9.CheckSourceFailure(lines, 'E1382: Member "var3": type mismatch, expected list<dict<number>> but got list<dict<string>>')
+enddef
+
+" Test for extending an interface with duplicate variables and methods
+def Test_interface_extends_with_dup_members()
+ var lines =<< trim END
+ vim9script
+ interface A
+ this.n1: number
+ def Foo1(): number
+ endinterface
+ interface B extends A
+ this.n2: number
+ this.n1: number
+ def Foo2(): number
+ def Foo1(): number
+ endinterface
+ class C implements B
+ this.n1 = 10
+ this.n2 = 20
+ def Foo1(): number
+ return 30
+ enddef
+ def Foo2(): number
+ return 40
+ enddef
+ endclass
+ def T1(a: A)
+ assert_equal(10, a.n1)
+ assert_equal(30, a.Foo1())
+ enddef
+ def T2(b: B)
+ assert_equal(10, b.n1)
+ assert_equal(20, b.n2)
+ assert_equal(30, b.Foo1())
+ assert_equal(40, b.Foo2())
+ enddef
+ var c = C.new()
+ T1(c)
+ T2(c)
+ END
+ v9.CheckSourceSuccess(lines)
+enddef
+
+" Test for using "any" type for a variable in a sub-class while it has a
+" concrete type in the interface
+def Test_implements_using_var_type_any()
+ var lines =<< trim END
+ vim9script
+ interface A
+ this.val: list<dict<string>>
+ endinterface
+ class B implements A
+ this.val = [{a: '1'}, {b: '2'}]
+ endclass
+ var b = B.new()
+ assert_equal([{a: '1'}, {b: '2'}], b.val)
+ END
+ v9.CheckSourceSuccess(lines)
+
+ # initialize instance variable using a different type
+ lines =<< trim END
+ vim9script
+ interface A
+ this.val: list<dict<string>>
+ endinterface
+ class B implements A
+ this.val = {a: 1, b: 2}
+ endclass
+ var b = B.new()
+ END
+ v9.CheckSourceFailure(lines, 'E1382: Member "val": type mismatch, expected list<dict<string>> but got dict<number>')
+enddef
+
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
var lines =<< trim END
vim9script
interface I
- public static s_var: number
public this.o_var: number
- public static s_var2: number
public this.o_var2: number
endinterface
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1906,
/**/
1905,
/**/
* Returns TRUE if the class name "extends_names" is a valid class.
*/
static int
-validate_extends_class(char_u *extends_name, class_T **extends_clp)
+validate_extends_class(
+ char_u *extends_name,
+ class_T **extends_clp,
+ int is_class)
{
typval_T tv;
int success = FALSE;
return success;
}
- if (tv.v_type != VAR_CLASS
- || tv.vval.v_class == NULL
- || (tv.vval.v_class->class_flags & CLASS_INTERFACE) != 0)
+ if (tv.v_type != VAR_CLASS || tv.vval.v_class == NULL
+ || (is_class
+ && (tv.vval.v_class->class_flags & CLASS_INTERFACE) != 0)
+ || (!is_class
+ && (tv.vval.v_class->class_flags & CLASS_INTERFACE) == 0))
+ // a interface cannot extend a class and a class cannot extend an
+ // interface.
semsg(_(e_cannot_extend_str), extends_name);
else
{
if (extends_private)
pstr++;
+ // When comparing the method names, ignore the access type (public
+ // and private methods are considered the same).
for (int j = 0; j < method_count; j++)
{
char_u *qstr = cl_fp[j]->uf_name;
* are no duplicates.
*/
static int
-validate_extends_members(
+extends_check_dup_members(
garray_T *objmembers_gap,
class_T *extends_cl)
{
- // loop == 1: check class members
- // loop == 2: check object members
int member_count = objmembers_gap->ga_len;
if (member_count == 0)
return TRUE;
return TRUE;
}
+/*
+ * Compare the variable type of interface variables in "objmembers_gap" against
+ * the variable in any of the extended super interface lineage. Used to
+ * compare the variable types when extending interfaces. Returns TRUE if the
+ * variable types are the same.
+ */
+ static int
+extends_check_intf_var_type(
+ garray_T *objmembers_gap,
+ class_T *extends_cl)
+{
+ int member_count = objmembers_gap->ga_len;
+ if (member_count == 0)
+ return TRUE;
+
+ ocmember_T *members = (ocmember_T *)(objmembers_gap->ga_data);
+
+ // Validate each member variable
+ for (int c_i = 0; c_i < member_count; c_i++)
+ {
+ class_T *p_cl = extends_cl;
+ ocmember_T *c_m = members + c_i;
+ int var_found = FALSE;
+
+ // Check in all the parent classes in the lineage
+ while (p_cl != NULL && !var_found)
+ {
+ int p_member_count = p_cl->class_obj_member_count;
+ if (p_member_count == 0)
+ {
+ p_cl = p_cl->class_extends;
+ continue;
+ }
+ ocmember_T *p_members = p_cl->class_obj_members;
+
+ // Compare against all the members in the parent class
+ for (int p_i = 0; p_i < p_member_count; p_i++)
+ {
+ where_T where = WHERE_INIT;
+ ocmember_T *p_m = p_members + p_i;
+
+ if (STRCMP(p_m->ocm_name, c_m->ocm_name) != 0)
+ continue;
+
+ // Ensure the type is matching.
+ where.wt_func_name = (char *)c_m->ocm_name;
+ where.wt_kind = WT_MEMBER;
+
+ if (check_type(p_m->ocm_type, c_m->ocm_type, TRUE,
+ where) == FAIL)
+ return FALSE;
+
+ var_found = TRUE;
+ }
+
+ p_cl = p_cl->class_extends;
+ }
+ }
+
+ return TRUE;
+}
+
/*
* When extending an abstract class, check whether all the abstract methods in
* the parent class are implemented. Returns TRUE if all the methods are
}
/*
- * Check the members of the interface class "ifcl" match the class members
- * ("classmembers_gap") and object members ("objmembers_gap") of a class.
- * Returns TRUE if the class and object member names are valid.
+ * Returns TRUE if the interface variable "if_var" is present in the list of
+ * variables in "cl_mt" or in the parent lineage of one of the extended classes
+ * in "extends_cl". For a class variable, 'is_class_var' is TRUE.
*/
static int
-validate_interface_members(
+intf_variable_present(
+ char_u *intf_class_name,
+ ocmember_T *if_var,
+ int is_class_var,
+ ocmember_T *cl_mt,
+ int cl_member_count,
+ class_T *extends_cl)
+{
+ int variable_present = FALSE;
+
+ for (int cl_i = 0; cl_i < cl_member_count; ++cl_i)
+ {
+ ocmember_T *m = &cl_mt[cl_i];
+ where_T where = WHERE_INIT;
+
+ if (STRCMP(if_var->ocm_name, m->ocm_name) != 0)
+ continue;
+
+ // Ensure the access type is same
+ if (if_var->ocm_access != m->ocm_access)
+ {
+ semsg(_(e_member_str_of_interface_str_has_different_access),
+ if_var->ocm_name, intf_class_name);
+ return FALSE;
+ }
+
+ // Ensure the type is matching.
+ if (m->ocm_type == &t_any)
+ {
+ // variable type is not specified. Use the variable type in the
+ // interface.
+ m->ocm_type = if_var->ocm_type;
+ }
+ else
+ {
+ where.wt_func_name = (char *)m->ocm_name;
+ where.wt_kind = WT_MEMBER;
+ if (check_type(if_var->ocm_type, m->ocm_type, TRUE,
+ where) == FAIL)
+ return FALSE;
+ }
+
+ variable_present = TRUE;
+ break;
+ }
+
+ if (!variable_present && extends_cl != NULL)
+ {
+ int ext_cl_count = is_class_var
+ ? extends_cl->class_class_member_count
+ : extends_cl->class_obj_member_count;
+ ocmember_T *ext_cl_mt = is_class_var
+ ? extends_cl->class_class_members
+ : extends_cl->class_obj_members;
+ return intf_variable_present(intf_class_name, if_var,
+ is_class_var, ext_cl_mt,
+ ext_cl_count,
+ extends_cl->class_extends);
+ }
+
+ return variable_present;
+}
+
+/*
+ * Check the variables of the interface class "ifcl" match the class variables
+ * ("classmembers_gap") and object variables ("objmembers_gap") of a class.
+ * Returns TRUE if the class and object variables names are valid.
+ */
+ static int
+validate_interface_variables(
char_u *intf_class_name,
class_T *ifcl,
garray_T *classmembers_gap,
- garray_T *objmembers_gap)
+ garray_T *objmembers_gap,
+ class_T *extends_cl)
{
for (int loop = 1; loop <= 2; ++loop)
{
- // loop == 1: check class members
- // loop == 2: check object members
- int if_count = loop == 1 ? ifcl->class_class_member_count
+ // loop == 1: check class variables
+ // loop == 2: check object variables
+ int is_class_var = (loop == 1);
+ int if_count = is_class_var ? ifcl->class_class_member_count
: ifcl->class_obj_member_count;
if (if_count == 0)
continue;
- ocmember_T *if_ms = loop == 1 ? ifcl->class_class_members
+ ocmember_T *if_ms = is_class_var ? ifcl->class_class_members
: ifcl->class_obj_members;
- ocmember_T *cl_ms = (ocmember_T *)(loop == 1
+ ocmember_T *cl_ms = (ocmember_T *)(is_class_var
? classmembers_gap->ga_data
: objmembers_gap->ga_data);
- int cl_count = loop == 1 ? classmembers_gap->ga_len
+ int cl_count = is_class_var ? classmembers_gap->ga_len
: objmembers_gap->ga_len;
for (int if_i = 0; if_i < if_count; ++if_i)
{
- int cl_i;
- for (cl_i = 0; cl_i < cl_count; ++cl_i)
+ if (!intf_variable_present(intf_class_name, &if_ms[if_i],
+ is_class_var, cl_ms, cl_count, extends_cl))
{
- ocmember_T *m = &cl_ms[cl_i];
- where_T where = WHERE_INIT;
+ semsg(_(e_member_str_of_interface_str_not_implemented),
+ if_ms[if_i].ocm_name, intf_class_name);
+ return FALSE;
+ }
+ }
+ }
- if (STRCMP(if_ms[if_i].ocm_name, m->ocm_name) != 0)
- continue;
+ return TRUE;
+}
- // Ensure the type is matching.
- where.wt_func_name = (char *)m->ocm_name;
- where.wt_kind = WT_MEMBER;
- if (check_type(if_ms[if_i].ocm_type, m->ocm_type, TRUE,
+/*
+ * Returns TRUE if the method signature of "if_method" and "cl_method" matches.
+ */
+ static int
+intf_method_type_matches(ufunc_T *if_method, ufunc_T *cl_method)
+{
+ where_T where = WHERE_INIT;
+
+ // Ensure the type is matching.
+ where.wt_func_name = (char *)if_method->uf_name;
+ where.wt_kind = WT_METHOD;
+ if (check_type(if_method->uf_func_type, cl_method->uf_func_type, TRUE,
where) == FAIL)
- return FALSE;
+ return FALSE;
- if (if_ms[if_i].ocm_access != m->ocm_access)
- {
- semsg(_(e_member_str_of_interface_str_has_different_access),
- if_ms[if_i].ocm_name, intf_class_name);
- return FALSE;
- }
+ return TRUE;
+}
- break;
- }
- if (cl_i == cl_count)
- {
- semsg(_(e_member_str_of_interface_str_not_implemented),
- if_ms[if_i].ocm_name, intf_class_name);
+/*
+ * Returns TRUE if the interface method "if_ufunc" is present in the list of
+ * methods in "cl_fp" or in the parent lineage of one of the extended classes
+ * in "extends_cl". For a class method, 'is_class_method' is TRUE.
+ */
+ static int
+intf_method_present(
+ ufunc_T *if_ufunc,
+ int is_class_method,
+ ufunc_T **cl_fp,
+ int cl_count,
+ class_T *extends_cl)
+{
+ int method_present = FALSE;
+
+ for (int cl_i = 0; cl_i < cl_count; ++cl_i)
+ {
+ char_u *cl_name = cl_fp[cl_i]->uf_name;
+ if (STRCMP(if_ufunc->uf_name, cl_name) == 0)
+ {
+ // Ensure the type is matching.
+ if (!intf_method_type_matches(if_ufunc, cl_fp[cl_i]))
return FALSE;
- }
+ method_present = TRUE;
+ break;
}
}
- return TRUE;
+ if (!method_present && extends_cl != NULL)
+ {
+ ufunc_T **ext_cl_fp = (ufunc_T **)(is_class_method
+ ? extends_cl->class_class_functions
+ : extends_cl->class_obj_methods);
+ int ext_cl_count = is_class_method
+ ? extends_cl->class_class_function_count
+ : extends_cl->class_obj_method_count;
+ return intf_method_present(if_ufunc, is_class_method, ext_cl_fp,
+ ext_cl_count,
+ extends_cl->class_extends);
+ }
+
+ return method_present;
}
/*
- * Check the functions/methods of the interface class "ifcl" match the class
- * methods ("classfunctions_gap") and object functions ("objmemthods_gap") of a
- * class.
- * Returns TRUE if the class and object member names are valid.
+ * Validate that a new class implements all the class/instance methods in the
+ * interface "ifcl". The new class methods are in "classfunctions_gap" and the
+ * new object methods are in "objmemthods_gap". Also validates the method
+ * types.
+ * Returns TRUE if all the interface class/object methods are implemented in
+ * the new class.
*/
static int
validate_interface_methods(
char_u *intf_class_name,
class_T *ifcl,
garray_T *classfunctions_gap,
- garray_T *objmethods_gap)
+ garray_T *objmethods_gap,
+ class_T *extends_cl)
{
for (int loop = 1; loop <= 2; ++loop)
{
- // loop == 1: check class functions
+ // loop == 1: check class methods
// loop == 2: check object methods
- int if_count = loop == 1 ? ifcl->class_class_function_count
+ int is_class_method = (loop == 1);
+ int if_count = is_class_method ? ifcl->class_class_function_count
: ifcl->class_obj_method_count;
if (if_count == 0)
continue;
- ufunc_T **if_fp = loop == 1 ? ifcl->class_class_functions
+ ufunc_T **if_fp = is_class_method ? ifcl->class_class_functions
: ifcl->class_obj_methods;
- ufunc_T **cl_fp = (ufunc_T **)(loop == 1
+ ufunc_T **cl_fp = (ufunc_T **)(is_class_method
? classfunctions_gap->ga_data
: objmethods_gap->ga_data);
- int cl_count = loop == 1 ? classfunctions_gap->ga_len
+ int cl_count = is_class_method ? classfunctions_gap->ga_len
: objmethods_gap->ga_len;
for (int if_i = 0; if_i < if_count; ++if_i)
{
char_u *if_name = if_fp[if_i]->uf_name;
- int cl_i;
- for (cl_i = 0; cl_i < cl_count; ++cl_i)
- {
- char_u *cl_name = cl_fp[cl_i]->uf_name;
- if (STRCMP(if_name, cl_name) == 0)
- {
- where_T where = WHERE_INIT;
- // Ensure the type is matching.
- where.wt_func_name = (char *)if_name;
- where.wt_kind = WT_METHOD;
- if (check_type(if_fp[if_i]->uf_func_type,
- cl_fp[cl_i]->uf_func_type, TRUE, where) == FAIL)
- return FALSE;
- break;
- }
- }
- if (cl_i == cl_count)
+ if (!intf_method_present(if_fp[if_i], is_class_method, cl_fp,
+ cl_count, extends_cl))
{
- semsg(_(e_function_str_of_interface_str_not_implemented),
+ semsg(_(e_method_str_of_interface_str_not_implemented),
if_name, intf_class_name);
return FALSE;
}
garray_T *classfunctions_gap,
garray_T *classmembers_gap,
garray_T *objmethods_gap,
- garray_T *objmembers_gap)
+ garray_T *objmembers_gap,
+ class_T *extends_cl)
{
int success = TRUE;
intf_classes[i] = ifcl;
++ifcl->class_refcount;
- // check the members of the interface match the members of the class
- success = validate_interface_members(impl, ifcl, classmembers_gap,
- objmembers_gap);
+ // check the variables of the interface match the members of the class
+ success = validate_interface_variables(impl, ifcl, classmembers_gap,
+ objmembers_gap, extends_cl);
// check the functions/methods of the interface match the
// functions/methods of the class
if (success)
success = validate_interface_methods(impl, ifcl,
- classfunctions_gap, objmethods_gap);
+ classfunctions_gap, objmethods_gap,
+ extends_cl);
clear_tv(&tv);
}
class_T *ifcl,
class_T *cl,
garray_T *objmethods,
- int pobj_method_offset,
- int is_interface)
+ int pobj_method_offset)
{
if (ifcl == NULL)
return OK;
// extended class object method is not overridden by the child class.
// Keep the method declared in one of the parent classes in the
// lineage.
- if (!done && !is_interface)
+ if (!done)
{
// If "ifcl" is not the immediate parent of "cl", then search in
// the intermediate parent classes.
static int
add_lookup_tables(class_T *cl, class_T *extends_cl, garray_T *objmethods_gap)
{
+ // update the lookup table for all the implemented interfaces
for (int i = 0; i < cl->class_interface_count; ++i)
{
class_T *ifcl = cl->class_interfaces_cl[i];
- if (update_member_method_lookup_table(ifcl, cl, objmethods_gap,
- 0, TRUE) == FAIL)
- return FAIL;
+ // update the lookup table for this interface and all its super
+ // interfaces.
+ while (ifcl != NULL)
+ {
+ if (update_member_method_lookup_table(ifcl, cl, objmethods_gap,
+ 0) == FAIL)
+ return FAIL;
+ ifcl = ifcl->class_extends;
+ }
}
// Update the lookup table for the extended class, if any
while (pclass != NULL)
{
if (update_member_method_lookup_table(pclass, cl,
- objmethods_gap, pobj_method_offset, FALSE) == FAIL)
+ objmethods_gap, pobj_method_offset) == FAIL)
return FAIL;
pobj_method_offset += pclass->class_obj_method_count_child;
else if (STRNCMP(arg, "implements", 10) == 0
&& IS_WHITE_OR_NUL(arg[10]))
{
+ if (!is_class)
+ {
+ emsg(_(e_interface_cannot_use_implements));
+ goto early_ret;
+ }
+
if (ga_impl.ga_len > 0)
{
emsg(_(e_duplicate_implements));
break;
}
- if (!is_abstract)
+ if (!is_class)
+ // ignore "abstract" in an interface (as all the methods in an
+ // interface are abstract.
+ p = skipwhite(pa + 8);
+ else
{
- semsg(_(e_abstract_method_in_concrete_class), pa);
- break;
- }
+ if (!is_abstract)
+ {
+ semsg(_(e_abstract_method_in_concrete_class), pa);
+ break;
+ }
- abstract_method = TRUE;
- p = skipwhite(pa + 8);
- if (STRNCMP(p, "def", 3) != 0 && STRNCMP(p, "static", 6) != 0)
- {
- emsg(_(e_abstract_must_be_followed_by_def_or_static));
- break;
+ abstract_method = TRUE;
+ p = skipwhite(pa + 8);
+ if (STRNCMP(p, "def", 3) != 0 && STRNCMP(p, "static", 6) != 0)
+ {
+ emsg(_(e_abstract_must_be_followed_by_def_or_static));
+ break;
+ }
}
}
semsg(_(e_command_cannot_be_shortened_str), ps);
break;
}
+
+ if (!is_class)
+ {
+ emsg(_(e_static_cannot_be_used_in_interface));
+ break;
+ }
has_static = TRUE;
p = skipwhite(ps + 6);
}
char_u *varname_end = NULL;
type_T *type = NULL;
char_u *init_expr = NULL;
+
+ if (!is_class && *varname == '_')
+ {
+ // private variables are not supported in an interface
+ semsg(_(e_private_variable_str_in_interface), varname);
+ break;
+ }
+
if (parse_member(eap, line, varname, has_public,
&varname_end, &type_list, &type,
is_class ? &init_expr: NULL) == FAIL)
char_u *name = uf->uf_name;
int is_new = STRNCMP(name, "new", 3) == 0;
+ if (!is_class && *name == '_')
+ {
+ // private variables are not supported in an interface
+ semsg(_(e_private_method_str_in_interface), name);
+ func_clear_free(uf, FALSE);
+ break;
+ }
if (is_new && !is_valid_constructor(uf, is_abstract,
has_static))
{
// Check the "extends" class is valid.
if (success && extends != NULL)
- success = validate_extends_class(extends, &extends_cl);
+ success = validate_extends_class(extends, &extends_cl, is_class);
VIM_CLEAR(extends);
// Check the new object methods to make sure their access (public or
success = validate_extends_methods(&objmethods, extends_cl);
// Check the new class and object variables are not duplicates of the
- // variables in the extended class lineage.
+ // variables in the extended class lineage. If an interface is extending
+ // another interface, then it can duplicate the member variables.
if (success && extends_cl != NULL)
- success = validate_extends_members(&objmembers, extends_cl);
+ {
+ if (is_class)
+ success = extends_check_dup_members(&objmembers, extends_cl);
+ else
+ success = extends_check_intf_var_type(&objmembers, extends_cl);
+ }
// When extending an abstract class, make sure all the abstract methods in
// the parent class are implemented. If the current class is an abstract
success = validate_implements_classes(&ga_impl, intf_classes,
&classfunctions, &classmembers,
- &objmethods, &objmembers);
+ &objmethods, &objmembers,
+ extends_cl);
}
// Check no function argument name is used as a class member.
{
if (cl == other_cl)
return TRUE;
- // Check the implemented interfaces.
+ // Check the implemented interfaces and the super interfaces
for (int i = cl->class_interface_count - 1; i >= 0; --i)
- if (cl->class_interfaces_cl[i] == other_cl)
- return TRUE;
+ {
+ class_T *intf = cl->class_interfaces_cl[i];
+ while (intf != NULL)
+ {
+ if (intf == other_cl)
+ return TRUE;
+ // check the super interfaces
+ intf = intf->class_extends;
+ }
+ }
}
return FALSE;