Skip to content

Commit 03e93b3

Browse files
committed
checker: move arr << logic to check_append()
1 parent 262a72e commit 03e93b3

File tree

4 files changed

+81
-63
lines changed

4 files changed

+81
-63
lines changed

vlib/v/checker/containers.v

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,3 +775,67 @@ fn (mut c Checker) check_elements_initialized(typ ast.Type) ! {
775775
else {}
776776
}
777777
}
778+
779+
fn (mut c Checker) check_append(mut node ast.InfixExpr, left_type ast.Type, right_type ast.Type,
780+
right_final_sym ast.TypeSymbol) ast.Type {
781+
if !node.is_stmt {
782+
c.error('array append cannot be used in an expression', node.pos)
783+
}
784+
if left_type.has_flag(.option) && node.left is ast.Ident && node.left.or_expr.kind == .absent {
785+
c.error('unwrapped Option cannot be used in an infix expression', node.pos)
786+
}
787+
right_pos := node.right.pos()
788+
mut right_sym := c.table.sym(right_type)
789+
mut left_sym := c.table.sym(left_type)
790+
// `array << elm`
791+
c.check_expr_option_or_result_call(node.right, right_type)
792+
node.auto_locked, _ = c.fail_if_immutable(mut node.left)
793+
left_value_type := c.table.value_type(c.unwrap_generic(left_type))
794+
left_value_sym := c.table.sym(c.unwrap_generic(left_value_type))
795+
if !left_value_type.has_flag(.option) && right_type.has_flag(.option) {
796+
c.error('unwrapped Option cannot be used in an infix expression', node.pos)
797+
}
798+
if left_value_sym.kind == .interface {
799+
if right_final_sym.kind != .array {
800+
// []Animal << Cat
801+
if c.type_implements(right_type, left_value_type, right_pos) {
802+
if !right_type.is_any_kind_of_pointer() && !c.inside_unsafe
803+
&& right_sym.kind != .interface {
804+
c.mark_as_referenced(mut &node.right, true)
805+
}
806+
}
807+
} else {
808+
// []Animal << []Cat
809+
c.type_implements(c.table.value_type(right_type), left_value_type, right_pos)
810+
}
811+
return ast.void_type
812+
} else if left_value_sym.kind == .sum_type {
813+
if right_sym.kind != .array {
814+
if !c.table.is_sumtype_or_in_variant(left_value_type, ast.mktyp(c.unwrap_generic(right_type))) {
815+
c.error('cannot append `${right_sym.name}` to `${left_sym.name}`', right_pos)
816+
}
817+
} else {
818+
right_value_type := c.table.value_type(c.unwrap_generic(right_type))
819+
if !c.table.is_sumtype_or_in_variant(left_value_type, ast.mktyp(right_value_type)) {
820+
c.error('cannot append `${right_sym.name}` to `${left_sym.name}`', right_pos)
821+
}
822+
}
823+
return ast.void_type
824+
}
825+
// []T << T or []T << []T
826+
unwrapped_right_type := c.unwrap_generic(right_type)
827+
if c.check_types(unwrapped_right_type, left_value_type) {
828+
// []&T << T is wrong: we check for that, !(T.is_ptr()) && ?(&T).is_ptr()
829+
if !(!unwrapped_right_type.is_ptr() && left_value_type.is_ptr()
830+
&& left_value_type.share() == .mut_t) {
831+
return ast.void_type
832+
}
833+
} else if c.check_types(unwrapped_right_type, c.unwrap_generic(left_type)) {
834+
return ast.void_type
835+
}
836+
if left_value_type.has_flag(.option) && right_type == ast.none_type {
837+
return ast.void_type
838+
}
839+
c.error('cannot append `${right_sym.name}` to `${left_sym.name}`', right_pos)
840+
return ast.void_type
841+
}

vlib/v/checker/infix.v

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -631,69 +631,7 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
631631
.left_shift {
632632
if left_final_sym.kind == .array
633633
|| c.table.sym(c.unwrap_generic(left_type)).kind == .array {
634-
if !node.is_stmt {
635-
c.error('array append cannot be used in an expression', node.pos)
636-
}
637-
if left_type.has_flag(.option) && node.left is ast.Ident
638-
&& node.left.or_expr.kind == .absent {
639-
c.error('unwrapped Option cannot be used in an infix expression',
640-
node.pos)
641-
}
642-
// `array << elm`
643-
c.check_expr_option_or_result_call(node.right, right_type)
644-
node.auto_locked, _ = c.fail_if_immutable(mut node.left)
645-
left_value_type := c.table.value_type(c.unwrap_generic(left_type))
646-
left_value_sym := c.table.sym(c.unwrap_generic(left_value_type))
647-
if !left_value_type.has_flag(.option) && right_type.has_flag(.option) {
648-
c.error('unwrapped Option cannot be used in an infix expression',
649-
node.pos)
650-
}
651-
if left_value_sym.kind == .interface {
652-
if right_final_sym.kind != .array {
653-
// []Animal << Cat
654-
if c.type_implements(right_type, left_value_type, right_pos) {
655-
if !right_type.is_any_kind_of_pointer() && !c.inside_unsafe
656-
&& right_sym.kind != .interface {
657-
c.mark_as_referenced(mut &node.right, true)
658-
}
659-
}
660-
} else {
661-
// []Animal << []Cat
662-
c.type_implements(c.table.value_type(right_type), left_value_type,
663-
right_pos)
664-
}
665-
return ast.void_type
666-
} else if left_value_sym.kind == .sum_type {
667-
if right_sym.kind != .array {
668-
if !c.table.is_sumtype_or_in_variant(left_value_type, ast.mktyp(c.unwrap_generic(right_type))) {
669-
c.error('cannot append `${right_sym.name}` to `${left_sym.name}`',
670-
right_pos)
671-
}
672-
} else {
673-
right_value_type := c.table.value_type(c.unwrap_generic(right_type))
674-
if !c.table.is_sumtype_or_in_variant(left_value_type, ast.mktyp(right_value_type)) {
675-
c.error('cannot append `${right_sym.name}` to `${left_sym.name}`',
676-
right_pos)
677-
}
678-
}
679-
return ast.void_type
680-
}
681-
// []T << T or []T << []T
682-
unwrapped_right_type := c.unwrap_generic(right_type)
683-
if c.check_types(unwrapped_right_type, left_value_type) {
684-
// []&T << T is wrong: we check for that, !(T.is_ptr()) && ?(&T).is_ptr()
685-
if !(!unwrapped_right_type.is_ptr() && left_value_type.is_ptr()
686-
&& left_value_type.share() == .mut_t) {
687-
return ast.void_type
688-
}
689-
} else if c.check_types(unwrapped_right_type, c.unwrap_generic(left_type)) {
690-
return ast.void_type
691-
}
692-
if left_value_type.has_flag(.option) && right_type == ast.none_type {
693-
return ast.void_type
694-
}
695-
c.error('cannot append `${right_sym.name}` to `${left_sym.name}`', right_pos)
696-
return ast.void_type
634+
return c.check_append(mut node, left_type, right_type, right_final_sym)
697635
} else {
698636
node.promoted_type = c.check_shift(mut node, left_type, right_type)
699637
return node.promoted_type

vlib/v/checker/tests/ban_const_ref_mutation.out

Whitespace-only changes.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
struct Foobar {
3+
mut:
4+
foo int
5+
}
6+
7+
const foobar_const = Foobar{123}
8+
9+
fn main() {
10+
println("foobar_const.foo: ${foobar_const.foo}") // foobar_const.foo: 123
11+
mut foobars := []&Foobar{}
12+
foobars << &foobar_const
13+
foobars[0].foo = 456
14+
println("foobar_const.foo: ${foobar_const.foo}") // foobar_const.foo: 456
15+
}
16+
*/

0 commit comments

Comments
 (0)