[dev.typeparams] cmd/compile/internal/syntax: implement parsing of type parameters

Port from dev.go2go prototype branch. The compiler doesn't yet set the
syntax.AllowGenerics mode, so parsing of generic code remains disabled.

Known issue: The doc strings documenting the specific syntax accepted
by parser methods are not all up-to-date.

Change-Id: I13d134289fd9330fd0ed7f97c997cca6f23466fd
Reviewed-on: https://go-review.googlesource.com/c/go/+/261658
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Robert Griesemer 2020-10-12 14:07:31 -07:00
parent 617b633917
commit b627988b0c
2 changed files with 447 additions and 207 deletions

View file

@ -459,20 +459,21 @@ func isEmptyFuncDecl(dcl Decl) bool {
// Declarations // Declarations
// list parses a possibly empty, sep-separated list, optionally // list parses a possibly empty, sep-separated list, optionally
// followed by sep and enclosed by ( and ) or { and }. open is // followed sep, and closed by close. sep must be one of _Comma
// one of _Lparen, or _Lbrace, sep is one of _Comma or _Semi, // or _Semi, and close must be one of _Rparen, _Rbrace, or _Rbrack.
// and close is expected to be the (closing) opposite of open.
// For each list element, f is called. After f returns true, no // For each list element, f is called. After f returns true, no
// more list elements are accepted. list returns the position // more list elements are accepted. list returns the position
// of the closing token. // of the closing token.
// //
// list = "(" { f sep } ")" | // list = { f sep } ")" |
// "{" { f sep } "}" . // sep is optional before ")" or "}" // { f sep } "}" . // "," or ";" is optional before ")", "}" or "]"
// //
func (p *parser) list(open, sep, close token, f func() bool) Pos { func (p *parser) list(sep, close token, f func() bool) Pos {
p.want(open) if debug && (sep != _Comma && sep != _Semi || close != _Rparen && close != _Rbrace && close != _Rbrack) {
panic("invalid sep or close argument for list")
}
var done bool done := false
for p.tok != _EOF && p.tok != close && !done { for p.tok != _EOF && p.tok != close && !done {
done = f() done = f()
// sep is optional before close // sep is optional before close
@ -496,7 +497,8 @@ func (p *parser) appendGroup(list []Decl, f func(*Group) Decl) []Decl {
if p.tok == _Lparen { if p.tok == _Lparen {
g := new(Group) g := new(Group)
p.clearPragma() p.clearPragma()
p.list(_Lparen, _Semi, _Rparen, func() bool { p.next() // must consume "(" after calling clearPragma!
p.list(_Semi, _Rparen, func() bool {
list = append(list, f(g)) list = append(list, f(g))
return false return false
}) })
@ -566,7 +568,7 @@ func (p *parser) constDecl(group *Group) Decl {
return d return d
} }
// TypeSpec = identifier [ "=" ] Type . // TypeSpec = identifier [ TypeParams ] [ "=" ] Type .
func (p *parser) typeDecl(group *Group) Decl { func (p *parser) typeDecl(group *Group) Decl {
if trace { if trace {
defer p.trace("typeDecl")() defer p.trace("typeDecl")()
@ -578,8 +580,42 @@ func (p *parser) typeDecl(group *Group) Decl {
d.Pragma = p.takePragma() d.Pragma = p.takePragma()
d.Name = p.name() d.Name = p.name()
if p.tok == _Lbrack {
// array/slice or generic type
pos := p.pos()
p.next()
switch p.tok {
case _Rbrack:
p.next()
d.Type = p.sliceType(pos)
case _Name:
// array or generic type
p.xnest++
x := p.expr()
p.xnest--
if name0, ok := x.(*Name); p.mode&AllowGenerics != 0 && ok && p.tok != _Rbrack {
// generic type
d.TParamList = p.paramList(name0, _Rbrack)
pos := p.pos()
if p.gotAssign() {
p.syntaxErrorAt(pos, "generic type cannot be alias")
}
d.Type = p.typeOrNil()
} else {
// x is the array length expression
if debug && x == nil {
panic("internal error: nil expression")
}
d.Type = p.arrayType(pos, x)
}
default:
d.Type = p.arrayType(pos, nil)
}
} else {
d.Alias = p.gotAssign() d.Alias = p.gotAssign()
d.Type = p.typeOrNil() d.Type = p.typeOrNil()
}
if d.Type == nil { if d.Type == nil {
d.Type = p.badExpr() d.Type = p.badExpr()
p.syntaxError("in type declaration") p.syntaxError("in type declaration")
@ -613,7 +649,7 @@ func (p *parser) varDecl(group *Group) Decl {
return d return d
} }
// FunctionDecl = "func" FunctionName ( Function | Signature ) . // FunctionDecl = "func" FunctionName [ TypeParams ] ( Function | Signature ) .
// FunctionName = identifier . // FunctionName = identifier .
// Function = Signature FunctionBody . // Function = Signature FunctionBody .
// MethodDecl = "func" Receiver MethodName ( Function | Signature ) . // MethodDecl = "func" Receiver MethodName ( Function | Signature ) .
@ -627,8 +663,8 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
f.pos = p.pos() f.pos = p.pos()
f.Pragma = p.takePragma() f.Pragma = p.takePragma()
if p.tok == _Lparen { if p.got(_Lparen) {
rcvr := p.paramList() rcvr := p.paramList(nil, _Rparen)
switch len(rcvr) { switch len(rcvr) {
case 0: case 0:
p.error("method has no receiver") p.error("method has no receiver")
@ -647,6 +683,14 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
} }
f.Name = p.name() f.Name = p.name()
if p.mode&AllowGenerics != 0 && p.got(_Lbrack) {
if p.tok == _Rbrack {
p.syntaxError("empty type parameter list")
p.next()
} else {
f.TParamList = p.paramList(nil, _Rbrack)
}
}
f.Type = p.funcType() f.Type = p.funcType()
if p.tok == _Lbrace { if p.tok == _Lbrace {
f.Body = p.funcBody() f.Body = p.funcBody()
@ -850,13 +894,7 @@ func (p *parser) operand(keep_parens bool) Expr {
// Optimization: Record presence of ()'s only where needed // Optimization: Record presence of ()'s only where needed
// for error reporting. Don't bother in other cases; it is // for error reporting. Don't bother in other cases; it is
// just a waste of memory and time. // just a waste of memory and time.
//
// Parentheses are not permitted on lhs of := .
// switch x.Op {
// case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW:
// keep_parens = true
// }
// Parentheses are not permitted around T in a composite // Parentheses are not permitted around T in a composite
// literal T{}. If the next token is a {, assume x is a // literal T{}. If the next token is a {, assume x is a
// composite literal type T (it may not be, { could be // composite literal type T (it may not be, { could be
@ -879,19 +917,19 @@ func (p *parser) operand(keep_parens bool) Expr {
case _Func: case _Func:
pos := p.pos() pos := p.pos()
p.next() p.next()
t := p.funcType() ftyp := p.funcType()
if p.tok == _Lbrace { if p.tok == _Lbrace {
p.xnest++ p.xnest++
f := new(FuncLit) f := new(FuncLit)
f.pos = pos f.pos = pos
f.Type = t f.Type = ftyp
f.Body = p.funcBody() f.Body = p.funcBody()
p.xnest-- p.xnest--
return f return f
} }
return t return ftyp
case _Lbrack, _Chan, _Map, _Struct, _Interface: case _Lbrack, _Chan, _Map, _Struct, _Interface:
return p.type_() // othertype return p.type_() // othertype
@ -971,6 +1009,14 @@ loop:
case _Lbrack: case _Lbrack:
p.next() p.next()
if p.tok == _Rbrack {
// invalid empty instance, slice or index expression; accept but complain
p.syntaxError("expecting operand")
p.next()
break
}
p.xnest++ p.xnest++
var i Expr var i Expr
@ -986,6 +1032,20 @@ loop:
p.xnest-- p.xnest--
break break
} }
if p.mode&AllowGenerics != 0 && p.tok == _Comma {
// x[i, ... (instantiated type)
// TODO(gri) Suggestion by mdempsky@: Use IndexExpr + ExprList for this case.
// Then we can get rid of CallExpr.Brackets.
t := new(CallExpr)
t.pos = pos
t.Fun = x
t.ArgList, _ = p.argList(i, _Rbrack)
t.Brackets = true
x = t
p.xnest--
break
}
} }
// x[i:... // x[i:...
@ -1022,8 +1082,9 @@ loop:
case _Lparen: case _Lparen:
t := new(CallExpr) t := new(CallExpr)
t.pos = pos t.pos = pos
p.next()
t.Fun = x t.Fun = x
t.ArgList, t.HasDots = p.argList() t.ArgList, t.HasDots = p.argList(nil, _Rparen)
x = t x = t
case _Lbrace: case _Lbrace:
@ -1032,10 +1093,20 @@ loop:
t := unparen(x) t := unparen(x)
// determine if '{' belongs to a composite literal or a block statement // determine if '{' belongs to a composite literal or a block statement
complit_ok := false complit_ok := false
switch t.(type) { switch t := t.(type) {
case *Name, *SelectorExpr: case *Name, *SelectorExpr:
if p.xnest >= 0 { if p.xnest >= 0 {
// x is considered a composite literal type // x is possibly a composite literal type
complit_ok = true
}
case *CallExpr:
if t.Brackets && p.xnest >= 0 {
// x is possibly a composite literal type
complit_ok = true
}
case *IndexExpr:
if p.xnest >= 0 {
// x is possibly a composite literal type
complit_ok = true complit_ok = true
} }
case *ArrayType, *SliceType, *StructType, *MapType: case *ArrayType, *SliceType, *StructType, *MapType:
@ -1085,7 +1156,8 @@ func (p *parser) complitexpr() *CompositeLit {
x.pos = p.pos() x.pos = p.pos()
p.xnest++ p.xnest++
x.Rbrace = p.list(_Lbrace, _Comma, _Rbrace, func() bool { p.want(_Lbrace)
x.Rbrace = p.list(_Comma, _Rbrace, func() bool {
// value // value
e := p.bare_complitexpr() e := p.bare_complitexpr()
if p.tok == _Colon { if p.tok == _Colon {
@ -1170,26 +1242,10 @@ func (p *parser) typeOrNil() Expr {
// '[' oexpr ']' ntype // '[' oexpr ']' ntype
// '[' _DotDotDot ']' ntype // '[' _DotDotDot ']' ntype
p.next() p.next()
p.xnest++
if p.got(_Rbrack) { if p.got(_Rbrack) {
// []T return p.sliceType(pos)
p.xnest--
t := new(SliceType)
t.pos = pos
t.Elem = p.type_()
return t
} }
return p.arrayType(pos, nil)
// [n]T
t := new(ArrayType)
t.pos = pos
if !p.got(_DotDotDot) {
t.Len = p.expr()
}
p.want(_Rbrack)
p.xnest--
t.Elem = p.type_()
return t
case _Chan: case _Chan:
// _Chan non_recvchantype // _Chan non_recvchantype
@ -1221,7 +1277,7 @@ func (p *parser) typeOrNil() Expr {
return p.interfaceType() return p.interfaceType()
case _Name: case _Name:
return p.dotname(p.name()) return p.qualifiedName(nil)
case _Lparen: case _Lparen:
p.next() p.next()
@ -1233,6 +1289,27 @@ func (p *parser) typeOrNil() Expr {
return nil return nil
} }
func (p *parser) typeInstance(typ Expr) Expr {
if trace {
defer p.trace("typeInstance")()
}
pos := p.pos()
p.want(_Lbrack)
if p.tok == _Rbrack {
p.error("expecting type")
p.next()
return typ
}
call := new(CallExpr)
call.pos = pos
call.Fun = typ
call.ArgList, _ = p.argList(nil, _Rbrack)
call.Brackets = true
return call
}
func (p *parser) funcType() *FuncType { func (p *parser) funcType() *FuncType {
if trace { if trace {
defer p.trace("funcType")() defer p.trace("funcType")()
@ -1240,12 +1317,41 @@ func (p *parser) funcType() *FuncType {
typ := new(FuncType) typ := new(FuncType)
typ.pos = p.pos() typ.pos = p.pos()
typ.ParamList = p.paramList() p.want(_Lparen)
typ.ParamList = p.paramList(nil, _Rparen)
typ.ResultList = p.funcResult() typ.ResultList = p.funcResult()
return typ return typ
} }
// "[" has already been consumed, and pos is its position.
// If len != nil it is the already consumed array length.
func (p *parser) arrayType(pos Pos, len Expr) Expr {
if trace {
defer p.trace("arrayType")()
}
if len == nil && !p.got(_DotDotDot) {
p.xnest++
len = p.expr()
p.xnest--
}
p.want(_Rbrack)
t := new(ArrayType)
t.pos = pos
t.Len = len
t.Elem = p.type_()
return t
}
// "[" and "]" have already been consumed, and pos is the position of "[".
func (p *parser) sliceType(pos Pos) Expr {
t := new(SliceType)
t.pos = pos
t.Elem = p.type_()
return t
}
func (p *parser) chanElem() Expr { func (p *parser) chanElem() Expr {
if trace { if trace {
defer p.trace("chanElem")() defer p.trace("chanElem")()
@ -1261,22 +1367,6 @@ func (p *parser) chanElem() Expr {
return typ return typ
} }
func (p *parser) dotname(name *Name) Expr {
if trace {
defer p.trace("dotname")()
}
if p.tok == _Dot {
s := new(SelectorExpr)
s.pos = p.pos()
p.next()
s.X = name
s.Sel = p.name()
return s
}
return name
}
// StructType = "struct" "{" { FieldDecl ";" } "}" . // StructType = "struct" "{" { FieldDecl ";" } "}" .
func (p *parser) structType() *StructType { func (p *parser) structType() *StructType {
if trace { if trace {
@ -1287,7 +1377,8 @@ func (p *parser) structType() *StructType {
typ.pos = p.pos() typ.pos = p.pos()
p.want(_Struct) p.want(_Struct)
p.list(_Lbrace, _Semi, _Rbrace, func() bool { p.want(_Lbrace)
p.list(_Semi, _Rbrace, func() bool {
p.fieldDecl(typ) p.fieldDecl(typ)
return false return false
}) })
@ -1305,9 +1396,56 @@ func (p *parser) interfaceType() *InterfaceType {
typ.pos = p.pos() typ.pos = p.pos()
p.want(_Interface) p.want(_Interface)
p.list(_Lbrace, _Semi, _Rbrace, func() bool { p.want(_Lbrace)
if m := p.methodDecl(); m != nil { p.list(_Semi, _Rbrace, func() bool {
typ.MethodList = append(typ.MethodList, m) switch p.tok {
case _Name:
typ.MethodList = append(typ.MethodList, p.methodDecl())
case _Lparen:
p.syntaxError("cannot parenthesize embedded type")
f := new(Field)
f.pos = p.pos()
p.next()
f.Type = p.qualifiedName(nil)
p.want(_Rparen)
typ.MethodList = append(typ.MethodList, f)
case _Type:
if p.mode&AllowGenerics != 0 {
// TODO(gri) factor this better
type_ := new(Name)
type_.pos = p.pos()
type_.Value = "type" // cannot have a method named "type"
p.next()
if p.tok != _Semi && p.tok != _Rbrace {
f := new(Field)
f.pos = p.pos()
f.Name = type_
f.Type = p.type_()
typ.MethodList = append(typ.MethodList, f)
for p.got(_Comma) {
f := new(Field)
f.pos = p.pos()
f.Name = type_
f.Type = p.type_()
typ.MethodList = append(typ.MethodList, f)
}
} else {
p.syntaxError("expecting type")
}
break
}
fallthrough
default:
if p.mode&AllowGenerics != 0 {
p.syntaxError("expecting method, interface name, or type list")
p.advance(_Semi, _Rbrace, _Type)
} else {
p.syntaxError("expecting method or interface name")
p.advance(_Semi, _Rbrace)
}
} }
return false return false
}) })
@ -1321,8 +1459,8 @@ func (p *parser) funcResult() []*Field {
defer p.trace("funcResult")() defer p.trace("funcResult")()
} }
if p.tok == _Lparen { if p.got(_Lparen) {
return p.paramList() return p.paramList(nil, _Rparen)
} }
pos := p.pos() pos := p.pos()
@ -1368,59 +1506,71 @@ func (p *parser) fieldDecl(styp *StructType) {
case _Name: case _Name:
name := p.name() name := p.name()
if p.tok == _Dot || p.tok == _Literal || p.tok == _Semi || p.tok == _Rbrace { if p.tok == _Dot || p.tok == _Literal || p.tok == _Semi || p.tok == _Rbrace {
// embed oliteral // embedded type
typ := p.qualifiedName(name) typ := p.qualifiedName(name)
tag := p.oliteral() tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag) p.addField(styp, pos, nil, typ, tag)
return break
} }
// new_name_list ntype oliteral // name1, name2, ... Type [ tag ]
names := p.nameList(name) names := p.nameList(name)
typ := p.type_() var typ Expr
// Careful dance: We don't know if we have an embedded instantiated
// type T[P1, P2, ...] or a field T of array/slice type [P]E or []E.
if p.mode&AllowGenerics != 0 && len(names) == 1 && p.tok == _Lbrack {
typ = p.arrayOrTArgs()
if typ, ok := typ.(*CallExpr); ok {
// embedded type T[P1, P2, ...]
typ.Fun = name // name == names[0]
tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag)
break
}
} else {
// T P
typ = p.type_()
}
tag := p.oliteral() tag := p.oliteral()
for _, name := range names { for _, name := range names {
p.addField(styp, name.Pos(), name, typ, tag) p.addField(styp, name.Pos(), name, typ, tag)
} }
case _Lparen:
p.next()
if p.tok == _Star {
// '(' '*' embed ')' oliteral
pos := p.pos()
p.next()
typ := newIndirect(pos, p.qualifiedName(nil))
p.want(_Rparen)
tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag)
p.syntaxError("cannot parenthesize embedded type")
} else {
// '(' embed ')' oliteral
typ := p.qualifiedName(nil)
p.want(_Rparen)
tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag)
p.syntaxError("cannot parenthesize embedded type")
}
case _Star: case _Star:
p.next() p.next()
if p.got(_Lparen) { var typ Expr
// '*' '(' embed ')' oliteral if p.tok == _Lparen {
typ := newIndirect(pos, p.qualifiedName(nil)) // *(T)
p.want(_Rparen)
tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag)
p.syntaxError("cannot parenthesize embedded type") p.syntaxError("cannot parenthesize embedded type")
p.next()
typ = p.qualifiedName(nil)
p.got(_Rparen) // no need to complain if missing
} else { } else {
// '*' embed oliteral // *T
typ := newIndirect(pos, p.qualifiedName(nil)) typ = p.qualifiedName(nil)
}
tag := p.oliteral()
p.addField(styp, pos, nil, newIndirect(pos, typ), tag)
case _Lparen:
p.syntaxError("cannot parenthesize embedded type")
p.next()
var typ Expr
if p.tok == _Star {
// (*T)
pos := p.pos()
p.next()
typ = newIndirect(pos, p.qualifiedName(nil))
} else {
// (T)
typ = p.qualifiedName(nil)
}
p.got(_Rparen) // no need to complain if missing
tag := p.oliteral() tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag) p.addField(styp, pos, nil, typ, tag)
}
default: default:
p.syntaxError("expecting field name or embedded type") p.syntaxError("expecting field name or embedded type")
@ -1428,6 +1578,39 @@ func (p *parser) fieldDecl(styp *StructType) {
} }
} }
func (p *parser) arrayOrTArgs() Expr {
if trace {
defer p.trace("arrayOrTArgs")()
}
pos := p.pos()
p.want(_Lbrack)
if p.got(_Rbrack) {
return p.sliceType(pos)
}
// x [P]E or x[P]
args, _ := p.argList(nil, _Rbrack)
if len(args) == 1 {
if elem := p.typeOrNil(); elem != nil {
// x [P]E
t := new(ArrayType)
t.pos = pos
t.Len = args[0]
t.Elem = elem
return t
}
}
// x[P], x[P1, P2], ...
t := new(CallExpr)
t.pos = pos
// t.Fun will be filled in by caller
t.ArgList = args
t.Brackets = true
return t
}
func (p *parser) oliteral() *BasicLit { func (p *parser) oliteral() *BasicLit {
if p.tok == _Literal { if p.tok == _Literal {
b := new(BasicLit) b := new(BasicLit)
@ -1449,11 +1632,14 @@ func (p *parser) methodDecl() *Field {
defer p.trace("methodDecl")() defer p.trace("methodDecl")()
} }
switch p.tok { f := new(Field)
case _Name: f.pos = p.pos()
name := p.name() name := p.name()
// accept potential name list but complain // accept potential name list but complain
// TODO(gri) We probably don't need this special check anymore.
// Nobody writes this kind of code. It's from ancient
// Go beginnings.
hasNameList := false hasNameList := false
for p.got(_Comma) { for p.got(_Comma) {
p.name() p.name()
@ -1464,36 +1650,75 @@ func (p *parser) methodDecl() *Field {
// already progressed, no need to advance // already progressed, no need to advance
} }
f := new(Field) switch p.tok {
f.pos = name.Pos() case _Lparen:
if p.tok != _Lparen { // method
// packname
f.Type = p.qualifiedName(name)
return f
}
f.Name = name f.Name = name
f.Type = p.funcType() f.Type = p.funcType()
return f
case _Lparen: case _Lbrack:
p.syntaxError("cannot parenthesize embedded type") if p.mode&AllowGenerics != 0 {
f := new(Field) // Careful dance: We don't know if we have a generic method m[T C](x T)
f.pos = p.pos() // or an embedded instantiated type T[P1, P2] (we accept generic methods
// for generality and robustness of parsing).
pos := p.pos()
p.next() p.next()
f.Type = p.qualifiedName(nil)
p.want(_Rparen) // empty type parameter or argument lists are not permitted
return f if p.tok == _Rbrack {
// name[]
pos := p.pos()
p.next()
if p.tok == _Lparen {
// name[](
p.errorAt(pos, "empty type parameter list")
f.Name = name
f.Type = p.funcType()
} else {
p.errorAt(pos, "empty type argument list")
f.Type = name
}
break
}
// A type argument list looks like a parameter list with only
// types. Parse a parameter list and decide afterwards.
list := p.paramList(nil, _Rbrack)
if len(list) > 0 && list[0].Name != nil {
// generic method
f.Name = name
f.Type = p.funcType()
// TODO(gri) Record list as type parameter list with f.Type
// if we want to type-check the generic method.
// For now, report an error so this is not a silent event.
p.errorAt(pos, "interface method cannot have type parameters")
break
}
// embedded instantiated type
call := new(CallExpr)
call.pos = pos
call.Fun = name
call.Brackets = true
call.ArgList = make([]Expr, len(list))
for i := range list {
call.ArgList[i] = list[i].Type
}
f.Type = call
break
}
fallthrough
default: default:
p.syntaxError("expecting method or interface name") // embedded type
p.advance(_Semi, _Rbrace) f.Type = p.qualifiedName(name)
return nil
} }
return f
} }
// ParameterDecl = [ IdentifierList ] [ "..." ] Type . // ParameterDecl = [ IdentifierList ] [ "..." ] Type .
func (p *parser) paramDeclOrNil() *Field { func (p *parser) paramDeclOrNil(name *Name) *Field {
if trace { if trace {
defer p.trace("paramDecl")() defer p.trace("paramDecl")()
} }
@ -1501,73 +1726,67 @@ func (p *parser) paramDeclOrNil() *Field {
f := new(Field) f := new(Field)
f.pos = p.pos() f.pos = p.pos()
switch p.tok { if p.tok == _Name || name != nil {
case _Name: if name == nil {
f.Name = p.name() name = p.name()
switch p.tok {
case _Name, _Star, _Arrow, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen:
// sym name_or_type
f.Type = p.type_()
case _DotDotDot:
// sym dotdotdot
f.Type = p.dotsType()
case _Dot:
// name_or_type
// from dotname
f.Type = p.dotname(f.Name)
f.Name = nil
} }
case _Arrow, _Star, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen: if p.mode&AllowGenerics != 0 && p.tok == _Lbrack {
// name_or_type f.Type = p.arrayOrTArgs()
f.Type = p.type_() if typ, ok := f.Type.(*CallExpr); ok {
typ.Fun = name
case _DotDotDot: } else {
// dotdotdot f.Name = name
f.Type = p.dotsType()
default:
p.syntaxError("expecting )")
p.advance(_Comma, _Rparen)
return nil
} }
return f return f
}
// ...Type
func (p *parser) dotsType() *DotsType {
if trace {
defer p.trace("dotsType")()
} }
if p.tok == _Dot {
// name_or_type
f.Type = p.qualifiedName(name)
return f
}
f.Name = name
}
if p.tok == _DotDotDot {
t := new(DotsType) t := new(DotsType)
t.pos = p.pos() t.pos = p.pos()
p.next()
p.want(_DotDotDot)
t.Elem = p.typeOrNil() t.Elem = p.typeOrNil()
if t.Elem == nil { if t.Elem == nil {
t.Elem = p.badExpr() t.Elem = p.badExpr()
p.syntaxError("final argument in variadic function missing type") p.syntaxError("final argument in variadic function missing type")
} }
f.Type = t
return f
}
return t f.Type = p.typeOrNil()
if f.Name != nil || f.Type != nil {
return f
}
p.syntaxError("expecting )")
p.advance(_Comma, _Rparen)
return nil
} }
// Parameters = "(" [ ParameterList [ "," ] ] ")" . // Parameters = "(" [ ParameterList [ "," ] ] ")" .
// ParameterList = ParameterDecl { "," ParameterDecl } . // ParameterList = ParameterDecl { "," ParameterDecl } .
func (p *parser) paramList() (list []*Field) { // "(" or "[" has already been consumed.
// If name != nil, it is the first name after "(" or "[".
func (p *parser) paramList(name *Name, close token) (list []*Field) {
if trace { if trace {
defer p.trace("paramList")() defer p.trace("paramList")()
} }
pos := p.pos() var named int // number of parameters that have an explicit name and type/bound
p.list(_Comma, close, func() bool {
var named int // number of parameters that have an explicit name and type par := p.paramDeclOrNil(name)
p.list(_Lparen, _Comma, _Rparen, func() bool { name = nil // 1st name was consumed if present
if par := p.paramDeclOrNil(); par != nil { if par != nil {
if debug && par.Name == nil && par.Type == nil { if debug && par.Name == nil && par.Type == nil {
panic("parameter without name or type") panic("parameter without name or type")
} }
@ -1589,30 +1808,30 @@ func (p *parser) paramList() (list []*Field) {
} }
} }
} else if named != len(list) { } else if named != len(list) {
// some named => all must be named // some named => all must have names and types
ok := true var pos Pos // error position (or unknown)
var typ Expr var typ Expr
for i := len(list) - 1; i >= 0; i-- { for i := len(list) - 1; i >= 0; i-- {
if par := list[i]; par.Type != nil { if par := list[i]; par.Type != nil {
typ = par.Type typ = par.Type
if par.Name == nil { if par.Name == nil {
ok = false pos = typ.Pos()
n := p.newName("_") n := p.newName("_")
n.pos = typ.Pos() // correct position n.pos = pos // correct position
par.Name = n par.Name = n
} }
} else if typ != nil { } else if typ != nil {
par.Type = typ par.Type = typ
} else { } else {
// par.Type == nil && typ == nil => we only have a par.Name // par.Type == nil && typ == nil => we only have a par.Name
ok = false pos = par.Name.Pos()
t := p.badExpr() t := p.badExpr()
t.pos = par.Name.Pos() // correct position t.pos = pos // correct position
par.Type = t par.Type = t
} }
} }
if !ok { if pos.IsKnown() {
p.syntaxErrorAt(pos, "mixed named and unnamed function parameters") p.syntaxErrorAt(pos, "mixed named and unnamed parameters")
} }
} }
@ -2209,15 +2428,21 @@ func (p *parser) stmtList() (l []Stmt) {
} }
// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" . // Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
func (p *parser) argList() (list []Expr, hasDots bool) { func (p *parser) argList(arg Expr, close token) (list []Expr, hasDots bool) {
if trace { if trace {
defer p.trace("argList")() defer p.trace("argList")()
} }
p.xnest++ p.xnest++
p.list(_Lparen, _Comma, _Rparen, func() bool { p.list(_Comma, close, func() bool {
list = append(list, p.expr()) if arg == nil {
arg = p.expr()
}
list = append(list, arg)
arg = nil
if close == _Rparen {
hasDots = p.got(_DotDotDot) hasDots = p.got(_DotDotDot)
}
return hasDots return hasDots
}) })
p.xnest-- p.xnest--
@ -2275,18 +2500,32 @@ func (p *parser) qualifiedName(name *Name) Expr {
defer p.trace("qualifiedName")() defer p.trace("qualifiedName")()
} }
var x Expr
switch { switch {
case name != nil: case name != nil:
// name is provided x = name
case p.tok == _Name: case p.tok == _Name:
name = p.name() x = p.name()
default: default:
name = p.newName("_") x = p.newName("_")
p.syntaxError("expecting name") p.syntaxError("expecting name")
p.advance(_Dot, _Semi, _Rbrace) p.advance(_Dot, _Semi, _Rbrace)
} }
return p.dotname(name) if p.tok == _Dot {
s := new(SelectorExpr)
s.pos = p.pos()
p.next()
s.X = x
s.Sel = p.name()
x = s
}
if p.mode&AllowGenerics != 0 && p.tok == _Lbrack {
x = p.typeInstance(x)
}
return x
} }
// ExpressionList = Expression { "," Expression } . // ExpressionList = Expression { "," Expression } .

View file

@ -16,6 +16,7 @@ type Mode uint
// Modes supported by the parser. // Modes supported by the parser.
const ( const (
CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements
AllowGenerics
) )
// Error describes a syntax error. Error implements the error interface. // Error describes a syntax error. Error implements the error interface.