]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile/internal/syntax: implement parsing of type parameters
authorRobert Griesemer <gri@golang.org>
Mon, 12 Oct 2020 21:07:31 +0000 (14:07 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 13 Oct 2020 04:38:33 +0000 (04:38 +0000)
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>
src/cmd/compile/internal/syntax/parser.go
src/cmd/compile/internal/syntax/syntax.go

index 146f83ed017698b0864ec22b84078a3c3f6db382..126b87b4ee99dad55c9595826a75c9d7e208be43 100644 (file)
@@ -459,20 +459,21 @@ func isEmptyFuncDecl(dcl Decl) bool {
 // Declarations
 
 // list parses a possibly empty, sep-separated list, optionally
-// followed by sep and enclosed by ( and ) or { and }. open is
-// one of _Lparen, or _Lbrace, sep is one of _Comma or _Semi,
-// and close is expected to be the (closing) opposite of open.
+// followed sep, and closed by close. sep must be one of _Comma
+// or _Semi, and close must be one of _Rparen, _Rbrace, or _Rbrack.
 // For each list element, f is called. After f returns true, no
 // more list elements are accepted. list returns the position
 // of the closing token.
 //
-// list = "(" { f sep } ")" |
-//        "{" { f sep } "}" . // sep is optional before ")" or "}"
+// list = { f sep } ")" |
+//        { f sep } "}" . // "," or ";" is optional before ")", "}" or "]"
 //
-func (p *parser) list(open, sep, close token, f func() bool) Pos {
-       p.want(open)
+func (p *parser) list(sep, close token, f func() bool) Pos {
+       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 {
                done = f()
                // sep is optional before close
@@ -496,7 +497,8 @@ func (p *parser) appendGroup(list []Decl, f func(*Group) Decl) []Decl {
        if p.tok == _Lparen {
                g := new(Group)
                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))
                        return false
                })
@@ -566,7 +568,7 @@ func (p *parser) constDecl(group *Group) Decl {
        return d
 }
 
-// TypeSpec = identifier [ "=" ] Type .
+// TypeSpec = identifier [ TypeParams ] [ "=" ] Type .
 func (p *parser) typeDecl(group *Group) Decl {
        if trace {
                defer p.trace("typeDecl")()
@@ -578,8 +580,42 @@ func (p *parser) typeDecl(group *Group) Decl {
        d.Pragma = p.takePragma()
 
        d.Name = p.name()
-       d.Alias = p.gotAssign()
-       d.Type = p.typeOrNil()
+       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.Type = p.typeOrNil()
+       }
+
        if d.Type == nil {
                d.Type = p.badExpr()
                p.syntaxError("in type declaration")
@@ -613,7 +649,7 @@ func (p *parser) varDecl(group *Group) Decl {
        return d
 }
 
-// FunctionDecl = "func" FunctionName ( Function | Signature ) .
+// FunctionDecl = "func" FunctionName [ TypeParams ] ( Function | Signature ) .
 // FunctionName = identifier .
 // Function     = Signature FunctionBody .
 // MethodDecl   = "func" Receiver MethodName ( Function | Signature ) .
@@ -627,8 +663,8 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
        f.pos = p.pos()
        f.Pragma = p.takePragma()
 
-       if p.tok == _Lparen {
-               rcvr := p.paramList()
+       if p.got(_Lparen) {
+               rcvr := p.paramList(nil, _Rparen)
                switch len(rcvr) {
                case 0:
                        p.error("method has no receiver")
@@ -647,6 +683,14 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
        }
 
        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()
        if p.tok == _Lbrace {
                f.Body = p.funcBody()
@@ -850,13 +894,7 @@ func (p *parser) operand(keep_parens bool) Expr {
                // Optimization: Record presence of ()'s only where needed
                // for error reporting. Don't bother in other cases; it is
                // 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
                // literal T{}. If the next token is a {, assume x is a
                // composite literal type T (it may not be, { could be
@@ -879,19 +917,19 @@ func (p *parser) operand(keep_parens bool) Expr {
        case _Func:
                pos := p.pos()
                p.next()
-               t := p.funcType()
+               ftyp := p.funcType()
                if p.tok == _Lbrace {
                        p.xnest++
 
                        f := new(FuncLit)
                        f.pos = pos
-                       f.Type = t
+                       f.Type = ftyp
                        f.Body = p.funcBody()
 
                        p.xnest--
                        return f
                }
-               return t
+               return ftyp
 
        case _Lbrack, _Chan, _Map, _Struct, _Interface:
                return p.type_() // othertype
@@ -971,6 +1009,14 @@ loop:
 
                case _Lbrack:
                        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++
 
                        var i Expr
@@ -986,6 +1032,20 @@ loop:
                                        p.xnest--
                                        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:...
@@ -1022,8 +1082,9 @@ loop:
                case _Lparen:
                        t := new(CallExpr)
                        t.pos = pos
+                       p.next()
                        t.Fun = x
-                       t.ArgList, t.HasDots = p.argList()
+                       t.ArgList, t.HasDots = p.argList(nil, _Rparen)
                        x = t
 
                case _Lbrace:
@@ -1032,10 +1093,20 @@ loop:
                        t := unparen(x)
                        // determine if '{' belongs to a composite literal or a block statement
                        complit_ok := false
-                       switch t.(type) {
+                       switch t := t.(type) {
                        case *Name, *SelectorExpr:
                                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
                                }
                        case *ArrayType, *SliceType, *StructType, *MapType:
@@ -1085,7 +1156,8 @@ func (p *parser) complitexpr() *CompositeLit {
        x.pos = p.pos()
 
        p.xnest++
-       x.Rbrace = p.list(_Lbrace, _Comma, _Rbrace, func() bool {
+       p.want(_Lbrace)
+       x.Rbrace = p.list(_Comma, _Rbrace, func() bool {
                // value
                e := p.bare_complitexpr()
                if p.tok == _Colon {
@@ -1170,26 +1242,10 @@ func (p *parser) typeOrNil() Expr {
                // '[' oexpr ']' ntype
                // '[' _DotDotDot ']' ntype
                p.next()
-               p.xnest++
                if p.got(_Rbrack) {
-                       // []T
-                       p.xnest--
-                       t := new(SliceType)
-                       t.pos = pos
-                       t.Elem = p.type_()
-                       return t
+                       return p.sliceType(pos)
                }
-
-               // [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
+               return p.arrayType(pos, nil)
 
        case _Chan:
                // _Chan non_recvchantype
@@ -1221,7 +1277,7 @@ func (p *parser) typeOrNil() Expr {
                return p.interfaceType()
 
        case _Name:
-               return p.dotname(p.name())
+               return p.qualifiedName(nil)
 
        case _Lparen:
                p.next()
@@ -1233,6 +1289,27 @@ func (p *parser) typeOrNil() Expr {
        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 {
        if trace {
                defer p.trace("funcType")()
@@ -1240,12 +1317,41 @@ func (p *parser) funcType() *FuncType {
 
        typ := new(FuncType)
        typ.pos = p.pos()
-       typ.ParamList = p.paramList()
+       p.want(_Lparen)
+       typ.ParamList = p.paramList(nil, _Rparen)
        typ.ResultList = p.funcResult()
 
        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 {
        if trace {
                defer p.trace("chanElem")()
@@ -1261,22 +1367,6 @@ func (p *parser) chanElem() Expr {
        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 ";" } "}" .
 func (p *parser) structType() *StructType {
        if trace {
@@ -1287,7 +1377,8 @@ func (p *parser) structType() *StructType {
        typ.pos = p.pos()
 
        p.want(_Struct)
-       p.list(_Lbrace, _Semi, _Rbrace, func() bool {
+       p.want(_Lbrace)
+       p.list(_Semi, _Rbrace, func() bool {
                p.fieldDecl(typ)
                return false
        })
@@ -1305,9 +1396,56 @@ func (p *parser) interfaceType() *InterfaceType {
        typ.pos = p.pos()
 
        p.want(_Interface)
-       p.list(_Lbrace, _Semi, _Rbrace, func() bool {
-               if m := p.methodDecl(); m != nil {
-                       typ.MethodList = append(typ.MethodList, m)
+       p.want(_Lbrace)
+       p.list(_Semi, _Rbrace, func() bool {
+               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
        })
@@ -1321,8 +1459,8 @@ func (p *parser) funcResult() []*Field {
                defer p.trace("funcResult")()
        }
 
-       if p.tok == _Lparen {
-               return p.paramList()
+       if p.got(_Lparen) {
+               return p.paramList(nil, _Rparen)
        }
 
        pos := p.pos()
@@ -1368,59 +1506,71 @@ func (p *parser) fieldDecl(styp *StructType) {
        case _Name:
                name := p.name()
                if p.tok == _Dot || p.tok == _Literal || p.tok == _Semi || p.tok == _Rbrace {
-                       // embed oliteral
+                       // embedded type
                        typ := p.qualifiedName(name)
                        tag := p.oliteral()
                        p.addField(styp, pos, nil, typ, tag)
-                       return
+                       break
                }
 
-               // new_name_list ntype oliteral
+               // name1, name2, ... Type [ tag ]
                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()
 
                for _, name := range names {
                        p.addField(styp, name.Pos(), name, typ, tag)
                }
 
-       case _Lparen:
+       case _Star:
                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)
+               var typ Expr
+               if p.tok == _Lparen {
+                       // *(T)
                        p.syntaxError("cannot parenthesize embedded type")
-
+                       p.next()
+                       typ = p.qualifiedName(nil)
+                       p.got(_Rparen) // no need to complain if missing
                } 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")
+                       // *T
+                       typ = p.qualifiedName(nil)
                }
+               tag := p.oliteral()
+               p.addField(styp, pos, nil, newIndirect(pos, typ), tag)
 
-       case _Star:
+       case _Lparen:
+               p.syntaxError("cannot parenthesize embedded type")
                p.next()
-               if p.got(_Lparen) {
-                       // '*' '(' embed ')' oliteral
-                       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")
-
+               var typ Expr
+               if p.tok == _Star {
+                       // (*T)
+                       pos := p.pos()
+                       p.next()
+                       typ = newIndirect(pos, p.qualifiedName(nil))
                } else {
-                       // '*' embed oliteral
-                       typ := newIndirect(pos, p.qualifiedName(nil))
-                       tag := p.oliteral()
-                       p.addField(styp, pos, nil, typ, tag)
+                       // (T)
+                       typ = p.qualifiedName(nil)
                }
+               p.got(_Rparen) // no need to complain if missing
+               tag := p.oliteral()
+               p.addField(styp, pos, nil, typ, tag)
 
        default:
                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 {
        if p.tok == _Literal {
                b := new(BasicLit)
@@ -1449,51 +1632,93 @@ func (p *parser) methodDecl() *Field {
                defer p.trace("methodDecl")()
        }
 
-       switch p.tok {
-       case _Name:
-               name := p.name()
-
-               // accept potential name list but complain
-               hasNameList := false
-               for p.got(_Comma) {
-                       p.name()
-                       hasNameList = true
-               }
-               if hasNameList {
-                       p.syntaxError("name list not allowed in interface type")
-                       // already progressed, no need to advance
-               }
+       f := new(Field)
+       f.pos = p.pos()
+       name := p.name()
 
-               f := new(Field)
-               f.pos = name.Pos()
-               if p.tok != _Lparen {
-                       // packname
-                       f.Type = p.qualifiedName(name)
-                       return f
-               }
+       // 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
+       for p.got(_Comma) {
+               p.name()
+               hasNameList = true
+       }
+       if hasNameList {
+               p.syntaxError("name list not allowed in interface type")
+               // already progressed, no need to advance
+       }
 
+       switch p.tok {
+       case _Lparen:
+               // method
                f.Name = name
                f.Type = p.funcType()
-               return f
 
-       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)
-               return f
+       case _Lbrack:
+               if p.mode&AllowGenerics != 0 {
+                       // Careful dance: We don't know if we have a generic method m[T C](x T)
+                       // or an embedded instantiated type T[P1, P2] (we accept generic methods
+                       // for generality and robustness of parsing).
+                       pos := p.pos()
+                       p.next()
+
+                       // empty type parameter or argument lists are not permitted
+                       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:
-               p.syntaxError("expecting method or interface name")
-               p.advance(_Semi, _Rbrace)
-               return nil
+               // embedded type
+               f.Type = p.qualifiedName(name)
        }
+
+       return f
 }
 
 // ParameterDecl = [ IdentifierList ] [ "..." ] Type .
-func (p *parser) paramDeclOrNil() *Field {
+func (p *parser) paramDeclOrNil(name *Name) *Field {
        if trace {
                defer p.trace("paramDecl")()
        }
@@ -1501,73 +1726,67 @@ func (p *parser) paramDeclOrNil() *Field {
        f := new(Field)
        f.pos = p.pos()
 
-       switch p.tok {
-       case _Name:
-               f.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_()
+       if p.tok == _Name || name != nil {
+               if name == nil {
+                       name = p.name()
+               }
 
-               case _DotDotDot:
-                       // sym dotdotdot
-                       f.Type = p.dotsType()
+               if p.mode&AllowGenerics != 0 && p.tok == _Lbrack {
+                       f.Type = p.arrayOrTArgs()
+                       if typ, ok := f.Type.(*CallExpr); ok {
+                               typ.Fun = name
+                       } else {
+                               f.Name = name
+                       }
+                       return f
+               }
 
-               case _Dot:
+               if p.tok == _Dot {
                        // name_or_type
-                       // from dotname
-                       f.Type = p.dotname(f.Name)
-                       f.Name = nil
+                       f.Type = p.qualifiedName(name)
+                       return f
                }
 
-       case _Arrow, _Star, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen:
-               // name_or_type
-               f.Type = p.type_()
-
-       case _DotDotDot:
-               // dotdotdot
-               f.Type = p.dotsType()
-
-       default:
-               p.syntaxError("expecting )")
-               p.advance(_Comma, _Rparen)
-               return nil
+               f.Name = name
        }
 
-       return f
-}
-
-// ...Type
-func (p *parser) dotsType() *DotsType {
-       if trace {
-               defer p.trace("dotsType")()
+       if p.tok == _DotDotDot {
+               t := new(DotsType)
+               t.pos = p.pos()
+               p.next()
+               t.Elem = p.typeOrNil()
+               if t.Elem == nil {
+                       t.Elem = p.badExpr()
+                       p.syntaxError("final argument in variadic function missing type")
+               }
+               f.Type = t
+               return f
        }
 
-       t := new(DotsType)
-       t.pos = p.pos()
-
-       p.want(_DotDotDot)
-       t.Elem = p.typeOrNil()
-       if t.Elem == nil {
-               t.Elem = p.badExpr()
-               p.syntaxError("final argument in variadic function missing type")
+       f.Type = p.typeOrNil()
+       if f.Name != nil || f.Type != nil {
+               return f
        }
 
-       return t
+       p.syntaxError("expecting )")
+       p.advance(_Comma, _Rparen)
+       return nil
 }
 
 // Parameters    = "(" [ ParameterList [ "," ] ] ")" .
 // 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 {
                defer p.trace("paramList")()
        }
 
-       pos := p.pos()
-
-       var named int // number of parameters that have an explicit name and type
-       p.list(_Lparen, _Comma, _Rparen, func() bool {
-               if par := p.paramDeclOrNil(); par != nil {
+       var named int // number of parameters that have an explicit name and type/bound
+       p.list(_Comma, close, func() bool {
+               par := p.paramDeclOrNil(name)
+               name = nil // 1st name was consumed if present
+               if par != nil {
                        if debug && par.Name == nil && par.Type == nil {
                                panic("parameter without name or type")
                        }
@@ -1589,30 +1808,30 @@ func (p *parser) paramList() (list []*Field) {
                        }
                }
        } else if named != len(list) {
-               // some named => all must be named
-               ok := true
+               // some named => all must have names and types
+               var pos Pos // error position (or unknown)
                var typ Expr
                for i := len(list) - 1; i >= 0; i-- {
                        if par := list[i]; par.Type != nil {
                                typ = par.Type
                                if par.Name == nil {
-                                       ok = false
+                                       pos = typ.Pos()
                                        n := p.newName("_")
-                                       n.pos = typ.Pos() // correct position
+                                       n.pos = pos // correct position
                                        par.Name = n
                                }
                        } else if typ != nil {
                                par.Type = typ
                        } else {
                                // par.Type == nil && typ == nil => we only have a par.Name
-                               ok = false
+                               pos = par.Name.Pos()
                                t := p.badExpr()
-                               t.pos = par.Name.Pos() // correct position
+                               t.pos = pos // correct position
                                par.Type = t
                        }
                }
-               if !ok {
-                       p.syntaxErrorAt(pos, "mixed named and unnamed function parameters")
+               if pos.IsKnown() {
+                       p.syntaxErrorAt(pos, "mixed named and unnamed parameters")
                }
        }
 
@@ -2209,15 +2428,21 @@ func (p *parser) stmtList() (l []Stmt) {
 }
 
 // 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 {
                defer p.trace("argList")()
        }
 
        p.xnest++
-       p.list(_Lparen, _Comma, _Rparen, func() bool {
-               list = append(list, p.expr())
-               hasDots = p.got(_DotDotDot)
+       p.list(_Comma, close, func() bool {
+               if arg == nil {
+                       arg = p.expr()
+               }
+               list = append(list, arg)
+               arg = nil
+               if close == _Rparen {
+                       hasDots = p.got(_DotDotDot)
+               }
                return hasDots
        })
        p.xnest--
@@ -2275,18 +2500,32 @@ func (p *parser) qualifiedName(name *Name) Expr {
                defer p.trace("qualifiedName")()
        }
 
+       var x Expr
        switch {
        case name != nil:
-               // name is provided
+               x = name
        case p.tok == _Name:
-               name = p.name()
+               x = p.name()
        default:
-               name = p.newName("_")
+               x = p.newName("_")
                p.syntaxError("expecting name")
                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 } .
index e51b5538b3b18221a111830519f12358528f6d7b..f3d4c09ed5e045fad13d469def95cb386b73cd6a 100644 (file)
@@ -16,6 +16,7 @@ type Mode uint
 // Modes supported by the parser.
 const (
        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.