[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 <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>
This commit is contained in:
Rob Findley 2020-11-25 11:17:38 -05:00 committed by Robert Findley
parent ab18125567
commit 72cc2353f0
6 changed files with 184 additions and 51 deletions

View 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) { func (p *printer) parameters(fields *ast.FieldList, isTypeParam bool) {
p.print(fields.Opening, token.LPAREN) openTok, closeTok := token.LPAREN, token.RPAREN
if isTypeParam {
openTok, closeTok = token.LBRACK, token.RBRACK
}
p.print(fields.Opening, openTok)
if len(fields.List) > 0 { if len(fields.List) > 0 {
prevLine := p.lineFor(fields.Opening) prevLine := p.lineFor(fields.Opening)
ws := indent ws := indent
@ -328,13 +332,8 @@ func (p *printer) parameters(fields *ast.FieldList) {
// determine par begin and end line (may be different // determine par begin and end line (may be different
// if there are multiple parameter names for this par // if there are multiple parameter names for this par
// or the type is on a separate line) // or the type is on a separate line)
var parLineBeg int parLineBeg := p.lineFor(par.Pos())
if len(par.Names) > 0 { parLineEnd := p.lineFor(par.End())
parLineBeg = p.lineFor(par.Names[0].Pos())
} else {
parLineBeg = p.lineFor(par.Type.Pos())
}
var parLineEnd = p.lineFor(par.Type.End())
// separating "," if needed // separating "," if needed
needsLinebreak := 0 < prevLine && prevLine < parLineBeg needsLinebreak := 0 < prevLine && prevLine < parLineBeg
if i > 0 { if i > 0 {
@ -379,25 +378,29 @@ func (p *printer) parameters(fields *ast.FieldList) {
p.print(unindent) p.print(unindent)
} }
} }
p.print(fields.Closing, token.RPAREN) p.print(fields.Closing, closeTok)
} }
func (p *printer) signature(params, result *ast.FieldList) { func (p *printer) signature(sig *ast.FuncType) {
if params != nil { if sig.TParams != nil {
p.parameters(params) p.parameters(sig.TParams, true)
}
if sig.Params != nil {
p.parameters(sig.Params, false)
} else { } else {
p.print(token.LPAREN, token.RPAREN) p.print(token.LPAREN, token.RPAREN)
} }
n := result.NumFields() res := sig.Results
n := res.NumFields()
if n > 0 { if n > 0 {
// result != nil // res != nil
p.print(blank) p.print(blank)
if n == 1 && result.List[0].Names == nil { if n == 1 && res.List[0].Names == nil {
// single anonymous result; no ()'s // single anonymous res; no ()'s
p.expr(stripParensAlways(result.List[0].Type)) p.expr(stripParensAlways(res.List[0].Type))
return 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) p.expr(f.Type)
} else { // interface } else { // interface
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp { 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 // method
p.expr(f.Names[0]) p.signature(f.Type.(*ast.FuncType)) // don't print "func"
p.signature(ftyp.Params, ftyp.Results) }
} else { } else {
// embedded interface // embedded interface
p.expr(f.Type) p.expr(f.Type)
@ -538,19 +549,47 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
} else { // interface } else { // interface
var line int var line int
var prev *ast.Ident // previous "type" identifier
for i, f := range list { 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 { 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.setComment(f.Doc)
p.recordLine(&line) p.recordLine(&line)
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp { 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 // method
p.expr(f.Names[0]) p.expr(name)
p.signature(ftyp.Params, ftyp.Results) p.signature(f.Type.(*ast.FuncType)) // don't print "func"
prev = nil
}
} else { } else {
// embedded interface // embedded interface
p.expr(f.Type) p.expr(f.Type)
prev = nil
} }
p.setComment(f.Comment) 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) p.print(x.Type.Pos(), token.FUNC)
// See the comment in funcDecl about how the header size is computed. // See the comment in funcDecl about how the header size is computed.
startCol := p.out.Column - len("func") 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) p.funcBody(p.distanceFrom(x.Type.Pos(), startCol), blank, x.Body)
case *ast.ParenExpr: case *ast.ParenExpr:
@ -880,6 +919,12 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
depth++ depth++
} }
var wasIndented bool var wasIndented bool
if x.Brackets {
wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
p.print(x.Lparen, token.LBRACK)
p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
p.print(x.Rparen, token.RBRACK)
} else {
if _, ok := x.Fun.(*ast.FuncType); ok { if _, ok := x.Fun.(*ast.FuncType); ok {
// conversions to literal function types require parentheses around the type // conversions to literal function types require parentheses around the type
p.print(token.LPAREN) p.print(token.LPAREN)
@ -899,6 +944,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false) 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 { if wasIndented {
p.print(unindent) p.print(unindent)
} }
@ -945,7 +991,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
case *ast.FuncType: case *ast.FuncType:
p.print(token.FUNC) p.print(token.FUNC)
p.signature(x.Params, x.Results) p.signature(x)
case *ast.InterfaceType: case *ast.InterfaceType:
p.print(token.INTERFACE) p.print(token.INTERFACE)
@ -1585,6 +1631,9 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
case *ast.TypeSpec: case *ast.TypeSpec:
p.setComment(s.Doc) p.setComment(s.Doc)
p.expr(s.Name) p.expr(s.Name)
if s.TParams != nil {
p.parameters(s.TParams, true)
}
if n == 1 { if n == 1 {
p.print(blank) p.print(blank)
} else { } else {
@ -1773,11 +1822,11 @@ func (p *printer) funcDecl(d *ast.FuncDecl) {
// FUNC is emitted). // FUNC is emitted).
startCol := p.out.Column - len("func ") startCol := p.out.Column - len("func ")
if d.Recv != nil { if d.Recv != nil {
p.parameters(d.Recv) // method: print receiver p.parameters(d.Recv, false) // method: print receiver
p.print(blank) p.print(blank)
} }
p.expr(d.Name) 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) p.funcBody(p.distanceFrom(d.Pos(), startCol), vtab, d.Body)
} }

View File

@ -42,7 +42,7 @@ const (
// if any. // if any.
func format(src []byte, mode checkMode) ([]byte, error) { func format(src []byte, mode checkMode) ([]byte, error) {
// parse src // parse src
f, err := parser.ParseFile(fset, "", src, parser.ParseComments) f, err := parser.ParseFile(fset, "", src, parser.ParseComments|parser.ParseTypeParams)
if err != nil { if err != nil {
return nil, fmt.Errorf("parse: %s\n%s", err, src) 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 // make sure formatted output is syntactically correct
res := buf.Bytes() 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()) return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes())
} }
@ -206,6 +206,7 @@ var data = []entry{
{"complit.input", "complit.x", export}, {"complit.input", "complit.x", export},
{"go2numbers.input", "go2numbers.golden", idempotent}, {"go2numbers.input", "go2numbers.golden", idempotent},
{"go2numbers.input", "go2numbers.norm", normNumber | idempotent}, {"go2numbers.input", "go2numbers.norm", normNumber | idempotent},
{"generics.input", "generics.golden", idempotent},
} }
func TestFiles(t *testing.T) { func TestFiles(t *testing.T) {

View File

@ -942,6 +942,13 @@ type _ interface {
x ...int) x ...int)
} }
// properly format one-line type lists
type _ interface{ type a }
type _ interface {
type a, b, c
}
// omit superfluous parentheses in parameter lists // omit superfluous parentheses in parameter lists
func _(int) func _(int)
func _(int) func _(int)
@ -992,6 +999,10 @@ func _(struct {
y int y int
}) // no extra comma between } and ) }) // 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 // alias declarations
type c0 struct{} type c0 struct{}

View File

@ -955,6 +955,11 @@ r string,
x ...int) x ...int)
} }
// properly format one-line type lists
type _ interface { type a }
type _ interface { type a,b,c }
// omit superfluous parentheses in parameter lists // omit superfluous parentheses in parameter lists
func _((int)) func _((int))
func _((((((int)))))) func _((((((int))))))
@ -1005,6 +1010,10 @@ func _(struct {
y int y int
}) // no extra comma between } and ) }) // 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 // alias declarations
type c0 struct{} type c0 struct{}

33
src/go/printer/testdata/generics.golden vendored Normal file
View File

@ -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]{}
}

30
src/go/printer/testdata/generics.input vendored Normal file
View File

@ -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]{}
}