]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: implement type checking of "clear" built-in
authorRobert Griesemer <gri@golang.org>
Fri, 4 Nov 2022 22:12:32 +0000 (15:12 -0700)
committerGopher Robot <gobot@golang.org>
Thu, 17 Nov 2022 17:24:51 +0000 (17:24 +0000)
Will become available with Go 1.21.

Recognizing the `clear` built-in early is not causing any problems:
if existing code defines a `clear`, that will be used as before. If
code doesn't define `clear` the error message will make it clear
that with 1.21 the function will be available. It's still possible
to define a local `clear` and get rid of the error; but more likely
the name choice should be avoided going forward, so this provides a
useful early "heads-up".

For #56351.

Change-Id: I3d0fb1eb3508fbc78d7514b6238eac89610158c9
Reviewed-on: https://go-review.googlesource.com/c/go/+/448076
Run-TryBot: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>

src/cmd/compile/internal/types2/builtins.go
src/cmd/compile/internal/types2/builtins_test.go
src/cmd/compile/internal/types2/universe.go
src/go/types/builtins.go
src/go/types/builtins_test.go
src/go/types/universe.go
src/internal/types/errors/codes.go
src/internal/types/testdata/check/builtins0.go
src/internal/types/testdata/check/builtins1.go
src/internal/types/testdata/fixedbugs/issue56351.go [new file with mode: 0644]

index aab4ae95ddf6376fcd8ebcd8b810e1a5ef10e9d9..531e41dd7d96dbfbde11a611350b4d56ed93f539 100644 (file)
@@ -232,6 +232,33 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                x.typ = Typ[Int]
                x.val = val
 
+       case _Clear:
+               // clear(m)
+               if !check.allowVersion(check.pkg, 1, 21) {
+                       check.versionErrorf(call.Fun, "go1.21", "clear")
+                       return
+               }
+
+               if !underIs(x.typ, func(u Type) bool {
+                       switch u := u.(type) {
+                       case *Map, *Slice:
+                               return true
+                       case *Pointer:
+                               if _, ok := under(u.base).(*Array); ok {
+                                       return true
+                               }
+                       }
+                       check.errorf(x, InvalidClear, invalidArg+"cannot clear %s: argument must be (or constrained by) map, slice, or array pointer", x)
+                       return false
+               }) {
+                       return
+               }
+
+               x.mode = novalue
+               if check.recordTypes() {
+                       check.recordBuiltinType(call.Fun, makeSig(nil, x.typ))
+               }
+
        case _Close:
                // close(c)
                if !underIs(x.typ, func(u Type) bool {
index e382c47b914cdf62515e4595b0795eee6b6163fa..12c139f492217297fcae68671c01fd5e5c443ddc 100644 (file)
@@ -41,6 +41,11 @@ var builtinCalls = []struct {
        {"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
        {"len", `var s P; _ = len(s)`, `func(P) int`},
 
+       {"clear", `var m map[float64]int; clear(m)`, `func(map[float64]int)`},
+       {"clear", `var s []byte; clear(s)`, `func([]byte)`},
+       {"clear", `var p *[10]int; clear(p)`, `func(*[10]int)`},
+       {"clear", `var s P; clear(s)`, `func(P)`},
+
        {"close", `var c chan int; close(c)`, `func(chan int)`},
        {"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
 
index 301526c8d6095122dded7753b2644a6461f080fb..3fe849e737e0528704f1ed1615a3ea6feb08b362 100644 (file)
@@ -145,6 +145,7 @@ const (
        // universe scope
        _Append builtinId = iota
        _Cap
+       _Clear
        _Close
        _Complex
        _Copy
@@ -182,6 +183,7 @@ var predeclaredFuncs = [...]struct {
 }{
        _Append:  {"append", 1, true, expression},
        _Cap:     {"cap", 1, false, expression},
+       _Clear:   {"clear", 1, false, statement},
        _Close:   {"close", 1, false, statement},
        _Complex: {"complex", 2, false, expression},
        _Copy:    {"copy", 2, false, statement},
index a923ef557ff52d5777a29c2dafdbcb32e7bf2000..d3bca606b2f29e2dfc049f28229cb21e8251392a 100644 (file)
@@ -233,6 +233,33 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                x.typ = Typ[Int]
                x.val = val
 
+       case _Clear:
+               // clear(m)
+               if !check.allowVersion(check.pkg, 1, 21) {
+                       check.error(call.Fun, UnsupportedFeature, "clear requires go1.21 or later")
+                       return
+               }
+
+               if !underIs(x.typ, func(u Type) bool {
+                       switch u := u.(type) {
+                       case *Map, *Slice:
+                               return true
+                       case *Pointer:
+                               if _, ok := under(u.base).(*Array); ok {
+                                       return true
+                               }
+                       }
+                       check.errorf(x, InvalidClear, invalidArg+"cannot clear %s: argument must be (or constrained by) map, slice, or array pointer", x)
+                       return false
+               }) {
+                       return
+               }
+
+               x.mode = novalue
+               if check.Types != nil {
+                       check.recordBuiltinType(call.Fun, makeSig(nil, x.typ))
+               }
+
        case _Close:
                // close(c)
                if !underIs(x.typ, func(u Type) bool {
index a794f2fb54e9ae45c19158e5d6b0fc335f83b6d6..fb71c4887b2b0e365efdaf039df7314a2cce632e 100644 (file)
@@ -42,6 +42,11 @@ var builtinCalls = []struct {
        {"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
        {"len", `var s P; _ = len(s)`, `func(P) int`},
 
+       {"clear", `var m map[float64]int; clear(m)`, `func(map[float64]int)`},
+       {"clear", `var s []byte; clear(s)`, `func([]byte)`},
+       {"clear", `var p *[10]int; clear(p)`, `func(*[10]int)`},
+       {"clear", `var s P; clear(s)`, `func(P)`},
+
        {"close", `var c chan int; close(c)`, `func(chan int)`},
        {"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
 
index 8551ee00ff1b393b7803e1ba4cb6f5ce1a4968ab..9103fca713e686eeefcfff0b538baa25493ccd74 100644 (file)
@@ -146,6 +146,7 @@ const (
        // universe scope
        _Append builtinId = iota
        _Cap
+       _Clear
        _Close
        _Complex
        _Copy
@@ -183,6 +184,7 @@ var predeclaredFuncs = [...]struct {
 }{
        _Append:  {"append", 1, true, expression},
        _Cap:     {"cap", 1, false, expression},
+       _Clear:   {"clear", 1, false, statement},
        _Close:   {"close", 1, false, statement},
        _Complex: {"complex", 2, false, expression},
        _Copy:    {"copy", 2, false, statement},
index 7bf7b218bd719f3b5e502618573fe407d3c921c7..7a0c0e16b83929108382fc3567d4c9e35cc189e2 100644 (file)
@@ -1430,4 +1430,13 @@ const (
        // InvalidUnsafeStringData occurs if it is used in a package
        // compiled for a language version before go1.20.
        _ // not used anymore
+
+       // InvalidClear occurs when clear is called with an argument
+       // that is not of map, slice, or pointer-to-array type.
+       //
+       // Example:
+       //  func _(x int) {
+       //      clear(x)
+       //  }
+       InvalidClear
 )
index c4bce4147323c44629958737086e296671211794..308f70b9ccec4778d3abeddab18628defe4c9502 100644 (file)
@@ -139,6 +139,17 @@ func cap3() {
        )
 }
 
+func clear1() {
+       var a [10]int
+       var m map[float64]string
+       var s []byte
+       clear(a /* ERROR cannot clear a */)
+       clear(&a)
+       clear(m)
+       clear(s)
+       clear([]int{})
+}
+
 func close1() {
        var c chan int
        var r <-chan int
index 861597399e3b1f0865de38a7f5bc3ed9310ef5dd..33488615821540c331de6d29ad4cc133a0fad6ce 100644 (file)
@@ -8,6 +8,20 @@ package builtins
 
 import "unsafe"
 
+// clear
+
+func _[T any](x T) {
+       clear(x /* ERROR cannot clear x */)
+}
+
+func _[T ~map[int]string | ~[]byte | ~*[10]int](x T) {
+       clear(x)
+}
+
+func _[T ~map[int]string | ~[]byte | ~*[10]int | string](x T) {
+       clear(x /* ERROR cannot clear x */)
+}
+
 // close
 
 type C0 interface{ int }
diff --git a/src/internal/types/testdata/fixedbugs/issue56351.go b/src/internal/types/testdata/fixedbugs/issue56351.go
new file mode 100644 (file)
index 0000000..d7d04b0
--- /dev/null
@@ -0,0 +1,11 @@
+// -lang=go1.20
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func _(s []int) {
+       clear /* ERROR clear requires go1\.21 or later */ (s)
+}