mirror of
https://github.com/golang/go
synced 2024-11-23 06:00:08 -07:00
[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:
parent
ab18125567
commit
72cc2353f0
@ -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)
|
||||
} 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)
|
||||
}
|
||||
} else {
|
||||
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 {
|
||||
// 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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
11
src/go/printer/testdata/declarations.golden
vendored
11
src/go/printer/testdata/declarations.golden
vendored
@ -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{}
|
||||
|
9
src/go/printer/testdata/declarations.input
vendored
9
src/go/printer/testdata/declarations.input
vendored
@ -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{}
|
||||
|
33
src/go/printer/testdata/generics.golden
vendored
Normal file
33
src/go/printer/testdata/generics.golden
vendored
Normal 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
30
src/go/printer/testdata/generics.input
vendored
Normal 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]{}
|
||||
}
|
Loading…
Reference in New Issue
Block a user