}
}
-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
// 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 {
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)
}
}
}
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)
} 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)
}
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:
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)
}
case *ast.FuncType:
p.print(token.FUNC)
- p.signature(x.Params, x.Results)
+ p.signature(x)
case *ast.InterfaceType:
p.print(token.INTERFACE)
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 {
// 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)
}
// 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)
}
// 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())
}
{"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) {