go/parser: complain if type parameters are not permitted

Always accept them but complain if they are not permitted.
The analogous parser check was lost in a recent change.

Also: Fix index computation in collectTypeParams.

Change-Id: I7cb89944984df6dadd7f603b56f0c3941d60f7c5
This commit is contained in:
Robert Griesemer 2019-11-20 15:00:05 -08:00
parent c47bad9a28
commit 46442bd4a9
2 changed files with 21 additions and 14 deletions

View File

@ -1116,11 +1116,14 @@ func (p *parser) parseTypeParams(scope *ast.Scope) *ast.FieldList {
return &ast.FieldList{Opening: lbrack, List: fields, Closing: rbrack} return &ast.FieldList{Opening: lbrack, List: fields, Closing: rbrack}
} }
func (p *parser) parseParameters(scope *ast.Scope, typeParamsOk, ellipsisOk bool) (tparams, params *ast.FieldList) { func (p *parser) parseParameters(scope *ast.Scope, typeParamsOk, ellipsisOk bool, context string) (tparams, params *ast.FieldList) {
if p.trace { if p.trace {
defer un(trace(p, "Parameters")) defer un(trace(p, "Parameters"))
} }
// We always accept type parameters for robustness
// and complain later if they are not permitted.
var lparen token.Pos var lparen token.Pos
if useBrackets && p.tok == token.LBRACK { if useBrackets && p.tok == token.LBRACK {
// assume [type T](params) syntax // assume [type T](params) syntax
@ -1142,6 +1145,11 @@ func (p *parser) parseParameters(scope *ast.Scope, typeParamsOk, ellipsisOk bool
} }
} }
if tparams != nil && !typeParamsOk {
p.error(tparams.Opening, context+" must have no type parameters")
tparams = nil
}
var fields []*ast.Field var fields []*ast.Field
if p.tok != token.RPAREN { if p.tok != token.RPAREN {
fields = p.parseParameterList(scope, ellipsisOk) fields = p.parseParameterList(scope, ellipsisOk)
@ -1159,7 +1167,7 @@ func (p *parser) parseResult(scope *ast.Scope, typeContext bool) *ast.FieldList
} }
if p.tok == token.LPAREN { if p.tok == token.LPAREN {
_, results := p.parseParameters(scope, false, false) _, results := p.parseParameters(scope, false, false, "result")
return results return results
} }
@ -1180,7 +1188,7 @@ func (p *parser) parseFuncType(typeContext bool) (*ast.FuncType, *ast.Scope) {
pos := p.expect(token.FUNC) pos := p.expect(token.FUNC)
scope := ast.NewScope(p.topScope) // function scope scope := ast.NewScope(p.topScope) // function scope
_, params := p.parseParameters(scope, false, true) _, params := p.parseParameters(scope, false, true, "function type")
results := p.parseResult(scope, typeContext) results := p.parseResult(scope, typeContext)
return &ast.FuncType{Func: pos, Params: params, Results: results}, scope return &ast.FuncType{Func: pos, Params: params, Results: results}, scope
@ -1199,7 +1207,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
// method // method
idents = []*ast.Ident{ident} idents = []*ast.Ident{ident}
scope := ast.NewScope(nil) // method scope scope := ast.NewScope(nil) // method scope
_, params := p.parseParameters(scope, false, true) _, params := p.parseParameters(scope, false, true, "method")
results := p.parseResult(scope, true) results := p.parseResult(scope, true)
typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results} typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
} else { } else {
@ -1340,7 +1348,7 @@ func (p *parser) parseConstraint() *ast.Constraint {
// method // method
mname = ident mname = ident
scope := ast.NewScope(nil) // method scope scope := ast.NewScope(nil) // method scope
_, params := p.parseParameters(scope, false, true) _, params := p.parseParameters(scope, false, true, "method")
results := p.parseResult(scope, true) results := p.parseResult(scope, true)
typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results} typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
} }
@ -2886,12 +2894,12 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
var recv *ast.FieldList var recv *ast.FieldList
if p.tok == token.LPAREN { if p.tok == token.LPAREN {
_, recv = p.parseParameters(scope, false, false) _, recv = p.parseParameters(scope, false, false, "receiver")
} }
ident := p.parseIdent() ident := p.parseIdent()
tparams, params := p.parseParameters(scope, recv == nil, true) tparams, params := p.parseParameters(scope, recv == nil, true, "method") // context string only used in methods
results := p.parseResult(scope, true) results := p.parseResult(scope, true)
var body *ast.BlockStmt var body *ast.BlockStmt

View File

@ -635,13 +635,12 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam
} }
// set the type parameter's bound // set the type parameter's bound
if bound != nil { // (do this even if bound == nil to make sure index is correctly increasing)
for _, name := range f.Names { for _, name := range f.Names {
tname := tparams[index] tname := tparams[index]
assert(name.Name == tname.name) assert(name.Name == tname.name) // keep - this assertion caught index errors
tname.typ.(*TypeParam).bound = bound tname.typ.(*TypeParam).bound = bound
index++ index++
}
} }
} }