checker: support value array elements of `[heap]` type inside struct ref (#9899)

pull/9892/head^2
Uwe Krüger 2021-04-28 06:47:00 +02:00 committed by GitHub
parent f46868133b
commit f4e92997f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 140 additions and 2 deletions

View File

@ -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,8 +5899,10 @@ pub fn (mut c Checker) mark_as_referenced(mut node ast.Expr) {
}
}
ast.SelectorExpr {
if !node.expr_type.is_ptr() {
c.mark_as_referenced(mut &node.expr)
}
}
ast.IndexExpr {
c.mark_as_referenced(mut &node.left)
}

View 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'"
}

View File

@ -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
}