patch 9.1.0398: Vim9: imported vars are not properly type checked
Problem:  Vim9: imported vars are not properly type checked
Solution: Check the imported variable type properly
          (Yegappan Lakshmanan)
closes: #14729
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
			
			
This commit is contained in:
		
				
					committed by
					
						 Christian Brabandt
						Christian Brabandt
					
				
			
			
				
	
			
			
			
						parent
						
							c7a8eb5ff2
						
					
				
				
					commit
					9937d8b619
				
			
							
								
								
									
										37
									
								
								src/eval.c
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								src/eval.c
									
									
									
									
									
								
							| @ -1170,12 +1170,10 @@ get_lval_check_access( | ||||
|     static char_u * | ||||
| get_lval_imported( | ||||
|     lval_T	*lp, | ||||
|     typval_T	*rettv, | ||||
|     scid_T	imp_sid, | ||||
|     char_u	*p, | ||||
|     dictitem_T	**dip, | ||||
|     int		fne_flags, | ||||
|     int		vim9script) | ||||
|     int		fne_flags) | ||||
| { | ||||
|     ufunc_T	*ufunc; | ||||
|     type_T	*type = NULL; | ||||
| @ -1197,16 +1195,6 @@ get_lval_imported( | ||||
| 								TRUE) == -1) | ||||
| 	goto failed; | ||||
|  | ||||
|     if (vim9script && type != NULL) | ||||
|     { | ||||
| 	where_T	    where = WHERE_INIT; | ||||
|  | ||||
| 	// In a vim9 script, do type check and make sure the variable is | ||||
| 	// writable. | ||||
| 	if (check_typval_type(type, rettv, where) == FAIL) | ||||
| 	    goto failed; | ||||
|     } | ||||
|  | ||||
|     // Get the typval for the exported item | ||||
|     hashtab_T *ht = &SCRIPT_VARS(imp_sid); | ||||
|     if (ht == NULL) | ||||
| @ -1232,6 +1220,7 @@ get_lval_imported( | ||||
| 	goto failed; | ||||
|  | ||||
|     lp->ll_tv = &di->di_tv; | ||||
|     lp->ll_valtype = type; | ||||
|  | ||||
| success: | ||||
|     rc = OK; | ||||
| @ -1410,8 +1399,7 @@ get_lval( | ||||
| 	if (import != NULL) | ||||
| 	{ | ||||
| 	    p++;	// skip '.' | ||||
| 	    p = get_lval_imported(lp, rettv, import->imp_sid, p, &v, | ||||
| 						fne_flags, vim9script); | ||||
| 	    p = get_lval_imported(lp, import->imp_sid, p, &v, fne_flags); | ||||
| 	    if (p == NULL) | ||||
| 		return NULL; | ||||
| 	} | ||||
| @ -1754,6 +1742,12 @@ get_lval( | ||||
| 								       == FAIL) | ||||
| 		    return NULL; | ||||
| 	    } | ||||
|  | ||||
| 	    if (!lp->ll_range) | ||||
| 		// Indexing a single byte in a blob.  So the rhs type is a | ||||
| 		// number. | ||||
| 		lp->ll_valtype = &t_number; | ||||
|  | ||||
| 	    lp->ll_blob = lp->ll_tv->vval.v_blob; | ||||
| 	    lp->ll_tv = NULL; | ||||
| 	    break; | ||||
| @ -1782,7 +1776,7 @@ get_lval( | ||||
| 		return NULL; | ||||
| 	    } | ||||
|  | ||||
| 	    if (lp->ll_valtype != NULL) | ||||
| 	    if (lp->ll_valtype != NULL && !lp->ll_range) | ||||
| 		// use the type of the member | ||||
| 		lp->ll_valtype = lp->ll_valtype->tt_member; | ||||
|  | ||||
| @ -1896,6 +1890,17 @@ get_lval( | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     if (vim9script && lp->ll_valtype != NULL && rettv != NULL) | ||||
|     { | ||||
| 	where_T	    where = WHERE_INIT; | ||||
|  | ||||
| 	// In a vim9 script, do type check and make sure the variable is | ||||
| 	// writable. | ||||
| 	if (check_typval_type(lp->ll_valtype, rettv, where) == FAIL) | ||||
| 	    return NULL; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     clear_tv(&var1); | ||||
|     lp->ll_name_end = p; | ||||
|     return p; | ||||
|  | ||||
| @ -95,6 +95,18 @@ func Test_blob_assign() | ||||
|   END | ||||
|   call v9.CheckLegacyAndVim9Failure(lines, 'E979:') | ||||
|  | ||||
|   let lines =<< trim END | ||||
|       VAR b = 0zDEADBEEF | ||||
|       LET b[0 : 1] = 0x1122 | ||||
|   END | ||||
|   call v9.CheckLegacyAndVim9Failure(lines, ['E709:', 'E1012:', 'E709:']) | ||||
|  | ||||
|   let lines =<< trim END | ||||
|       VAR b = 0zDEADBEEF | ||||
|       LET b[0] = 0z11 | ||||
|   END | ||||
|   call v9.CheckLegacyAndVim9Failure(lines, ['E974:', 'E974:', 'E1012:']) | ||||
|  | ||||
|   let lines =<< trim END | ||||
|       VAR b = 0zDEADBEEF | ||||
|       LET b ..= 0z33 | ||||
|  | ||||
| @ -650,7 +650,7 @@ def Test_assign_index() | ||||
|       var bl = 0z11 | ||||
|       bl[1] = g:val | ||||
|   END | ||||
|   v9.CheckDefExecAndScriptFailure(lines, 'E1030: Using a String as a Number: "22"') | ||||
|   v9.CheckDefExecAndScriptFailure(lines, ['E1030: Using a String as a Number: "22"', 'E1012: Type mismatch; expected number but got string']) | ||||
|  | ||||
|   # should not read the next line when generating "a.b" | ||||
|   var a = {} | ||||
|  | ||||
| @ -3222,4 +3222,65 @@ def Test_autoload_import_dict_func() | ||||
|   &rtp = save_rtp | ||||
| enddef | ||||
|  | ||||
| " Test for changing the value of an imported Dict item | ||||
| def Test_set_imported_dict_item() | ||||
|   var lines =<< trim END | ||||
|     vim9script | ||||
|     export var dict1: dict<bool> = {bflag: false} | ||||
|     export var dict2: dict<dict<bool>> = {x: {bflag: false}} | ||||
|   END | ||||
|   writefile(lines, 'XimportedDict.vim', 'D') | ||||
|  | ||||
|   lines =<< trim END | ||||
|     vim9script | ||||
|     import './XimportedDict.vim' | ||||
|     assert_equal(XimportedDict.dict1.bflag, false) | ||||
|     XimportedDict.dict1.bflag = true | ||||
|     assert_equal(XimportedDict.dict1.bflag, true) | ||||
|     XimportedDict.dict2.x.bflag = true | ||||
|     assert_equal(XimportedDict.dict2.x.bflag, true) | ||||
|     assert_equal('bool', typename(XimportedDict.dict1.bflag)) | ||||
|     assert_equal('bool', typename(XimportedDict.dict2.x.bflag)) | ||||
|     assert_equal('bool', typename(XimportedDict.dict2['x'].bflag)) | ||||
|     assert_equal('bool', typename(XimportedDict.dict2.x['bflag'])) | ||||
|  | ||||
|     assert_equal(XimportedDict.dict1['bflag'], true) | ||||
|     XimportedDict.dict1['bflag'] = false | ||||
|     assert_equal(XimportedDict.dict1.bflag, false) | ||||
|     XimportedDict.dict2['x']['bflag'] = false | ||||
|     assert_equal(XimportedDict.dict2['x'].bflag, false) | ||||
|   END | ||||
|   v9.CheckScriptSuccess(lines) | ||||
|  | ||||
|   lines =<< trim END | ||||
|     vim9script | ||||
|     import './XimportedDict.vim' | ||||
|     XimportedDict.dict2.x.bflag = [] | ||||
|   END | ||||
|   v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected bool but got list<any>', 3) | ||||
| enddef | ||||
|  | ||||
| " Test for changing the value of an imported class member | ||||
| def Test_set_imported_class_member() | ||||
|   var lines =<< trim END | ||||
|     vim9script | ||||
|     export class Config | ||||
|       public static var option = false | ||||
|     endclass | ||||
|   END | ||||
|   writefile(lines, 'XimportedClass.vim', 'D') | ||||
|  | ||||
|   lines =<< trim END | ||||
|     vim9script | ||||
|     import './XimportedClass.vim' as foo | ||||
|     type FooConfig = foo.Config | ||||
|     assert_equal(false, FooConfig.option) | ||||
|     assert_equal(false, foo.Config.option) | ||||
|     foo.Config.option = true | ||||
|     assert_equal(true, foo.Config.option) | ||||
|     assert_equal(true, FooConfig.option) | ||||
|   END | ||||
|   v9.CheckScriptSuccess(lines) | ||||
| enddef | ||||
|  | ||||
| " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker | ||||
|  | ||||
| @ -704,6 +704,8 @@ static char *(features[]) = | ||||
|  | ||||
| static int included_patches[] = | ||||
| {   /* Add new patch number below this line */ | ||||
| /**/ | ||||
|     398, | ||||
| /**/ | ||||
|     397, | ||||
| /**/ | ||||
|  | ||||
		Reference in New Issue
	
	Block a user