Skip to content

Commit e73cd5a

Browse files
committed
gopls/internal/golang: implement dynamicFuncCallType with typeutil.ClassifyCall
Also fix some typos I came across. Change-Id: Ib3e73852c8260bf0a537ffb7c23ec1815c9546e1 Reviewed-on: https://go-review.googlesource.com/c/tools/+/658236 Reviewed-by: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 11a9b3f commit e73cd5a

File tree

4 files changed

+45
-83
lines changed

4 files changed

+45
-83
lines changed

gopls/internal/golang/implementation.go

+7-22
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"golang.org/x/tools/internal/astutil/cursor"
3333
"golang.org/x/tools/internal/astutil/edge"
3434
"golang.org/x/tools/internal/event"
35+
"golang.org/x/tools/internal/typesinternal"
3536
)
3637

3738
// This file defines the new implementation of the 'implementation'
@@ -937,6 +938,9 @@ func implFuncs(pkg *cache.Package, pgf *parsego.File, pos token.Pos) ([]protocol
937938
}
938939

939940
info := pkg.TypesInfo()
941+
if info.Types == nil || info.Defs == nil || info.Uses == nil {
942+
panic("one of info.Types, .Defs or .Uses is nil")
943+
}
940944

941945
// Find innermost enclosing FuncType or CallExpr.
942946
//
@@ -1088,29 +1092,10 @@ func beneathFuncDef(cur cursor.Cursor) bool {
10881092
//
10891093
// Tested via ../test/marker/testdata/implementation/signature.txt.
10901094
func dynamicFuncCallType(info *types.Info, call *ast.CallExpr) types.Type {
1091-
fun := ast.Unparen(call.Fun)
1092-
tv := info.Types[fun]
1093-
1094-
// Reject conversion, or call to built-in.
1095-
if !tv.IsValue() {
1096-
return nil
1097-
}
1098-
1099-
// Reject call to named func/method.
1100-
if id, ok := fun.(*ast.Ident); ok && is[*types.Func](info.Uses[id]) {
1101-
return nil
1095+
if typesinternal.ClassifyCall(info, call) == typesinternal.CallDynamic {
1096+
return info.Types[call.Fun].Type.Underlying()
11021097
}
1103-
1104-
// Reject method selections (T.method() or x.method())
1105-
if sel, ok := fun.(*ast.SelectorExpr); ok {
1106-
seln, ok := info.Selections[sel]
1107-
if !ok || seln.Kind() != types.FieldVal {
1108-
return nil
1109-
}
1110-
}
1111-
1112-
// TODO(adonovan): consider x() where x : TypeParam.
1113-
return tv.Type.Underlying() // e.g. x() or x.field()
1098+
return nil
11141099
}
11151100

11161101
// inToken reports whether pos is within the token of

gopls/internal/test/marker/testdata/implementation/issue67041.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
This test verifies that implementations uses the correct object when querying
2-
local implementations . As described in golang/go#67041), a bug led to it
1+
This test verifies that Implementations uses the correct object when querying
2+
local implementations. As described in golang/go#67041, a bug led to it
33
comparing types from different realms.
44

55
-- go.mod --

internal/typesinternal/classify_call.go

+14-27
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,6 @@ func (k CallKind) String() string {
4242
// and further classifies function calls as static calls (where the function is known),
4343
// dynamic interface calls, and other dynamic calls.
4444
//
45-
// For static, interface and builtin calls, ClassifyCall returns the [types.Object]
46-
// for the name of the caller. For calls of instantiated functions and
47-
// methods, it returns the object for the corresponding generic function
48-
// or method on the generic type.
49-
// The relationships between the return values are:
50-
//
51-
// CallKind object
52-
// CallStatic *types.Func
53-
// CallInterface *types.Func
54-
// CallBuiltin *types.Builtin
55-
// CallDynamic nil
56-
// CallConversion nil
57-
//
5845
// For the declarations:
5946
//
6047
// func f() {}
@@ -66,33 +53,33 @@ func (k CallKind) String() string {
6653
//
6754
// ClassifyCall returns the following:
6855
//
69-
// f() CallStatic the *types.Func for f
70-
// g[int]() CallStatic the *types.Func for g[T]
71-
// i.M() CallInterface the *types.Func for i.M
72-
// min(1, 2) CallBuiltin the *types.Builtin for min
73-
// v() CallDynamic nil
74-
// s[0]() CallDynamic nil
75-
// int(x) CallConversion nil
76-
// []byte("") CallConversion nil
77-
func ClassifyCall(info *types.Info, call *ast.CallExpr) (CallKind, types.Object) {
56+
// f() CallStatic
57+
// g[int]() CallStatic
58+
// i.M() CallInterface
59+
// min(1, 2) CallBuiltin
60+
// v() CallDynamic
61+
// s[0]() CallDynamic
62+
// int(x) CallConversion
63+
// []byte("") CallConversion
64+
func ClassifyCall(info *types.Info, call *ast.CallExpr) CallKind {
7865
if info.Types == nil {
7966
panic("ClassifyCall: info.Types is nil")
8067
}
8168
if info.Types[call.Fun].IsType() {
82-
return CallConversion, nil
69+
return CallConversion
8370
}
8471
obj := Used(info, call.Fun)
8572
// Classify the call by the type of the object, if any.
8673
switch obj := obj.(type) {
8774
case *types.Builtin:
88-
return CallBuiltin, obj
75+
return CallBuiltin
8976
case *types.Func:
9077
if interfaceMethod(obj) {
91-
return CallInterface, obj
78+
return CallInterface
9279
}
93-
return CallStatic, obj
80+
return CallStatic
9481
default:
95-
return CallDynamic, nil
82+
return CallDynamic
9683
}
9784
}
9885

internal/typesinternal/classify_call_test.go

+22-32
Original file line numberDiff line numberDiff line change
@@ -101,34 +101,30 @@ func TestClassifyCallAndUsed(t *testing.T) {
101101

102102
typeParam := lookup("tests").Type().(*types.Signature).TypeParams().At(0).Obj()
103103

104-
// A unique value for marking that Used returns the same object as ClassifyCall.
105-
same := &types.Label{}
106-
107104
// Expected Calls are in the order of CallExprs at the end of src, above.
108105
wants := []struct {
109-
kind ti.CallKind
110-
classifyObj types.Object // the object returned from ClassifyCall
111-
usedObj types.Object // the object returned from Used, sometimes different
106+
kind ti.CallKind
107+
usedObj types.Object // the object returned from Used
112108
}{
113-
{ti.CallStatic, lookup("g"), same}, // g
114-
{ti.CallDynamic, nil, lookup("f")}, // f
115-
{ti.CallBuiltin, printlnObj, same}, // println
116-
{ti.CallStatic, member("S", "g"), same}, // z.g
117-
{ti.CallStatic, member("S", "g"), same}, // a.b.c.g
118-
{ti.CallStatic, member("S", "g"), same}, // S.g(z, 1)
119-
{ti.CallDynamic, nil, member("z", "f")}, // z.f
120-
{ti.CallInterface, member("I", "m"), same}, // I(nil).m
121-
{ti.CallConversion, nil, lookup("I")}, // I(nil)
122-
{ti.CallDynamic, nil, same}, // m[0]
123-
{ti.CallDynamic, nil, same}, // n[0]
124-
{ti.CallStatic, lookup("F"), same}, // F[int]
125-
{ti.CallStatic, lookup("F"), same}, // F[T]
126-
{ti.CallDynamic, nil, same}, // f(){}
127-
{ti.CallConversion, nil, same}, // []byte
128-
{ti.CallConversion, nil, lookup("A")}, // A[int]
129-
{ti.CallConversion, nil, typeParam}, // T
130-
{ti.CallStatic, member("S", "g"), same}, // (z.g)
131-
{ti.CallStatic, member("S", "g"), same}, // (z).g
109+
{ti.CallStatic, lookup("g")}, // g
110+
{ti.CallDynamic, lookup("f")}, // f
111+
{ti.CallBuiltin, printlnObj}, // println
112+
{ti.CallStatic, member("S", "g")}, // z.g
113+
{ti.CallStatic, member("S", "g")}, // a.b.c.g
114+
{ti.CallStatic, member("S", "g")}, // S.g(z, 1)
115+
{ti.CallDynamic, member("z", "f")}, // z.f
116+
{ti.CallInterface, member("I", "m")}, // I(nil).m
117+
{ti.CallConversion, lookup("I")}, // I(nil)
118+
{ti.CallDynamic, nil}, // m[0]
119+
{ti.CallDynamic, nil}, // n[0]
120+
{ti.CallStatic, lookup("F")}, // F[int]
121+
{ti.CallStatic, lookup("F")}, // F[T]
122+
{ti.CallDynamic, nil}, // f(){}
123+
{ti.CallConversion, nil}, // []byte
124+
{ti.CallConversion, lookup("A")}, // A[int]
125+
{ti.CallConversion, typeParam}, // T
126+
{ti.CallStatic, member("S", "g")}, // (z.g)
127+
{ti.CallStatic, member("S", "g")}, // (z).g
132128
}
133129

134130
i := 0
@@ -143,20 +139,14 @@ func TestClassifyCallAndUsed(t *testing.T) {
143139
}
144140
prefix := fmt.Sprintf("%s (#%d)", buf.String(), i)
145141

146-
gotKind, gotObj := ti.ClassifyCall(info, call)
142+
gotKind := ti.ClassifyCall(info, call)
147143
want := wants[i]
148144

149145
if gotKind != want.kind {
150146
t.Errorf("%s kind: got %s, want %s", prefix, gotKind, want.kind)
151147
}
152-
if gotObj != want.classifyObj {
153-
t.Errorf("%s obj: got %v (%[2]T), want %v", prefix, gotObj, want.classifyObj)
154-
}
155148

156149
w := want.usedObj
157-
if w == same {
158-
w = want.classifyObj
159-
}
160150
if g := ti.Used(info, call.Fun); g != w {
161151
t.Errorf("%s used obj: got %v (%[2]T), want %v", prefix, g, w)
162152
}

0 commit comments

Comments
 (0)