" Test for :type command to create type aliases
def Test_typealias()
+ # Use type alias at script level
var lines =<< trim END
vim9script
type ListOfStrings = list<string>
- var a: ListOfStrings = ['a', 'b']
- assert_equal(['a', 'b'], a)
- def Foo(b: ListOfStrings): ListOfStrings
- var c: ListOfStrings = ['c', 'd']
- assert_equal(['c', 'd'], c)
- return b
+ def Foo(a: ListOfStrings): ListOfStrings
+ return a
enddef
+ var b: ListOfStrings = ['a', 'b']
+ assert_equal(['a', 'b'], b)
assert_equal(['e', 'f'], Foo(['e', 'f']))
assert_equal('typealias<list<string>>', typename(ListOfStrings))
assert_equal(v:t_typealias, type(ListOfStrings))
END
v9.CheckSourceSuccess(lines)
+ # Use type alias at def function level
+ lines =<< trim END
+ vim9script
+ type ListOfStrings = list<string>
+ def Foo(a: ListOfStrings): ListOfStrings
+ return a
+ enddef
+ def Bar()
+ var c: ListOfStrings = ['c', 'd']
+ assert_equal(['c', 'd'], c)
+ assert_equal(['e', 'f'], Foo(['e', 'f']))
+ assert_equal('typealias<list<string>>', typename(ListOfStrings))
+ assert_equal(v:t_typealias, type(ListOfStrings))
+ assert_equal('ListOfStrings', string(ListOfStrings))
+ assert_equal(false, null == ListOfStrings)
+ enddef
+ Bar()
+ END
+ v9.CheckSourceSuccess(lines)
+
# Use :type outside a Vim9 script
lines =<< trim END
type Index = number
# type alias starting with lower-case letter
lines =<< trim END
vim9script
- type index number
+ type index = number
END
- v9.CheckSourceFailure(lines, 'E1394: Type name must start with an uppercase letter: index number', 2)
+ v9.CheckSourceFailure(lines, 'E1394: Type name must start with an uppercase letter: index = number', 2)
# No white space following the alias name
lines =<< trim END
END
v9.CheckSourceFailure(lines, 'E1396: Type alias "MyList" already exists', 3)
- # Sourcing a script twice (which will free script local variables)
+ # def function argument name collision with a type alias
+ lines =<< trim END
+ vim9script
+ type A = list<number>
+ def Foo(A: number)
+ enddef
+ END
+ v9.CheckSourceFailure(lines, 'E1168: Argument already declared in the script: A: number)', 3)
+
+ # def function local variable name collision with a type alias
+ lines =<< trim END
+ vim9script
+ type A = list<number>
+ def Foo()
+ var A: number = 10
+ enddef
+ Foo()
+ END
+ v9.CheckSourceFailure(lines, 'E1054: Variable already declared in the script: A', 1)
+
+ # type alias a variable
+ lines =<< trim END
+ vim9script
+ var A: list<number> = []
+ type B = A
+ END
+ v9.CheckSourceFailure(lines, 'E1010: Type not recognized: A', 3)
+
+ # type alias a class
lines =<< trim END
vim9script
class C
endclass
type AC = C
- assert_equal('typealias<object<C>>', typename(AC))
+ assert_equal('class<C>', typename(AC))
END
+ v9.CheckSourceSuccess(lines)
+
+ # Sourcing a script twice (which will free script local variables)
+ # Uses "lines" from the previous test
new
setline(1, lines)
:source
:source
bw!
+ # type alias a type alias
+ lines =<< trim END
+ vim9script
+ type A = string
+ type B = A
+ var b: B = 'abc'
+ assert_equal('abc', b)
+ def Foo()
+ var c: B = 'def'
+ assert_equal('def', c)
+ enddef
+ Foo()
+ END
+ v9.CheckSourceSuccess(lines)
+
# Assigning to a type alias (script level)
lines =<< trim END
vim9script
type MyType = list<number>
MyType = [1, 2, 3]
END
- v9.CheckSourceFailure(lines, 'E1395: Type alias "MyType" cannot be used as a variable', 3)
+ v9.CheckSourceFailure(lines, 'E1395: Type alias "MyType" cannot be modified', 3)
# Assigning a type alias (def function level)
lines =<< trim END
enddef
Foo()
END
- v9.CheckSourceFailure(lines, 'E1395: Type alias "A" cannot be used as a variable', 1)
+ v9.CheckSourceFailure(lines, 'E1403: Type alias "A" cannot be used as a value', 1)
# Using type alias in an expression (script level)
lines =<< trim END
vim9script
type MyType = list<number>
- assert_fails('var m = MyType', 'E1395: Type alias "MyType" cannot be used as a variable')
- assert_fails('var i = MyType + 1', 'E1395: Type alias "MyType" cannot be used as a variable')
- assert_fails('var f = 1.0 + MyType', 'E1395: Type alias "MyType" cannot be used as a variable')
- assert_fails('MyType += 10', 'E1395: Type alias "MyType" cannot be used as a variable')
+ assert_fails('var m = MyType', 'E1403: Type alias "MyType" cannot be used as a value')
+ assert_fails('var i = MyType + 1', 'E1400: Using type alias "MyType" as a Number')
+ assert_fails('var f = 1.0 + MyType', 'E1400: Using type alias "MyType" as a Number')
+ assert_fails('MyType += 10', 'E1395: Type alias "MyType" cannot be modified')
+ assert_fails('var x = $"-{MyType}-"', 'E1402: Using type alias "MyType" as a String')
+ assert_fails('var x = MyType[1]', 'E909: Cannot index a special variable')
END
v9.CheckSourceSuccess(lines)
enddef
Foo()
END
- v9.CheckSourceFailure(lines, 'E1395: Type alias "MyType" cannot be used as a variable', 1)
+ v9.CheckSourceFailure(lines, 'E1051: Wrong argument type for +', 1)
# Using type alias in an expression (def function level)
lines =<< trim END
END
v9.CheckSourceFailure(lines, 'E46: Cannot change read-only variable "MyType"', 1)
+ # Convert type alias to a string (def function level)
+ lines =<< trim END
+ vim9script
+ type MyType = list<number>
+ def Foo()
+ var x = $"-{MyType}-"
+ enddef
+ Foo()
+ END
+ v9.CheckSourceFailure(lines, 'E1105: Cannot convert typealias to string', 1)
+
+ # Using type alias as a float
+ lines =<< trim END
+ vim9script
+ type B = number
+ sort([1.1, B], 'f')
+ END
+ v9.CheckSourceFailure(lines, 'E1401: Using type alias "B" as a Float', 3)
+
# Creating a typealias in a def function
lines =<< trim END
vim9script
enddef
Foo()
END
- v9.CheckSourceFailure(lines, 'E1395: Type alias "A" cannot be used as a variable', 2)
+ v9.CheckSourceFailure(lines, 'E1072: Cannot compare typealias with number', 2)
+
+ # casting a number to a type alias (script level)
+ lines =<< trim END
+ vim9script
+ type MyType = bool
+ assert_equal(true, <MyType>1 == true)
+ END
+ v9.CheckSourceSuccess(lines)
enddef
" Test for exporting and importing type aliases
-def Test_import_typealias()
+def Test_typealias_import()
var lines =<< trim END
vim9script
export type MyType = list<number>
assert_equal([4, 5, 6], myList2)
END
v9.CheckScriptSuccess(lines)
+
+ # Using an exported class to create a type alias
+ lines =<< trim END
+ vim9script
+ export class MyClass
+ this.val = 10
+ endclass
+ END
+ writefile(lines, 'Xtypeexport4.vim', 'D')
+ lines =<< trim END
+ vim9script
+ import './Xtypeexport4.vim' as T
+
+ type MyType3 = T.MyClass
+ var c: MyType3 = T.MyClass.new()
+ assert_equal(10, c.val)
+ END
+ v9.CheckScriptSuccess(lines)
enddef
" Test for using typealias as a def function argument and return type
END
v9.CheckScriptFailure(lines, 'E701: Invalid type for len()', 3)
+ # Using a type alias with len()
+ lines =<< trim END
+ vim9script
+ type A = list<func>
+ def Foo()
+ var x = len(A)
+ enddef
+ Foo()
+ END
+ v9.CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected list<any> but got typealias', 1)
+
# Using a type alias with eval()
lines =<< trim END
vim9script
enddef
Foo()
END
- v9.CheckScriptFailure(lines, 'E1395: Type alias "A" cannot be used as a variable', 1)
+ v9.CheckScriptFailure(lines, 'E1403: Type alias "A" cannot be used as a value', 1)
enddef
" Test for type alias refcount
v9.CheckScriptSuccess(lines)
enddef
+" Test for using instanceof() with a type alias
+def Test_typealias_instanceof()
+ var lines =<< trim END
+ vim9script
+ class C
+ endclass
+
+ type Ctype = C
+ var o = C.new()
+ assert_equal(1, instanceof(o, Ctype))
+ type Ntype = number
+ assert_fails('instanceof(o, Ntype)', 'E693: List or Class required for argument 2')
+ assert_equal(1, instanceof(o, [Ctype]))
+ END
+ v9.CheckScriptSuccess(lines)
+enddef
+
+" Test for type aliasing a class
+def Test_typealias_class()
+ var lines =<< trim END
+ vim9script
+ class C
+ this.color = 'green'
+ endclass
+ type MyClass = C
+ var o: MyClass = MyClass.new()
+ assert_equal('green', o.color)
+ END
+ v9.CheckScriptSuccess(lines)
+enddef
+
" Keep this last, it messes up highlighting.
def Test_substitute_cmd()
new
goto done;
}
- // Add the user-defined type to the script-local variables.
- tv.v_type = VAR_TYPEALIAS;
- tv.v_lock = 0;
- tv.vval.v_typealias = ALLOC_CLEAR_ONE(typealias_T);
- ++tv.vval.v_typealias->ta_refcount;
- tv.vval.v_typealias->ta_name = vim_strsave(name_start);
- tv.vval.v_typealias->ta_type = type;
+ // Create a script-local variable for the type alias.
+ if (type->tt_type != VAR_OBJECT)
+ {
+ tv.v_type = VAR_TYPEALIAS;
+ tv.v_lock = 0;
+ tv.vval.v_typealias = ALLOC_CLEAR_ONE(typealias_T);
+ ++tv.vval.v_typealias->ta_refcount;
+ tv.vval.v_typealias->ta_name = vim_strsave(name_start);
+ tv.vval.v_typealias->ta_type = type;
+ }
+ else
+ {
+ // When creating a type alias for a class, use the class type itself to
+ // create the type alias variable. This is needed to use the type
+ // alias to invoke class methods (e.g. new()) and use class variables.
+ tv.v_type = VAR_CLASS;
+ tv.v_lock = 0;
+ tv.vval.v_class = type->tt_class;
+ ++tv.vval.v_class->class_refcount;
+ }
set_var_const(name_start, current_sctx.sc_sid, NULL, &tv, FALSE,
ASSIGN_CONST | ASSIGN_FINAL, 0);
typval_T *object_tv = &argvars[0];
typval_T *classinfo_tv = &argvars[1];
listitem_T *li;
+ class_T *c;
rettv->vval.v_number = VVAL_FALSE;
{
FOR_ALL_LIST_ITEMS(classinfo_tv->vval.v_list, li)
{
- if (li->li_tv.v_type != VAR_CLASS)
+ if (li->li_tv.v_type != VAR_CLASS && !tv_class_alias(&li->li_tv))
{
emsg(_(e_class_required));
return;
}
- if (class_instance_of(object_tv->vval.v_object->obj_class,
- li->li_tv.vval.v_class) == TRUE)
+ if (li->li_tv.v_type == VAR_TYPEALIAS)
+ c = li->li_tv.vval.v_typealias->ta_type->tt_class;
+ else
+ c = li->li_tv.vval.v_class;
+
+ if (class_instance_of(object_tv->vval.v_object->obj_class, c)
+ == TRUE)
{
rettv->vval.v_number = VVAL_TRUE;
return;
}
}
+
+ return;
}
- else if (classinfo_tv->v_type == VAR_CLASS)
- {
- rettv->vval.v_number = class_instance_of(object_tv->vval.v_object->obj_class,
- classinfo_tv->vval.v_class);
- }
+
+ if (classinfo_tv->v_type == VAR_TYPEALIAS)
+ c = classinfo_tv->vval.v_typealias->ta_type->tt_class;
+ else
+ c = classinfo_tv->vval.v_class;
+
+ rettv->vval.v_number =
+ class_instance_of(object_tv->vval.v_object->obj_class, c);
}
#endif // FEAT_EVAL