aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Donovan <adonovan@google.com>2024-02-20 10:24:21 -0500
committerAlan Donovan <adonovan@google.com>2024-04-18 22:17:27 +0000
commit01064622a21f921a54c4442ef9f5436c89e998c7 (patch)
tree70afcc4ef2212f3b90c36d8fc5237faf72e3ce8a
parentdfc86e922cd033155339c22aff64e109f6c8cc89 (diff)
downloadgo-01064622a21f921a54c4442ef9f5436c89e998c7.tar.gz
go-01064622a21f921a54c4442ef9f5436c89e998c7.zip
go/types: add Func.Signature method
Unfortunately we can't enforce the repr invariant that Func.typ != nil without thinking about the object color invariants. For now, return a trivial Signature if typ == nil, which should never happen in bug-free client code. Fixes golang/go#65772 Change-Id: I7f89c6d8fdc8dcd4b8880572e54bb0ed9b6136eb Reviewed-on: https://go-review.googlesource.com/c/go/+/565375 Commit-Queue: Robert Griesemer <gri@google.com> Reviewed-by: Robert Findley <rfindley@google.com> Reviewed-by: Robert Griesemer <gri@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
-rw-r--r--api/next/65772.txt1
-rw-r--r--doc/next/6-stdlib/99-minor/go/types/65772.md4
-rw-r--r--src/cmd/compile/internal/types2/object.go22
-rw-r--r--src/cmd/compile/internal/types2/subst.go2
-rw-r--r--src/go/types/api_test.go8
-rw-r--r--src/go/types/issues_test.go4
-rw-r--r--src/go/types/object.go22
-rw-r--r--src/go/types/resolver.go4
-rw-r--r--src/go/types/subst.go2
9 files changed, 57 insertions, 12 deletions
diff --git a/api/next/65772.txt b/api/next/65772.txt
new file mode 100644
index 0000000000..1244df8dd3
--- /dev/null
+++ b/api/next/65772.txt
@@ -0,0 +1 @@
+pkg go/types, method (*Func) Signature() *Signature #65772
diff --git a/doc/next/6-stdlib/99-minor/go/types/65772.md b/doc/next/6-stdlib/99-minor/go/types/65772.md
new file mode 100644
index 0000000000..33e949db3d
--- /dev/null
+++ b/doc/next/6-stdlib/99-minor/go/types/65772.md
@@ -0,0 +1,4 @@
+The [`Func`](/go/types#Func) type, which represents a function or
+method symbol, now has a [`Signature`](/go/types#Func.Signature)
+method that returns the function's type, which is always a
+`Signature`. \ No newline at end of file
diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go
index 776986f111..3026777cad 100644
--- a/src/cmd/compile/internal/types2/object.go
+++ b/src/cmd/compile/internal/types2/object.go
@@ -374,14 +374,34 @@ type Func struct {
// NewFunc returns a new function with the given signature, representing
// the function's type.
func NewFunc(pos syntax.Pos, pkg *Package, name string, sig *Signature) *Func {
- // don't store a (typed) nil signature
var typ Type
if sig != nil {
typ = sig
+ } else {
+ // Don't store a (typed) nil *Signature.
+ // We can't simply replace it with new(Signature) either,
+ // as this would violate object.{Type,color} invariants.
+ // TODO(adonovan): propose to disallow NewFunc with nil *Signature.
}
return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, false, nil}
}
+// Signature returns the signature (type) of the function or method.
+func (obj *Func) Signature() *Signature {
+ if obj.typ != nil {
+ return obj.typ.(*Signature) // normal case
+ }
+ // No signature: Signature was called either:
+ // - within go/types, before a FuncDecl's initially
+ // nil Func.Type was lazily populated, indicating
+ // a types bug; or
+ // - by a client after NewFunc(..., nil),
+ // which is arguably a client bug, but we need a
+ // proposal to tighten NewFunc's precondition.
+ // For now, return a trivial signature.
+ return new(Signature)
+}
+
// FullName returns the package- or receiver-type-qualified name of
// function or method obj.
func (obj *Func) FullName() string {
diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go
index fa636a1e1e..215d1f2d4f 100644
--- a/src/cmd/compile/internal/types2/subst.go
+++ b/src/cmd/compile/internal/types2/subst.go
@@ -421,7 +421,7 @@ func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) {
func replaceRecvType(in []*Func, old, new Type) (out []*Func, copied bool) {
out = in
for i, method := range in {
- sig := method.Type().(*Signature)
+ sig := method.Signature()
if sig.recv != nil && sig.recv.Type() == old {
if !copied {
// Allocate a new methods slice before mutating for the first time.
diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go
index 5bc4e8a61f..564bbc2423 100644
--- a/src/go/types/api_test.go
+++ b/src/go/types/api_test.go
@@ -2324,7 +2324,7 @@ func f(x int) { y := x; print(y) }
wantParent = false
}
case *Func:
- if obj.Type().(*Signature).Recv() != nil { // method
+ if obj.Signature().Recv() != nil { // method
wantParent = false
}
}
@@ -2615,9 +2615,9 @@ func fn() {
// Methods and method fields
{"concreteMethod", lookup("t").(*Named).Method(0)},
- {"recv", lookup("t").(*Named).Method(0).Type().(*Signature).Recv()},
- {"mParam", lookup("t").(*Named).Method(0).Type().(*Signature).Params().At(0)},
- {"mResult", lookup("t").(*Named).Method(0).Type().(*Signature).Results().At(0)},
+ {"recv", lookup("t").(*Named).Method(0).Signature().Recv()},
+ {"mParam", lookup("t").(*Named).Method(0).Signature().Params().At(0)},
+ {"mResult", lookup("t").(*Named).Method(0).Signature().Results().At(0)},
// Interface methods
{"interfaceMethod", lookup("i").Underlying().(*Interface).Method(0)},
diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go
index 4f4bf6f077..379d833bf2 100644
--- a/src/go/types/issues_test.go
+++ b/src/go/types/issues_test.go
@@ -115,7 +115,7 @@ type T struct{} // receiver type after method declaration
}
m := f.Decls[0].(*ast.FuncDecl)
- res1 := defs[m.Name].(*Func).Type().(*Signature).Results().At(0)
+ res1 := defs[m.Name].(*Func).Signature().Results().At(0)
res2 := defs[m.Type.Results.List[0].Names[0]].(*Var)
if res1 != res2 {
@@ -369,7 +369,7 @@ func TestIssue28005(t *testing.T) {
// must match the method's name per the choice in the source file.
for i := 0; i < iface.NumMethods(); i++ {
m := iface.Method(i)
- recvName := m.Type().(*Signature).Recv().Type().(*Named).Obj().Name()
+ recvName := m.Signature().Recv().Type().(*Named).Obj().Name()
if recvName != m.Name() {
t.Errorf("perm %v: got recv %s; want %s", perm, recvName, m.Name())
}
diff --git a/src/go/types/object.go b/src/go/types/object.go
index 400b47ebe1..d564d37e7a 100644
--- a/src/go/types/object.go
+++ b/src/go/types/object.go
@@ -377,14 +377,34 @@ type Func struct {
// NewFunc returns a new function with the given signature, representing
// the function's type.
func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
- // don't store a (typed) nil signature
var typ Type
if sig != nil {
typ = sig
+ } else {
+ // Don't store a (typed) nil *Signature.
+ // We can't simply replace it with new(Signature) either,
+ // as this would violate object.{Type,color} invariants.
+ // TODO(adonovan): propose to disallow NewFunc with nil *Signature.
}
return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, false, nil}
}
+// Signature returns the signature (type) of the function or method.
+func (obj *Func) Signature() *Signature {
+ if obj.typ != nil {
+ return obj.typ.(*Signature) // normal case
+ }
+ // No signature: Signature was called either:
+ // - within go/types, before a FuncDecl's initially
+ // nil Func.Type was lazily populated, indicating
+ // a types bug; or
+ // - by a client after NewFunc(..., nil),
+ // which is arguably a client bug, but we need a
+ // proposal to tighten NewFunc's precondition.
+ // For now, return a trivial signature.
+ return new(Signature)
+}
+
// FullName returns the package- or receiver-type-qualified name of
// function or method obj.
func (obj *Func) FullName() string {
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index f336057c53..918e18de3e 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -395,8 +395,8 @@ func (check *Checker) collectObjects() {
check.declarePkgObj(d.spec.Name, obj, &declInfo{file: fileScope, tdecl: d.spec})
case funcDecl:
name := d.decl.Name.Name
- obj := NewFunc(d.decl.Name.Pos(), pkg, name, nil)
- hasTParamError := false // avoid duplicate type parameter errors
+ obj := NewFunc(d.decl.Name.Pos(), pkg, name, nil) // signature set later
+ hasTParamError := false // avoid duplicate type parameter errors
if d.decl.Recv.NumFields() == 0 {
// regular function
if d.decl.Recv != nil {
diff --git a/src/go/types/subst.go b/src/go/types/subst.go
index 1d180abb65..a3ea16d9b9 100644
--- a/src/go/types/subst.go
+++ b/src/go/types/subst.go
@@ -424,7 +424,7 @@ func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) {
func replaceRecvType(in []*Func, old, new Type) (out []*Func, copied bool) {
out = in
for i, method := range in {
- sig := method.Type().(*Signature)
+ sig := method.Signature()
if sig.recv != nil && sig.recv.Type() == old {
if !copied {
// Allocate a new methods slice before mutating for the first time.