switch id {
case _Append:
// append(s S, x ...E) S, where E is the element type of S
- // spec: "The variadic function append appends zero or more values x to a slice s
- // of type S and returns the resulting slice, also of type S.
- // The values x are passed to a parameter of type ...E where E is the element type
- // of S and the respective parameter passing rules apply."
- S := x.typ
-
- // determine E
- var E Type
- typeset(S, func(_, u Type) bool {
- s, _ := u.(*Slice)
- if s == nil {
- var cause string
- if x.isNil() {
- // Printing x in this case would just print "nil".
- // Special case this so we can emphasize "untyped".
- cause = "untyped nil"
- } else {
- cause = check.sprintf("%s", x)
- }
- check.errorf(x, InvalidAppend, "invalid append: first argument must be a slice; have %s", cause)
- E = nil
- return false
- }
- if E == nil {
- E = s.elem
- } else if !Identical(E, s.elem) {
- check.errorf(x, InvalidAppend, "invalid append: mismatched slice element types %s and %s in %s", E, s.elem, x)
- E = nil
- return false
- }
- return true
- })
- if E == nil {
- return
- }
-
- // spec: "As a special case, append also accepts a first argument assignable
+ // spec: "The variadic function append appends zero or more values x to
+ // a slice s of type S and returns the resulting slice, also of type S.
+ // The values x are passed to a parameter of type ...E where E is the
+ // element type of S and the respective parameter passing rules apply.
+ // As a special case, append also accepts a first argument assignable
// to type []byte with a second argument of string type followed by ... .
// This form appends the bytes of the string."
+
+ // get special case out of the way
+ var sig *Signature
if nargs == 2 && hasDots(call) {
if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
- y := args[1] // valid if != nil
+ y := args[1]
typeset(y.typ, func(_, u Type) bool {
if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) {
return true
y = nil
return false
})
-
if y != nil {
- if check.recordTypes() {
- sig := makeSig(S, S, y.typ)
- sig.variadic = true
- check.recordBuiltinType(call.Fun, sig)
- }
- x.mode = value
- x.typ = S
- break
+ // setting the signature also signals that we're done
+ sig = makeSig(x.typ, x.typ, y.typ)
+ sig.variadic = true
}
}
}
- // check general case by creating custom signature
- sig := makeSig(S, S, NewSlice(E)) // []E required for variadic signature
- sig.variadic = true
- check.arguments(call, sig, nil, nil, args, nil) // discard result (we know the result type)
- // ok to continue even if check.arguments reported errors
+ // general case
+ if sig == nil {
+ // spec: "If S is a type parameter, all types in its type set
+ // must have the same underlying slice type []E."
+ E, err := sliceElem(x)
+ if err != nil {
+ check.errorf(x, InvalidAppend, "invalid append: %s", err.format(check))
+ return
+ }
+ // check arguments by creating custom signature
+ sig = makeSig(x.typ, x.typ, NewSlice(E)) // []E required for variadic signature
+ sig.variadic = true
+ check.arguments(call, sig, nil, nil, args, nil) // discard result (we know the result type)
+ // ok to continue even if check.arguments reported errors
+ }
- x.mode = value
- x.typ = S
if check.recordTypes() {
check.recordBuiltinType(call.Fun, sig)
}
+ x.mode = value
+ // x.typ is unchanged
case _Cap, _Len:
// cap(x)
x.typ = resTyp
case _Copy:
- // copy(x, y []T) int
- u, _ := commonUnder(x.typ, nil)
- dst, _ := u.(*Slice)
-
+ // copy(x, y []E) int
+ // spec: "The function copy copies slice elements from a source src to a destination
+ // dst and returns the number of elements copied. Both arguments must have identical
+ // element type E and must be assignable to a slice of type []E.
+ // The number of elements copied is the minimum of len(src) and len(dst).
+ // As a special case, copy also accepts a destination argument assignable to type
+ // []byte with a source argument of a string type.
+ // This form copies the bytes from the string into the byte slice."
+
+ // get special case out of the way
y := args[1]
- src0 := coreString(y.typ)
- if src0 != nil && isString(src0) {
- src0 = NewSlice(universeByte)
- }
- src, _ := src0.(*Slice)
-
- if dst == nil || src == nil {
- check.errorf(x, InvalidCopy, invalidArg+"copy expects slice arguments; found %s and %s", x, y)
- return
+ var special bool
+ if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
+ special = true
+ typeset(y.typ, func(_, u Type) bool {
+ if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) {
+ return true
+ }
+ if isString(u) {
+ return true
+ }
+ special = false
+ return false
+ })
}
- if !Identical(dst.elem, src.elem) {
- check.errorf(x, InvalidCopy, invalidArg+"arguments to copy %s and %s have different element types %s and %s", x, y, dst.elem, src.elem)
- return
+ // general case
+ if !special {
+ // spec: "If the type of one or both arguments is a type parameter, all types
+ // in their respective type sets must have the same underlying slice type []E."
+ dstE, err := sliceElem(x)
+ if err != nil {
+ check.errorf(x, InvalidCopy, "invalid copy: %s", err.format(check))
+ return
+ }
+ srcE, err := sliceElem(y)
+ if err != nil {
+ // If we have a string, for a better error message proceed with byte element type.
+ if !allString(y.typ) {
+ check.errorf(y, InvalidCopy, "invalid copy: %s", err.format(check))
+ return
+ }
+ srcE = universeByte
+ }
+ if !Identical(dstE, srcE) {
+ check.errorf(x, InvalidCopy, "invalid copy: arguments %s and %s have different element types %s and %s", x, y, dstE, srcE)
+ return
+ }
}
if check.recordTypes() {
return true
}
+// sliceElem returns the slice element type for a slice operand x
+// or a type error if x is not a slice (or a type set of slices).
+func sliceElem(x *operand) (Type, *typeError) {
+ var E Type
+ var err *typeError
+ typeset(x.typ, func(_, u Type) bool {
+ s, _ := u.(*Slice)
+ if s == nil {
+ if x.isNil() {
+ // Printing x in this case would just print "nil".
+ // Special case this so we can emphasize "untyped".
+ err = typeErrorf("argument must be a slice; have untyped nil")
+ } else {
+ err = typeErrorf("argument must be a slice; have %s", x)
+ }
+ return false
+ }
+ if E == nil {
+ E = s.elem
+ } else if !Identical(E, s.elem) {
+ err = typeErrorf("mismatched slice element types %s and %s in %s", E, s.elem, x)
+ return false
+ }
+ return true
+ })
+ if err != nil {
+ return nil, err
+ }
+ return E, nil
+}
+
// hasVarSize reports if the size of type t is variable due to type parameters
// or if the type is infinitely-sized due to a cycle for which the type has not
// yet been checked.
var err *typeError
bad := func(format string, args ...any) bool {
- cu = nil
err = typeErrorf(format, args...)
return false
}
typeset(t, func(t, u Type) bool {
if cond != nil {
if err = cond(t, u); err != nil {
- cu = nil
return false
}
}
return true
})
- return cu, err
+ if err != nil {
+ return nil, err
+ }
+ return cu, nil
}
// coreString is like coreType but also considers []byte
switch id {
case _Append:
// append(s S, x ...E) S, where E is the element type of S
- // spec: "The variadic function append appends zero or more values x to a slice s
- // of type S and returns the resulting slice, also of type S.
- // The values x are passed to a parameter of type ...E where E is the element type
- // of S and the respective parameter passing rules apply."
- S := x.typ
-
- // determine E
- var E Type
- typeset(S, func(_, u Type) bool {
- s, _ := u.(*Slice)
- if s == nil {
- var cause string
- if x.isNil() {
- // Printing x in this case would just print "nil".
- // Special case this so we can emphasize "untyped".
- cause = "untyped nil"
- } else {
- cause = check.sprintf("%s", x)
- }
- check.errorf(x, InvalidAppend, "invalid append: first argument must be a slice; have %s", cause)
- E = nil
- return false
- }
- if E == nil {
- E = s.elem
- } else if !Identical(E, s.elem) {
- check.errorf(x, InvalidAppend, "invalid append: mismatched slice element types %s and %s in %s", E, s.elem, x)
- E = nil
- return false
- }
- return true
- })
- if E == nil {
- return
- }
-
- // spec: "As a special case, append also accepts a first argument assignable
+ // spec: "The variadic function append appends zero or more values x to
+ // a slice s of type S and returns the resulting slice, also of type S.
+ // The values x are passed to a parameter of type ...E where E is the
+ // element type of S and the respective parameter passing rules apply.
+ // As a special case, append also accepts a first argument assignable
// to type []byte with a second argument of string type followed by ... .
// This form appends the bytes of the string."
+
+ // get special case out of the way
+ var sig *Signature
if nargs == 2 && hasDots(call) {
if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
- y := args[1] // valid if != nil
+ y := args[1]
typeset(y.typ, func(_, u Type) bool {
if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) {
return true
y = nil
return false
})
-
if y != nil {
- if check.recordTypes() {
- sig := makeSig(S, S, y.typ)
- sig.variadic = true
- check.recordBuiltinType(call.Fun, sig)
- }
- x.mode = value
- x.typ = S
- break
+ // setting the signature also signals that we're done
+ sig = makeSig(x.typ, x.typ, y.typ)
+ sig.variadic = true
}
}
}
- // check general case by creating custom signature
- sig := makeSig(S, S, NewSlice(E)) // []E required for variadic signature
- sig.variadic = true
- check.arguments(call, sig, nil, nil, args, nil) // discard result (we know the result type)
- // ok to continue even if check.arguments reported errors
+ // general case
+ if sig == nil {
+ // spec: "If S is a type parameter, all types in its type set
+ // must have the same underlying slice type []E."
+ E, err := sliceElem(x)
+ if err != nil {
+ check.errorf(x, InvalidAppend, "invalid append: %s", err.format(check))
+ return
+ }
+ // check arguments by creating custom signature
+ sig = makeSig(x.typ, x.typ, NewSlice(E)) // []E required for variadic signature
+ sig.variadic = true
+ check.arguments(call, sig, nil, nil, args, nil) // discard result (we know the result type)
+ // ok to continue even if check.arguments reported errors
+ }
- x.mode = value
- x.typ = S
if check.recordTypes() {
check.recordBuiltinType(call.Fun, sig)
}
+ x.mode = value
+ // x.typ is unchanged
case _Cap, _Len:
// cap(x)
x.typ = resTyp
case _Copy:
- // copy(x, y []T) int
- u, _ := commonUnder(x.typ, nil)
- dst, _ := u.(*Slice)
-
+ // copy(x, y []E) int
+ // spec: "The function copy copies slice elements from a source src to a destination
+ // dst and returns the number of elements copied. Both arguments must have identical
+ // element type E and must be assignable to a slice of type []E.
+ // The number of elements copied is the minimum of len(src) and len(dst).
+ // As a special case, copy also accepts a destination argument assignable to type
+ // []byte with a source argument of a string type.
+ // This form copies the bytes from the string into the byte slice."
+
+ // get special case out of the way
y := args[1]
- src0 := coreString(y.typ)
- if src0 != nil && isString(src0) {
- src0 = NewSlice(universeByte)
- }
- src, _ := src0.(*Slice)
-
- if dst == nil || src == nil {
- check.errorf(x, InvalidCopy, invalidArg+"copy expects slice arguments; found %s and %s", x, y)
- return
+ var special bool
+ if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
+ special = true
+ typeset(y.typ, func(_, u Type) bool {
+ if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) {
+ return true
+ }
+ if isString(u) {
+ return true
+ }
+ special = false
+ return false
+ })
}
- if !Identical(dst.elem, src.elem) {
- check.errorf(x, InvalidCopy, invalidArg+"arguments to copy %s and %s have different element types %s and %s", x, y, dst.elem, src.elem)
- return
+ // general case
+ if !special {
+ // spec: "If the type of one or both arguments is a type parameter, all types
+ // in their respective type sets must have the same underlying slice type []E."
+ dstE, err := sliceElem(x)
+ if err != nil {
+ check.errorf(x, InvalidCopy, "invalid copy: %s", err.format(check))
+ return
+ }
+ srcE, err := sliceElem(y)
+ if err != nil {
+ // If we have a string, for a better error message proceed with byte element type.
+ if !allString(y.typ) {
+ check.errorf(y, InvalidCopy, "invalid copy: %s", err.format(check))
+ return
+ }
+ srcE = universeByte
+ }
+ if !Identical(dstE, srcE) {
+ check.errorf(x, InvalidCopy, "invalid copy: arguments %s and %s have different element types %s and %s", x, y, dstE, srcE)
+ return
+ }
}
if check.recordTypes() {
return true
}
+// sliceElem returns the slice element type for a slice operand x
+// or a type error if x is not a slice (or a type set of slices).
+func sliceElem(x *operand) (Type, *typeError) {
+ var E Type
+ var err *typeError
+ typeset(x.typ, func(_, u Type) bool {
+ s, _ := u.(*Slice)
+ if s == nil {
+ if x.isNil() {
+ // Printing x in this case would just print "nil".
+ // Special case this so we can emphasize "untyped".
+ err = typeErrorf("argument must be a slice; have untyped nil")
+ } else {
+ err = typeErrorf("argument must be a slice; have %s", x)
+ }
+ return false
+ }
+ if E == nil {
+ E = s.elem
+ } else if !Identical(E, s.elem) {
+ err = typeErrorf("mismatched slice element types %s and %s in %s", E, s.elem, x)
+ return false
+ }
+ return true
+ })
+ if err != nil {
+ return nil, err
+ }
+ return E, nil
+}
+
// hasVarSize reports if the size of type t is variable due to type parameters
// or if the type is infinitely-sized due to a cycle for which the type has not
// yet been checked.
var err *typeError
bad := func(format string, args ...any) bool {
- cu = nil
err = typeErrorf(format, args...)
return false
}
typeset(t, func(t, u Type) bool {
if cond != nil {
if err = cond(t, u); err != nil {
- cu = nil
return false
}
}
return true
})
- return cu, err
+ if err != nil {
+ return nil, err
+ }
+ return cu, nil
}
// coreString is like coreType but also considers []byte
func copy1() {
copy() // ERROR "not enough arguments"
copy("foo") // ERROR "not enough arguments"
- copy([ /* ERROR "copy expects slice arguments" */ ...]int{}, []int{})
- copy([ /* ERROR "copy expects slice arguments" */ ]int{}, [...]int{})
- copy([ /* ERROR "different element types" */ ]int8{}, "foo")
+ copy([ /* ERROR "invalid copy: argument must be a slice; have [...]int{} (value of type [0]int)" */ ...]int{}, []int{})
+ copy([]int{}, [ /* ERROR "invalid copy: argument must be a slice; have [...]int{} (value of type [0]int)" */ ...]int{})
+ copy([ /* ERROR "invalid copy: arguments []int8{} (value of type []int8) and \"foo\" (untyped string constant) have different element types int8 and byte" */ ]int8{}, "foo")
// spec examples
var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
var t [][]int
copy(t, t)
- copy(t /* ERROR "copy expects slice arguments" */ , nil)
- copy(nil /* ERROR "copy expects slice arguments" */ , t)
- copy(nil /* ERROR "copy expects slice arguments" */ , nil)
+ copy(t, nil /* ERROR "invalid copy: argument must be a slice; have untyped nil" */ )
+ copy(nil /* ERROR "invalid copy: argument must be a slice; have untyped nil" */ , t)
+ copy(nil /* ERROR "invalid copy: argument must be a slice; have untyped nil" */ , nil)
copy(t... /* ERROR "invalid use of ..." */ )
}
// copy
func _[T any](x, y T) {
- copy(x /* ERROR "copy expects slice arguments" */ , y)
+ copy(x /* ERROR "invalid copy: argument must be a slice; have x (variable of type T constrained by any)" */ , y)
}
func _[T ~[]byte](x, y T) {
copy(x, y)
copy(x, "foo")
- copy("foo" /* ERROR "expects slice arguments" */ , y)
+ copy("foo" /* ERROR "argument must be a slice; have \"foo\" (untyped string constant)" */ , y)
var x2 []byte
copy(x2, y) // element types are identical
func _[T ~[]E, E any](x T, y []E) {
copy(x, y)
- copy(x /* ERROR "different element types" */ , "foo")
+ copy(x /* ERROR "arguments x (variable of type T constrained by ~[]E) and \"foo\" (untyped string constant) have different element types E and byte" */ , "foo")
}
func _[T ~string](x []byte, y T) {
copy(x, y)
- copy(y /* ERROR "expects slice arguments" */ , x)
+ copy([ /* ERROR "arguments []int{} (value of type []int) and y (variable of type T constrained by ~string) have different element types int and byte" */ ]int{}, y)
+ copy(y /* ERROR "argument must be a slice; have y (variable of type T constrained by ~string)" */ , x)
}
func _[T ~[]byte|~string](x T, y []byte) {
- copy(x /* ERROR "expects slice arguments" */ , y)
+ copy(x /* ERROR "argument must be a slice; have x (variable of type T constrained by ~[]byte | ~string)" */ , y)
copy(y, x)
}
package p
func _[P1 any, P2 ~byte, P3 []int | []byte](s1 P1, s2 P2, s3 P3) {
- _ = append(nil /* ERROR "invalid append: first argument must be a slice; have untyped nil" */, 0)
- _ = append(s1 /* ERROR "invalid append: first argument must be a slice; have s1 (variable of type P1 constrained by any)" */, 0)
- _ = append(s2 /* ERROR "invalid append: first argument must be a slice; have s2 (variable of type P2 constrained by ~byte)" */, 0)
+ _ = append(nil /* ERROR "invalid append: argument must be a slice; have untyped nil" */, 0)
+ _ = append(s1 /* ERROR "invalid append: argument must be a slice; have s1 (variable of type P1 constrained by any)" */, 0)
+ _ = append(s2 /* ERROR "invalid append: argument must be a slice; have s2 (variable of type P2 constrained by ~byte)" */, 0)
_ = append(s3 /* ERROR "invalid append: mismatched slice element types int and byte in s3 (variable of type P3 constrained by []int | []byte)" */, 0)
}
_ = copy(si, "hi") // ERROR "have different element types(.*int.*string| int and byte)"
_ = copy(si, sf) // ERROR "have different element types.*int.*float64"
- _ = copy(1, 2) // ERROR "must be slices; have int, int|expects slice arguments"
- _ = copy(1, si) // ERROR "first argument to copy should be|expects slice arguments"
- _ = copy(si, 2) // ERROR "second argument to copy should be|expects slice arguments"
+ _ = copy(1, 2) // ERROR "must be slices; have int, int|argument must be a slice; have 1"
+ _ = copy(1, si) // ERROR "first argument to copy should be|argument must be a slice; have 1"
+ _ = copy(si, 2) // ERROR "second argument to copy should be|argument must be a slice; have 2"
}
package main
func main() {
- _ = copy(nil, []int{}) // ERROR "use of untyped nil|left argument must be a slice|expects slice arguments"
- _ = copy([]int{}, nil) // ERROR "use of untyped nil|second argument must be slice or string|expects slice arguments"
+ _ = copy(nil, []int{}) // ERROR "use of untyped nil|left argument must be a slice|argument must be a slice; have untyped nil"
+ _ = copy([]int{}, nil) // ERROR "use of untyped nil|second argument must be slice or string|argument must be a slice; have untyped nil"
_ = 1 + true // ERROR "mismatched types untyped int and untyped bool|incompatible types|cannot convert"
}