Skip to content

Commit

Permalink
[release-branch.go1.19] go/types, types2: allow (string...) signature…
Browse files Browse the repository at this point in the history
… 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 <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/431935
  • Loading branch information
griesemer authored and cherrymui committed Sep 21, 2022
1 parent 4b0e03d commit a366ed5
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 9 deletions.
37 changes: 37 additions & 0 deletions src/cmd/compile/internal/types2/issues_test.go
Expand Up @@ -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})))
}
}
15 changes: 10 additions & 5 deletions src/cmd/compile/internal/types2/signature.go
Expand Up @@ -4,7 +4,10 @@

package types2

import "cmd/compile/internal/syntax"
import (
"cmd/compile/internal/syntax"
"fmt"
)

// ----------------------------------------------------------------------------
// API
Expand All @@ -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}
Expand Down
37 changes: 37 additions & 0 deletions src/go/types/issues_test.go
Expand Up @@ -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})))
}
}
11 changes: 7 additions & 4 deletions src/go/types/signature.go
Expand Up @@ -5,6 +5,7 @@
package types

import (
"fmt"
"go/ast"
"go/token"
)
Expand Down Expand Up @@ -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}
Expand Down

0 comments on commit a366ed5

Please sign in to comment.