parser: fix a bug when using some types like map in generic methods (#7872)
parent
2fc50a4045
commit
5c1981379e
|
@ -1048,6 +1048,30 @@ pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (p Parser) is_generic_call() bool {
|
||||||
|
lit0_is_capital := if p.tok.kind != .eof && p.tok.lit.len > 0 {
|
||||||
|
p.tok.lit[0].is_capital()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
// use heuristics to detect `func<T>()` from `var < expr`
|
||||||
|
return !lit0_is_capital && p.peek_tok.kind == .lt && (match p.peek_tok2.kind {
|
||||||
|
.name {
|
||||||
|
// maybe `f<int>`, `f<map[`
|
||||||
|
(p.peek_tok2.kind == .name &&
|
||||||
|
p.peek_tok3.kind == .gt) ||
|
||||||
|
(p.peek_tok2.lit == 'map' && p.peek_tok3.kind == .lsbr)
|
||||||
|
}
|
||||||
|
.lsbr {
|
||||||
|
// maybe `f<[]T>`, assume `var < []` is invalid
|
||||||
|
p.peek_tok3.kind == .rsbr
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut p Parser) name_expr() ast.Expr {
|
pub fn (mut p Parser) name_expr() ast.Expr {
|
||||||
prev_tok_kind := p.prev_tok.kind
|
prev_tok_kind := p.prev_tok.kind
|
||||||
mut node := ast.Expr{}
|
mut node := ast.Expr{}
|
||||||
|
@ -1173,28 +1197,12 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
// use heuristics to detect `func<T>()` from `var < expr`
|
|
||||||
is_generic_call := !lit0_is_capital && p.peek_tok.kind == .lt && (match p.peek_tok2.kind {
|
|
||||||
.name {
|
|
||||||
// maybe `f<int>`, `f<map[`
|
|
||||||
(p.peek_tok2.kind == .name &&
|
|
||||||
p.peek_tok3.kind == .gt) ||
|
|
||||||
(p.peek_tok2.lit == 'map' && p.peek_tok3.kind == .lsbr)
|
|
||||||
}
|
|
||||||
.lsbr {
|
|
||||||
// maybe `f<[]T>`, assume `var < []` is invalid
|
|
||||||
p.peek_tok3.kind == .rsbr
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// p.warn('name expr $p.tok.lit $p.peek_tok.str()')
|
// p.warn('name expr $p.tok.lit $p.peek_tok.str()')
|
||||||
same_line := p.tok.line_nr == p.peek_tok.line_nr
|
same_line := p.tok.line_nr == p.peek_tok.line_nr
|
||||||
// `(` must be on same line as name token otherwise it's a ParExpr
|
// `(` must be on same line as name token otherwise it's a ParExpr
|
||||||
if !same_line && p.peek_tok.kind == .lpar {
|
if !same_line && p.peek_tok.kind == .lpar {
|
||||||
node = p.parse_ident(language)
|
node = p.parse_ident(language)
|
||||||
} else if p.peek_tok.kind == .lpar || is_generic_call {
|
} else if p.peek_tok.kind == .lpar || p.is_generic_call() {
|
||||||
// foo(), foo<int>() or type() cast
|
// foo(), foo<int>() or type() cast
|
||||||
mut name := p.tok.lit
|
mut name := p.tok.lit
|
||||||
if mod.len > 0 {
|
if mod.len > 0 {
|
||||||
|
@ -1407,6 +1415,7 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
||||||
if p.tok.kind == .dollar {
|
if p.tok.kind == .dollar {
|
||||||
return p.comptime_method_call(left)
|
return p.comptime_method_call(left)
|
||||||
}
|
}
|
||||||
|
is_generic_call := p.is_generic_call()
|
||||||
name_pos := p.tok.position()
|
name_pos := p.tok.position()
|
||||||
mut field_name := ''
|
mut field_name := ''
|
||||||
// check if the name is on the same line as the dot
|
// check if the name is on the same line as the dot
|
||||||
|
@ -1427,7 +1436,7 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
||||||
// TODO move to fn.v call_expr()
|
// TODO move to fn.v call_expr()
|
||||||
mut generic_type := table.void_type
|
mut generic_type := table.void_type
|
||||||
mut generic_list_pos := p.tok.position()
|
mut generic_list_pos := p.tok.position()
|
||||||
if p.tok.kind == .lt && p.peek_tok.kind == .name && p.peek_tok2.kind == .gt {
|
if is_generic_call {
|
||||||
// `g.foo<int>(10)`
|
// `g.foo<int>(10)`
|
||||||
p.next() // `<`
|
p.next() // `<`
|
||||||
generic_type = p.parse_type()
|
generic_type = p.parse_type()
|
||||||
|
|
|
@ -35,3 +35,19 @@ fn test_generic_method_with_fixed_arg_type() {
|
||||||
res := person.show('bob', 10)
|
res := person.show('bob', 10)
|
||||||
assert res == 'name: bob, data: 10'
|
assert res == 'name: bob, data: 10'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Foo {}
|
||||||
|
|
||||||
|
fn (v Foo) new<T>() T {
|
||||||
|
return T{}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generic_method_with_map_type() {
|
||||||
|
foo := Foo{}
|
||||||
|
assert foo.new<map[string]string>() == map[string]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generic_method_with_array_type() {
|
||||||
|
foo := Foo{}
|
||||||
|
assert foo.new<[]string>() == []string{}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue