mirror of
https://github.com/golang/go
synced 2024-09-29 02:24:33 -06:00
go/types: allow slicing for operands with []byte|string type sets
This is a port of CL 363662 from types2 to go/types. An error message was adjusted to be on the operand in test data. Change-Id: I4d2d69976f4f05e0d89ba1c6bf8b3e4cf1a82316 Reviewed-on: https://go-review.googlesource.com/c/go/+/364899 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
353cb71ea2
commit
ce7e5013a6
@ -342,26 +342,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
if y.mode == invalid {
|
||||
return
|
||||
}
|
||||
// src, _ := structuralType(y.typ).(*Slice); but also accepts strings
|
||||
var src *Slice
|
||||
var elem Type // == src.elem if valid
|
||||
if underIs(y.typ, func(u Type) bool {
|
||||
switch u := u.(type) {
|
||||
case *Basic:
|
||||
if isString(u) && (elem == nil || Identical(elem, universeByte)) {
|
||||
elem = universeByte
|
||||
return true
|
||||
}
|
||||
case *Slice:
|
||||
if elem == nil || Identical(elem, u.elem) {
|
||||
elem = u.elem
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}) {
|
||||
src = NewSlice(elem)
|
||||
src0 := structuralString(y.typ)
|
||||
if src0 != nil && isString(src0) {
|
||||
src0 = NewSlice(universeByte)
|
||||
}
|
||||
src, _ := src0.(*Slice)
|
||||
|
||||
if dst == nil || src == nil {
|
||||
check.invalidArg(x, _InvalidCopy, "copy expects slice arguments; found %s and %s", x, &y)
|
||||
|
@ -214,7 +214,7 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
|
||||
|
||||
valid := false
|
||||
length := int64(-1) // valid if >= 0
|
||||
switch u := structuralType(x.typ).(type) {
|
||||
switch u := structuralString(x.typ).(type) {
|
||||
case nil:
|
||||
check.invalidOp(x, _NonSliceableOperand, "cannot slice %s: %s has no structural type", x, x.typ)
|
||||
x.mode = invalid
|
||||
@ -233,7 +233,7 @@ func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
|
||||
}
|
||||
// spec: "For untyped string operands the result
|
||||
// is a non-constant value of type string."
|
||||
if u.kind == UntypedString {
|
||||
if isUntyped(x.typ) {
|
||||
x.typ = Typ[String]
|
||||
}
|
||||
}
|
||||
|
4
src/go/types/testdata/check/typeparams.go2
vendored
4
src/go/types/testdata/check/typeparams.go2
vendored
@ -136,6 +136,10 @@ type myByte2 []byte
|
||||
func _[T interface{ []byte | myByte1 | myByte2 }] (x T, i, j, k int) { var _ T = x[i:j:k] }
|
||||
func _[T interface{ []byte | myByte1 | []int }] (x T, i, j, k int) { var _ T = x /* ERROR no structural type */ [i:j:k] }
|
||||
|
||||
func _[T interface{ []byte | myByte1 | myByte2 | string }] (x T, i, j, k int) { var _ T = x[i:j] }
|
||||
func _[T interface{ []byte | myByte1 | myByte2 | string }] (x T, i, j, k int) { var _ T = x /* ERROR 3-index slice of string */ [i:j:k] }
|
||||
func _[T interface{ []byte | myByte1 | []int | string }] (x T, i, j, k int) { var _ T = x /* ERROR no structural type */ [i:j] }
|
||||
|
||||
// len/cap built-ins
|
||||
|
||||
func _[T any](x T) { _ = len(x /* ERROR invalid argument */ ) }
|
||||
|
@ -87,3 +87,40 @@ func structuralType(t Type) Type {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// structuralString is like structuralType but also considers []byte
|
||||
// and strings as identical. In this case, if successful and we saw
|
||||
// a string, the result is of type (possibly untyped) string.
|
||||
func structuralString(t Type) Type {
|
||||
tpar, _ := t.(*TypeParam)
|
||||
if tpar == nil {
|
||||
return under(t) // string or untyped string
|
||||
}
|
||||
|
||||
var su Type
|
||||
hasString := false
|
||||
if tpar.underIs(func(u Type) bool {
|
||||
if u == nil {
|
||||
return false
|
||||
}
|
||||
if isString(u) {
|
||||
u = NewSlice(universeByte)
|
||||
hasString = true
|
||||
}
|
||||
if su != nil {
|
||||
u = match(su, u)
|
||||
if u == nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// su == nil || match(su, u) != nil
|
||||
su = u
|
||||
return true
|
||||
}) {
|
||||
if hasString {
|
||||
return Typ[String]
|
||||
}
|
||||
return su
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user