From e40a130cc02cca954ff8e33aa9f5950ecab99e3b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 12 Sep 2022 15:51:32 -0700 Subject: [PATCH] [release-branch.go1.18] go/types, types2: allow (string...) signature with NewSignatureType Includes cases where the core type of the variadic parameter is a slice or bytestring. Permits a client to create the signature for various instantiations of append. Fixes #55148. Change-Id: I0f4983eb00c088cbe1d87954ee0b2df0ccc3bc49 Reviewed-on: https://go-review.googlesource.com/c/go/+/430455 TryBot-Result: Gopher Robot Reviewed-by: Robert Findley Auto-Submit: Robert Griesemer Reviewed-by: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-on: https://go-review.googlesource.com/c/go/+/431915 --- .../compile/internal/types2/issues_test.go | 37 +++++++++++++++++++ src/cmd/compile/internal/types2/signature.go | 15 +++++--- src/go/types/issues_test.go | 37 +++++++++++++++++++ src/go/types/signature.go | 11 ++++-- 4 files changed, 91 insertions(+), 9 deletions(-) diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go index 697a73525c..fc4aeb1634 100644 --- a/src/cmd/compile/internal/types2/issues_test.go +++ b/src/cmd/compile/internal/types2/issues_test.go @@ -637,3 +637,40 @@ func TestIssue50646(t *testing.T) { t.Errorf("comparable not assignable to any") } } + +func TestIssue55030(t *testing.T) { + // makeSig makes the signature func(typ...) + makeSig := func(typ Type) { + par := NewVar(nopos, nil, "", typ) + params := NewTuple(par) + NewSignatureType(nil, nil, nil, params, nil, true) + } + + // makeSig must not panic for the following (example) types: + // []int + makeSig(NewSlice(Typ[Int])) + + // string + makeSig(Typ[String]) + + // P where P's core type is string + { + P := NewTypeName(nopos, nil, "P", nil) // [P string] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{Typ[String]}))) + } + + // P where P's core type is an (unnamed) slice + { + P := NewTypeName(nopos, nil, "P", nil) // [P []int] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{NewSlice(Typ[Int])}))) + } + + // P where P's core type is bytestring (i.e., string or []byte) + { + t1 := NewTerm(true, Typ[String]) // ~string + t2 := NewTerm(false, NewSlice(Typ[Byte])) // []byte + u := NewUnion([]*Term{t1, t2}) // ~string | []byte + P := NewTypeName(nopos, nil, "P", nil) // [P ~string | []byte] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{u}))) + } +} diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index c98024f924..f52f3e25b2 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -4,7 +4,10 @@ package types2 -import "cmd/compile/internal/syntax" +import ( + "cmd/compile/internal/syntax" + "fmt" +) // ---------------------------------------------------------------------------- // API @@ -28,16 +31,18 @@ type Signature struct { // NewSignatureType creates a new function type for the given receiver, // receiver type parameters, type parameters, parameters, and results. If // variadic is set, params must hold at least one parameter and the last -// parameter must be of unnamed slice type. If recv is non-nil, typeParams must -// be empty. If recvTypeParams is non-empty, recv must be non-nil. +// parameter's core type must be of unnamed slice or bytestring type. +// If recv is non-nil, typeParams must be empty. If recvTypeParams is +// non-empty, recv must be non-nil. func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params, results *Tuple, variadic bool) *Signature { if variadic { n := params.Len() if n == 0 { panic("variadic function must have at least one parameter") } - if _, ok := params.At(n - 1).typ.(*Slice); !ok { - panic("variadic parameter must be of unnamed slice type") + core := coreString(params.At(n - 1).typ) + if _, ok := core.(*Slice); !ok && !isString(core) { + panic(fmt.Sprintf("got %s, want variadic parameter with unnamed slice type or string as core type", core.String())) } } sig := &Signature{recv: recv, params: params, results: results, variadic: variadic} diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go index bd98f48177..2892aab38e 100644 --- a/src/go/types/issues_test.go +++ b/src/go/types/issues_test.go @@ -664,3 +664,40 @@ func TestIssue50646(t *testing.T) { t.Errorf("comparable not assignable to any") } } + +func TestIssue55030(t *testing.T) { + // makeSig makes the signature func(typ...) + makeSig := func(typ Type) { + par := NewVar(token.NoPos, nil, "", typ) + params := NewTuple(par) + NewSignatureType(nil, nil, nil, params, nil, true) + } + + // makeSig must not panic for the following (example) types: + // []int + makeSig(NewSlice(Typ[Int])) + + // string + makeSig(Typ[String]) + + // P where P's core type is string + { + P := NewTypeName(token.NoPos, nil, "P", nil) // [P string] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{Typ[String]}))) + } + + // P where P's core type is an (unnamed) slice + { + P := NewTypeName(token.NoPos, nil, "P", nil) // [P []int] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{NewSlice(Typ[Int])}))) + } + + // P where P's core type is bytestring (i.e., string or []byte) + { + t1 := NewTerm(true, Typ[String]) // ~string + t2 := NewTerm(false, NewSlice(Typ[Byte])) // []byte + u := NewUnion([]*Term{t1, t2}) // ~string | []byte + P := NewTypeName(token.NoPos, nil, "P", nil) // [P ~string | []byte] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{u}))) + } +} diff --git a/src/go/types/signature.go b/src/go/types/signature.go index a340ac701e..d22646d7a8 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -5,6 +5,7 @@ package types import ( + "fmt" "go/ast" "go/token" ) @@ -41,16 +42,18 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { // NewSignatureType creates a new function type for the given receiver, // receiver type parameters, type parameters, parameters, and results. If // variadic is set, params must hold at least one parameter and the last -// parameter must be of unnamed slice type. If recv is non-nil, typeParams must -// be empty. If recvTypeParams is non-empty, recv must be non-nil. +// parameter's core type must be of unnamed slice or bytestring type. +// If recv is non-nil, typeParams must be empty. If recvTypeParams is +// non-empty, recv must be non-nil. func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params, results *Tuple, variadic bool) *Signature { if variadic { n := params.Len() if n == 0 { panic("variadic function must have at least one parameter") } - if _, ok := params.At(n - 1).typ.(*Slice); !ok { - panic("variadic parameter must be of unnamed slice type") + core := coreString(params.At(n - 1).typ) + if _, ok := core.(*Slice); !ok && !isString(core) { + panic(fmt.Sprintf("got %s, want variadic parameter with unnamed slice type or string as core type", core.String())) } } sig := &Signature{recv: recv, params: params, results: results, variadic: variadic} -- 2.48.1