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
pull/5687/head
KrisChambers 2020-07-05 13:29:39 -04:00 committed by GitHub
parent f6ab63f3a0
commit 8d035a446a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 98 additions and 19 deletions

View File

@ -98,25 +98,8 @@ pub fn (mut p Parser) parse_type_with_mut(is_mut bool) table.Type {
return typ return typ
} }
pub fn (mut p Parser) parse_type() table.Type { // Parses any language indicators on a type.
// optional pub fn (mut p Parser) parse_language() table.Language {
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()
}
language := if p.tok.lit == 'C' { language := if p.tok.lit == 'C' {
table.Language.c table.Language.c
@ -130,6 +113,40 @@ pub fn (mut p Parser) parse_type() table.Type {
p.next() p.next()
p.check(.dot) 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 mut typ := table.void_type
if p.tok.kind != .lcbr { if p.tok.kind != .lcbr {
pos := p.tok.position() pos := p.tok.position()

View File

@ -279,3 +279,40 @@ fn test_optional_val_with_empty_or() {
ret_none() or {} ret_none() or {}
assert true 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
}
}

View File

@ -313,3 +313,28 @@ fn test_struct_with_default_values_no_init() {
assert s2.field_optional == 3 assert s2.field_optional == 3
assert s3.field_optional == 2 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
}
}