Skip to content

Commit b3aff93

Browse files
committed
go/types: LookupSelection: returns LookupFieldOrMethod as a Selection
Also, rewrite some uses of LookupFieldOrMethod in terms of it. + doc, relnote Fixes golang#70737 Change-Id: I58a6dd78ee78560d8b6ea2d821381960a72660ab Reviewed-on: https://go-review.googlesource.com/c/go/+/647196 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Griesemer <gri@google.com>
1 parent e9242ee commit b3aff93

File tree

7 files changed

+109
-25
lines changed

7 files changed

+109
-25
lines changed

api/go1.25.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pkg go/types, const RecvVar = 3 #70250
1010
pkg go/types, const RecvVar VarKind #70250
1111
pkg go/types, const ResultVar = 5 #70250
1212
pkg go/types, const ResultVar VarKind #70250
13+
pkg go/types, func LookupSelection(Type, bool, *Package, string) (Selection, bool) #70737
1314
pkg go/types, method (*Var) Kind() VarKind #70250
1415
pkg go/types, method (*Var) SetKind(VarKind) #70250
1516
pkg go/types, method (VarKind) String() string #70250
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The new [LookupSelection] function looks up the field or method of a
2+
given name and receiver type, like the existing [LookupFieldOrMethod]
3+
function, but returns the result in the form of a [Selection].

src/cmd/compile/internal/types2/instantiate_test.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,12 +181,11 @@ var X T[int]
181181
src := prefix + test.decl
182182
pkg := mustTypecheck(src, nil, nil)
183183
typ := NewPointer(pkg.Scope().Lookup("X").Type())
184-
obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
185-
m, _ := obj.(*Func)
186-
if m == nil {
187-
t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
184+
sel, ok := LookupSelection(typ, false, pkg, "m")
185+
if !ok {
186+
t.Fatalf(`LookupSelection(%s, "m") failed, want func m`, typ)
188187
}
189-
if got := ObjectString(m, RelativeTo(pkg)); got != test.want {
188+
if got := ObjectString(sel.Obj(), RelativeTo(pkg)); got != test.want {
190189
t.Errorf("instantiated %q, want %q", got, test.want)
191190
}
192191
}
@@ -203,15 +202,15 @@ var _ T[int]
203202
`
204203
pkg := mustTypecheck(src, nil, nil)
205204
typ := pkg.Scope().Lookup("T").Type().(*Named)
206-
obj, _, _ := LookupFieldOrMethod(typ, false, pkg, "m")
207-
if obj == nil {
208-
t.Fatalf(`LookupFieldOrMethod(%s, "m") = %v, want func m`, typ, obj)
205+
sel, ok := LookupSelection(typ, false, pkg, "m")
206+
if !ok {
207+
t.Fatalf(`LookupSelection(%s, "m") failed, want func m`, typ)
209208
}
210209

211210
// Verify that the original method is not mutated by instantiating T (this
212211
// bug manifested when subst did not return a new signature).
213212
want := "func (T[P]).m()"
214-
if got := stripAnnotations(ObjectString(obj, RelativeTo(pkg))); got != want {
213+
if got := stripAnnotations(ObjectString(sel.Obj(), RelativeTo(pkg))); got != want {
215214
t.Errorf("instantiated %q, want %q", got, want)
216215
}
217216
}

src/cmd/compile/internal/types2/lookup.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,45 @@ package types2
88

99
import "bytes"
1010

11+
// LookupSelection selects the field or method whose ID is Id(pkg,
12+
// name), on a value of type T. If addressable is set, T is the type
13+
// of an addressable variable (this matters only for method lookups).
14+
// T must not be nil.
15+
//
16+
// If the selection is valid:
17+
//
18+
// - [Selection.Obj] returns the field ([Var]) or method ([Func]);
19+
// - [Selection.Indirect] reports whether there were any pointer
20+
// indirections on the path to the field or method.
21+
// - [Selection.Index] returns the index sequence, defined below.
22+
//
23+
// The last index entry is the field or method index in the (possibly
24+
// embedded) type where the entry was found, either:
25+
//
26+
// 1. the list of declared methods of a named type; or
27+
// 2. the list of all methods (method set) of an interface type; or
28+
// 3. the list of fields of a struct type.
29+
//
30+
// The earlier index entries are the indices of the embedded struct
31+
// fields traversed to get to the found entry, starting at depth 0.
32+
//
33+
// See also [LookupFieldOrMethod], which returns the components separately.
34+
func LookupSelection(T Type, addressable bool, pkg *Package, name string) (Selection, bool) {
35+
obj, index, indirect := LookupFieldOrMethod(T, addressable, pkg, name)
36+
var kind SelectionKind
37+
switch obj.(type) {
38+
case nil:
39+
return Selection{}, false
40+
case *Func:
41+
kind = MethodVal
42+
case *Var:
43+
kind = FieldVal
44+
default:
45+
panic(obj) // can't happen
46+
}
47+
return Selection{kind, T, obj, index, indirect}, true
48+
}
49+
1150
// Internal use of LookupFieldOrMethod: If the obj result is a method
1251
// associated with a concrete (non-interface) type, the method's signature
1352
// may not be fully set up. Call Checker.objDecl(obj, nil) before accessing
@@ -38,6 +77,8 @@ import "bytes"
3877
// - If indirect is set, a method with a pointer receiver type was found
3978
// but there was no pointer on the path from the actual receiver type to
4079
// the method's formal receiver base type, nor was the receiver addressable.
80+
//
81+
// See also [LookupSelection], which returns the result as a [Selection].
4182
func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
4283
if T == nil {
4384
panic("LookupFieldOrMethod on nil type")

src/go/internal/gcimporter/gcimporter_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -632,14 +632,14 @@ func TestIssue13898(t *testing.T) {
632632
}
633633

634634
// lookup go/types.Object.Pkg method
635-
m, index, indirect := types.LookupFieldOrMethod(typ, false, nil, "Pkg")
636-
if m == nil {
637-
t.Fatalf("go/types.Object.Pkg not found (index = %v, indirect = %v)", index, indirect)
635+
sel, ok := types.LookupSelection(typ, false, nil, "Pkg")
636+
if !ok {
637+
t.Fatalf("go/types.Object.Pkg not found")
638638
}
639639

640640
// the method must belong to go/types
641-
if m.Pkg().Path() != "go/types" {
642-
t.Fatalf("found %v; want go/types", m.Pkg())
641+
if sel.Obj().Pkg().Path() != "go/types" {
642+
t.Fatalf("found %v; want go/types", sel.Obj().Pkg())
643643
}
644644
}
645645

@@ -699,8 +699,8 @@ func TestIssue20046(t *testing.T) {
699699
// "./issue20046".V.M must exist
700700
pkg := compileAndImportPkg(t, "issue20046")
701701
obj := lookupObj(t, pkg.Scope(), "V")
702-
if m, index, indirect := types.LookupFieldOrMethod(obj.Type(), false, nil, "M"); m == nil {
703-
t.Fatalf("V.M not found (index = %v, indirect = %v)", index, indirect)
702+
if _, ok := types.LookupSelection(obj.Type(), false, nil, "M"); !ok {
703+
t.Fatalf("V.M not found")
704704
}
705705
}
706706
func TestIssue25301(t *testing.T) {

src/go/types/instantiate_test.go

Lines changed: 8 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/go/types/lookup.go

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)