From cdf64106f621b47987f332d5003afaefd9204b08 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 7 Nov 2025 15:50:14 -0800 Subject: [PATCH] go/types, types2: first argument to append must never be be nil The current implementation followed the spec faithfully for the special case for append. Per the spec: As a special case, append also accepts a first argument assignable to type []byte with a second argument of string type followed by ... . As it happens, nil is assignable to []byte, so append(nil, ""...) didn't get an error message but a subsequent assertion failed. This CL ensures that the first argument to append is never nil and always a slice. We should make the spec more precise (separate CL). Fixes #76220. Change-Id: I581d11827a75afbb257077814beea813d4fe2441 Reviewed-on: https://go-review.googlesource.com/c/go/+/718860 Auto-Submit: Robert Griesemer Reviewed-by: Alan Donovan Reviewed-by: Robert Griesemer Reviewed-by: Brett Howell LUCI-TryBot-Result: Go LUCI --- src/cmd/compile/internal/types2/builtins.go | 18 +++++++++++------- src/go/types/builtins.go | 18 +++++++++++------- .../types/testdata/fixedbugs/issue76220.go | 17 +++++++++++++++++ 3 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 src/internal/types/testdata/fixedbugs/issue76220.go diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index d4463bc4b0..549d94615b 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -91,6 +91,17 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( // to type []byte with a second argument of string type followed by ... . // This form appends the bytes of the string." + // In either case, the first argument must be a slice; in particular it + // cannot be the predeclared nil value. Note that nil is not excluded by + // the assignability requirement alone for the special case (go.dev/issue/76220). + // 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 + } + // Handle append(bytes, y...) special case, where // the type set of y is {string} or {string, []byte}. var sig *Signature @@ -119,13 +130,6 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( // 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 diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 04d294db0c..90a3b4a901 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -94,6 +94,17 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b // to type []byte with a second argument of string type followed by ... . // This form appends the bytes of the string." + // In either case, the first argument must be a slice; in particular it + // cannot be the predeclared nil value. Note that nil is not excluded by + // the assignability requirement alone for the special case (go.dev/issue/76220). + // 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 + } + // Handle append(bytes, y...) special case, where // the type set of y is {string} or {string, []byte}. var sig *Signature @@ -122,13 +133,6 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b // 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 diff --git a/src/internal/types/testdata/fixedbugs/issue76220.go b/src/internal/types/testdata/fixedbugs/issue76220.go new file mode 100644 index 0000000000..ad465010a0 --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue76220.go @@ -0,0 +1,17 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func _() { + append(nil /* ERROR "argument must be a slice; have untyped nil" */, ""...) +} + +// test case from issue + +func main() { + s := "hello" + msg := append(nil /* ERROR "argument must be a slice; have untyped nil" */, s...) + print(msg) +} -- 2.52.0