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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 37 deletions

View File

@ -553,7 +553,9 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
right_name := c.table.type_to_str(right_type_unwrapped)
parent_sym := c.table.final_sym(left_type_unwrapped)
if left_sym.kind == .alias && right_sym.kind != .alias {
c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
if !parent_sym.is_primitive() {
c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
}
}
extracted_op := match node.op {
.plus_assign { '+' }
@ -572,15 +574,14 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
node.pos)
}
} else {
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 {
c.error('undefined operation `${left_name}` ${extracted_op} `${right_name}`',
node.pos)
} else {
c.error('mismatched types `${left_name}` and `${right_name}`', node.pos)
if !parent_sym.is_primitive() {
if left_name == right_name {
c.error('undefined operation `${left_name}` ${extracted_op} `${right_name}`',
node.pos)
} else {
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 {
c.error('operator comparison methods should return `bool`', node.pos)
} else if parent_sym.is_primitive() {
c.error('cannot define operator methods on type alias for `${parent_sym.name}`',
node.pos)
// aliases of primitive types are explicitly allowed
} else if receiver_type != param_type {
srtype := c.table.type_to_str(receiver_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 | }
7 |
vlib/v/checker/tests/method_op_alias_err.vv:8:1: error: cannot define operator methods on type alias for `string`
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`
vlib/v/checker/tests/method_op_alias_err.vv:14:6: error: operator `+` must return `Foo` to be used as an assignment operator
12 | fn main() {
13 | mut f := Foo('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')
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_expected_left := 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 {
// a[0] += str => `array_set(&a, 0, &(string[]) {string__plus(...))})`
g.expr(left)

View File

@ -4,16 +4,14 @@ type MyInt = int
type MyString = string
fn ok() {
assert true
}
type Foo = string
// bytes
fn test_byte_aliasing() {
dump(u8(123))
dump(MyByte(u8(123)))
dump(u8(MyByte(u8(123))))
ok()
assert true
}
fn test_pbyte_aliasing() {
@ -22,7 +20,7 @@ fn test_pbyte_aliasing() {
dump(voidptr(&MyByte(&u8(123))))
dump(voidptr(&u8(&MyByte(&u8(123)))))
}
ok()
assert true
}
// ints
@ -30,7 +28,7 @@ fn test_int_aliasing() {
dump(int(123))
dump(int(MyInt(123)))
dump(MyInt(int(MyInt(123))))
ok()
assert true
}
fn test_pint_aliasing() {
@ -39,7 +37,7 @@ fn test_pint_aliasing() {
dump(voidptr(&MyInt(&int(123456))))
dump(voidptr(&int(&MyInt(&int(123456)))))
}
ok()
assert true
}
// strings
@ -52,7 +50,7 @@ fn test_string_aliasing() {
dump(string(MyString('abc')))
dump(MyString(string(MyString('abc'))))
}
ok()
assert true
}
fn test_pstring_aliasing() {
@ -62,5 +60,55 @@ fn test_pstring_aliasing() {
dump(voidptr(&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'
}