From 8d035a446aa41d59f09d29e9973fc6b7fd37a5f4 Mon Sep 17 00:00:00 2001 From: KrisChambers Date: Sun, 5 Jul 2020 13:29:39 -0400 Subject: [PATCH] Fix v/parser: Failure to parse structs with fields typed as anonymous functions returning having an optional void (`?`) return type. (#5684) * Handle optional void return type in function types in struct fields. * Add more testing for optional return types in struct fields. * Move language parsing into it's own function * Fix issue caused by not setting typ. * Fix test for structs containing anon fn with optional void return types --- vlib/v/parser/parse_type.v | 55 +++++++++++++++++++++++++------------- vlib/v/tests/option_test.v | 37 +++++++++++++++++++++++++ vlib/v/tests/struct_test.v | 25 +++++++++++++++++ 3 files changed, 98 insertions(+), 19 deletions(-) diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index cee0aaac23..c9b9ede3e0 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -98,25 +98,8 @@ pub fn (mut p Parser) parse_type_with_mut(is_mut bool) table.Type { return typ } -pub fn (mut p Parser) parse_type() table.Type { - // optional - mut is_optional := false - if p.tok.kind == .question { - p.next() - is_optional = true - } - is_shared := p.tok.kind in [.key_shared, .key_rwshared] - is_atomic_or_rw := p.tok.kind in [.key_rwshared, .key_atomic] - mut nr_muls := 0 - if p.tok.kind == .key_mut || is_shared || is_atomic_or_rw { - nr_muls++ - p.next() - } - // &Type - for p.tok.kind == .amp { - nr_muls++ - p.next() - } +// Parses any language indicators on a type. +pub fn (mut p Parser) parse_language() table.Language { language := if p.tok.lit == 'C' { table.Language.c @@ -130,6 +113,40 @@ pub fn (mut p Parser) parse_type() table.Type { p.next() p.check(.dot) } + + return language +} + +pub fn (mut p Parser) parse_type() table.Type { + // optional + mut is_optional := false + if p.tok.kind == .question { + line_nr := p.tok.line_nr + p.next() + is_optional = true + + if p.tok.line_nr > line_nr { + mut typ := table.void_type + if is_optional { + typ = typ.set_flag(.optional) + } + return typ + } + } + is_shared := p.tok.kind in [.key_shared, .key_rwshared] + is_atomic_or_rw := p.tok.kind in [.key_rwshared, .key_atomic] + + mut nr_muls := 0 + if p.tok.kind == .key_mut || is_shared || is_atomic_or_rw { + nr_muls++ + p.next() + } + // &Type + for p.tok.kind == .amp { + nr_muls++ + p.next() + } + language := p.parse_language() mut typ := table.void_type if p.tok.kind != .lcbr { pos := p.tok.position() diff --git a/vlib/v/tests/option_test.v b/vlib/v/tests/option_test.v index 8a221244a7..ba1e432bf6 100644 --- a/vlib/v/tests/option_test.v +++ b/vlib/v/tests/option_test.v @@ -279,3 +279,40 @@ fn test_optional_val_with_empty_or() { ret_none() or {} assert true } + +fn test_optional_void_return_types_of_anon_fn() { + f := fn(i int) ? { + if i == 0 { + return error("0") + } + + return + } + + f(0) or { + assert err == "0" + return + } +} + +struct Foo { + f fn(int) ? +} + +fn test_option_void_return_types_of_anon_fn_in_struct() { + foo := Foo { + f: fn(i int) ? { + if i == 0 { + return error("0") + } + + return + } + } + + foo.f(0) or { + assert err == "0" + return + } +} + diff --git a/vlib/v/tests/struct_test.v b/vlib/v/tests/struct_test.v index f6695f2097..e5f1316252 100644 --- a/vlib/v/tests/struct_test.v +++ b/vlib/v/tests/struct_test.v @@ -313,3 +313,28 @@ fn test_struct_with_default_values_no_init() { assert s2.field_optional == 3 assert s3.field_optional == 2 } + +struct FieldsWithOptionalVoidReturnType { + f fn() ? + g fn() ? +} + +fn test_fields_anon_fn_with_optional_void_return_type() { + foo := FieldsWithOptionalVoidReturnType { + f: fn() ? { + return error("oops") + } + g: fn() ? { + return + } + } + + foo.f() or { + assert err == "oops" + } + + foo.g() or { + assert false + } +} +