Skip to content

Commit 5c834a2

Browse files
griesemergopherbot
authored andcommitted
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 <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Robert Findley <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> Auto-Submit: Robert Griesemer <[email protected]>
1 parent cafb49a commit 5c834a2

File tree

10 files changed

+113
-0
lines changed

10 files changed

+113
-0
lines changed

src/cmd/compile/internal/types2/builtins.go

+27
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,33 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
232232
x.typ = Typ[Int]
233233
x.val = val
234234

235+
case _Clear:
236+
// clear(m)
237+
if !check.allowVersion(check.pkg, 1, 21) {
238+
check.versionErrorf(call.Fun, "go1.21", "clear")
239+
return
240+
}
241+
242+
if !underIs(x.typ, func(u Type) bool {
243+
switch u := u.(type) {
244+
case *Map, *Slice:
245+
return true
246+
case *Pointer:
247+
if _, ok := under(u.base).(*Array); ok {
248+
return true
249+
}
250+
}
251+
check.errorf(x, InvalidClear, invalidArg+"cannot clear %s: argument must be (or constrained by) map, slice, or array pointer", x)
252+
return false
253+
}) {
254+
return
255+
}
256+
257+
x.mode = novalue
258+
if check.recordTypes() {
259+
check.recordBuiltinType(call.Fun, makeSig(nil, x.typ))
260+
}
261+
235262
case _Close:
236263
// close(c)
237264
if !underIs(x.typ, func(u Type) bool {

src/cmd/compile/internal/types2/builtins_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ var builtinCalls = []struct {
4141
{"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
4242
{"len", `var s P; _ = len(s)`, `func(P) int`},
4343

44+
{"clear", `var m map[float64]int; clear(m)`, `func(map[float64]int)`},
45+
{"clear", `var s []byte; clear(s)`, `func([]byte)`},
46+
{"clear", `var p *[10]int; clear(p)`, `func(*[10]int)`},
47+
{"clear", `var s P; clear(s)`, `func(P)`},
48+
4449
{"close", `var c chan int; close(c)`, `func(chan int)`},
4550
{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
4651

src/cmd/compile/internal/types2/universe.go

+2
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ const (
145145
// universe scope
146146
_Append builtinId = iota
147147
_Cap
148+
_Clear
148149
_Close
149150
_Complex
150151
_Copy
@@ -182,6 +183,7 @@ var predeclaredFuncs = [...]struct {
182183
}{
183184
_Append: {"append", 1, true, expression},
184185
_Cap: {"cap", 1, false, expression},
186+
_Clear: {"clear", 1, false, statement},
185187
_Close: {"close", 1, false, statement},
186188
_Complex: {"complex", 2, false, expression},
187189
_Copy: {"copy", 2, false, statement},

src/go/types/builtins.go

+27
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,33 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
233233
x.typ = Typ[Int]
234234
x.val = val
235235

236+
case _Clear:
237+
// clear(m)
238+
if !check.allowVersion(check.pkg, 1, 21) {
239+
check.error(call.Fun, UnsupportedFeature, "clear requires go1.21 or later")
240+
return
241+
}
242+
243+
if !underIs(x.typ, func(u Type) bool {
244+
switch u := u.(type) {
245+
case *Map, *Slice:
246+
return true
247+
case *Pointer:
248+
if _, ok := under(u.base).(*Array); ok {
249+
return true
250+
}
251+
}
252+
check.errorf(x, InvalidClear, invalidArg+"cannot clear %s: argument must be (or constrained by) map, slice, or array pointer", x)
253+
return false
254+
}) {
255+
return
256+
}
257+
258+
x.mode = novalue
259+
if check.Types != nil {
260+
check.recordBuiltinType(call.Fun, makeSig(nil, x.typ))
261+
}
262+
236263
case _Close:
237264
// close(c)
238265
if !underIs(x.typ, func(u Type) bool {

src/go/types/builtins_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ var builtinCalls = []struct {
4242
{"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
4343
{"len", `var s P; _ = len(s)`, `func(P) int`},
4444

45+
{"clear", `var m map[float64]int; clear(m)`, `func(map[float64]int)`},
46+
{"clear", `var s []byte; clear(s)`, `func([]byte)`},
47+
{"clear", `var p *[10]int; clear(p)`, `func(*[10]int)`},
48+
{"clear", `var s P; clear(s)`, `func(P)`},
49+
4550
{"close", `var c chan int; close(c)`, `func(chan int)`},
4651
{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
4752

src/go/types/universe.go

+2
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ const (
146146
// universe scope
147147
_Append builtinId = iota
148148
_Cap
149+
_Clear
149150
_Close
150151
_Complex
151152
_Copy
@@ -183,6 +184,7 @@ var predeclaredFuncs = [...]struct {
183184
}{
184185
_Append: {"append", 1, true, expression},
185186
_Cap: {"cap", 1, false, expression},
187+
_Clear: {"clear", 1, false, statement},
186188
_Close: {"close", 1, false, statement},
187189
_Complex: {"complex", 2, false, expression},
188190
_Copy: {"copy", 2, false, statement},

src/internal/types/errors/codes.go

+9
Original file line numberDiff line numberDiff line change
@@ -1430,4 +1430,13 @@ const (
14301430
// InvalidUnsafeStringData occurs if it is used in a package
14311431
// compiled for a language version before go1.20.
14321432
_ // not used anymore
1433+
1434+
// InvalidClear occurs when clear is called with an argument
1435+
// that is not of map, slice, or pointer-to-array type.
1436+
//
1437+
// Example:
1438+
// func _(x int) {
1439+
// clear(x)
1440+
// }
1441+
InvalidClear
14331442
)

src/internal/types/testdata/check/builtins0.go

+11
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,17 @@ func cap3() {
139139
)
140140
}
141141

142+
func clear1() {
143+
var a [10]int
144+
var m map[float64]string
145+
var s []byte
146+
clear(a /* ERROR cannot clear a */)
147+
clear(&a)
148+
clear(m)
149+
clear(s)
150+
clear([]int{})
151+
}
152+
142153
func close1() {
143154
var c chan int
144155
var r <-chan int

src/internal/types/testdata/check/builtins1.go

+14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ package builtins
88

99
import "unsafe"
1010

11+
// clear
12+
13+
func _[T any](x T) {
14+
clear(x /* ERROR cannot clear x */)
15+
}
16+
17+
func _[T ~map[int]string | ~[]byte | ~*[10]int](x T) {
18+
clear(x)
19+
}
20+
21+
func _[T ~map[int]string | ~[]byte | ~*[10]int | string](x T) {
22+
clear(x /* ERROR cannot clear x */)
23+
}
24+
1125
// close
1226

1327
type C0 interface{ int }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// -lang=go1.20
2+
3+
// Copyright 2022 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package p
8+
9+
func _(s []int) {
10+
clear /* ERROR clear requires go1\.21 or later */ (s)
11+
}

0 commit comments

Comments
 (0)