mirror of https://github.com/golang/go.git
go/types: ensure that we always get a new signature in expandNamed
CL 349412 introduced a bug when Checker.subst does not return a new signature: we were still setting the receiver to the instantiated type. I'm not sure how this could manifest in practice (other than confusing object strings). It's possible that I could generate a testdata-driven test for this, but in the interest of time I just added a test to verify object strings. Change-Id: I29bc8e1419ddc4574755c3def52d18cb71c738eb Reviewed-on: https://go-review.googlesource.com/c/go/+/350143 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
3fa7dbeff5
commit
3fa35b5f97
|
|
@ -6,6 +6,7 @@ package types_test
|
|||
|
||||
import (
|
||||
. "go/types"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -109,3 +110,45 @@ var X T[int]
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImmutableSignatures(t *testing.T) {
|
||||
const src = genericPkg + `p
|
||||
|
||||
type T[P any] struct{}
|
||||
|
||||
func (T[P]) m() {}
|
||||
|
||||
var _ T[int]
|
||||
`
|
||||
pkg, err := pkgFor(".", src, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
typ := pkg.Scope().Lookup("T").Type().(*Named)
|
||||
obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
|
||||
if obj == nil {
|
||||
t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
|
||||
}
|
||||
|
||||
// Verify that the original method is not mutated by instantiating T (this
|
||||
// bug manifested when subst did not return a new signature).
|
||||
want := "func (T[P]).m()"
|
||||
if got := stripAnnotations(ObjectString(obj, RelativeTo(pkg))); got != want {
|
||||
t.Errorf("instantiated %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from errors.go.
|
||||
func stripAnnotations(s string) string {
|
||||
var b strings.Builder
|
||||
for _, r := range s {
|
||||
// strip #'s and subscript digits
|
||||
if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
|
||||
b.WriteRune(r)
|
||||
}
|
||||
}
|
||||
if b.Len() < len(s) {
|
||||
return b.String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
|||
|
|
@ -309,6 +309,12 @@ func (check *Checker) completeMethod(env *Environment, m *Func) {
|
|||
|
||||
smap := makeSubstMap(origSig.RecvTypeParams().list(), rtyp.targs.list())
|
||||
sig := check.subst(orig.pos, origSig, smap, env).(*Signature)
|
||||
if sig == origSig {
|
||||
// No substitution occurred, but we still need to create a copy to hold the
|
||||
// instantiated receiver.
|
||||
copy := *origSig
|
||||
sig = ©
|
||||
}
|
||||
sig.recv = NewParam(origSig.recv.pos, origSig.recv.pkg, origSig.recv.name, rtyp)
|
||||
|
||||
m.typ = sig
|
||||
|
|
|
|||
Loading…
Reference in New Issue