]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/syntax: parser to accept ~x as unary expression
authorRobert Griesemer <gri@golang.org>
Mon, 25 Apr 2022 23:26:10 +0000 (16:26 -0700)
committerGopher Robot <gobot@golang.org>
Tue, 26 Apr 2022 02:19:42 +0000 (02:19 +0000)
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>

src/cmd/compile/internal/syntax/parser.go
src/cmd/compile/internal/syntax/testdata/typeset.go
src/cmd/compile/internal/types2/expr.go
src/cmd/compile/internal/types2/testdata/check/expr0.go
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49482.go
test/fixedbugs/issue23587.go

index fe1c76e81b8b9e00e7188d0a6147716c19ff23d2..a89dcfae521a3870814ab8d05a8dac5e8a82bbd8 100644 (file)
@@ -827,7 +827,7 @@ func (p *parser) unaryExpr() Expr {
        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
index 19b74f28eacdb8e24ceea65735167ec1c5bd5369..fe5c3f45a815f9fd8032e3eab316b02e0db73714 100644 (file)
@@ -65,15 +65,17 @@ func _[_ t[t] | t[t]]() {}
 
 // 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 (
index 27f290420b994b6ea8083b78abd7b7bd6e234566..33d329f82d894c5f2ccba71d2eddcf76c1ff6efb 100644 (file)
@@ -208,6 +208,12 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
                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) {
index 1aac726327b28265af426a838d801fe15ed1ab6d..821b07f007544ca84fc5a2da21930c55e41660b1 100644 (file)
@@ -178,3 +178,10 @@ func _() {
        _ = -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
index f289d2e52d3015d835d5b3321f0afec29cc11ff2..503d9946b46729c8bd8bde96b21a76d3bb7663cc 100644 (file)
@@ -22,4 +22,4 @@ type _[P /* ERROR non-function P */ (*int)] int
 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{}
index 2308992347a9c7d5438402f46a61710f49892df8..9040767f8cb6261c83743a2f674edab1cd499e67 100644 (file)
@@ -7,7 +7,7 @@
 package p
 
 func _(x int) {
-       _ = ~x    // ERROR "unexpected ~"
+       _ = ~x    // unary ~ permitted but the type-checker will complain
 }
 
 func _(x int) {