cmd/compile/internal/syntax: parser to accept ~x as unary expression
Accept ~x as ordinary unary expression in the parser but recognize
such expressions as invalid in the type checker.
This change opens the door to recognizing complex type constraint
literals such as `*E|~int` in `[P *E|~int]` and parse them correctly
instead of reporting a parse error because `P*E|~int` syntactically
looks like an incorrect array length expression (binary expression
where the RHS of | is an invalid unary expression ~int).
As a result, the parser is more forgiving with expressions but the
type checker will reject invalid uses as before.
We could pass extra information into the binary/unary expression
parse functions to prevent the use of ~ in invalid situations but
it doesn't seem worth the trouble. In fact it may be advantageous
to allow a more liberal expression syntax especially in the presence
of errors (better parser synchronization after an error).
Preparation for fixing #49482.
Change-Id: I119e8bd9445dfa6460fcd7e0658e3554a34b2769
Reviewed-on: https://go-review.googlesource.com/c/go/+/402255
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
index fe1c76e..a89dcfa 100644
--- a/src/cmd/compile/internal/syntax/parser.go
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -827,7 +827,7 @@
switch p.tok {
case _Operator, _Star:
switch p.op {
- case Mul, Add, Sub, Not, Xor:
+ case Mul, Add, Sub, Not, Xor, Tilde:
x := new(Operation)
x.pos = p.pos()
x.Op = p.op
diff --git a/src/cmd/compile/internal/syntax/testdata/typeset.go b/src/cmd/compile/internal/syntax/testdata/typeset.go
index 19b74f2..fe5c3f4 100644
--- a/src/cmd/compile/internal/syntax/testdata/typeset.go
+++ b/src/cmd/compile/internal/syntax/testdata/typeset.go
@@ -65,15 +65,17 @@
// Single-expression type parameter lists and those that don't start
// with a (type parameter) name are considered array sizes.
-// The term must be a valid expression (it could be a type - and then
-// a type-checker will complain - but we don't allow ~ in the expr).
+// The term must be a valid expression (it could be a type incl. a
+// tilde term) but the type-checker will complain.
type (
_[t] t
- _[/* ERROR unexpected ~ */ ~t] t
_[t|t] t
- _[/* ERROR unexpected ~ */ ~t|t] t
- _[t| /* ERROR unexpected ~ */ ~t] t
- _[/* ERROR unexpected ~ */ ~t|~t] t
+
+ // These are invalid and the type-checker will complain.
+ _[~t] t
+ _[~t|t] t
+ _[t|~t] t
+ _[~t|~t] t
)
type (
diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go
index 27f2904..33d329f 100644
--- a/src/cmd/compile/internal/types2/expr.go
+++ b/src/cmd/compile/internal/types2/expr.go
@@ -208,6 +208,12 @@
x.typ = ch.elem
check.hasCallOrRecv = true
return
+
+ case syntax.Tilde:
+ // Provide a better error position and message than what check.op below could do.
+ check.error(e, "cannot use ~ outside of interface or type constraint")
+ x.mode = invalid
+ return
}
if !check.op(unaryOpPredicates, x, e.Op) {
diff --git a/src/cmd/compile/internal/types2/testdata/check/expr0.go b/src/cmd/compile/internal/types2/testdata/check/expr0.go
index 1aac726..821b07f 100644
--- a/src/cmd/compile/internal/types2/testdata/check/expr0.go
+++ b/src/cmd/compile/internal/types2/testdata/check/expr0.go
@@ -178,3 +178,10 @@
_ = -g /* ERROR 2-valued g */ ()
_ = <-g /* ERROR 2-valued g */ ()
}
+
+// ~ is accepted as unary operator only permitted in interface type elements
+var (
+ _ = ~ /* ERROR cannot use ~ outside of interface or type constraint */ 0
+ _ = ~ /* ERROR cannot use ~ outside of interface or type constraint */ "foo"
+ _ = ~ /* ERROR cannot use ~ outside of interface or type constraint */ i0
+)
\ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49482.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49482.go
index f289d2e..503d994 100644
--- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49482.go
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49482.go
@@ -22,4 +22,4 @@
type _[P *struct /* ERROR "not an expression" */ {}| int /* ERROR "not an expression" */ ] struct{}
// The following fails to parse, due to the '~'
-type _[P *struct /* ERROR "not an expression" */ {}|~ /* ERROR "unexpected ~" */ int] struct{}
+type _[P *struct /* ERROR "not an expression" */ {}|~int /* ERROR "not an expression" */ ] struct{}
diff --git a/test/fixedbugs/issue23587.go b/test/fixedbugs/issue23587.go
index 2308992..9040767 100644
--- a/test/fixedbugs/issue23587.go
+++ b/test/fixedbugs/issue23587.go
@@ -7,7 +7,7 @@
package p
func _(x int) {
- _ = ~x // ERROR "unexpected ~"
+ _ = ~x // unary ~ permitted but the type-checker will complain
}
func _(x int) {