From 66b509a402b846d4531262d60197403c61396d08 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 15 May 2019 14:29:37 -0700 Subject: [PATCH] go/*: remove ast.TypeParamList in favor of ast.FieldList --- src/go/ast/ast.go | 55 ++++++++++++++++---------------------- src/go/parser/parser.go | 58 ++++++++++++++++++++--------------------- src/go/printer/nodes.go | 10 ++----- src/go/types/decl.go | 2 +- src/go/types/typexpr.go | 20 ++++++++------ 5 files changed, 66 insertions(+), 79 deletions(-) diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go index fb530e41e8..469cb0a01c 100644 --- a/src/go/ast/ast.go +++ b/src/go/ast/ast.go @@ -191,8 +191,8 @@ func isDirective(c string) bool { // type Field struct { Doc *CommentGroup // associated documentation; or nil - Names []*Ident // field/method/parameter names; or nil - Type Expr // field/method/parameter type + Names []*Ident // field/method/(type) parameter names; or nil + Type Expr // field/method/parameter type or contract Tag *BasicLit // field tag; or nil Comment *CommentGroup // line comments; or nil } @@ -242,7 +242,7 @@ func (f *FieldList) End() token.Pos { return token.NoPos } -// NumFields returns the number of parameters or struct fields represented by a FieldList. +// NumFields returns the number of (type) parameters or struct fields represented by a FieldList. func (f *FieldList) NumFields() int { n := 0 if f != nil { @@ -257,17 +257,6 @@ func (f *FieldList) NumFields() int { return n } -// A TypeParamList represents a list of type parameters with contract, enclosed by parentheses. -type TypeParamList struct { - Lparen token.Pos // position of "(" - Names []*Ident // type parameter names; or nil - Contract Expr // contract; or nil - Rparen token.Pos // position of ")" -} - -func (t *TypeParamList) Pos() token.Pos { return t.Lparen } -func (t *TypeParamList) End() token.Pos { return t.Rparen } - // An expression is represented by a tree consisting of one // or more of the following concrete expression nodes. // @@ -465,18 +454,18 @@ type ( // A ContractType node represents a contract. ContractType struct { - Contract token.Pos // position of "contract" pseudo keyword - Params *TypeParamList // list of type parameters; non-nil - Lbrace token.Pos // position of "{" - Constraints []*Constraint // list of constraints - Rbrace token.Pos // position of "}" + Contract token.Pos // position of "contract" pseudo keyword + TParams []*Ident // list of type parameters; or nil + Lbrace token.Pos // position of "{" + Constraints []*Constraint // list of constraints + Rbrace token.Pos // position of "}" } ) type Constraint struct { Param *Ident // constrained type parameter; or nil (for embedded constraints) - MName *Ident // method name, "==" or "!="; or nil - Type Expr // embedded constraint (CallExpr), constraint type, BasicLit (0, 0.0, 0i), method type (*FuncType); or nil + MName *Ident // method name; or nil + Type Expr // embedded constraint (CallExpr), constraint type, method type (*FuncType); or nil } // Pos and End implementations for expression/type nodes. @@ -914,12 +903,12 @@ type ( // A TypeSpec node represents a type declaration (TypeSpec production). TypeSpec struct { - Doc *CommentGroup // associated documentation; or nil - Name *Ident // type name - TPar *TypeParamList // type parameters; or nil - Assign token.Pos // position of '=', if any - Type Expr // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes - Comment *CommentGroup // line comments; or nil + Doc *CommentGroup // associated documentation; or nil + Name *Ident // type name + TParams *FieldList // type parameters; or nil + Assign token.Pos // position of '=', if any + Type Expr // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes + Comment *CommentGroup // line comments; or nil } ) @@ -992,12 +981,12 @@ type ( // A FuncDecl node represents a function declaration. FuncDecl struct { - Doc *CommentGroup // associated documentation; or nil - Recv *FieldList // receiver (methods); or nil (functions) - Name *Ident // function/method name - TPar *TypeParamList // type parameters; or nil - Type *FuncType // function signature: parameters, results, and position of "func" keyword - Body *BlockStmt // function body; or nil for external (non-Go) function + Doc *CommentGroup // associated documentation; or nil + Recv *FieldList // receiver (methods); or nil (functions) + Name *Ident // function/method name + TParams *FieldList // type parameters; or nil + Type *FuncType // function signature: parameters, results, and position of "func" keyword + Body *BlockStmt // function body; or nil for external (non-Go) function } ) diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 45d5b8851c..b51c008a12 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -26,6 +26,9 @@ import ( "unicode" ) +// Enable parsing of type parameters in [] rather than () parentheses. +// This code was an experiment which we eventually decided against due +// to various unpleasant ambiguities. Leave around for now, just in case. const useBrackets = false // The parser structure holds the parser's internal state. @@ -1081,7 +1084,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [ return } -func (p *parser) parseTypeParams(scope *ast.Scope) *ast.TypeParamList { +func (p *parser) parseTypeParams(scope *ast.Scope) *ast.FieldList { if p.trace { defer un(trace(p, "TypeParams")) } @@ -1095,26 +1098,24 @@ func (p *parser) parseTypeParams(scope *ast.Scope) *ast.TypeParamList { p.expect(token.TYPE) } - var names []*ast.Ident - var contract ast.Expr + f := new(ast.Field) if p.tok != token.RBRACK && p.tok != token.RPAREN { - names = p.parseIdentList() + f.Names = p.parseIdentList() } if p.tok == token.IDENT { // contract - contract = p.parseTypeName(nil) + f.Type = p.parseTypeName(nil) } + p.declare(f, nil, scope, ast.Typ, f.Names...) if lbrack.IsValid() { rbrack = p.expect(token.RBRACK) } - tparams := &ast.TypeParamList{Lparen: lbrack, Names: names, Contract: contract, Rparen: rbrack} - p.declare(tparams, nil, scope, ast.Typ, names...) - return tparams + return &ast.FieldList{Opening: lbrack, List: []*ast.Field{f}, Closing: rbrack} } -func (p *parser) parseParameters(scope *ast.Scope, typeParamsOk, ellipsisOk bool) (tparams *ast.TypeParamList, params *ast.FieldList) { +func (p *parser) parseParameters(scope *ast.Scope, typeParamsOk, ellipsisOk bool) (tparams, params *ast.FieldList) { if p.trace { defer un(trace(p, "Parameters")) } @@ -1132,9 +1133,9 @@ func (p *parser) parseParameters(scope *ast.Scope, typeParamsOk, ellipsisOk bool tparams = p.parseTypeParams(scope) rparen := p.expect(token.RPAREN) - // fix tparams - tparams.Lparen = lparen - tparams.Rparen = rparen + // fix parentheses positions + tparams.Opening = lparen + tparams.Closing = rparen lparen = p.expect(token.LPAREN) } @@ -1283,19 +1284,18 @@ func (p *parser) parseContractType() *ast.ContractType { defer un(trace(p, "ContractType")) } - var names []*ast.Ident - lparen := p.expect(token.LPAREN) + var params []*ast.Ident + p.expect(token.LPAREN) scope := ast.NewScope(nil) // contract scope for p.tok != token.RPAREN && p.tok != token.EOF { - names = append(names, p.parseIdent()) + params = append(params, p.parseIdent()) if !p.atComma("contract parameter list", token.RPAREN) { break } p.next() } - p.declare(nil, nil, scope, ast.Typ, names...) - rparen := p.expect(token.RPAREN) - params := &ast.TypeParamList{Lparen: lparen, Names: names, Rparen: rparen} + p.declare(nil, nil, scope, ast.Typ, params...) + p.expect(token.RPAREN) var constraints []*ast.Constraint lbrace := p.expect(token.LBRACE) @@ -1305,7 +1305,7 @@ func (p *parser) parseContractType() *ast.ContractType { } rbrace := p.expect(token.RBRACE) - return &ast.ContractType{Params: params, Lbrace: lbrace, Constraints: constraints, Rbrace: rbrace} + return &ast.ContractType{TParams: params, Lbrace: lbrace, Constraints: constraints, Rbrace: rbrace} } // Constraint = TypeParam Type | TypeParam MethodName Signature | ContractTypeName "(" [ TypeList [ "," ] ] ")" . @@ -2755,9 +2755,9 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast. p.next() p.openScope() tparams := p.parseTypeParams(p.topScope) - tparams.Lparen = lbrack - tparams.Rparen = p.expect(token.RBRACK) - spec.TPar = tparams + tparams.Opening = lbrack + tparams.Closing = p.expect(token.RBRACK) + spec.TParams = tparams if p.tok == token.ASSIGN { // type alias spec.Assign = p.pos @@ -2781,9 +2781,9 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast. p.next() p.openScope() tparams := p.parseTypeParams(p.topScope) - tparams.Lparen = lparen - tparams.Rparen = p.expect(token.RPAREN) - spec.TPar = tparams + tparams.Opening = lparen + tparams.Closing = p.expect(token.RPAREN) + spec.TParams = tparams if p.tok == token.ASSIGN { // type alias spec.Assign = p.pos @@ -2898,10 +2898,10 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl { } decl := &ast.FuncDecl{ - Doc: doc, - Recv: recv, - Name: ident, - TPar: tparams, + Doc: doc, + Recv: recv, + Name: ident, + TParams: tparams, Type: &ast.FuncType{ Func: pos, Params: params, diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go index 21e2533f48..cac9c09701 100644 --- a/src/go/printer/nodes.go +++ b/src/go/printer/nodes.go @@ -1773,14 +1773,8 @@ func (p *printer) funcDecl(d *ast.FuncDecl) { p.print(blank) } p.expr(d.Name) - // TODO(gri) decide if we should print empty type parameter lists "(type)" at all - if tparams := d.TPar; tparams != nil { - p.print(tparams.Lparen, token.LPAREN, token.TYPE) - if len(tparams.Names) > 0 { - p.print(blank) - p.identList(tparams.Names, true) - } - p.print(tparams.Rparen, token.RPAREN) + if d.TParams.NumFields() != 0 { + p.parameters(d.TParams) } p.signature(d.Type.Params, d.Type.Results) p.funcBody(p.distanceFrom(d.Pos(), startCol), vtab, d.Body) diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 7bbda9c55d..a4d0531b22 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -649,7 +649,7 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) { sig := new(Signature) obj.typ = sig // guard against cycles fdecl := decl.fdecl - check.funcType(sig, fdecl.Recv, fdecl.TPar, fdecl.Type) + check.funcType(sig, fdecl.Recv, fdecl.TParams, fdecl.Type) if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) { check.errorf(fdecl.Pos(), "func init must have no arguments and no return values") // ok to continue diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 0fcd6da862..449df36385 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -143,10 +143,10 @@ func (check *Checker) definedType(e ast.Expr, def *Named) (T Type) { } // funcType type-checks a function or method type. -func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, tpar *ast.TypeParamList, ftyp *ast.FuncType) { +func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, tpar *ast.FieldList, ftyp *ast.FuncType) { // type parameters are in a scope enclosing the function scope // TODO(gri) should we always have this extra scope? - if tpar != nil && len(tpar.Names) > 0 { + if tpar.NumFields() != 0 { check.scope = NewScope(check.scope, token.NoPos, token.NoPos, "function type parameters") // TODO(gri) replace with check.openScope call defer check.closeScope() } @@ -406,16 +406,20 @@ func (check *Checker) arrayLength(e ast.Expr) int64 { return -1 } -func (check *Checker) collectTypeParams(scope *Scope, list *ast.TypeParamList) (tparams []*TypeName) { +func (check *Checker) collectTypeParams(scope *Scope, list *ast.FieldList) (tparams []*TypeName) { if list == nil { return } - for i, name := range list.Names { - tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil) - NewTypeParam(tpar, i) // assigns type to tpar as a side-effect - check.declare(scope, name, tpar, scope.pos) - tparams = append(tparams, tpar) + index := 0 + for _, f := range list.List { + for _, name := range f.Names { + tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil) + NewTypeParam(tpar, index) // assigns type to tpar as a side-effect + check.declare(scope, name, tpar, scope.pos) + tparams = append(tparams, tpar) + index++ + } } return