mirror of
https://github.com/golang/go
synced 2024-11-24 16:20:13 -07:00
cmd/compile/internal/types2: factor out slice elem computation for copy built-in
Implement singleUnder[String] which determines a single underlying type for a given type: either the underlying type, or the single underlying type for a type parameter, if it exists. Use singleUnder[String] instead of optype for copy built-in. This CL removes a dependency on optype and also makes the copy built-in slighty more general for generic arguments (the source argument may be constrained by a slice or string simultaneously). Change-Id: Ia329e96afc69a09d2ca3b1f82fe712d4f7ba1d9f Reviewed-on: https://go-review.googlesource.com/c/go/+/357413 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
b0f7eb6c0d
commit
3cd28baffd
@ -325,33 +325,22 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
|||||||
|
|
||||||
case _Copy:
|
case _Copy:
|
||||||
// copy(x, y []T) int
|
// copy(x, y []T) int
|
||||||
var dst Type
|
dst, _ := singleUnder(x.typ).(*Slice)
|
||||||
if t := asSlice(x.typ); t != nil {
|
|
||||||
dst = t.elem
|
|
||||||
}
|
|
||||||
|
|
||||||
var y operand
|
var y operand
|
||||||
arg(&y, 1)
|
arg(&y, 1)
|
||||||
if y.mode == invalid {
|
if y.mode == invalid {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var src Type
|
src, _ := singleUnderString(y.typ).(*Slice)
|
||||||
switch t := optype(y.typ).(type) {
|
|
||||||
case *Basic:
|
|
||||||
if isString(y.typ) {
|
|
||||||
src = universeByte
|
|
||||||
}
|
|
||||||
case *Slice:
|
|
||||||
src = t.elem
|
|
||||||
}
|
|
||||||
|
|
||||||
if dst == nil || src == nil {
|
if dst == nil || src == nil {
|
||||||
check.errorf(x, invalidArg+"copy expects slice arguments; found %s and %s", x, &y)
|
check.errorf(x, invalidArg+"copy expects slice arguments; found %s and %s", x, &y)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Identical(dst, src) {
|
if !Identical(dst.elem, src.elem) {
|
||||||
check.errorf(x, invalidArg+"arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
|
check.errorf(x, invalidArg+"arguments to copy %s and %s have different element types %s and %s", x, &y, dst.elem, src.elem)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -774,6 +763,46 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
|||||||
return true
|
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.
|
// hasVarSize reports if the size of type t is variable due to type parameters.
|
||||||
func hasVarSize(t Type) bool {
|
func hasVarSize(t Type) bool {
|
||||||
switch t := under(t).(type) {
|
switch t := under(t).(type) {
|
||||||
|
@ -78,8 +78,14 @@ func _[T ~string](x []byte, y T) {
|
|||||||
|
|
||||||
func _[T ~[]byte|~string](x T, y []byte) {
|
func _[T ~[]byte|~string](x T, y []byte) {
|
||||||
copy(x /* ERROR expects slice arguments */ , y)
|
copy(x /* ERROR expects slice arguments */ , y)
|
||||||
// TODO(gri) should this be valid?
|
copy(y, x)
|
||||||
copy(y /* ERROR expects slice arguments */ , x)
|
}
|
||||||
|
|
||||||
|
type L0 []int
|
||||||
|
type L1 []int
|
||||||
|
|
||||||
|
func _[T L0 | L1](x, y T) {
|
||||||
|
copy(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
|
Loading…
Reference in New Issue
Block a user