diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 5d4f04ddacb8a4..51a6a7c99315ed 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -417,8 +417,8 @@ pub: end_comments []Comment embeds []Embed - is_implements bool - implements_type Type + is_implements bool + implements_types []Type pub mut: fields []StructField } diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index f4850568a5995e..61b30ad5920307 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -333,7 +333,9 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { // XTODO2 // cgen error if I use `println(sym)` without handling the option with `or{}` struct_type := c.table.find_type_idx(node.name) // or { panic(err) } - c.type_implements(struct_type, node.implements_type, node.pos) + for t in node.implements_types { + c.type_implements(struct_type, t, node.pos) + } } } diff --git a/vlib/v/checker/tests/implements_keyword.out b/vlib/v/checker/tests/implements_keyword.out index 6b75ddc74543af..1dcef2b16bad87 100644 --- a/vlib/v/checker/tests/implements_keyword.out +++ b/vlib/v/checker/tests/implements_keyword.out @@ -5,3 +5,17 @@ vlib/v/checker/tests/implements_keyword.vv:5:1: error: `CustomError` doesn't imp | ~~~~~~~~~~~~~~~~~~ 6 | } 7 | +vlib/v/checker/tests/implements_keyword.vv:15:1: error: `CustomError2` doesn't implement method `print_error` of interface `MyError` + 13 | } + 14 | + 15 | struct CustomError2 implements MyError, MyError2 { + | ~~~~~~~~~~~~~~~~~~~ + 16 | } + 17 | +vlib/v/checker/tests/implements_keyword.vv:15:1: error: `CustomError2` doesn't implement method `print_error2` of interface `MyError2` + 13 | } + 14 | + 15 | struct CustomError2 implements MyError, MyError2 { + | ~~~~~~~~~~~~~~~~~~~ + 16 | } + 17 | diff --git a/vlib/v/checker/tests/implements_keyword.vv b/vlib/v/checker/tests/implements_keyword.vv index 4b2bf45146c209..960e1e3f4858a2 100644 --- a/vlib/v/checker/tests/implements_keyword.vv +++ b/vlib/v/checker/tests/implements_keyword.vv @@ -7,3 +7,13 @@ struct CustomError implements MyError { fn (e CustomError) print_error2() { } + +interface MyError2 { + print_error2() +} + +struct CustomError2 implements MyError, MyError2 { +} + +fn (e CustomError2) print_error3() { +} diff --git a/vlib/v/fmt/struct.v b/vlib/v/fmt/struct.v index 2febda9e124a7e..0c85e63b4ee999 100644 --- a/vlib/v/fmt/struct.v +++ b/vlib/v/fmt/struct.v @@ -33,7 +33,12 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl, is_anon bool) { mut field_types := []string{cap: node.fields.len} if node.is_implements { f.write(' implements ') - f.write(f.table.type_to_str_using_aliases(node.implements_type, f.mod2alias)) + for i, t in node.implements_types { + f.write(f.table.type_to_str_using_aliases(t, f.mod2alias)) + if i < node.implements_types.len - 1 { + f.write(', ') + } + } } // Calculate the alignments first f.calculate_alignment(node.fields, mut type_align, mut comment_align, mut default_expr_align, mut diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 4325c9eb36ac9f..a2f85d2b35de51 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -94,14 +94,19 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { mut is_field_pub := false mut is_field_global := false mut is_implements := false - mut implements_type := ast.void_type + mut implements_types := []ast.Type{cap: 3} // ast.void_type mut last_line := p.prev_tok.pos().line_nr + 1 mut end_comments := []ast.Comment{} if !no_body { if p.tok.kind == .key_implements { - p.next() - implements_type = p.parse_type() is_implements = true + for { + p.next() + implements_types << p.parse_type() + if p.tok.kind != .comma { + break + } + } } p.check(.lcbr) pre_comments << p.eat_comments() @@ -378,24 +383,24 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { } p.expr_mod = '' return ast.StructDecl{ - name: name - is_pub: is_pub - fields: ast_fields - pos: start_pos.extend_with_last_line(name_pos, last_line) - mut_pos: mut_pos - pub_pos: pub_pos - pub_mut_pos: pub_mut_pos - global_pos: global_pos - module_pos: module_pos - language: language - is_union: is_union - attrs: if is_anon { []ast.Attr{} } else { attrs } // anon structs can't have attributes - pre_comments: pre_comments - end_comments: end_comments - generic_types: generic_types - embeds: embeds - is_implements: is_implements - implements_type: implements_type + name: name + is_pub: is_pub + fields: ast_fields + pos: start_pos.extend_with_last_line(name_pos, last_line) + mut_pos: mut_pos + pub_pos: pub_pos + pub_mut_pos: pub_mut_pos + global_pos: global_pos + module_pos: module_pos + language: language + is_union: is_union + attrs: if is_anon { []ast.Attr{} } else { attrs } // anon structs can't have attributes + pre_comments: pre_comments + end_comments: end_comments + generic_types: generic_types + embeds: embeds + is_implements: is_implements + implements_types: implements_types } }