From: Rob Findley Date: Wed, 25 Nov 2020 16:17:38 +0000 (-0500) Subject: [dev.typeparams] go/printer: adapt changes from dev.go2go X-Git-Tag: go1.17beta1~1473^2~179 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=72cc2353f0522ec7e2ccfc8d4320e3ca932041cf;p=gostls13.git [dev.typeparams] go/printer: adapt changes from dev.go2go 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 TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Trust: Robert Griesemer Trust: Robert Findley --- diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go index 95b9e91891..cc795532b0 100644 --- a/src/go/printer/nodes.go +++ b/src/go/printer/nodes.go @@ -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) } diff --git a/src/go/printer/printer_test.go b/src/go/printer/printer_test.go index b64bc6bfb7..3efa468d82 100644 --- a/src/go/printer/printer_test.go +++ b/src/go/printer/printer_test.go @@ -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) { diff --git a/src/go/printer/testdata/declarations.golden b/src/go/printer/testdata/declarations.golden index fe0f7838de..74ffce7d73 100644 --- a/src/go/printer/testdata/declarations.golden +++ b/src/go/printer/testdata/declarations.golden @@ -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{} diff --git a/src/go/printer/testdata/declarations.input b/src/go/printer/testdata/declarations.input index a858051ef0..ab2022142a 100644 --- a/src/go/printer/testdata/declarations.input +++ b/src/go/printer/testdata/declarations.input @@ -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 index 0000000000..88c461622e --- /dev/null +++ b/src/go/printer/testdata/generics.golden @@ -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 index 0000000000..5fdf8cdb87 --- /dev/null +++ b/src/go/printer/testdata/generics.input @@ -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]{} +}