mirror of
https://github.com/golang/go
synced 2024-09-18 15:32:18 +00:00
cmd/compile/internal/syntax: fix printing of ambiguous constraint literals
Without this change, the type parameter list "[P T | T]" is printed as "[P T | T,]" in an attempt to avoid an ambiguity. But the type parameter P cannot syntactically combine with the constraint T | T and make a new valid expression. This change introduces a specific combinesWithName predicate that reports whether a constraint expression can combine with a type parameter name to form a new valid (value) expression. Use combinesWithName to accurately determine when a comma is needed. For #49482. Change-Id: Id1d17a18f0c9af04495da7b0453e83798f32b04a Reviewed-on: https://go-review.googlesource.com/c/go/+/404397 Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
7f71e1fc28
commit
ea6c828455
|
@ -919,16 +919,38 @@ func (p *printer) printParameterList(list []*Field, tok token) {
|
|||
}
|
||||
p.printNode(unparen(f.Type)) // no need for (extra) parentheses around parameter types
|
||||
}
|
||||
// A type parameter list [P *T] where T is not a type element requires a comma as in [P *T,]
|
||||
// so that it's not parsed as [P*T].
|
||||
if tok == _Type && len(list) == 1 {
|
||||
if t, _ := list[0].Type.(*Operation); t != nil && !isTypeElem(t) {
|
||||
p.print(_Comma)
|
||||
}
|
||||
// A type parameter list [P T] where the name P and the type expression T syntactically
|
||||
// combine to another valid (value) expression requires a trailing comma, as in [P *T,]
|
||||
// (or an enclosing interface as in [P interface(*T)]), so that the type parameter list
|
||||
// is not parsed as an array length [P*T].
|
||||
if tok == _Type && len(list) == 1 && combinesWithName(list[0].Type) {
|
||||
p.print(_Comma)
|
||||
}
|
||||
p.print(close)
|
||||
}
|
||||
|
||||
// combinesWithName reports whether a name followed by the expression x
|
||||
// syntactically combines to another valid (value) expression. For instance
|
||||
// using *T for x, "name *T" syntactically appears as the expression x*T.
|
||||
// On the other hand, using P|Q or *P|~Q for x, "name P|Q" or name *P|~Q"
|
||||
// cannot be combined into a valid (value) expression.
|
||||
func combinesWithName(x Expr) bool {
|
||||
switch x := x.(type) {
|
||||
case *Operation:
|
||||
if x.Y == nil {
|
||||
// name *x.X combines to name*x.X if x.X is not a type element
|
||||
return x.Op == Mul && !isTypeElem(x.X)
|
||||
}
|
||||
// binary expressions
|
||||
return combinesWithName(x.X) && !isTypeElem(x.Y)
|
||||
case *ParenExpr:
|
||||
// name(x) combines but we are making sure at
|
||||
// the call site that x is never parenthesized.
|
||||
panic("unexpected parenthesized expression")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *printer) printStmtList(list []Stmt, braces bool) {
|
||||
for i, x := range list {
|
||||
p.print(x, _Semi)
|
||||
|
|
|
@ -76,6 +76,8 @@ var stringTests = [][2]string{
|
|||
|
||||
// a type literal in an |-expression indicates a type parameter list (blank after type parameter list and type)
|
||||
dup("package p; type _[P *[]int] struct{}"),
|
||||
dup("package p; type _[P T | T] struct{}"),
|
||||
dup("package p; type _[P T | T | T | T] struct{}"),
|
||||
dup("package p; type _[P *T | T, Q T] struct{}"),
|
||||
dup("package p; type _[P *[]T | T] struct{}"),
|
||||
dup("package p; type _[P *T | T | T | T | ~T] struct{}"),
|
||||
|
@ -84,7 +86,7 @@ var stringTests = [][2]string{
|
|||
dup("package p; type _[P <-chan int] struct{}"),
|
||||
dup("package p; type _[P *T | struct{} | T] struct{}"),
|
||||
|
||||
// a trailing comma always indicates a type parameter list (blank after type parameter list and type)
|
||||
// a trailing comma always indicates a (possibly invalid) type parameter list (blank after type parameter list and type)
|
||||
dup("package p; type _[P *T,] struct{}"),
|
||||
dup("package p; type _[P *T | T,] struct{}"),
|
||||
dup("package p; type _[P *T | <-T | T,] struct{}"),
|
||||
|
|
Loading…
Reference in a new issue