1
0
mirror of https://github.com/golang/go synced 2024-11-18 08:04:40 -07:00

go/printer: parenthesize type in <-((<-chan int)(nil))

When printing synthetic syntax (not created by the parser),
the tree for <-((<-chan int)(nil)) without any ParenExpr nodes
was misprinted so that it was parsed back as a receive of
a receive. This changes emits parens around the channel type.

Fixes #63362

Change-Id: I2041ced224f0bca001cee5d37f7a127265d21020
Reviewed-on: https://go-review.googlesource.com/c/go/+/532556
Auto-Submit: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
Alan Donovan 2023-10-04 10:26:17 -04:00 committed by Gopher Robot
parent a903639608
commit 0c64ebce7e
2 changed files with 40 additions and 8 deletions

View File

@ -974,15 +974,24 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
if len(x.Args) > 1 {
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)
wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
p.print(token.RPAREN)
} else {
wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
// Conversions to literal function types or <-chan
// types require parentheses around the type.
paren := false
switch t := x.Fun.(type) {
case *ast.FuncType:
paren = true
case *ast.ChanType:
paren = t.Dir == ast.RECV
}
if paren {
p.print(token.LPAREN)
}
wasIndented := p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
if paren {
p.print(token.RPAREN)
}
p.setPos(x.Lparen)
p.print(token.LPAREN)
if x.Ellipsis.IsValid() {

View File

@ -604,6 +604,29 @@ func f()
}
}
// TestChanType tests that the tree for <-(<-chan int), without
// ParenExpr, is correctly formatted with parens.
// Test case for issue #63362.
func TestChanType(t *testing.T) {
expr := &ast.UnaryExpr{
Op: token.ARROW,
X: &ast.CallExpr{
Fun: &ast.ChanType{
Dir: ast.RECV,
Value: &ast.Ident{Name: "int"},
},
Args: []ast.Expr{&ast.Ident{Name: "nil"}},
},
}
var buf bytes.Buffer
if err := Fprint(&buf, fset, expr); err != nil {
t.Fatal(err)
}
if got, want := buf.String(), `<-(<-chan int)(nil)`; got != want {
t.Fatalf("got:\n%s\nwant:\n%s\n", got, want)
}
}
type limitWriter struct {
remaining int
errCount int