diff options
Diffstat (limited to 'src/cmd/compile/internal/syntax/parser.go')
-rw-r--r-- | src/cmd/compile/internal/syntax/parser.go | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index e89796cb31..82cb06b180 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -276,7 +276,9 @@ func (p *parser) syntaxErrorAt(pos Pos, msg string) { } // tokstring returns the English word for selected punctuation tokens -// for more readable error messages. +// for more readable error messages. Use tokstring (not tok.String()) +// for user-facing (error) messages; use tok.String() for debugging +// output. func tokstring(tok token) string { switch tok { case _Comma: @@ -1839,7 +1841,7 @@ func (p *parser) embeddedTerm() Expr { } // ParameterDecl = [ IdentifierList ] [ "..." ] Type . -func (p *parser) paramDeclOrNil(name *Name) *Field { +func (p *parser) paramDeclOrNil(name *Name, follow token) *Field { if trace { defer p.trace("paramDecl")() } @@ -1893,8 +1895,8 @@ func (p *parser) paramDeclOrNil(name *Name) *Field { return f } - p.syntaxError("expecting )") - p.advance(_Comma, _Rparen) + p.syntaxError("expecting " + tokstring(follow)) + p.advance(_Comma, follow) return nil } @@ -1908,9 +1910,10 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []* defer p.trace("paramList")() } - var named int // number of parameters that have an explicit name and type/bound - p.list(_Comma, close, func() bool { - par := p.paramDeclOrNil(name) + var named int // number of parameters that have an explicit name and type + var typed int // number of parameters that have an explicit type + end := p.list(_Comma, close, func() bool { + par := p.paramDeclOrNil(name, close) name = nil // 1st name was consumed if present if par != nil { if debug && par.Name == nil && par.Type == nil { @@ -1919,6 +1922,9 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []* if par.Name != nil && par.Type != nil { named++ } + if par.Type != nil { + typed++ + } list = append(list, par) } return false @@ -1939,10 +1945,11 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []* } } else if named != len(list) { // some named => all must have names and types - var pos Pos // left-most error position (or unknown) - var typ Expr + var pos Pos // left-most error position (or unknown) + var typ Expr // current type (from right to left) for i := len(list) - 1; i >= 0; i-- { - if par := list[i]; par.Type != nil { + par := list[i] + if par.Type != nil { typ = par.Type if par.Name == nil { pos = typ.Pos() @@ -1961,7 +1968,12 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []* if pos.IsKnown() { var msg string if requireNames { - msg = "type parameters must be named" + if named == typed { + pos = end // position error at closing ] + msg = "missing type constraint" + } else { + msg = "type parameters must be named" + } } else { msg = "mixed named and unnamed parameters" } @@ -2201,7 +2213,7 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS if p.tok != _Semi { // accept potential varDecl but complain if p.got(_Var) { - p.syntaxError(fmt.Sprintf("var declaration not allowed in %s initializer", keyword.String())) + p.syntaxError(fmt.Sprintf("var declaration not allowed in %s initializer", tokstring(keyword))) } init = p.simpleStmt(nil, keyword) // If we have a range clause, we are done (can only happen for keyword == _For). |