From: Robert Griesemer Date: Mon, 12 Sep 2022 22:51:32 +0000 (-0700) Subject: [release-branch.go1.19] go/types, types2: allow (string...) signature with NewSignatu... X-Git-Tag: go1.19.2~8 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=a366ed5982d674d7e468ccc5f8b6c5b8a402a00a;p=gostls13.git [release-branch.go1.19] 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 #55149. 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/+/431935 --- 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 1b61b368d2..2e518adc41 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 82177a1c58..b8ef42b288 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}