}
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)
// 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{}"),
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{}"),