mirror of https://github.com/golang/go.git
go/types, types2: implement type checking of "clear" built-in
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>
This commit is contained in:
parent
cafb49ac73
commit
5c834a2eb0
|
|
@ -232,6 +232,33 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||||
x.typ = Typ[Int]
|
x.typ = Typ[Int]
|
||||||
x.val = val
|
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:
|
case _Close:
|
||||||
// close(c)
|
// close(c)
|
||||||
if !underIs(x.typ, func(u Type) bool {
|
if !underIs(x.typ, func(u Type) bool {
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,11 @@ var builtinCalls = []struct {
|
||||||
{"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
|
{"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
|
||||||
{"len", `var s P; _ = len(s)`, `func(P) 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 int; close(c)`, `func(chan int)`},
|
||||||
{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
|
{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,7 @@ const (
|
||||||
// universe scope
|
// universe scope
|
||||||
_Append builtinId = iota
|
_Append builtinId = iota
|
||||||
_Cap
|
_Cap
|
||||||
|
_Clear
|
||||||
_Close
|
_Close
|
||||||
_Complex
|
_Complex
|
||||||
_Copy
|
_Copy
|
||||||
|
|
@ -182,6 +183,7 @@ var predeclaredFuncs = [...]struct {
|
||||||
}{
|
}{
|
||||||
_Append: {"append", 1, true, expression},
|
_Append: {"append", 1, true, expression},
|
||||||
_Cap: {"cap", 1, false, expression},
|
_Cap: {"cap", 1, false, expression},
|
||||||
|
_Clear: {"clear", 1, false, statement},
|
||||||
_Close: {"close", 1, false, statement},
|
_Close: {"close", 1, false, statement},
|
||||||
_Complex: {"complex", 2, false, expression},
|
_Complex: {"complex", 2, false, expression},
|
||||||
_Copy: {"copy", 2, false, statement},
|
_Copy: {"copy", 2, false, statement},
|
||||||
|
|
|
||||||
|
|
@ -233,6 +233,33 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
x.typ = Typ[Int]
|
x.typ = Typ[Int]
|
||||||
x.val = val
|
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:
|
case _Close:
|
||||||
// close(c)
|
// close(c)
|
||||||
if !underIs(x.typ, func(u Type) bool {
|
if !underIs(x.typ, func(u Type) bool {
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,11 @@ var builtinCalls = []struct {
|
||||||
{"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
|
{"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
|
||||||
{"len", `var s P; _ = len(s)`, `func(P) 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 int; close(c)`, `func(chan int)`},
|
||||||
{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
|
{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ const (
|
||||||
// universe scope
|
// universe scope
|
||||||
_Append builtinId = iota
|
_Append builtinId = iota
|
||||||
_Cap
|
_Cap
|
||||||
|
_Clear
|
||||||
_Close
|
_Close
|
||||||
_Complex
|
_Complex
|
||||||
_Copy
|
_Copy
|
||||||
|
|
@ -183,6 +184,7 @@ var predeclaredFuncs = [...]struct {
|
||||||
}{
|
}{
|
||||||
_Append: {"append", 1, true, expression},
|
_Append: {"append", 1, true, expression},
|
||||||
_Cap: {"cap", 1, false, expression},
|
_Cap: {"cap", 1, false, expression},
|
||||||
|
_Clear: {"clear", 1, false, statement},
|
||||||
_Close: {"close", 1, false, statement},
|
_Close: {"close", 1, false, statement},
|
||||||
_Complex: {"complex", 2, false, expression},
|
_Complex: {"complex", 2, false, expression},
|
||||||
_Copy: {"copy", 2, false, statement},
|
_Copy: {"copy", 2, false, statement},
|
||||||
|
|
|
||||||
|
|
@ -1430,4 +1430,13 @@ const (
|
||||||
// InvalidUnsafeStringData occurs if it is used in a package
|
// InvalidUnsafeStringData occurs if it is used in a package
|
||||||
// compiled for a language version before go1.20.
|
// compiled for a language version before go1.20.
|
||||||
_ // not used anymore
|
_ // 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
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
func close1() {
|
||||||
var c chan int
|
var c chan int
|
||||||
var r <-chan int
|
var r <-chan int
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,20 @@ package builtins
|
||||||
|
|
||||||
import "unsafe"
|
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
|
// close
|
||||||
|
|
||||||
type C0 interface{ int }
|
type C0 interface{ int }
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue