Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go/printer: Fprint crashes with unexpected parenthesized expression panic #69206

Closed
mateusz834 opened this issue Sep 2, 2024 · 8 comments
Closed
Assignees
Labels
FixPending Issues that have a fix which has not yet been reviewed or submitted. NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@mateusz834
Copy link
Member

Reproducer:

func TestPrinterPanic(t *testing.T) {
	const src = `package A
type A[C((D)),] struct{}
`

	fs := token.NewFileSet()
	f, err := parser.ParseFile(fs, "test.go", src, parser.ParseComments|parser.SkipObjectResolution)
	if err != nil {
		t.Fatal(err)
	}
	Fprint(io.Discard, fs, f) // panic: unexpected parenthesized expression.
}
panic: unexpected parenthesized expression [recovered]
        panic: unexpected parenthesized expression

goroutine 6 [running]:
testing.tRunner.func1.2({0x586300, 0x5fbc80})
        testing/testing.go:1706 +0x230
testing.tRunner.func1()
        testing/testing.go:1709 +0x35e
panic({0x586300?, 0x5fbc80?})
        runtime/panic.go:785 +0x132
go/printer.combinesWithName({0x5fe0b8?, 0xc0000700e0?})
        go/printer/nodes.go:416 +0x5c
go/printer.(*printer).parameters(0xc0000a21a0, 0xc0000845a0, 0x2)
        go/printer/nodes.go:383 +0xa3d
go/printer.(*printer).spec(0xc0000a21a0, {0x5fe358?, 0xc000090a40}, 0x1, 0x1?)
        go/printer/nodes.go:1719 +0x419
go/printer.(*printer).genDecl(0xc0000a21a0, 0xc000090b00)
        go/printer/nodes.go:1777 +0x407
go/printer.(*printer).decl(0xc0000a21a0?, {0x5fdfc8?, 0xc000090b00?})
        go/printer/nodes.go:1945 +0x51
go/printer.(*printer).declList(0xc0000a21a0, {0xc000020460?, 0xc000070060?, 0x0?})
        go/printer/nodes.go:1990 +0x39
go/printer.(*printer).file(0xc0000a21a0, 0xc000080280)
        go/printer/nodes.go:1999 +0x16f
go/printer.(*printer).printNode(0xc0000a21a0, {0x592020?, 0xc000080280?})
        go/printer/printer.go:1172 +0x16a
go/printer.(*Config).fprint(0xc0000c9f20, {0x5fcea0, 0x72a020}, 0x586300?, {0x592020, 0xc000080280}, 0x4dabc0?)
        go/printer/printer.go:1364 +0xab
go/printer.(*Config).Fprint(...)
        go/printer/printer.go:1424
go/printer.Fprint(...)
        go/printer/printer.go:1432
@mateusz834
Copy link
Member Author

I wonder whether this is the right fix:

diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go
index a4651e0608..495ec22031 100644
--- a/src/go/printer/nodes.go
+++ b/src/go/printer/nodes.go
@@ -411,9 +411,7 @@ func combinesWithName(x ast.Expr) bool {
        case *ast.BinaryExpr:
                return combinesWithName(x.X) && !isTypeElem(x.Y)
        case *ast.ParenExpr:
-               // name(x) combines but we are making sure at
-               // the call site that x is never parenthesized.
-               panic("unexpected parenthesized expression")
+               return combinesWithName(x.X)
        }
        return false
 }

@mateusz834 mateusz834 added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Sep 2, 2024
@mateusz834
Copy link
Member Author

But also looking at the parser, I wonder whether the parser is right here:

go/src/go/parser/parser.go

Lines 2695 to 2702 in fc9f02c

case *ast.CallExpr:
if name, _ := x.Fun.(*ast.Ident); name != nil {
if len(x.Args) == 1 && x.Ellipsis == token.NoPos && (force || isTypeElem(x.Args[0])) {
// x = name "(" x.ArgList[0] ")"
return name, x.Args[0]
}
}
}

We are loosing some bits of the AST, i believe it should be converted to *ast.ParenExpr:

diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index 17808b366f..6c418fd796 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -2695,8 +2695,11 @@ func extractName(x ast.Expr, force bool) (*ast.Ident, ast.Expr) {
        case *ast.CallExpr:
                if name, _ := x.Fun.(*ast.Ident); name != nil {
                        if len(x.Args) == 1 && x.Ellipsis == token.NoPos && (force || isTypeElem(x.Args[0])) {
-                               // x = name "(" x.ArgList[0] ")"
-                               return name, x.Args[0]
+                               return name, &ast.ParenExpr{
+                                       Lparen: x.Lparen,
+                                       X:      x.Args[0],
+                                       Rparen: x.Rparen,
+                               }
                        }
                }
        }

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/610115 mentions this issue: go/printer: do not panic on *ast.ParenExpr in combinesWithName

@ianlancetaylor
Copy link
Contributor

CC @griesemer

@griesemer griesemer self-assigned this Sep 3, 2024
@griesemer griesemer added this to the Go1.24 milestone Sep 3, 2024
@griesemer
Copy link
Contributor

I think this looks right. Will comment on the CL.

@dmitshur dmitshur added NeedsFix The path to resolution is known, but the work has not been done. FixPending Issues that have a fix which has not yet been reviewed or submitted. and removed NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Sep 4, 2024
gopherbot pushed a commit that referenced this issue Sep 4, 2024
We are loosing a bit of the AST information, i believe we should
convert *ast.CallExpr into *ast.ParenExpr.

See #69206 (comment)

Change-Id: I2d9ad8a3dead664a4fa9ac324e8d8a955a4d97c8
GitHub-Last-Rev: e5db56d
GitHub-Pull-Request: #69209
Reviewed-on: https://go-review.googlesource.com/c/go/+/610078
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/610758 mentions this issue: cmd/compile/internal/syntax: handle parentheses around constraints consistently

gopherbot pushed a commit that referenced this issue Sep 5, 2024
…nsistently

Generally, the parser strips (i.e., does not record in the syntax tree)
unnecessary parentheses. Specifically, given a type parameter list of
the form

        [P (C),]

it records it as

        [P C]

and then no comma is required when printing. However it did only strip
one level of parentheses, and

        [P ((C)),]

made it through, causing a panic when printing. Somewhat related,
the printer stripped parentheses around constraints as well.

This CL implements a more consistent behavior:

1) The parser strips all parentheses around constraints. For testing
   purposes, a local flag (keep_parens) can be set to retain the
   parentheses.

2) The printer code now correctly intruces a comma if parentheses
   are present (e.g., when testing with keep_parens). This case does
   not occur in normal operation.

3) The printer does not strip parentheses around constraints since
   the parser does it already.

For #69206.

Change-Id: I974a800265625e8daf9477faa9ee4dd74dbd17ce
Reviewed-on: https://go-review.googlesource.com/c/go/+/610758
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/611355 mentions this issue: go/printer: check whether !isTypeElem, instead of combinesWithName when ParenExpr

gopherbot pushed a commit that referenced this issue Sep 6, 2024
…en ParenExpr

See discussion in CL 610115 and CL 610758.

For #69206

Change-Id: I16f394cb3440106650fb64a466f2723a4dba3871
GitHub-Last-Rev: 37993b5
GitHub-Pull-Request: #69309
Reviewed-on: https://go-review.googlesource.com/c/go/+/611355
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FixPending Issues that have a fix which has not yet been reviewed or submitted. NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants