--- /dev/null
+pkg go/types, method (*Func) Origin() *Func #51682
+pkg go/types, method (*Var) Origin() *Var #51682
field P
}
-func (recv *T[Q]) concreteMethod() {}
+func (recv *T[Q]) concreteMethod(mParam Q) (mResult Q) { return }
-type FT[P any] func(ftp P) (ftrp P)
+type FT[P any] func(ftParam P) (ftResult P)
-func F[P any](fp P) (frp P){ return }
+func F[P any](fParam P) (fResult P){ return }
type I[P any] interface {
interfaceMethod(P)
}
+type R[P any] T[P]
+
+func (R[P]) m() {} // having a method triggers expansion of R
+
var (
t T[int]
ft FT[int]
f = F[int]
i I[int]
)
+
+func fn() {
+ var r R[int]
+ _ = r
+}
`
info := &Info{
Defs: make(map[*syntax.Name]Object),
}
lookup := func(name string) Type { return pkg.Scope().Lookup(name).Type() }
+ fnScope := pkg.Scope().Lookup("fn").(*Func).Scope()
+
tests := []struct {
- ident string
- obj Object
+ name string
+ obj Object
}{
+ // Struct fields
{"field", lookup("t").Underlying().(*Struct).Field(0)},
+ {"field", fnScope.Lookup("r").Type().Underlying().(*Struct).Field(0)},
+
+ // Methods and method fields
{"concreteMethod", lookup("t").(*Named).Method(0)},
{"recv", lookup("t").(*Named).Method(0).Type().(*Signature).Recv()},
- {"ftp", lookup("ft").Underlying().(*Signature).Params().At(0)},
- {"ftrp", lookup("ft").Underlying().(*Signature).Results().At(0)},
- {"fp", lookup("f").(*Signature).Params().At(0)},
- {"frp", lookup("f").(*Signature).Results().At(0)},
+ {"mParam", lookup("t").(*Named).Method(0).Type().(*Signature).Params().At(0)},
+ {"mResult", lookup("t").(*Named).Method(0).Type().(*Signature).Results().At(0)},
+
+ // Interface methods
{"interfaceMethod", lookup("i").Underlying().(*Interface).Method(0)},
+
+ // Function type fields
+ {"ftParam", lookup("ft").Underlying().(*Signature).Params().At(0)},
+ {"ftResult", lookup("ft").Underlying().(*Signature).Results().At(0)},
+
+ // Function fields
+ {"fParam", lookup("f").(*Signature).Params().At(0)},
+ {"fResult", lookup("f").(*Signature).Results().At(0)},
}
// Collect all identifiers by name.
for _, test := range tests {
test := test
- t.Run(test.ident, func(t *testing.T) {
- if got := len(idents[test.ident]); got != 1 {
- t.Fatalf("found %d identifiers named %s, want 1", got, test.ident)
+ t.Run(test.name, func(t *testing.T) {
+ if got := len(idents[test.name]); got != 1 {
+ t.Fatalf("found %d identifiers named %s, want 1", got, test.name)
}
- ident := idents[test.ident][0]
+ ident := idents[test.name][0]
def := info.Defs[ident]
if def == test.obj {
- t.Fatalf("info.Defs[%s] contains the test object", test.ident)
+ t.Fatalf("info.Defs[%s] contains the test object", test.name)
+ }
+ if orig := originObject(test.obj); def != orig {
+ t.Errorf("info.Defs[%s] does not match obj.Origin()", test.name)
}
if def.Pkg() != test.obj.Pkg() {
t.Errorf("Pkg() = %v, want %v", def.Pkg(), test.obj.Pkg())
}
}
+func originObject(obj Object) Object {
+ switch obj := obj.(type) {
+ case *Var:
+ return obj.Origin()
+ case *Func:
+ return obj.Origin()
+ }
+ return obj
+}
+
func TestImplements(t *testing.T) {
const src = `
package p
}
sig.recv = substVar(origSig.recv, rtyp)
- return NewFunc(origm.pos, origm.pkg, origm.name, sig)
+ return substFunc(origm, sig)
}
// SetUnderlying sets the underlying type and marks t as complete.
embedded bool // if set, the variable is an embedded struct field, and name is the type name
isField bool // var is struct field
used bool // set if the variable was used
+ origin *Var // if non-nil, the Var from which this one was instantiated
}
// NewVar returns a new variable.
// IsField reports whether the variable is a struct field.
func (obj *Var) IsField() bool { return obj.isField }
+// Origin returns the canonical Var for its receiver, i.e. the Var object
+// recorded in Info.Defs.
+//
+// For synthetic Vars created during instantiation (such as struct fields or
+// function parameters that depend on type arguments), this will be the
+// corresponding Var on the generic (uninstantiated) type. For all other Vars
+// Origin returns the receiver.
+func (obj *Var) Origin() *Var {
+ if obj.origin != nil {
+ return obj.origin
+ }
+ return obj
+}
+
func (*Var) isDependency() {} // a variable may be a dependency of an initialization expression
// A Func represents a declared function, concrete method, or abstract
// An abstract method may belong to many interfaces due to embedding.
type Func struct {
object
- hasPtrRecv_ bool // only valid for methods that don't have a type yet; use hasPtrRecv() to read
+ hasPtrRecv_ bool // only valid for methods that don't have a type yet; use hasPtrRecv() to read
+ origin *Func // if non-nil, the Func from which this one was instantiated
}
// NewFunc returns a new function with the given signature, representing
if sig != nil {
typ = sig
}
- return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, false}
+ return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, false, nil}
}
// FullName returns the package- or receiver-type-qualified name of
// (but there is also no mechanism to get to an instantiated function).
func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
+// Origin returns the canonical Func for its receiver, i.e. the Func object
+// recorded in Info.Defs.
+//
+// For synthetic functions created during instantiation (such as methods on an
+// instantiated Named type or interface methods that depend on type arguments),
+// this will be the corresponding Func on the generic (uninstantiated) type.
+// For all other Funcs Origin returns the receiver.
+func (obj *Func) Origin() *Func {
+ if obj.origin != nil {
+ return obj.origin
+ }
+ return obj
+}
+
// hasPtrRecv reports whether the receiver is of the form *T for the given method obj.
func (obj *Func) hasPtrRecv() bool {
// If a method's receiver type is set, use that as the source of truth for the receiver.
{PkgName{}, 64, 104},
{Const{}, 64, 104},
{TypeName{}, 56, 88},
- {Var{}, 60, 96},
- {Func{}, 60, 96},
+ {Var{}, 64, 104},
+ {Func{}, 64, 104},
{Label{}, 60, 96},
{Builtin{}, 60, 96},
{Nil{}, 56, 88},
func substVar(v *Var, typ Type) *Var {
copy := *v
copy.typ = typ
+ copy.origin = v.Origin()
return ©
}
func (subst *subster) func_(f *Func) *Func {
if f != nil {
if typ := subst.typ(f.typ); typ != f.typ {
- copy := *f
- copy.typ = typ
- return ©
+ return substFunc(f, typ)
}
}
return f
}
+func substFunc(f *Func, typ Type) *Func {
+ copy := *f
+ copy.typ = typ
+ copy.origin = f.Origin()
+ return ©
+}
+
func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
out = in
for i, f := range in {
}
newsig := *sig
newsig.recv = substVar(sig.recv, new)
- out[i] = NewFunc(method.pos, method.pkg, method.name, &newsig)
+ out[i] = substFunc(method, &newsig)
}
}
return
`m`,
`func (generic_m10.E[int]).m()`,
},
+ {`package generic_m11; type T[A any] interface{ m(); n() }; func _(t1 T[int], t2 T[string]) { t1.m(); t2.n() }`, `m`, `func (generic_m11.T[int]).m()`},
+ {`package generic_m12; type T[A any] interface{ m(); n() }; func _(t1 T[int], t2 T[string]) { t1.m(); t2.n() }`, `n`, `func (generic_m12.T[string]).n()`},
}
for _, test := range tests {
field P
}
-func (recv *T[Q]) concreteMethod() {}
+func (recv *T[Q]) concreteMethod(mParam Q) (mResult Q) { return }
-type FT[P any] func(ftp P) (ftrp P)
+type FT[P any] func(ftParam P) (ftResult P)
-func F[P any](fp P) (frp P){ return }
+func F[P any](fParam P) (fResult P){ return }
type I[P any] interface {
interfaceMethod(P)
}
+type R[P any] T[P]
+
+func (R[P]) m() {} // having a method triggers expansion of R
+
var (
t T[int]
ft FT[int]
f = F[int]
i I[int]
)
+
+func fn() {
+ var r R[int]
+ _ = r
+}
`
info := &Info{
Defs: make(map[*ast.Ident]Object),
}
lookup := func(name string) Type { return pkg.Scope().Lookup(name).Type() }
+ fnScope := pkg.Scope().Lookup("fn").(*Func).Scope()
+
tests := []struct {
name string
obj Object
}{
+ // Struct fields
{"field", lookup("t").Underlying().(*Struct).Field(0)},
+ {"field", fnScope.Lookup("r").Type().Underlying().(*Struct).Field(0)},
+
+ // Methods and method fields
{"concreteMethod", lookup("t").(*Named).Method(0)},
{"recv", lookup("t").(*Named).Method(0).Type().(*Signature).Recv()},
- {"ftp", lookup("ft").Underlying().(*Signature).Params().At(0)},
- {"ftrp", lookup("ft").Underlying().(*Signature).Results().At(0)},
- {"fp", lookup("f").(*Signature).Params().At(0)},
- {"frp", lookup("f").(*Signature).Results().At(0)},
+ {"mParam", lookup("t").(*Named).Method(0).Type().(*Signature).Params().At(0)},
+ {"mResult", lookup("t").(*Named).Method(0).Type().(*Signature).Results().At(0)},
+
+ // Interface methods
{"interfaceMethod", lookup("i").Underlying().(*Interface).Method(0)},
+
+ // Function type fields
+ {"ftParam", lookup("ft").Underlying().(*Signature).Params().At(0)},
+ {"ftResult", lookup("ft").Underlying().(*Signature).Results().At(0)},
+
+ // Function fields
+ {"fParam", lookup("f").(*Signature).Params().At(0)},
+ {"fResult", lookup("f").(*Signature).Results().At(0)},
}
// Collect all identifiers by name.
if def == test.obj {
t.Fatalf("info.Defs[%s] contains the test object", test.name)
}
+ if orig := originObject(test.obj); def != orig {
+ t.Errorf("info.Defs[%s] does not match obj.Origin()", test.name)
+ }
if def.Pkg() != test.obj.Pkg() {
t.Errorf("Pkg() = %v, want %v", def.Pkg(), test.obj.Pkg())
}
}
}
+func originObject(obj Object) Object {
+ switch obj := obj.(type) {
+ case *Var:
+ return obj.Origin()
+ case *Func:
+ return obj.Origin()
+ }
+ return obj
+}
+
func TestImplements(t *testing.T) {
const src = `
package p
}
sig.recv = substVar(origSig.recv, rtyp)
- return NewFunc(origm.pos, origm.pkg, origm.name, sig)
+ return substFunc(origm, sig)
}
// SetUnderlying sets the underlying type and marks t as complete.
embedded bool // if set, the variable is an embedded struct field, and name is the type name
isField bool // var is struct field
used bool // set if the variable was used
+ origin *Var // if non-nil, the Var from which this one was instantiated
}
// NewVar returns a new variable.
// IsField reports whether the variable is a struct field.
func (obj *Var) IsField() bool { return obj.isField }
+// Origin returns the canonical Var for its receiver, i.e. the Var object
+// recorded in Info.Defs.
+//
+// For synthetic Vars created during instantiation (such as struct fields or
+// function parameters that depend on type arguments), this will be the
+// corresponding Var on the generic (uninstantiated) type. For all other Vars
+// Origin returns the receiver.
+func (obj *Var) Origin() *Var {
+ if obj.origin != nil {
+ return obj.origin
+ }
+ return obj
+}
+
func (*Var) isDependency() {} // a variable may be a dependency of an initialization expression
// A Func represents a declared function, concrete method, or abstract
// An abstract method may belong to many interfaces due to embedding.
type Func struct {
object
- hasPtrRecv_ bool // only valid for methods that don't have a type yet; use hasPtrRecv() to read
+ hasPtrRecv_ bool // only valid for methods that don't have a type yet; use hasPtrRecv() to read
+ origin *Func // if non-nil, the Func from which this one was instantiated
}
// NewFunc returns a new function with the given signature, representing
if sig != nil {
typ = sig
}
- return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, false}
+ return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, false, nil}
}
// FullName returns the package- or receiver-type-qualified name of
// (but there is also no mechanism to get to an instantiated function).
func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
+// Origin returns the canonical Func for its receiver, i.e. the Func object
+// recorded in Info.Defs.
+//
+// For synthetic functions created during instantiation (such as methods on an
+// instantiated Named type or interface methods that depend on type arguments),
+// this will be the corresponding Func on the generic (uninstantiated) type.
+// For all other Funcs Origin returns the receiver.
+func (obj *Func) Origin() *Func {
+ if obj.origin != nil {
+ return obj.origin
+ }
+ return obj
+}
+
// hasPtrRecv reports whether the receiver is of the form *T for the given method obj.
func (obj *Func) hasPtrRecv() bool {
// If a method's receiver type is set, use that as the source of truth for the receiver.
{PkgName{}, 48, 88},
{Const{}, 48, 88},
{TypeName{}, 40, 72},
- {Var{}, 44, 80},
- {Func{}, 44, 80},
+ {Var{}, 48, 88},
+ {Func{}, 48, 88},
{Label{}, 44, 80},
{Builtin{}, 44, 80},
{Nil{}, 40, 72},
func substVar(v *Var, typ Type) *Var {
copy := *v
copy.typ = typ
+ copy.origin = v.Origin()
return ©
}
func (subst *subster) func_(f *Func) *Func {
if f != nil {
if typ := subst.typ(f.typ); typ != f.typ {
- copy := *f
- copy.typ = typ
- return ©
+ return substFunc(f, typ)
}
}
return f
}
+func substFunc(f *Func, typ Type) *Func {
+ copy := *f
+ copy.typ = typ
+ copy.origin = f.Origin()
+ return ©
+}
+
func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
out = in
for i, f := range in {
}
newsig := *sig
newsig.recv = substVar(sig.recv, new)
- out[i] = NewFunc(method.pos, method.pkg, method.name, &newsig)
+ out[i] = substFunc(method, &newsig)
}
}
return