mirror of
				https://github.com/vim/vim.git
				synced 2025-10-31 09:57:14 -04:00 
			
		
		
		
	patch 9.0.2072: Vim9: no nr2str conversion in list-unpack
Problem: Vim9: no nr2str conversion in list-unpack Solution: Generate 2STRING instruction to convert dict index to string Generate instruction to convert dict index to a string fixes: #13417 closes: #13424 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
		
				
					committed by
					
						 Christian Brabandt
						Christian Brabandt
					
				
			
			
				
	
			
			
			
						parent
						
							10407df7a9
						
					
				
				
					commit
					c229a6ac07
				
			| @@ -2986,4 +2986,21 @@ def Test_heredoc_expr() | ||||
|   v9.CheckDefAndScriptFailure(lines, 'E15: Invalid expression: "}"') | ||||
| enddef | ||||
|  | ||||
| " Test for assigning to a multi-dimensional list item. | ||||
| def Test_list_item_assign() | ||||
|   var lines =<< trim END | ||||
|     vim9script | ||||
|  | ||||
|     def Foo() | ||||
|         var l: list<list<string>> = [['x', 'x', 'x'], ['y', 'y', 'y']] | ||||
|         var z: number = 1 | ||||
|  | ||||
|         [l[1][2], z] = ['a', 20] | ||||
|         assert_equal([['x', 'x', 'x'], ['y', 'y', 'a']], l) | ||||
|     enddef | ||||
|     Foo() | ||||
|   END | ||||
|   v9.CheckSourceSuccess(lines) | ||||
| enddef | ||||
|  | ||||
| " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker | ||||
|   | ||||
| @@ -8442,4 +8442,133 @@ def Test_class_variable_as_operands() | ||||
|   v9.CheckSourceSuccess(lines) | ||||
| enddef | ||||
|  | ||||
| " Test for checking the type of the key used to access an object dict member. | ||||
| def Test_dict_member_key_type_check() | ||||
|   var lines =<< trim END | ||||
|     vim9script | ||||
|  | ||||
|     abstract class State | ||||
|       this.numbers: dict<string> = {0: 'nil', 1: 'unity'} | ||||
|     endclass | ||||
|  | ||||
|     class Test extends State | ||||
|       def ObjMethodTests() | ||||
|         var cursor: number = 0 | ||||
|         var z: number = 0 | ||||
|         [this.numbers[cursor]] = ['zero.1'] | ||||
|         assert_equal({0: 'zero.1', 1: 'unity'}, this.numbers) | ||||
|         [this.numbers[string(cursor)], z] = ['zero.2', 1] | ||||
|         assert_equal({0: 'zero.2', 1: 'unity'}, this.numbers) | ||||
|         [z, this.numbers[string(cursor)]] = [1, 'zero.3'] | ||||
|         assert_equal({0: 'zero.3', 1: 'unity'}, this.numbers) | ||||
|         [this.numbers[cursor], z] = ['zero.4', 1] | ||||
|         assert_equal({0: 'zero.4', 1: 'unity'}, this.numbers) | ||||
|         [z, this.numbers[cursor]] = [1, 'zero.5'] | ||||
|         assert_equal({0: 'zero.5', 1: 'unity'}, this.numbers) | ||||
|       enddef | ||||
|  | ||||
|       static def ClassMethodTests(that: State) | ||||
|         var cursor: number = 0 | ||||
|         var z: number = 0 | ||||
|         [that.numbers[cursor]] = ['zero.1'] | ||||
|         assert_equal({0: 'zero.1', 1: 'unity'}, that.numbers) | ||||
|         [that.numbers[string(cursor)], z] = ['zero.2', 1] | ||||
|         assert_equal({0: 'zero.2', 1: 'unity'}, that.numbers) | ||||
|         [z, that.numbers[string(cursor)]] = [1, 'zero.3'] | ||||
|         assert_equal({0: 'zero.3', 1: 'unity'}, that.numbers) | ||||
|         [that.numbers[cursor], z] = ['zero.4', 1] | ||||
|         assert_equal({0: 'zero.4', 1: 'unity'}, that.numbers) | ||||
|         [z, that.numbers[cursor]] = [1, 'zero.5'] | ||||
|         assert_equal({0: 'zero.5', 1: 'unity'}, that.numbers) | ||||
|       enddef | ||||
|  | ||||
|       def new() | ||||
|       enddef | ||||
|  | ||||
|       def newMethodTests() | ||||
|         var cursor: number = 0 | ||||
|         var z: number | ||||
|         [this.numbers[cursor]] = ['zero.1'] | ||||
|         assert_equal({0: 'zero.1', 1: 'unity'}, this.numbers) | ||||
|         [this.numbers[string(cursor)], z] = ['zero.2', 1] | ||||
|         assert_equal({0: 'zero.2', 1: 'unity'}, this.numbers) | ||||
|         [z, this.numbers[string(cursor)]] = [1, 'zero.3'] | ||||
|         assert_equal({0: 'zero.3', 1: 'unity'}, this.numbers) | ||||
|         [this.numbers[cursor], z] = ['zero.4', 1] | ||||
|         assert_equal({0: 'zero.4', 1: 'unity'}, this.numbers) | ||||
|         [z, this.numbers[cursor]] = [1, 'zero.5'] | ||||
|         assert_equal({0: 'zero.5', 1: 'unity'}, this.numbers) | ||||
|       enddef | ||||
|     endclass | ||||
|  | ||||
|     def DefFuncTests(that: Test) | ||||
|       var cursor: number = 0 | ||||
|       var z: number | ||||
|       [that.numbers[cursor]] = ['zero.1'] | ||||
|       assert_equal({0: 'zero.1', 1: 'unity'}, that.numbers) | ||||
|       [that.numbers[string(cursor)], z] = ['zero.2', 1] | ||||
|       assert_equal({0: 'zero.2', 1: 'unity'}, that.numbers) | ||||
|       [z, that.numbers[string(cursor)]] = [1, 'zero.3'] | ||||
|       assert_equal({0: 'zero.3', 1: 'unity'}, that.numbers) | ||||
|       [that.numbers[cursor], z] = ['zero.4', 1] | ||||
|       assert_equal({0: 'zero.4', 1: 'unity'}, that.numbers) | ||||
|       [z, that.numbers[cursor]] = [1, 'zero.5'] | ||||
|       assert_equal({0: 'zero.5', 1: 'unity'}, that.numbers) | ||||
|     enddef | ||||
|  | ||||
|     Test.newMethodTests() | ||||
|     Test.new().ObjMethodTests() | ||||
|     Test.ClassMethodTests(Test.new()) | ||||
|     DefFuncTests(Test.new()) | ||||
|  | ||||
|     const test: Test = Test.new() | ||||
|     var cursor: number = 0 | ||||
|     [test.numbers[cursor], cursor] = ['zero', 1] | ||||
|     [cursor, test.numbers[cursor]] = [1, 'one'] | ||||
|     assert_equal({0: 'zero', 1: 'one'}, test.numbers) | ||||
|   END | ||||
|   v9.CheckSourceSuccess(lines) | ||||
|  | ||||
|   lines =<< trim END | ||||
|     vim9script | ||||
|  | ||||
|     class A | ||||
|       this.numbers: dict<string> = {a: '1', b: '2'} | ||||
|  | ||||
|       def new() | ||||
|       enddef | ||||
|  | ||||
|       def Foo() | ||||
|         var z: number | ||||
|         [this.numbers.a, z] = [{}, 10] | ||||
|       enddef | ||||
|     endclass | ||||
|  | ||||
|     var a = A.new() | ||||
|     a.Foo() | ||||
|   END | ||||
|   v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected string but got dict<unknown>', 2) | ||||
|  | ||||
|   lines =<< trim END | ||||
|     vim9script | ||||
|  | ||||
|     class A | ||||
|       this.numbers: dict<number> = {a: 1, b: 2} | ||||
|  | ||||
|       def new() | ||||
|       enddef | ||||
|  | ||||
|       def Foo() | ||||
|         var x: string = 'a' | ||||
|         var y: number | ||||
|         [this.numbers[x], y] = [{}, 10] | ||||
|       enddef | ||||
|     endclass | ||||
|  | ||||
|     var a = A.new() | ||||
|     a.Foo() | ||||
|   END | ||||
|   v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected number but got dict<unknown>', 3) | ||||
| enddef | ||||
|  | ||||
| " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker | ||||
|   | ||||
| @@ -560,6 +560,7 @@ def Test_disassemble_store_index() | ||||
|         '\d LOAD $0\_s*' .. | ||||
|         '\d MEMBER dd\_s*' .. | ||||
|         '\d\+ USEDICT\_s*' .. | ||||
|         '\d\+ 2STRING stack\[-2\]\_s*' .. | ||||
|         '\d\+ STOREINDEX any\_s*' .. | ||||
|         '\d\+ RETURN void', | ||||
|         res) | ||||
|   | ||||
| @@ -704,6 +704,8 @@ static char *(features[]) = | ||||
|  | ||||
| static int included_patches[] = | ||||
| {   /* Add new patch number below this line */ | ||||
| /**/ | ||||
|     2072, | ||||
| /**/ | ||||
|     2071, | ||||
| /**/ | ||||
|   | ||||
| @@ -2040,9 +2040,7 @@ compile_lhs( | ||||
| 	    lhs->lhs_member_type = m->ocm_type; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 	    lhs->lhs_member_type = lhs->lhs_type->tt_member; | ||||
| 	} | ||||
|     } | ||||
|     return OK; | ||||
| } | ||||
| @@ -2220,16 +2218,27 @@ compile_load_lhs( | ||||
| 		return FAIL; | ||||
| 	} | ||||
|  | ||||
| 	if (lhs->lhs_type->tt_type == VAR_DICT && var_start[varlen] == '[') | ||||
| 	{ | ||||
| 	    // If the lhs is a Dict variable and an item is accessed by "[", | ||||
| 	    // then need to convert the key into a string.  The top item in the | ||||
| 	    // type stack is the Dict and the second last item is the key. | ||||
| 	    if (may_generate_2STRING(-2, FALSE, cctx) == FAIL) | ||||
| 		return FAIL; | ||||
| 	} | ||||
|  | ||||
| 	// Now we can properly check the type.  The variable is indexed, thus | ||||
| 	// we need the member type.  For a class or object we don't know the | ||||
| 	// type yet, it depends on what member is used. | ||||
| 	// The top item in the stack is the Dict, followed by the key and then | ||||
| 	// the type of the value. | ||||
| 	vartype_T vartype = lhs->lhs_type->tt_type; | ||||
| 	type_T *member_type = lhs->lhs_type->tt_member; | ||||
| 	if (rhs_type != NULL && member_type != NULL | ||||
| 		&& vartype != VAR_OBJECT && vartype != VAR_CLASS | ||||
| 		&& rhs_type != &t_void | ||||
| 		&& need_type(rhs_type, member_type, FALSE, | ||||
| 					    -2, 0, cctx, FALSE, FALSE) == FAIL) | ||||
| 					    -3, 0, cctx, FALSE, FALSE) == FAIL) | ||||
| 	    return FAIL; | ||||
|     } | ||||
|     else | ||||
|   | ||||
		Reference in New Issue
	
	Block a user