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

checker: relax checks on operators done on aliases of primitives like int, u8, string etc.; add tests (#17029)

This commit is contained in:
Delyan Angelov
2023-01-19 11:45:56 +02:00
committed by GitHub
parent 269833b72c
commit 92c7e3f7ff
5 changed files with 71 additions and 37 deletions

View File

@@ -553,8 +553,10 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
right_name := c.table.type_to_str(right_type_unwrapped) right_name := c.table.type_to_str(right_type_unwrapped)
parent_sym := c.table.final_sym(left_type_unwrapped) parent_sym := c.table.final_sym(left_type_unwrapped)
if left_sym.kind == .alias && right_sym.kind != .alias { if left_sym.kind == .alias && right_sym.kind != .alias {
if !parent_sym.is_primitive() {
c.error('mismatched types `${left_name}` and `${right_name}`', node.pos) c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
} }
}
extracted_op := match node.op { extracted_op := match node.op {
.plus_assign { '+' } .plus_assign { '+' }
.minus_assign { '-' } .minus_assign { '-' }
@@ -572,15 +574,14 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
node.pos) node.pos)
} }
} else { } else {
if parent_sym.is_primitive() { if !parent_sym.is_primitive() {
c.error('cannot use operator methods on type alias for `${parent_sym.name}`',
node.pos)
}
if left_name == right_name { if left_name == right_name {
c.error('undefined operation `${left_name}` ${extracted_op} `${right_name}`', c.error('undefined operation `${left_name}` ${extracted_op} `${right_name}`',
node.pos) node.pos)
} else { } else {
c.error('mismatched types `${left_name}` and `${right_name}`', node.pos) c.error('mismatched types `${left_name}` and `${right_name}`',
node.pos)
}
} }
} }
} }

View File

@@ -301,8 +301,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
} else if node.name in ['<', '=='] && node.return_type != ast.bool_type { } else if node.name in ['<', '=='] && node.return_type != ast.bool_type {
c.error('operator comparison methods should return `bool`', node.pos) c.error('operator comparison methods should return `bool`', node.pos)
} else if parent_sym.is_primitive() { } else if parent_sym.is_primitive() {
c.error('cannot define operator methods on type alias for `${parent_sym.name}`', // aliases of primitive types are explicitly allowed
node.pos)
} else if receiver_type != param_type { } else if receiver_type != param_type {
srtype := c.table.type_to_str(receiver_type) srtype := c.table.type_to_str(receiver_type)
sptype := c.table.type_to_str(param_type) sptype := c.table.type_to_str(param_type)

View File

@@ -12,14 +12,7 @@ vlib/v/checker/tests/method_op_alias_err.vv:5:17: error: infix expr: cannot use
| ~~~~~~ | ~~~~~~
6 | } 6 | }
7 | 7 |
vlib/v/checker/tests/method_op_alias_err.vv:8:1: error: cannot define operator methods on type alias for `string` vlib/v/checker/tests/method_op_alias_err.vv:14:6: error: operator `+` must return `Foo` to be used as an assignment operator
6 | }
7 |
8 | fn (f Foo) * (f1 Foo) Foo {
| ~~~~~~~~~~~~~~~~~~~~~~~~~
9 | return Foo(f + f1)
10 | }
vlib/v/checker/tests/method_op_alias_err.vv:14:6: error: mismatched types `Foo` and `string`
12 | fn main() { 12 | fn main() {
13 | mut f := Foo('fg') 13 | mut f := Foo('fg')
14 | f += 'fg' 14 | f += 'fg'
@@ -33,10 +26,3 @@ vlib/v/checker/tests/method_op_alias_err.vv:15:9: error: cannot assign to `f`: e
| ~~~~~~~~~ | ~~~~~~~~~
16 | f -= Foo('fo') 16 | f -= Foo('fo')
17 | println(f) 17 | println(f)
vlib/v/checker/tests/method_op_alias_err.vv:16:6: error: cannot use operator methods on type alias for `string`
14 | f += 'fg'
15 | f *= Foo2('2')
16 | f -= Foo('fo')
| ~~
17 | println(f)
18 | }

View File

@@ -275,7 +275,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
mut op_overloaded := false mut op_overloaded := false
mut op_expected_left := ast.Type(0) mut op_expected_left := ast.Type(0)
mut op_expected_right := ast.Type(0) mut op_expected_right := ast.Type(0)
if var_type == ast.string_type_idx && node.op == .plus_assign { if node.op == .plus_assign && unaliased_right_sym.kind == .string {
if left is ast.IndexExpr { if left is ast.IndexExpr {
// a[0] += str => `array_set(&a, 0, &(string[]) {string__plus(...))})` // a[0] += str => `array_set(&a, 0, &(string[]) {string__plus(...))})`
g.expr(left) g.expr(left)

View File

@@ -4,16 +4,14 @@ type MyInt = int
type MyString = string type MyString = string
fn ok() { type Foo = string
assert true
}
// bytes // bytes
fn test_byte_aliasing() { fn test_byte_aliasing() {
dump(u8(123)) dump(u8(123))
dump(MyByte(u8(123))) dump(MyByte(u8(123)))
dump(u8(MyByte(u8(123)))) dump(u8(MyByte(u8(123))))
ok() assert true
} }
fn test_pbyte_aliasing() { fn test_pbyte_aliasing() {
@@ -22,7 +20,7 @@ fn test_pbyte_aliasing() {
dump(voidptr(&MyByte(&u8(123)))) dump(voidptr(&MyByte(&u8(123))))
dump(voidptr(&u8(&MyByte(&u8(123))))) dump(voidptr(&u8(&MyByte(&u8(123)))))
} }
ok() assert true
} }
// ints // ints
@@ -30,7 +28,7 @@ fn test_int_aliasing() {
dump(int(123)) dump(int(123))
dump(int(MyInt(123))) dump(int(MyInt(123)))
dump(MyInt(int(MyInt(123)))) dump(MyInt(int(MyInt(123))))
ok() assert true
} }
fn test_pint_aliasing() { fn test_pint_aliasing() {
@@ -39,7 +37,7 @@ fn test_pint_aliasing() {
dump(voidptr(&MyInt(&int(123456)))) dump(voidptr(&MyInt(&int(123456))))
dump(voidptr(&int(&MyInt(&int(123456))))) dump(voidptr(&int(&MyInt(&int(123456)))))
} }
ok() assert true
} }
// strings // strings
@@ -52,7 +50,7 @@ fn test_string_aliasing() {
dump(string(MyString('abc'))) dump(string(MyString('abc')))
dump(MyString(string(MyString('abc')))) dump(MyString(string(MyString('abc'))))
} }
ok() assert true
} }
fn test_pstring_aliasing() { fn test_pstring_aliasing() {
@@ -62,5 +60,55 @@ fn test_pstring_aliasing() {
dump(voidptr(&string(&MyString(&s)))) dump(voidptr(&string(&MyString(&s))))
dump(voidptr(&MyString(&string(&MyString(&s))))) dump(voidptr(&MyString(&string(&MyString(&s)))))
} }
ok() assert true
}
//
struct MyStruct {
mut:
a MyInt
b MyByte
c MyString
}
fn test_modifying_a_struct_using_an_alias_to_int() {
mut my_struct := MyStruct{}
my_struct.a += 5
my_struct.b += 10
my_struct.c += 'abc'
//
my_struct.a += 3
my_struct.b += 20
my_struct.c += 'def'
println(my_struct)
//
assert my_struct.a == 8
assert my_struct.b == 30
assert my_struct.c == 'abcdef'
}
fn (f Foo) + (f1 Foo) Foo {
return '${f} _+_ ${f1}'
}
fn (f Foo) - (f1 Foo) Foo {
return '${f} _-_ ${f1}'
}
fn (f Foo) * (f1 Foo) Foo {
return '${f} _*_ ${f1}'
}
fn (f Foo) / (f1 Foo) Foo {
return '${f} _/_ ${f1}'
}
fn test_op_overrides_for_string_aliases() {
a := Foo('abc')
b := Foo('def')
assert a + b == 'abc _+_ def'
assert a - b == 'abc _-_ def'
assert a * b == 'abc _*_ def'
assert a / b == 'abc _/_ def'
} }