]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: allow (string...) signature with NewSignatureType
authorRobert Griesemer <gri@golang.org>
Mon, 12 Sep 2022 22:51:32 +0000 (15:51 -0700)
committerGopher Robot <gobot@golang.org>
Fri, 16 Sep 2022 16:18:44 +0000 (16:18 +0000)
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 #55030.

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>

src/cmd/compile/internal/types2/issues_test.go
src/cmd/compile/internal/types2/signature.go
src/go/types/issues_test.go
src/go/types/signature.go

index 8588687803169e8e2709e7408f2c1bd4e991ddcd..b77e8a8fe1c857693d4adb486871ea967460577c 100644 (file)
@@ -636,3 +636,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})))
+       }
+}
index 3f1066e050af88abf22c186d62ee93ccce45cc3c..07399f77aa1281ce44e32f9d5f86846551a96cf5 100644 (file)
@@ -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}
index d46d085ba877e67f4ec2ffee747d1cbb12a348e0..4f926ed421c4a7ff7d18afe5d9679f6856a7c92e 100644 (file)
@@ -663,3 +663,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})))
+       }
+}
index f44d257d8f53b6b2aecff9459176f9d726b9be88..918f8a9733a1fbf149633a679ac57955c63ab3bd 100644 (file)
@@ -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}