checker: improve message and positioning for operator overloading (#8133)

pull/8159/head
Swastik Baranwal 2021-01-17 08:07:44 +05:30 committed by GitHub
parent ee9f9c9d81
commit ef627c9d21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 15 additions and 10 deletions

View File

@ -792,7 +792,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
left_name := c.table.type_to_str(left_type) left_name := c.table.type_to_str(left_type)
right_name := c.table.type_to_str(right_type) right_name := c.table.type_to_str(right_type)
if left_name == right_name { if left_name == right_name {
c.error('operation `$left_name` $infix_expr.op.str() `$right_name` does not exist, please define it', c.error('undefined operation `$left_name` $infix_expr.op.str() `$right_name`',
left_pos) left_pos)
} else { } else {
c.error('mismatched types `$left_name` and `$right_name`', left_pos) c.error('mismatched types `$left_name` and `$right_name`', left_pos)
@ -809,7 +809,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
left_name := c.table.type_to_str(left_type) left_name := c.table.type_to_str(left_type)
right_name := c.table.type_to_str(right_type) right_name := c.table.type_to_str(right_type)
if left_name == right_name { if left_name == right_name {
c.error('operation `$left_name` $infix_expr.op.str() `$right_name` does not exist, please define it', c.error('undefined operation `$left_name` $infix_expr.op.str() `$right_name`',
right_pos) right_pos)
} else { } else {
c.error('mismatched types `$left_name` and `$right_name`', right_pos) c.error('mismatched types `$left_name` and `$right_name`', right_pos)
@ -852,7 +852,7 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
left_name := c.table.type_to_str(left_type) left_name := c.table.type_to_str(left_type)
right_name := c.table.type_to_str(right_type) right_name := c.table.type_to_str(right_type)
if left_name == right_name { if left_name == right_name {
c.error('operation `$left_name` $infix_expr.op.str() `$right_name` does not exist, please define it', c.error('undefined operation `$left_name` $infix_expr.op.str() `$right_name`',
infix_expr.pos) infix_expr.pos)
} else { } else {
c.error('mismatched types `$left_name` and `$right_name`', infix_expr.pos) c.error('mismatched types `$left_name` and `$right_name`', infix_expr.pos)
@ -2600,7 +2600,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
assign_stmt.pos) assign_stmt.pos)
} }
if left_name == right_name { if left_name == right_name {
c.error('operation `$left_name` $extracted_op `$right_name` does not exist, please define it', c.error('undefined operation `$left_name` $extracted_op `$right_name`',
assign_stmt.pos) assign_stmt.pos)
} else { } else {
c.error('mismatched types `$left_name` and `$right_name`', assign_stmt.pos) c.error('mismatched types `$left_name` and `$right_name`', assign_stmt.pos)
@ -5227,7 +5227,8 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
} else if node.params[1].is_mut { } else if node.params[1].is_mut {
c.error('argument cannot be `mut` for operator overloading', node.pos) c.error('argument cannot be `mut` for operator overloading', node.pos)
} else if node.receiver.typ != node.params[1].typ { } else if node.receiver.typ != node.params[1].typ {
c.error('both sides of an operator must be the same type', node.pos) c.error('expected `$receiver_sym.name` not `$param_sym.name` - both operands must be the same type for operator overloading',
node.params[1].type_pos)
} else if node.name in ['<', '>', '==', '!=', '>=', '<='] && } else if node.name in ['<', '>', '==', '!=', '>=', '<='] &&
node.return_type != table.bool_type node.return_type != table.bool_type
{ {

View File

@ -1,8 +1,8 @@
vlib/v/checker/tests/method_op_alias_err.vv:4:1: error: both sides of an operator must be the same type vlib/v/checker/tests/method_op_alias_err.vv:4:18: error: expected `Foo` not `Foo2` - both operands must be the same type for operator overloading
2 | type Foo2 = string 2 | type Foo2 = string
3 | 3 |
4 | fn (f Foo) + (f1 Foo2) Foo2 { 4 | fn (f Foo) + (f1 Foo2) Foo2 {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ~~~~
5 | return Foo2(f + f1) 5 | return Foo2(f + f1)
6 | } 6 | }
vlib/v/checker/tests/method_op_alias_err.vv:5:19: error: infix expr: cannot use `string` (right expression) as `string` vlib/v/checker/tests/method_op_alias_err.vv:5:19: error: infix expr: cannot use `string` (right expression) as `string`

View File

@ -5,11 +5,11 @@ vlib/v/checker/tests/method_op_err.vv:11:1: error: operator methods should have
| ~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~
12 | } 12 | }
13 | 13 |
vlib/v/checker/tests/method_op_err.vv:14:1: error: both sides of an operator must be the same type vlib/v/checker/tests/method_op_err.vv:14:18: error: expected `User` not `Foo` - both operands must be the same type for operator overloading
12 | } 12 | }
13 | 13 |
14 | fn (u User) - (f Foo) User { 14 | fn (u User) - (f Foo) User {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~ | ~~~
15 | return User{u.a - f.a, u.b-f.a} 15 | return User{u.a - f.a, u.b-f.a}
16 | } 16 | }
vlib/v/checker/tests/method_op_err.vv:18:1: error: operator comparison methods should return `bool` vlib/v/checker/tests/method_op_err.vv:18:1: error: operator comparison methods should return `bool`
@ -40,7 +40,7 @@ vlib/v/checker/tests/method_op_err.vv:36:24: error: infix expr: cannot use `Foo`
| ^ | ^
37 | println(User{3, 2} < User{2, 4}) 37 | println(User{3, 2} < User{2, 4})
38 | println(User{3, 4} < Foo{3, 4}) 38 | println(User{3, 4} < Foo{3, 4})
vlib/v/checker/tests/method_op_err.vv:37:24: error: operation `User` < `User` does not exist, please define it vlib/v/checker/tests/method_op_err.vv:37:24: error: undefined operation `User` < `User`
35 | println(User{3, 4}) 35 | println(User{3, 4})
36 | println(User{3, 4} - Foo{3, 3}) 36 | println(User{3, 4} - Foo{3, 3})
37 | println(User{3, 2} < User{2, 4}) 37 | println(User{3, 2} < User{2, 4})

View File

@ -609,6 +609,7 @@ fn (mut p Parser) fn_args() ([]table.Param, bool, bool) {
} }
mut arg_pos := [p.tok.position()] mut arg_pos := [p.tok.position()]
mut arg_names := [p.check_name()] mut arg_names := [p.check_name()]
mut type_pos := [p.tok.position()]
// `a, b, c int` // `a, b, c int`
for p.tok.kind == .comma { for p.tok.kind == .comma {
if !p.pref.is_fmt { if !p.pref.is_fmt {
@ -618,6 +619,7 @@ fn (mut p Parser) fn_args() ([]table.Param, bool, bool) {
p.next() p.next()
arg_pos << p.tok.position() arg_pos << p.tok.position()
arg_names << p.check_name() arg_names << p.check_name()
type_pos << p.tok.position()
} }
if p.tok.kind == .key_mut { if p.tok.kind == .key_mut {
// TODO remove old syntax // TODO remove old syntax
@ -665,6 +667,7 @@ fn (mut p Parser) fn_args() ([]table.Param, bool, bool) {
name: arg_name name: arg_name
is_mut: is_mut is_mut: is_mut
typ: typ typ: typ
type_pos: type_pos[i]
} }
// if typ.typ.kind == .variadic && p.tok.kind == .comma { // if typ.typ.kind == .variadic && p.tok.kind == .comma {
if is_variadic && p.tok.kind == .comma { if is_variadic && p.tok.kind == .comma {

View File

@ -53,6 +53,7 @@ pub:
name string name string
is_mut bool is_mut bool
typ Type typ Type
type_pos token.Position
is_hidden bool // interface first arg is_hidden bool // interface first arg
} }