mirror of
https://github.com/golang/go
synced 2024-11-23 20:30:04 -07:00
go/types, types2: record correct argument type for cap, len
Record the actual argument type for a cap/len call, not the underlying type. Fixes #51055. Change-Id: Ia0e746a462377f030424ccaec0babf72b78da420 Reviewed-on: https://go-review.googlesource.com/c/go/+/383474 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
8f374aa27f
commit
49030c87e0
@ -142,9 +142,8 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
// cap(x)
|
||||
// len(x)
|
||||
mode := invalid
|
||||
var typ Type
|
||||
var val constant.Value
|
||||
switch typ = arrayPtrDeref(under(x.typ)); t := typ.(type) {
|
||||
switch t := arrayPtrDeref(under(x.typ)).(type) {
|
||||
case *Basic:
|
||||
if isString(t) && id == _Len {
|
||||
if x.mode == constant_ {
|
||||
@ -201,17 +200,19 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
}
|
||||
}
|
||||
|
||||
if mode == invalid && typ != Typ[Invalid] {
|
||||
if mode == invalid && under(x.typ) != Typ[Invalid] {
|
||||
check.errorf(x, invalidArg+"%s for %s", x, bin.name)
|
||||
return
|
||||
}
|
||||
|
||||
// record the signature before changing x.typ
|
||||
if check.Types != nil && mode != constant_ {
|
||||
check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ))
|
||||
}
|
||||
|
||||
x.mode = mode
|
||||
x.typ = Typ[Int]
|
||||
x.val = val
|
||||
if check.Types != nil && mode != constant_ {
|
||||
check.recordBuiltinType(call.Fun, makeSig(x.typ, typ))
|
||||
}
|
||||
|
||||
case _Close:
|
||||
// close(c)
|
||||
|
@ -28,6 +28,8 @@ var builtinCalls = []struct {
|
||||
{"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant
|
||||
{"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`},
|
||||
{"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`},
|
||||
{"cap", `type S []byte; var s S; _ = cap(s)`, `func(p.S) int`},
|
||||
{"cap", `var s P; _ = cap(s)`, `func(P) int`},
|
||||
|
||||
{"len", `_ = len("foo")`, `invalid type`}, // constant
|
||||
{"len", `var s string; _ = len(s)`, `func(string) int`},
|
||||
@ -36,6 +38,8 @@ var builtinCalls = []struct {
|
||||
{"len", `var s []int64; _ = len(s)`, `func([]int64) int`},
|
||||
{"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`},
|
||||
{"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`},
|
||||
{"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
|
||||
{"len", `var s P; _ = len(s)`, `func(P) int`},
|
||||
|
||||
{"close", `var c chan int; close(c)`, `func(chan int)`},
|
||||
{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
|
||||
@ -159,7 +163,7 @@ func parseGenericSrc(path, src string) (*syntax.File, error) {
|
||||
}
|
||||
|
||||
func testBuiltinSignature(t *testing.T, name, src0, want string) {
|
||||
src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _[P any]() { %s }`, src0)
|
||||
src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _[P ~[]byte]() { %s }`, src0)
|
||||
f, err := parseGenericSrc("", src)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %s", src0, err)
|
||||
|
@ -143,9 +143,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
// cap(x)
|
||||
// len(x)
|
||||
mode := invalid
|
||||
var typ Type
|
||||
var val constant.Value
|
||||
switch typ = arrayPtrDeref(under(x.typ)); t := typ.(type) {
|
||||
switch t := arrayPtrDeref(under(x.typ)).(type) {
|
||||
case *Basic:
|
||||
if isString(t) && id == _Len {
|
||||
if x.mode == constant_ {
|
||||
@ -202,7 +201,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
}
|
||||
}
|
||||
|
||||
if mode == invalid && typ != Typ[Invalid] {
|
||||
if mode == invalid && under(x.typ) != Typ[Invalid] {
|
||||
code := _InvalidCap
|
||||
if id == _Len {
|
||||
code = _InvalidLen
|
||||
@ -211,12 +210,14 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
return
|
||||
}
|
||||
|
||||
// record the signature before changing x.typ
|
||||
if check.Types != nil && mode != constant_ {
|
||||
check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ))
|
||||
}
|
||||
|
||||
x.mode = mode
|
||||
x.typ = Typ[Int]
|
||||
x.val = val
|
||||
if check.Types != nil && mode != constant_ {
|
||||
check.recordBuiltinType(call.Fun, makeSig(x.typ, typ))
|
||||
}
|
||||
|
||||
case _Close:
|
||||
// close(c)
|
||||
|
@ -29,6 +29,8 @@ var builtinCalls = []struct {
|
||||
{"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant
|
||||
{"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`},
|
||||
{"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`},
|
||||
{"cap", `type S []byte; var s S; _ = cap(s)`, `func(p.S) int`},
|
||||
{"cap", `var s P; _ = cap(s)`, `func(P) int`},
|
||||
|
||||
{"len", `_ = len("foo")`, `invalid type`}, // constant
|
||||
{"len", `var s string; _ = len(s)`, `func(string) int`},
|
||||
@ -37,6 +39,8 @@ var builtinCalls = []struct {
|
||||
{"len", `var s []int64; _ = len(s)`, `func([]int64) int`},
|
||||
{"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`},
|
||||
{"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`},
|
||||
{"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
|
||||
{"len", `var s P; _ = len(s)`, `func(P) int`},
|
||||
|
||||
{"close", `var c chan int; close(c)`, `func(chan int)`},
|
||||
{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
|
||||
@ -157,7 +161,7 @@ func TestBuiltinSignatures(t *testing.T) {
|
||||
// parseGenericSrc in types2 is not necessary. We can just parse in testBuiltinSignature below.
|
||||
|
||||
func testBuiltinSignature(t *testing.T, name, src0, want string) {
|
||||
src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _[P any]() { %s }`, src0)
|
||||
src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _[P ~[]byte]() { %s }`, src0)
|
||||
f, err := parser.ParseFile(fset, "", src, 0)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %s", src0, err)
|
||||
|
@ -279,7 +279,7 @@ func fib(x int) int {
|
||||
//
|
||||
// Types and Values of each expression:
|
||||
// 4: 8 | string | type : string
|
||||
// 6:15 | len | builtin : func(string) int
|
||||
// 6:15 | len | builtin : func(fib.S) int
|
||||
// 6:15 | len(b) | value : int
|
||||
// 6:19 | b | var : fib.S
|
||||
// 6:23 | S | type : fib.S
|
||||
|
Loading…
Reference in New Issue
Block a user