checker: support value array elements of `[heap]` type inside struct ref (#9899)
							parent
							
								
									f46868133b
								
							
						
					
					
						commit
						f4e92997f2
					
				|  | @ -86,6 +86,7 @@ mut: | |||
| 	using_new_err_struct bool | ||||
| 	inside_selector_expr bool | ||||
| 	inside_println_arg   bool | ||||
| 	inside_decl_rhs      bool | ||||
| } | ||||
| 
 | ||||
| pub fn new_checker(table &ast.Table, pref &pref.Preferences) Checker { | ||||
|  | @ -515,7 +516,8 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | |||
| 			c.error('struct `$type_sym.name` is declared with a `[noinit]` attribute, so ' + | ||||
| 				'it cannot be initialized with `$type_sym.name{}`', struct_init.pos) | ||||
| 		} | ||||
| 		if info.is_heap && !c.inside_ref_lit && !c.inside_unsafe && !struct_init.typ.is_ptr() { | ||||
| 		if info.is_heap && c.inside_decl_rhs && !c.inside_ref_lit && !c.inside_unsafe | ||||
| 			&& !struct_init.typ.is_ptr() { | ||||
| 			c.error('`$type_sym.name` type can only be used as a reference `&$type_sym.name` or inside a `struct` reference', | ||||
| 				struct_init.pos) | ||||
| 		} | ||||
|  | @ -2979,7 +2981,9 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) { | |||
| 					c.inside_ref_lit = c.inside_ref_lit || left.info.share == .shared_t | ||||
| 				} | ||||
| 			} | ||||
| 			c.inside_decl_rhs = is_decl | ||||
| 			right_type := c.expr(assign_stmt.right[i]) | ||||
| 			c.inside_decl_rhs = false | ||||
| 			c.inside_ref_lit = old_inside_ref_lit | ||||
| 			if assign_stmt.right_types.len == i { | ||||
| 				assign_stmt.right_types << c.check_expr_opt_call(assign_stmt.right[i], | ||||
|  | @ -5895,7 +5899,9 @@ pub fn (mut c Checker) mark_as_referenced(mut node ast.Expr) { | |||
| 			} | ||||
| 		} | ||||
| 		ast.SelectorExpr { | ||||
| 			c.mark_as_referenced(mut &node.expr) | ||||
| 			if !node.expr_type.is_ptr() { | ||||
| 				c.mark_as_referenced(mut &node.expr) | ||||
| 			} | ||||
| 		} | ||||
| 		ast.IndexExpr { | ||||
| 			c.mark_as_referenced(mut &node.left) | ||||
|  |  | |||
|  | @ -0,0 +1,101 @@ | |||
| [heap] | ||||
| struct GitStructure { | ||||
| pub mut: | ||||
| 	root  string | ||||
| 	repos []&GitRepo | ||||
| } | ||||
| 
 | ||||
| [heap] | ||||
| struct GitRepo { | ||||
| 	id int [skip] | ||||
| pub: | ||||
| 	path string // path on filesystem
 | ||||
| 	name string | ||||
| } | ||||
| 
 | ||||
| pub fn (mut gitstructure GitStructure) repo_get(name string) ?&GitRepo { | ||||
| 	for r in gitstructure.repos { | ||||
| 		if r.name == name { | ||||
| 			if name != '' { | ||||
| 				r2 := gitstructure.repos[r.id] | ||||
| 				return r2 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return error("Could not find repo for account name: '$name'") | ||||
| } | ||||
| 
 | ||||
| fn test_opt_ref_return() { | ||||
| 	mut gitstruct := &GitStructure{ | ||||
| 		root: 'r' | ||||
| 		repos: [ | ||||
| 			&GitRepo{ | ||||
| 				id: 0 | ||||
| 				path: 'testpath' | ||||
| 				name: 'thename' | ||||
| 			}, | ||||
| 		] | ||||
| 	} | ||||
| 	mut err_msg := '' | ||||
| 	a := gitstruct.repo_get('thename') or { | ||||
| 		err_msg = '$err' | ||||
| 		r := &GitRepo{} | ||||
| 		r | ||||
| 	} | ||||
| 	assert a.path == 'testpath' | ||||
| 	assert err_msg == '' | ||||
| 	b := gitstruct.repo_get('wrong_name') or { | ||||
| 		err_msg = '$err' | ||||
| 		r := &GitRepo{} | ||||
| 		r | ||||
| 	} | ||||
| 	assert b.path == '' | ||||
| 	assert err_msg == "Could not find repo for account name: 'wrong_name'" | ||||
| } | ||||
| 
 | ||||
| [heap] | ||||
| struct GitStructureNoRef { | ||||
| pub mut: | ||||
| 	root  string | ||||
| 	repos []GitRepo | ||||
| } | ||||
| 
 | ||||
| pub fn (mut gitstructure GitStructureNoRef) repo_get(name string) ?&GitRepo { | ||||
| 	for r in gitstructure.repos { | ||||
| 		if r.name == name { | ||||
| 			if name != '' { | ||||
| 				r2 := &gitstructure.repos[r.id] | ||||
| 				return r2 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return error("Could not find repo for account name: '$name'") | ||||
| } | ||||
| 
 | ||||
| fn test_opt_return() { | ||||
| 	mut gitstruct := &GitStructureNoRef{ | ||||
| 		root: 'r' | ||||
| 		repos: [ | ||||
| 			GitRepo{ | ||||
| 				id: 0 | ||||
| 				path: 'testpath2' | ||||
| 				name: 'thename2' | ||||
| 			}, | ||||
| 		] | ||||
| 	} | ||||
| 	mut err_msg := '' | ||||
| 	a := gitstruct.repo_get('thename2') or { | ||||
| 		err_msg = '$err' | ||||
| 		r := &GitRepo{} | ||||
| 		r | ||||
| 	} | ||||
| 	assert a.path == 'testpath2' | ||||
| 	assert err_msg == '' | ||||
| 	b := gitstruct.repo_get('wrong_name2') or { | ||||
| 		err_msg = '$err' | ||||
| 		r := &GitRepo{} | ||||
| 		r | ||||
| 	} | ||||
| 	assert b.path == '' | ||||
| 	assert err_msg == "Could not find repo for account name: 'wrong_name2'" | ||||
| } | ||||
|  | @ -63,3 +63,34 @@ fn test_ref_field() { | |||
| 	} | ||||
| 	assert y.a.n == 29 | ||||
| } | ||||
| 
 | ||||
| // Yxc should become [heap] implicitly because `Abc` is
 | ||||
| 
 | ||||
| struct Yxc { | ||||
| mut: | ||||
| 	a []Abc | ||||
| } | ||||
| 
 | ||||
| fn mod_heap_array(mut x Yxc) { | ||||
| 	x.a << Abc{ | ||||
| 		n: 9 | ||||
| 	} | ||||
| 	x.a[1] = Abc{ | ||||
| 		n: 13 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn test_heap_array() { | ||||
| 	mut z := &Yxc{ | ||||
| 		a: [ | ||||
| 			Abc{ | ||||
| 				n: 4 | ||||
| 			}, | ||||
| 			Abc{ | ||||
| 				n: 7 | ||||
| 			}, | ||||
| 		] | ||||
| 	} | ||||
| 	mod_heap_array(mut z) | ||||
| 	assert z.a[1].n == 13 | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue