mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: support value array elements of [heap]
type inside struct ref (#9899)
This commit is contained in:
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)
|
||||
|
101
vlib/v/tests/heap_reference_test.v
Normal file
101
vlib/v/tests/heap_reference_test.v
Normal file
@ -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
Block a user