From d10b8192c0eeabb574b7f198917a656b6fa51c38 Mon Sep 17 00:00:00 2001 From: Robert Findley Date: Tue, 8 Mar 2022 16:43:47 -0500 Subject: [PATCH] [release-branch.go1.18] go/printer: don't print unnecesary commas for func type param lists Type parameter lists are not ambiguous for function declarations in the way that they are ambiguous for type declarations. Avoid printing an extra comma to disambiguate. Fixes #51548 Change-Id: I8ca2b21e271982013653b9e220f92ee74f577ba2 Reviewed-on: https://go-review.googlesource.com/c/go/+/390914 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Robert Griesemer TryBot-Result: Gopher Robot (cherry picked from commit 0add0647d80f8ec794042b4608275830372fe298) Reviewed-on: https://go-review.googlesource.com/c/go/+/390957 Trust: Dmitri Shuralyov Run-TryBot: Dmitri Shuralyov Reviewed-by: Robert Findley --- src/go/printer/nodes.go | 24 +++++++++++++++-------- src/go/printer/testdata/generics.golden | 26 +++++++++++++++++++++++++ src/go/printer/testdata/generics.input | 25 ++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go index f2170dbc4f..9a09d58eb2 100644 --- a/src/go/printer/nodes.go +++ b/src/go/printer/nodes.go @@ -319,9 +319,17 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp } } -func (p *printer) parameters(fields *ast.FieldList, isTypeParam bool) { +type paramMode int + +const ( + funcParam paramMode = iota + funcTParam + typeTParam +) + +func (p *printer) parameters(fields *ast.FieldList, mode paramMode) { openTok, closeTok := token.LPAREN, token.RPAREN - if isTypeParam { + if mode != funcParam { openTok, closeTok = token.LBRACK, token.RBRACK } p.print(fields.Opening, openTok) @@ -373,7 +381,7 @@ func (p *printer) parameters(fields *ast.FieldList, isTypeParam bool) { if closing := p.lineFor(fields.Closing); 0 < prevLine && prevLine < closing { p.print(token.COMMA) p.linebreak(closing, 0, ignore, true) - } else if isTypeParam && fields.NumFields() == 1 { + } else if mode == typeTParam && fields.NumFields() == 1 { // Otherwise, if we are in a type parameter list that could be confused // with the constant array length expression [P*C], print a comma so that // parsing is unambiguous. @@ -411,10 +419,10 @@ func isTypeLit(x ast.Expr) bool { func (p *printer) signature(sig *ast.FuncType) { if sig.TypeParams != nil { - p.parameters(sig.TypeParams, true) + p.parameters(sig.TypeParams, funcTParam) } if sig.Params != nil { - p.parameters(sig.Params, false) + p.parameters(sig.Params, funcParam) } else { p.print(token.LPAREN, token.RPAREN) } @@ -428,7 +436,7 @@ func (p *printer) signature(sig *ast.FuncType) { p.expr(stripParensAlways(res.List[0].Type)) return } - p.parameters(res, false) + p.parameters(res, funcParam) } } @@ -1639,7 +1647,7 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) { p.setComment(s.Doc) p.expr(s.Name) if s.TypeParams != nil { - p.parameters(s.TypeParams, true) + p.parameters(s.TypeParams, typeTParam) } if n == 1 { p.print(blank) @@ -1829,7 +1837,7 @@ func (p *printer) funcDecl(d *ast.FuncDecl) { // FUNC is emitted). startCol := p.out.Column - len("func ") if d.Recv != nil { - p.parameters(d.Recv, false) // method: print receiver + p.parameters(d.Recv, funcParam) // method: print receiver p.print(blank) } p.expr(d.Name) diff --git a/src/go/printer/testdata/generics.golden b/src/go/printer/testdata/generics.golden index 4fac2c9c58..c3a7df8372 100644 --- a/src/go/printer/testdata/generics.golden +++ b/src/go/printer/testdata/generics.golden @@ -64,3 +64,29 @@ type _ [P*T - T]struct{} type _[ P *T, ] struct{} + +// equivalent test cases for potentially ambiguous type parameter lists, except +// for function declarations there is no ambiguity (issue #51548) +func _[P *T]() {} +func _[P *T, _ any]() {} +func _[P *T]() {} +func _[P *T, _ any]() {} +func _[P T]() {} +func _[P T, _ any]() {} + +func _[P *struct{}]() {} +func _[P *struct{}]() {} +func _[P []int]() {} + +func _[P T]() {} +func _[P T]() {} +func _[P **T]() {} +func _[P *T]() {} +func _[P *T]() {} +func _[P **T]() {} +func _[P *T]() {} + +func _[ + P *T, +]() { +} diff --git a/src/go/printer/testdata/generics.input b/src/go/printer/testdata/generics.input index fde9d32ef0..66e1554f7f 100644 --- a/src/go/printer/testdata/generics.input +++ b/src/go/printer/testdata/generics.input @@ -61,3 +61,28 @@ type _ [P * T - T]struct{} type _[ P *T, ] struct{} + +// equivalent test cases for potentially ambiguous type parameter lists, except +// for function declarations there is no ambiguity (issue #51548) +func _[P *T,]() {} +func _[P *T, _ any]() {} +func _[P (*T),]() {} +func _[P (*T), _ any]() {} +func _[P (T),]() {} +func _[P (T), _ any]() {} + +func _[P *struct{}] () {} +func _[P (*struct{})] () {} +func _[P ([]int)] () {} + +func _ [P(T)]() {} +func _ [P((T))]() {} +func _ [P * *T]() {} +func _ [P * T]() {} +func _ [P(*T)]() {} +func _ [P(**T)]() {} +func _ [P * T]() {} + +func _[ + P *T, +]() {} -- 2.48.1