]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] go/printer: adapt changes from dev.go2go
authorRob Findley <rfindley@google.com>
Wed, 25 Nov 2020 16:17:38 +0000 (11:17 -0500)
committerRobert Findley <rfindley@google.com>
Wed, 2 Dec 2020 20:46:14 +0000 (20:46 +0000)
Import go/printer changes from the dev.go2go branch, with the following
modifications:
 - update tests to only use bracketed notation for type parameters
 - remove the UseBrackets mode, since it is now implied
 - remove guards on ast.Field.Type != nil

Patchset #1 contains the dev.go2go source, unmodified except to resolve
merge conflicts.

Change-Id: I3ddecfd3bee0fc32425a30fe6bd93b24fd3187e9
Reviewed-on: https://go-review.googlesource.com/c/go/+/273226
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Trust: Robert Griesemer <gri@golang.org>
Trust: Robert Findley <rfindley@google.com>

src/go/printer/nodes.go
src/go/printer/printer_test.go
src/go/printer/testdata/declarations.golden
src/go/printer/testdata/declarations.input
src/go/printer/testdata/generics.golden [new file with mode: 0644]
src/go/printer/testdata/generics.input [new file with mode: 0644]

index 95b9e918917cd50685cb27e3ac03dc9ca89e4877..cc795532b0c5bdea1fc42f17f4aadf48ec169dca 100644 (file)
@@ -319,8 +319,12 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
        }
 }
 
-func (p *printer) parameters(fields *ast.FieldList) {
-       p.print(fields.Opening, token.LPAREN)
+func (p *printer) parameters(fields *ast.FieldList, isTypeParam bool) {
+       openTok, closeTok := token.LPAREN, token.RPAREN
+       if isTypeParam {
+               openTok, closeTok = token.LBRACK, token.RBRACK
+       }
+       p.print(fields.Opening, openTok)
        if len(fields.List) > 0 {
                prevLine := p.lineFor(fields.Opening)
                ws := indent
@@ -328,13 +332,8 @@ func (p *printer) parameters(fields *ast.FieldList) {
                        // determine par begin and end line (may be different
                        // if there are multiple parameter names for this par
                        // or the type is on a separate line)
-                       var parLineBeg int
-                       if len(par.Names) > 0 {
-                               parLineBeg = p.lineFor(par.Names[0].Pos())
-                       } else {
-                               parLineBeg = p.lineFor(par.Type.Pos())
-                       }
-                       var parLineEnd = p.lineFor(par.Type.End())
+                       parLineBeg := p.lineFor(par.Pos())
+                       parLineEnd := p.lineFor(par.End())
                        // separating "," if needed
                        needsLinebreak := 0 < prevLine && prevLine < parLineBeg
                        if i > 0 {
@@ -379,25 +378,29 @@ func (p *printer) parameters(fields *ast.FieldList) {
                        p.print(unindent)
                }
        }
-       p.print(fields.Closing, token.RPAREN)
+       p.print(fields.Closing, closeTok)
 }
 
-func (p *printer) signature(params, result *ast.FieldList) {
-       if params != nil {
-               p.parameters(params)
+func (p *printer) signature(sig *ast.FuncType) {
+       if sig.TParams != nil {
+               p.parameters(sig.TParams, true)
+       }
+       if sig.Params != nil {
+               p.parameters(sig.Params, false)
        } else {
                p.print(token.LPAREN, token.RPAREN)
        }
-       n := result.NumFields()
+       res := sig.Results
+       n := res.NumFields()
        if n > 0 {
-               // result != nil
+               // res != nil
                p.print(blank)
-               if n == 1 && result.List[0].Names == nil {
-                       // single anonymous result; no ()'s
-                       p.expr(stripParensAlways(result.List[0].Type))
+               if n == 1 && res.List[0].Names == nil {
+                       // single anonymous res; no ()'s
+                       p.expr(stripParensAlways(res.List[0].Type))
                        return
                }
-               p.parameters(result)
+               p.parameters(res, false)
        }
 }
 
@@ -467,10 +470,18 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
                                }
                                p.expr(f.Type)
                        } else { // interface
-                               if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
-                                       // method
-                                       p.expr(f.Names[0])
-                                       p.signature(ftyp.Params, ftyp.Results)
+                               if len(f.Names) > 0 {
+                                       // type list type or method
+                                       name := f.Names[0] // "type" or method name
+                                       p.expr(name)
+                                       if name.Name == "type" {
+                                               // type list type
+                                               p.print(blank)
+                                               p.expr(f.Type)
+                                       } else {
+                                               // method
+                                               p.signature(f.Type.(*ast.FuncType)) // don't print "func"
+                                       }
                                } else {
                                        // embedded interface
                                        p.expr(f.Type)
@@ -538,19 +549,47 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
        } else { // interface
 
                var line int
+               var prev *ast.Ident // previous "type" identifier
                for i, f := range list {
+                       var name *ast.Ident // first name, or nil
+                       if len(f.Names) > 0 {
+                               name = f.Names[0]
+                       }
                        if i > 0 {
-                               p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
+                               // don't do a line break (min == 0) if we are printing a list of types
+                               // TODO(gri) this doesn't work quite right if the list of types is
+                               //           spread across multiple lines
+                               min := 1
+                               if prev != nil && name == prev {
+                                       min = 0
+                               }
+                               p.linebreak(p.lineFor(f.Pos()), min, ignore, p.linesFrom(line) > 0)
                        }
                        p.setComment(f.Doc)
                        p.recordLine(&line)
-                       if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
-                               // method
-                               p.expr(f.Names[0])
-                               p.signature(ftyp.Params, ftyp.Results)
+                       if name != nil {
+                               // type list type or method
+                               if name.Name == "type" {
+                                       // type list type
+                                       if name == prev {
+                                               // type is part of a list of types
+                                               p.print(token.COMMA, blank)
+                                       } else {
+                                               // type starts a new list of types
+                                               p.print(name, blank)
+                                       }
+                                       p.expr(f.Type)
+                                       prev = name
+                               } else {
+                                       // method
+                                       p.expr(name)
+                                       p.signature(f.Type.(*ast.FuncType)) // don't print "func"
+                                       prev = nil
+                               }
                        } else {
                                // embedded interface
                                p.expr(f.Type)
+                               prev = nil
                        }
                        p.setComment(f.Comment)
                }
@@ -800,7 +839,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                p.print(x.Type.Pos(), token.FUNC)
                // See the comment in funcDecl about how the header size is computed.
                startCol := p.out.Column - len("func")
-               p.signature(x.Type.Params, x.Type.Results)
+               p.signature(x.Type)
                p.funcBody(p.distanceFrom(x.Type.Pos(), startCol), blank, x.Body)
 
        case *ast.ParenExpr:
@@ -880,25 +919,32 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                        depth++
                }
                var wasIndented bool
-               if _, ok := x.Fun.(*ast.FuncType); ok {
-                       // conversions to literal function types require parentheses around the type
-                       p.print(token.LPAREN)
+               if x.Brackets {
                        wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
-                       p.print(token.RPAREN)
+                       p.print(x.Lparen, token.LBRACK)
+                       p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
+                       p.print(x.Rparen, token.RBRACK)
                } else {
-                       wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
-               }
-               p.print(x.Lparen, token.LPAREN)
-               if x.Ellipsis.IsValid() {
-                       p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis, false)
-                       p.print(x.Ellipsis, token.ELLIPSIS)
-                       if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
-                               p.print(token.COMMA, formfeed)
+                       if _, ok := x.Fun.(*ast.FuncType); ok {
+                               // conversions to literal function types require parentheses around the type
+                               p.print(token.LPAREN)
+                               wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
+                               p.print(token.RPAREN)
+                       } else {
+                               wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
                        }
-               } else {
-                       p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
+                       p.print(x.Lparen, token.LPAREN)
+                       if x.Ellipsis.IsValid() {
+                               p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis, false)
+                               p.print(x.Ellipsis, token.ELLIPSIS)
+                               if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
+                                       p.print(token.COMMA, formfeed)
+                               }
+                       } else {
+                               p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
+                       }
+                       p.print(x.Rparen, token.RPAREN)
                }
-               p.print(x.Rparen, token.RPAREN)
                if wasIndented {
                        p.print(unindent)
                }
@@ -945,7 +991,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
 
        case *ast.FuncType:
                p.print(token.FUNC)
-               p.signature(x.Params, x.Results)
+               p.signature(x)
 
        case *ast.InterfaceType:
                p.print(token.INTERFACE)
@@ -1585,6 +1631,9 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
        case *ast.TypeSpec:
                p.setComment(s.Doc)
                p.expr(s.Name)
+               if s.TParams != nil {
+                       p.parameters(s.TParams, true)
+               }
                if n == 1 {
                        p.print(blank)
                } else {
@@ -1773,11 +1822,11 @@ func (p *printer) funcDecl(d *ast.FuncDecl) {
        // FUNC is emitted).
        startCol := p.out.Column - len("func ")
        if d.Recv != nil {
-               p.parameters(d.Recv) // method: print receiver
+               p.parameters(d.Recv, false) // method: print receiver
                p.print(blank)
        }
        p.expr(d.Name)
-       p.signature(d.Type.Params, d.Type.Results)
+       p.signature(d.Type)
        p.funcBody(p.distanceFrom(d.Pos(), startCol), vtab, d.Body)
 }
 
index b64bc6bfb7d9ae4112317d3aa45f67ec70a0e641..3efa468d8279a9caf5209aa02929d560a81a416b 100644 (file)
@@ -42,7 +42,7 @@ const (
 // if any.
 func format(src []byte, mode checkMode) ([]byte, error) {
        // parse src
-       f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
+       f, err := parser.ParseFile(fset, "", src, parser.ParseComments|parser.ParseTypeParams)
        if err != nil {
                return nil, fmt.Errorf("parse: %s\n%s", err, src)
        }
@@ -70,7 +70,7 @@ func format(src []byte, mode checkMode) ([]byte, error) {
 
        // make sure formatted output is syntactically correct
        res := buf.Bytes()
-       if _, err := parser.ParseFile(fset, "", res, 0); err != nil {
+       if _, err := parser.ParseFile(fset, "", res, parser.ParseTypeParams); err != nil {
                return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes())
        }
 
@@ -206,6 +206,7 @@ var data = []entry{
        {"complit.input", "complit.x", export},
        {"go2numbers.input", "go2numbers.golden", idempotent},
        {"go2numbers.input", "go2numbers.norm", normNumber | idempotent},
+       {"generics.input", "generics.golden", idempotent},
 }
 
 func TestFiles(t *testing.T) {
index fe0f7838de50617b2ead0e15a3d65d53c736454f..74ffce7d73f867aa3392c47e7a28b1f552d32de7 100644 (file)
@@ -942,6 +942,13 @@ type _ interface {
                x ...int)
 }
 
+// properly format one-line type lists
+type _ interface{ type a }
+
+type _ interface {
+       type a, b, c
+}
+
 // omit superfluous parentheses in parameter lists
 func _(int)
 func _(int)
@@ -992,6 +999,10 @@ func _(struct {
        y       int
 })     // no extra comma between } and )
 
+// type parameters
+func _[A, B any](a A, b B) int {}
+func _[T any](x, y T) T
+
 // alias declarations
 
 type c0 struct{}
index a858051ef01a650d69a9d4a4039d53e601513cac..ab2022142a6d48bbeb50d6aa9af5bcb0dbe446fd 100644 (file)
@@ -955,6 +955,11 @@ r string,
                x ...int)
 }
 
+// properly format one-line type lists
+type _ interface { type a }
+
+type _ interface { type a,b,c }
+
 // omit superfluous parentheses in parameter lists
 func _((int))
 func _((((((int))))))
@@ -1005,6 +1010,10 @@ func _(struct {
        y int
 }) // no extra comma between } and )
 
+// type parameters
+func _[A, B any](a A, b B) int {}
+func _[T any](x, y T) T
+
 // alias declarations
 
 type c0 struct{}
@@ -1018,4 +1027,4 @@ type (
        c = foo
        d = interface{}
        ddd = p.Foo
-)
\ No newline at end of file
+)
diff --git a/src/go/printer/testdata/generics.golden b/src/go/printer/testdata/generics.golden
new file mode 100644 (file)
index 0000000..88c4616
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package generics
+
+type T[P any] struct{}
+type T[P1, P2, P3 any] struct{}
+
+type T[P C] struct{}
+type T[P1, P2, P3 C] struct{}
+
+type T[P C[P]] struct{}
+type T[P1, P2, P3 C[P1, P2, P3]] struct{}
+
+func f[P any](x P)
+func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
+
+func f[P interface{}](x P)
+func f[P1, P2, P3 interface {
+       m1(P1)
+       type P2, P3
+}](x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](T1[P], T2[P]) T3[P]
+
+func (x T[P]) m()
+func (T[P]) m(x T[P]) P
+
+func _() {
+       type _ []T[P]
+       var _ []T[P]
+       _ = []T[P]{}
+}
diff --git a/src/go/printer/testdata/generics.input b/src/go/printer/testdata/generics.input
new file mode 100644 (file)
index 0000000..5fdf8cd
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package generics
+
+type T[P any] struct{}
+type T[P1, P2, P3 any] struct{}
+
+type T[P C] struct{}
+type T[P1, P2, P3 C] struct{}
+
+type T[P C[P]] struct{}
+type T[P1, P2, P3 C[P1, P2, P3]] struct{}
+
+func f[P any](x P)
+func f[P1, P2, P3 any](x1 P1, x2 P2, x3 P3) struct{}
+
+func f[P interface{}](x P)
+func f[P1, P2, P3 interface{ m1(P1); type P2, P3 }](x1 P1, x2 P2, x3 P3) struct{}
+func f[P any](T1[P], T2[P]) T3[P]
+
+func (x T[P]) m()
+func ((T[P])) m(x T[P]) P
+
+func _() {
+       type _ []T[P]
+       var _ []T[P]
+       _ = []T[P]{}
+}