// 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
+ // Handle append(bytes, y...) special case, where
+ // the type set of y is {string} or {string, []byte}.
var sig *Signature
if nargs == 2 && hasDots(call) {
if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
y := args[1]
+ hasString := false
typeset(y.typ, func(_, u Type) bool {
if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) {
return true
}
if isString(u) {
+ hasString = true
return true
}
y = nil
return false
})
- if y != nil {
+ if y != nil && hasString {
// setting the signature also signals that we're done
sig = makeSig(x.typ, x.typ, y.typ)
sig.variadic = true
t.Errorf("got:\n%s\nwant:\n%s", got, want)
}
}
+
+func TestIssue73871(t *testing.T) {
+ const src = `package p
+
+func f[T ~[]byte](y T) []byte { return append([]byte(nil), y...) }
+
+// for illustration only:
+type B []byte
+var _ = f[B]
+`
+ fset := token.NewFileSet()
+ f, _ := parser.ParseFile(fset, "p.go", src, 0)
+
+ pkg := NewPackage("p", "p")
+ info := &Info{Types: make(map[ast.Expr]TypeAndValue)}
+ check := NewChecker(&Config{}, fset, pkg, info)
+ if err := check.Files([]*ast.File{f}); err != nil {
+ t.Fatal(err)
+ }
+
+ // Check type inferred for 'append'.
+ //
+ // Before the fix, the inferred type of append's y parameter
+ // was T. When a client such as x/tools/go/ssa instantiated T=B,
+ // it would result in the Signature "func([]byte, B)" with the
+ // variadic flag set, an invalid combination that caused
+ // NewSignatureType to panic.
+ append := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.ReturnStmt).Results[0].(*ast.CallExpr).Fun
+ tAppend := info.TypeOf(append).(*Signature)
+ want := "func([]byte, ...byte) []byte"
+ if got := fmt.Sprint(tAppend); got != want {
+ // Before the fix, tAppend was func([]byte, T) []byte,
+ // where T prints as "<expected string type>".
+ t.Errorf("for append, inferred type %s, want %s", tAppend, want)
+ }
+}
// 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
+ // Handle append(bytes, y...) special case, where
+ // the type set of y is {string} or {string, []byte}.
var sig *Signature
if nargs == 2 && hasDots(call) {
if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
y := args[1]
+ hasString := false
typeset(y.typ, func(_, u Type) bool {
if s, _ := u.(*Slice); s != nil && Identical(s.elem, universeByte) {
return true
}
if isString(u) {
+ hasString = true
return true
}
y = nil
return false
})
- if y != nil {
+ if y != nil && hasString {
// setting the signature also signals that we're done
sig = makeSig(x.typ, x.typ, y.typ)
sig.variadic = true