mirror of
https://github.com/golang/go
synced 2024-10-14 11:53:56 +00:00
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>
This commit is contained in:
parent
dfc86e922c
commit
01064622a2
1
api/next/65772.txt
Normal file
1
api/next/65772.txt
Normal file
|
@ -0,0 +1 @@
|
|||
pkg go/types, method (*Func) Signature() *Signature #65772
|
4
doc/next/6-stdlib/99-minor/go/types/65772.md
Normal file
4
doc/next/6-stdlib/99-minor/go/types/65772.md
Normal file
|
@ -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`.
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)},
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue