1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen, checker, ast: add syntax support for reference x in for x in &somearrary { and for x in &somemap { loops (#15678)

This commit is contained in:
Ken 2022-09-08 19:36:40 +09:00 committed by GitHub
parent 9641ced901
commit 1738641567
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 112 additions and 14 deletions

View File

@ -1048,14 +1048,15 @@ pub:
val_is_mut bool // `for mut val in vals {` means that modifying `val` will modify the array
// and the array cannot be indexed inside the loop
pub mut:
cond Expr
key_type Type
val_type Type
cond_type Type
high_type Type
kind Kind // array/map/string
label string // `label: for {`
scope &Scope
val_is_ref bool // `for val in &arr {` means that value of `val` will be the reference of the value in `arr`
cond Expr
key_type Type
val_type Type
cond_type Type
high_type Type
kind Kind // array/map/string
label string // `label: for {`
scope &Scope
}
pub struct ForCStmt {

View File

@ -70,6 +70,22 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
node.scope.update_var_type(node.val_var, node.val_type)
} else {
sym := c.table.final_sym(typ)
if sym.kind != .string {
match mut node.cond {
ast.PrefixExpr {
node.val_is_ref = node.cond.op == .amp
}
ast.Ident {
match mut node.cond.info {
ast.IdentVar {
node.val_is_ref = !node.cond.is_mut() && node.cond.info.typ.is_ptr()
}
else {}
}
}
else {}
}
}
if sym.kind == .struct_ {
// iterators
next_fn := sym.find_method_with_generic_parent('next') or {
@ -148,6 +164,8 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
}
else {}
}
} else if node.val_is_ref {
value_type = value_type.ref()
}
node.cond_type = typ
node.kind = sym.kind

View File

@ -178,7 +178,7 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
// instead of
// `int* val = ((int**)arr.data)[i];`
// right := if node.val_is_mut { styp } else { styp + '*' }
right := if node.val_is_mut {
right := if node.val_is_mut || node.val_is_ref {
'(($styp)$cond_var${op_field}data) + $i'
} else {
'(($styp*)$cond_var${op_field}data)[$i]'
@ -295,7 +295,7 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
} else {
val_styp := g.typ(node.val_type)
if node.val_type.is_ptr() {
if node.val_is_mut {
if node.val_is_mut || node.val_is_ref {
g.write('$val_styp ${c_name(node.val_var)} = &(*($val_styp)')
} else {
g.write('$val_styp ${c_name(node.val_var)} = (*($val_styp*)')

View File

@ -0,0 +1,31 @@
fn test_for_in_ref_val_ref_arr() {
arr := [1, 2, 3, 4, 5]
mut rets := []&int{}
mut expects := unsafe { []&int{len: 5, init: &arr[it]} }
for val in &arr {
println(val)
rets << val
}
for i, val in &arr {
assert voidptr(val) == voidptr(rets[i])
}
assert rets == expects
}
fn test_for_in_ref_val_ref_arr_ident() {
arr_ := [1, 2, 3, 4, 5]
arr := &arr_
mut rets := []&int{}
mut expects := unsafe { []&int{len: 5, init: &arr_[it]} }
for val in arr {
rets << val
}
for i, val in arr {
assert voidptr(val) == voidptr(rets[i])
}
assert rets == expects
}

View File

@ -0,0 +1,48 @@
fn test_for_in_ref_val_ref_map() {
mut mp := {
'a': 1
'b': 2
'c': 3
'd': 4
'e': 5
}
mut rets := map[string]&int{}
mut expects := map[string]&int{}
for k, mut val in mp {
expects[k] = unsafe { val }
}
for k, val in &mp {
rets[k] = unsafe { val }
}
for k, val in &mp {
assert voidptr(val) == voidptr(expects[k])
}
assert rets == expects
}
fn test_for_in_ref_val_ref_map_ident() {
mut mp_ := {
'a': 1
'b': 2
'c': 3
'd': 4
'e': 5
}
mp := &mp_
mut rets := map[string]&int{}
mut expects := map[string]&int{}
for k, mut val in mp_ {
expects[k] = unsafe { val }
}
for k, val in mp {
rets[k] = unsafe { val }
}
for k, val in mp {
assert voidptr(val) == voidptr(expects[k])
}
assert rets == expects
}

View File

@ -2,10 +2,10 @@
98
99
abc
23
77
&23
&77
abc
> k: abc | v: xyz
> k: def | v: jkl
> k: abc | v: &xyz
> k: def | v: &jkl
abc
abc