From a988ef34749c2f8822c7301eb69d77336f6c511d Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Sat, 29 Oct 2022 09:06:44 +0530 Subject: [PATCH] checker: add check for mut ident but not if mut ident is for interfaces (#16214) --- vlib/v/checker/if.v | 9 +++++++++ .../tests/if_smartcast_mut_var_interface_err.out | 7 +++++++ .../tests/if_smartcast_mut_var_interface_err.vv | 16 ++++++++++++++++ vlib/v/checker/tests/incorrect_smartcast_err.out | 7 +++++++ vlib/v/tests/interface_fields_test.v | 4 ++-- .../tests/struct_embedding_with_interface_test.v | 2 +- 6 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 vlib/v/checker/tests/if_smartcast_mut_var_interface_err.out create mode 100644 vlib/v/checker/tests/if_smartcast_mut_var_interface_err.vv diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index 28b8dbee49..1561a8b0a0 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -353,6 +353,15 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) { && (node.left as ast.SelectorExpr).is_mut) { c.fail_if_immutable(node.left) } + // TODO: Add check for sum types in a way that it doesn't break a lot of compiler code + if node.left is ast.Ident + && (left_sym.kind == .interface_ && right_sym.kind != .interface_) { + v := scope.find_var(node.left.name) or { &ast.Var{} } + if v.is_mut && !node.left.is_mut { + c.error('smart casting a mutable interface value requires `if mut $node.left.name is ...`', + node.left.pos) + } + } if left_sym.kind in [.interface_, .sum_type] { c.smartcast(node.left, node.left_type, right_type, mut scope) } diff --git a/vlib/v/checker/tests/if_smartcast_mut_var_interface_err.out b/vlib/v/checker/tests/if_smartcast_mut_var_interface_err.out new file mode 100644 index 0000000000..d12813eb00 --- /dev/null +++ b/vlib/v/checker/tests/if_smartcast_mut_var_interface_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/if_smartcast_mut_var_interface_err.vv:13:5: error: smart casting a mutable interface value requires `if mut foo_mut is ...` + 11 | fn main() { + 12 | mut foo_mut := Foo(Bar{}) + 13 | if foo_mut is Bar { + | ~~~~~~~ + 14 | println(json.encode(foo_mut)) + 15 | } diff --git a/vlib/v/checker/tests/if_smartcast_mut_var_interface_err.vv b/vlib/v/checker/tests/if_smartcast_mut_var_interface_err.vv new file mode 100644 index 0000000000..add2d5d5ba --- /dev/null +++ b/vlib/v/checker/tests/if_smartcast_mut_var_interface_err.vv @@ -0,0 +1,16 @@ +import json + +interface Foo { + a int +} + +struct Bar { + a int +} + +fn main() { + mut foo_mut := Foo(Bar{}) + if foo_mut is Bar { + println(json.encode(foo_mut)) + } +} diff --git a/vlib/v/checker/tests/incorrect_smartcast_err.out b/vlib/v/checker/tests/incorrect_smartcast_err.out index e414220886..2f25c5cce6 100644 --- a/vlib/v/checker/tests/incorrect_smartcast_err.out +++ b/vlib/v/checker/tests/incorrect_smartcast_err.out @@ -5,6 +5,13 @@ vlib/v/checker/tests/incorrect_smartcast_err.vv:10:5: notice: smartcasting requi | ~~~~~~~ 11 | println(example.field) 12 | } +vlib/v/checker/tests/incorrect_smartcast_err.vv:10:5: error: smart casting a mutable interface value requires `if mut example is ...` + 8 | fn main(){ + 9 | mut example := IExample(Example{field:"test"}) + 10 | if example is Example{ + | ~~~~~~~ + 11 | println(example.field) + 12 | } vlib/v/checker/tests/incorrect_smartcast_err.vv:11:19: error: type `IExample` has no field named `field` 9 | mut example := IExample(Example{field:"test"}) 10 | if example is Example{ diff --git a/vlib/v/tests/interface_fields_test.v b/vlib/v/tests/interface_fields_test.v index f58bb83970..d0269eaf84 100644 --- a/vlib/v/tests/interface_fields_test.v +++ b/vlib/v/tests/interface_fields_test.v @@ -26,12 +26,12 @@ fn use_interface(a Animal) { } fn mutate_interface(mut a Animal) { - if a is Cat { + if mut a is Cat { a.breed = 'Siamese' } else { a.breed = 'Golden Retriever' } - if a is Cat { + if mut a is Cat { assert a.breed == 'Siamese' } else { assert a.breed == 'Golden Retriever' diff --git a/vlib/v/tests/struct_embedding_with_interface_test.v b/vlib/v/tests/struct_embedding_with_interface_test.v index 9425cb72b6..8b12a57b2f 100644 --- a/vlib/v/tests/struct_embedding_with_interface_test.v +++ b/vlib/v/tests/struct_embedding_with_interface_test.v @@ -43,7 +43,7 @@ pub fn (mut ll LinearLayout) layout() string { for mut l in ll.layoutables { dump(l.type_name()) output += '$l.type_name()\n' - if l is Container { + if mut l is Container { dump(l.type_name()) output += '$l.type_name()\n' }