From a10fe9f6e750454c9f4fcae7f86bab0c9cca43c7 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 21 Oct 2020 14:36:21 -0400 Subject: [PATCH] go/ast: import AST changes supporting typeparams from dev.go2go Minimal changes are made to existing types in go/ast to support type parameters. Namely: + FieldList is overloaded to hold type parameter lists. In this case, the field name becomes the type identifier, and the field type becomes the constraint. + FuncType and TypeSpec gain a TParams FieldList. + CallExpr gains a 'Brackets' flag, signaling that it uses '[]' rather than '()', representing a generic type expression with type parameters. Modifications from dev.go2go: the 'UseBrackets' field was removed from ast.File, as this support is no longer necessary. Change-Id: I21fd7390f1800dece3c14e6ec015fb2419e9fc52 Reviewed-on: https://go-review.googlesource.com/c/go/+/264181 Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Trust: Robert Griesemer Trust: Robert Findley --- src/go/ast/ast.go | 43 +++++++++++++++++++++++++------------- src/go/ast/example_test.go | 33 +++++++++++++++-------------- src/go/ast/walk.go | 10 ++++++++- 3 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go index 1061f1d3ce..df5498159a 100644 --- a/src/go/ast/ast.go +++ b/src/go/ast/ast.go @@ -188,11 +188,14 @@ func isDirective(c string) bool { // in a signature. // Field.Names is nil for unnamed parameters (parameter lists which only contain types) // and embedded struct fields. In the latter case, the field name is the type name. +// Field.Names contains a single name "type" for elements of interface type lists. +// Types belonging to the same type list share the same "type" identifier which also +// records the position of that keyword. // 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 type "type"; or nil + Type Expr // field/method/parameter type, type list type; or nil Tag *BasicLit // field tag; or nil Comment *CommentGroup // line comments; or nil } @@ -201,14 +204,23 @@ func (f *Field) Pos() token.Pos { if len(f.Names) > 0 { return f.Names[0].Pos() } - return f.Type.Pos() + if f.Type != nil { + return f.Type.Pos() + } + return token.NoPos } func (f *Field) End() token.Pos { if f.Tag != nil { return f.Tag.End() } - return f.Type.End() + if f.Type != nil { + return f.Type.End() + } + if len(f.Names) > 0 { + return f.Names[len(f.Names)-1].End() + } + return token.NoPos } // A FieldList represents a list of Fields, enclosed by parentheses or braces. @@ -242,7 +254,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 { @@ -285,12 +297,6 @@ type ( } // A BasicLit node represents a literal of basic type. - // - // Note that for the CHAR and STRING kinds, the literal is stored - // with its quotes. For example, for a double-quoted STRING, the - // first and the last rune in the Value field will be ". The - // Unquote and UnquoteChar functions in the strconv package can be - // used to unquote STRING and CHAR values, respectively. BasicLit struct { ValuePos token.Pos // literal position Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING @@ -361,6 +367,7 @@ type ( Args []Expr // function arguments; or nil Ellipsis token.Pos // position of "..." (token.NoPos if there is no "...") Rparen token.Pos // position of ")" + Brackets bool // if set, "[" and "]" are used instead of "(" and ")" } // A StarExpr node represents an expression of the form "*" Expression. @@ -432,6 +439,7 @@ type ( // A FuncType node represents a function type. FuncType struct { Func token.Pos // position of "func" keyword (token.NoPos if there is no "func") + TParams *FieldList // type parameters; or nil Params *FieldList // (incoming) parameters; non-nil Results *FieldList // (outgoing) results; or nil } @@ -439,8 +447,8 @@ type ( // An InterfaceType node represents an interface type. InterfaceType struct { Interface token.Pos // position of "interface" keyword - Methods *FieldList // list of methods - Incomplete bool // true if (source) methods are missing in the Methods list + Methods *FieldList // list of embedded interfaces, methods, or types + Incomplete bool // true if (source) methods or types are missing in the Methods list } // A MapType node represents a map type. @@ -893,6 +901,7 @@ type ( TypeSpec struct { 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 @@ -960,7 +969,7 @@ type ( GenDecl struct { Doc *CommentGroup // associated documentation; or nil TokPos token.Pos // position of Tok - Tok token.Token // IMPORT, CONST, TYPE, VAR + Tok token.Token // IMPORT, CONST, TYPE, or VAR Lparen token.Pos // position of '(', if any Specs []Spec Rparen token.Pos // position of ')', if any @@ -971,11 +980,15 @@ type ( Doc *CommentGroup // associated documentation; or nil Recv *FieldList // receiver (methods); or nil (functions) Name *Ident // function/method name - Type *FuncType // function signature: parameters, results, and position of "func" keyword + Type *FuncType // function signature: type and value parameters, results, and position of "func" keyword Body *BlockStmt // function body; or nil for external (non-Go) function } ) +func (f *FuncDecl) IsMethod() bool { + return f.Recv.NumFields() != 0 +} + // Pos and End implementations for declaration nodes. func (d *BadDecl) Pos() token.Pos { return d.From } diff --git a/src/go/ast/example_test.go b/src/go/ast/example_test.go index e3013f64be..c2b35205bb 100644 --- a/src/go/ast/example_test.go +++ b/src/go/ast/example_test.go @@ -119,22 +119,23 @@ func main() { // 40 . . . . . . . } // 41 . . . . . . . Ellipsis: - // 42 . . . . . . . Rparen: 4:25 - // 43 . . . . . . } - // 44 . . . . . } - // 45 . . . . } - // 46 . . . . Rbrace: 5:1 - // 47 . . . } - // 48 . . } - // 49 . } - // 50 . Scope: *ast.Scope { - // 51 . . Objects: map[string]*ast.Object (len = 1) { - // 52 . . . "main": *(obj @ 11) - // 53 . . } - // 54 . } - // 55 . Unresolved: []*ast.Ident (len = 1) { - // 56 . . 0: *(obj @ 29) - // 57 . } - // 58 } + // 43 . . . . . . . Brackets: false + // 44 . . . . . . } + // 45 . . . . . } + // 46 . . . . } + // 47 . . . . Rbrace: 5:1 + // 48 . . . } + // 49 . . } + // 50 . } + // 51 . Scope: *ast.Scope { + // 52 . . Objects: map[string]*ast.Object (len = 1) { + // 53 . . . "main": *(obj @ 11) + // 54 . . } + // 55 . } + // 56 . Unresolved: []*ast.Ident (len = 1) { + // 57 . . 0: *(obj @ 29) + // 58 . } + // 59 } } // This example illustrates how to remove a variable declaration diff --git a/src/go/ast/walk.go b/src/go/ast/walk.go index 8ca21959b1..f909c00b4b 100644 --- a/src/go/ast/walk.go +++ b/src/go/ast/walk.go @@ -71,7 +71,9 @@ func Walk(v Visitor, node Node) { Walk(v, n.Doc) } walkIdentList(v, n.Names) - Walk(v, n.Type) + if n.Type != nil { + Walk(v, n.Type) + } if n.Tag != nil { Walk(v, n.Tag) } @@ -161,6 +163,9 @@ func Walk(v Visitor, node Node) { Walk(v, n.Fields) case *FuncType: + if n.TParams != nil { + Walk(v, n.TParams) + } if n.Params != nil { Walk(v, n.Params) } @@ -315,6 +320,9 @@ func Walk(v Visitor, node Node) { Walk(v, n.Doc) } Walk(v, n.Name) + if n.TParams != nil { + Walk(v, n.TParams) + } Walk(v, n.Type) if n.Comment != nil { Walk(v, n.Comment) -- 2.50.0