mirror of
https://github.com/golang/go
synced 2024-11-18 01:04:48 -07:00
go/types: factor out slice elem computation for copy built-in
This is a port of CL 357413 to go/types. Some test constraints are also updated to remove 'interface', to coincide with the corresponding test data file in types2. Change-Id: I5248190501c2e4381eb7625f8d4fb269301d6e16 Reviewed-on: https://go-review.googlesource.com/c/go/+/359138 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
61536ec030
commit
6f0185bf38
@ -330,33 +330,22 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
|
||||
case _Copy:
|
||||
// copy(x, y []T) int
|
||||
var dst Type
|
||||
if t := asSlice(x.typ); t != nil {
|
||||
dst = t.elem
|
||||
}
|
||||
dst, _ := singleUnder(x.typ).(*Slice)
|
||||
|
||||
var y operand
|
||||
arg(&y, 1)
|
||||
if y.mode == invalid {
|
||||
return
|
||||
}
|
||||
var src Type
|
||||
switch t := optype(y.typ).(type) {
|
||||
case *Basic:
|
||||
if isString(y.typ) {
|
||||
src = universeByte
|
||||
}
|
||||
case *Slice:
|
||||
src = t.elem
|
||||
}
|
||||
src, _ := singleUnderString(y.typ).(*Slice)
|
||||
|
||||
if dst == nil || src == nil {
|
||||
check.invalidArg(x, _InvalidCopy, "copy expects slice arguments; found %s and %s", x, &y)
|
||||
return
|
||||
}
|
||||
|
||||
if !Identical(dst, src) {
|
||||
check.invalidArg(x, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
|
||||
if !Identical(dst.elem, src.elem) {
|
||||
check.errorf(x, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst.elem, src.elem)
|
||||
return
|
||||
}
|
||||
|
||||
@ -783,6 +772,46 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
return true
|
||||
}
|
||||
|
||||
// If typ is a type parameter, single under returns the single underlying
|
||||
// type of all types in the corresponding type constraint if it exists, or
|
||||
// nil if it doesn't exist. If typ is not a type parameter, singleUnder
|
||||
// just returns the underlying type.
|
||||
func singleUnder(typ Type) Type {
|
||||
var su Type
|
||||
if underIs(typ, func(u Type) bool {
|
||||
if su != nil && !Identical(su, u) {
|
||||
return false
|
||||
}
|
||||
// su == nil || Identical(su, u)
|
||||
su = u
|
||||
return true
|
||||
}) {
|
||||
return su
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// singleUnderString is like singleUnder but also considers []byte and
|
||||
// string as "identical". In this case, if successful, the result is always
|
||||
// []byte.
|
||||
func singleUnderString(typ Type) Type {
|
||||
var su Type
|
||||
if underIs(typ, func(u Type) bool {
|
||||
if isString(u) {
|
||||
u = NewSlice(universeByte)
|
||||
}
|
||||
if su != nil && !Identical(su, u) {
|
||||
return false
|
||||
}
|
||||
// su == nil || Identical(su, u)
|
||||
su = u
|
||||
return true
|
||||
}) {
|
||||
return su
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// hasVarSize reports if the size of type t is variable due to type parameters.
|
||||
func hasVarSize(t Type) bool {
|
||||
switch t := under(t).(type) {
|
||||
|
18
src/go/types/testdata/check/builtins.go2
vendored
18
src/go/types/testdata/check/builtins.go2
vendored
@ -51,7 +51,7 @@ func _[T any](x, y T) {
|
||||
copy(x /* ERROR copy expects slice arguments */ , y)
|
||||
}
|
||||
|
||||
func _[T interface{~[]byte}](x, y T) {
|
||||
func _[T ~[]byte](x, y T) {
|
||||
copy(x, y)
|
||||
copy(x, "foo")
|
||||
copy("foo" /* ERROR expects slice arguments */ , y)
|
||||
@ -66,20 +66,26 @@ func _[T interface{~[]byte}](x, y T) {
|
||||
copy(y /* ERROR different element types */ , x3)
|
||||
}
|
||||
|
||||
func _[T interface{~[]E}, E any](x T, y []E) {
|
||||
func _[T ~[]E, E any](x T, y []E) {
|
||||
copy(x, y)
|
||||
copy(x /* ERROR different element types */ , "foo")
|
||||
}
|
||||
|
||||
func _[T interface{~string}](x []byte, y T) {
|
||||
func _[T ~string](x []byte, y T) {
|
||||
copy(x, y)
|
||||
copy(y /* ERROR expects slice arguments */ , x)
|
||||
}
|
||||
|
||||
func _[T interface{~[]byte|~string}](x T, y []byte) {
|
||||
func _[T ~[]byte|~string](x T, y []byte) {
|
||||
copy(x /* ERROR expects slice arguments */ , y)
|
||||
// TODO(gri) should this be valid?
|
||||
copy(y /* ERROR expects slice arguments */ , x)
|
||||
copy(y, x)
|
||||
}
|
||||
|
||||
type L0 []int
|
||||
type L1 []int
|
||||
|
||||
func _[T L0 | L1](x, y T) {
|
||||
copy(x, y)
|
||||
}
|
||||
|
||||
// delete
|
||||
|
Loading…
Reference in New Issue
Block a user