Skip to content

Commit 2c8dd3e

Browse files
committed
gopls: add explicit Unalias operations
This CL does for the gopls module what CL 565035 did for the x/tools module. In particular, we don't yet address desired behavior changes for materialized aliases, nor generic aliases. Change-Id: Iace78c1f8466afe8a6a24e3da3d6f431bf5ebc3e Reviewed-on: https://go-review.googlesource.com/c/tools/+/565756 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Tim King <[email protected]>
1 parent 814f676 commit 2c8dd3e

File tree

23 files changed

+148
-148
lines changed

23 files changed

+148
-148
lines changed

gopls/internal/analysis/embeddirective/embeddirective.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"strings"
1313

1414
"golang.org/x/tools/go/analysis"
15+
"golang.org/x/tools/internal/aliases"
1516
"golang.org/x/tools/internal/analysisinternal"
1617
)
1718

@@ -147,7 +148,7 @@ func embeddableType(o types.Object) bool {
147148

148149
// For embed.FS the underlying type is an implementation detail.
149150
// As long as the named type resolves to embed.FS, it is OK.
150-
if named, ok := o.Type().(*types.Named); ok {
151+
if named, ok := aliases.Unalias(o.Type()).(*types.Named); ok {
151152
obj := named.Obj()
152153
if obj.Pkg() != nil && obj.Pkg().Path() == "embed" && obj.Name() == "FS" {
153154
return true

gopls/internal/analysis/fillstruct/fillstruct.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"golang.org/x/tools/go/ast/astutil"
2727
"golang.org/x/tools/go/ast/inspector"
2828
"golang.org/x/tools/gopls/internal/util/safetoken"
29+
"golang.org/x/tools/internal/aliases"
2930
"golang.org/x/tools/internal/analysisinternal"
3031
"golang.org/x/tools/internal/fuzzy"
3132
"golang.org/x/tools/internal/typeparams"
@@ -448,7 +449,7 @@ func populateValue(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
448449
}
449450

450451
case *types.Pointer:
451-
switch u.Elem().(type) {
452+
switch aliases.Unalias(u.Elem()).(type) {
452453
case *types.Basic:
453454
return &ast.CallExpr{
454455
Fun: &ast.Ident{
@@ -472,7 +473,7 @@ func populateValue(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
472473
}
473474

474475
case *types.Interface:
475-
if param, ok := typ.(*types.TypeParam); ok {
476+
if param, ok := aliases.Unalias(typ).(*types.TypeParam); ok {
476477
// *new(T) is the zero value of a type parameter T.
477478
// TODO(adonovan): one could give a more specific zero
478479
// value if the type has a core type that is, say,

gopls/internal/analysis/stubmethods/stubmethods.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"golang.org/x/tools/go/analysis"
1818
"golang.org/x/tools/go/ast/astutil"
1919
"golang.org/x/tools/gopls/internal/util/typesutil"
20+
"golang.org/x/tools/internal/aliases"
2021
"golang.org/x/tools/internal/analysisinternal"
2122
"golang.org/x/tools/internal/typesinternal"
2223
)
@@ -178,7 +179,7 @@ func fromCallExpr(fset *token.FileSet, info *types.Info, pos token.Pos, call *as
178179
if !ok {
179180
return nil
180181
}
181-
sig, ok := tv.Type.(*types.Signature)
182+
sig, ok := aliases.Unalias(tv.Type).(*types.Signature)
182183
if !ok {
183184
return nil
184185
}
@@ -343,7 +344,7 @@ func ifaceType(e ast.Expr, info *types.Info) *types.TypeName {
343344
}
344345

345346
func ifaceObjFromType(t types.Type) *types.TypeName {
346-
named, ok := t.(*types.Named)
347+
named, ok := aliases.Unalias(t).(*types.Named)
347348
if !ok {
348349
return nil
349350
}
@@ -372,11 +373,11 @@ func concreteType(e ast.Expr, info *types.Info) (*types.Named, bool) {
372373
return nil, false
373374
}
374375
typ := tv.Type
375-
ptr, isPtr := typ.(*types.Pointer)
376+
ptr, isPtr := aliases.Unalias(typ).(*types.Pointer)
376377
if isPtr {
377378
typ = ptr.Elem()
378379
}
379-
named, ok := typ.(*types.Named)
380+
named, ok := aliases.Unalias(typ).(*types.Named)
380381
if !ok {
381382
return nil, false
382383
}

gopls/internal/analysis/undeclaredname/undeclared.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"golang.org/x/tools/go/analysis"
1919
"golang.org/x/tools/go/ast/astutil"
2020
"golang.org/x/tools/gopls/internal/util/safetoken"
21+
"golang.org/x/tools/internal/aliases"
2122
"golang.org/x/tools/internal/analysisinternal"
2223
)
2324

@@ -317,7 +318,7 @@ func newFunctionDeclaration(path []ast.Node, file *ast.File, pkg *types.Package,
317318
func typeToArgName(ty types.Type) string {
318319
s := types.Default(ty).String()
319320

320-
switch t := ty.(type) {
321+
switch t := aliases.Unalias(ty).(type) {
321322
case *types.Basic:
322323
// use first letter in type name for basic types
323324
return s[0:1]

gopls/internal/cache/methodsets/methodsets.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import (
5454
"golang.org/x/tools/go/types/objectpath"
5555
"golang.org/x/tools/gopls/internal/util/frob"
5656
"golang.org/x/tools/gopls/internal/util/safetoken"
57+
"golang.org/x/tools/internal/aliases"
5758
)
5859

5960
// An Index records the non-empty method sets of all package-level
@@ -304,7 +305,7 @@ func methodSetInfo(t types.Type, setIndexInfo func(*gobMethod, *types.Func)) gob
304305
// EnsurePointer wraps T in a types.Pointer if T is a named, non-interface type.
305306
// This is useful to make sure you consider a named type's full method set.
306307
func EnsurePointer(T types.Type) types.Type {
307-
if _, ok := T.(*types.Named); ok && !types.IsInterface(T) {
308+
if _, ok := aliases.Unalias(T).(*types.Named); ok && !types.IsInterface(T) {
308309
return types.NewPointer(T)
309310
}
310311

@@ -329,6 +330,9 @@ func fingerprint(method *types.Func) (string, bool) {
329330
var fprint func(t types.Type)
330331
fprint = func(t types.Type) {
331332
switch t := t.(type) {
333+
case *aliases.Alias:
334+
fprint(aliases.Unalias(t))
335+
332336
case *types.Named:
333337
tname := t.Obj()
334338
if tname.Pkg() != nil {

gopls/internal/golang/code_lens.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"golang.org/x/tools/gopls/internal/file"
1818
"golang.org/x/tools/gopls/internal/protocol"
1919
"golang.org/x/tools/gopls/internal/protocol/command"
20-
"golang.org/x/tools/internal/typesinternal"
2120
)
2221

2322
type LensFunc func(context.Context, *cache.Snapshot, file.Handle) ([]protocol.CodeLens, error)
@@ -139,22 +138,27 @@ func matchTestFunc(fn *ast.FuncDecl, pkg *cache.Package, nameRe *regexp.Regexp,
139138
if info == nil {
140139
return false
141140
}
142-
obj := info.ObjectOf(fn.Name)
143-
if obj == nil {
144-
return false
145-
}
146-
sig, ok := obj.Type().(*types.Signature)
141+
obj, ok := info.ObjectOf(fn.Name).(*types.Func)
147142
if !ok {
148143
return false
149144
}
145+
sig := obj.Type().(*types.Signature)
150146
// Test functions should have only one parameter.
151147
if sig.Params().Len() != 1 {
152148
return false
153149
}
154150

155151
// Check the type of the only parameter
156-
isptr, named := typesinternal.ReceiverNamed(sig.Params().At(0))
157-
if !isptr || named == nil {
152+
// (We don't Unalias or use typesinternal.ReceiverNamed
153+
// in the two checks below because "go test" can't see
154+
// through aliases when enumerating Test* functions;
155+
// it's syntactic.)
156+
paramTyp, ok := sig.Params().At(0).Type().(*types.Pointer)
157+
if !ok {
158+
return false
159+
}
160+
named, ok := paramTyp.Elem().(*types.Named)
161+
if !ok {
158162
return false
159163
}
160164
namedObj := named.Obj()

gopls/internal/golang/completion/completion.go

Lines changed: 25 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,21 +1048,10 @@ func (c *completer) populateCommentCompletions(comment *ast.CommentGroup) {
10481048

10491049
// collect receiver struct fields
10501050
if node.Recv != nil {
1051-
for _, fields := range node.Recv.List {
1052-
for _, name := range fields.Names {
1053-
obj := c.pkg.TypesInfo().ObjectOf(name)
1054-
if obj == nil {
1055-
continue
1056-
}
1057-
1058-
recvType := obj.Type().Underlying()
1059-
if ptr, ok := recvType.(*types.Pointer); ok {
1060-
recvType = ptr.Elem()
1061-
}
1062-
recvStruct, ok := recvType.Underlying().(*types.Struct)
1063-
if !ok {
1064-
continue
1065-
}
1051+
sig := c.pkg.TypesInfo().Defs[node.Name].(*types.Func).Type().(*types.Signature)
1052+
_, named := typesinternal.ReceiverNamed(sig.Recv()) // may be nil if ill-typed
1053+
if named != nil {
1054+
if recvStruct, ok := named.Underlying().(*types.Struct); ok {
10661055
for i := 0; i < recvStruct.NumFields(); i++ {
10671056
field := recvStruct.Field(i)
10681057
c.deepState.enqueue(candidate{obj: field, score: lowScore})
@@ -1162,8 +1151,7 @@ func (c *completer) wantStructFieldCompletions() bool {
11621151
if clInfo == nil {
11631152
return false
11641153
}
1165-
1166-
return clInfo.isStruct() && (clInfo.inKey || clInfo.maybeInFieldName)
1154+
return is[*types.Struct](clInfo.clType) && (clInfo.inKey || clInfo.maybeInFieldName)
11671155
}
11681156

11691157
func (c *completer) wantTypeName() bool {
@@ -1575,6 +1563,8 @@ func (c *completer) methodsAndFields(typ types.Type, addressable bool, imp *impo
15751563

15761564
// isStarTestingDotF reports whether typ is *testing.F.
15771565
func isStarTestingDotF(typ types.Type) bool {
1566+
// No Unalias, since go test doesn't consider
1567+
// types when enumeratinf test funcs, only syntax.
15781568
ptr, _ := typ.(*types.Pointer)
15791569
if ptr == nil {
15801570
return false
@@ -1707,10 +1697,11 @@ func (c *completer) lexical(ctx context.Context) error {
17071697
// If we are completing a type param, offer each structural type.
17081698
// This ensures we suggest "[]int" and "[]float64" for a constraint
17091699
// with type union "[]int | []float64".
1710-
if t, _ := c.inference.objType.(*types.Interface); t != nil {
1711-
terms, _ := typeparams.InterfaceTermSet(t)
1712-
for _, term := range terms {
1713-
c.injectType(ctx, term.Type())
1700+
if t, ok := c.inference.objType.(*types.Interface); ok {
1701+
if terms, err := typeparams.InterfaceTermSet(t); err == nil {
1702+
for _, term := range terms {
1703+
c.injectType(ctx, term.Type())
1704+
}
17141705
}
17151706
}
17161707
} else {
@@ -1923,9 +1914,9 @@ func (c *completer) structLiteralFieldName(ctx context.Context) error {
19231914
}
19241915
}
19251916

1926-
deltaScore := 0.0001
1927-
switch t := clInfo.clType.(type) {
1928-
case *types.Struct:
1917+
// Add struct fields.
1918+
if t, ok := aliases.Unalias(clInfo.clType).(*types.Struct); ok {
1919+
const deltaScore = 0.0001
19291920
for i := 0; i < t.NumFields(); i++ {
19301921
field := t.Field(i)
19311922
if !addedFields[field] {
@@ -1936,21 +1927,14 @@ func (c *completer) structLiteralFieldName(ctx context.Context) error {
19361927
}
19371928
}
19381929

1939-
// Add lexical completions if we aren't certain we are in the key part of a
1940-
// key-value pair.
1941-
if clInfo.maybeInFieldName {
1942-
return c.lexical(ctx)
1930+
// Fall through and add lexical completions if we aren't
1931+
// certain we are in the key part of a key-value pair.
1932+
if !clInfo.maybeInFieldName {
1933+
return nil
19431934
}
1944-
default:
1945-
return c.lexical(ctx)
19461935
}
19471936

1948-
return nil
1949-
}
1950-
1951-
func (cl *compLitInfo) isStruct() bool {
1952-
_, ok := cl.clType.(*types.Struct)
1953-
return ok
1937+
return c.lexical(ctx)
19541938
}
19551939

19561940
// enclosingCompositeLiteral returns information about the composite literal enclosing the
@@ -3365,3 +3349,8 @@ func forEachPackageMember(content []byte, f func(tok token.Token, id *ast.Ident,
33653349
}
33663350
}
33673351
}
3352+
3353+
func is[T any](x any) bool {
3354+
_, ok := x.(T)
3355+
return ok
3356+
}

gopls/internal/golang/completion/format.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"golang.org/x/tools/gopls/internal/golang/completion/snippet"
1818
"golang.org/x/tools/gopls/internal/protocol"
1919
"golang.org/x/tools/gopls/internal/util/safetoken"
20+
"golang.org/x/tools/internal/aliases"
2021
"golang.org/x/tools/internal/event"
2122
"golang.org/x/tools/internal/imports"
2223
)
@@ -60,7 +61,7 @@ func (c *completer) item(ctx context.Context, cand candidate) (CompletionItem, e
6061
}
6162
if isTypeName(obj) && c.wantTypeParams() {
6263
x := cand.obj.(*types.TypeName)
63-
if named, ok := x.Type().(*types.Named); ok {
64+
if named, ok := aliases.Unalias(x.Type()).(*types.Named); ok {
6465
tp := named.TypeParams()
6566
label += golang.FormatTypeParams(tp)
6667
insert = label // maintain invariant above (label == insert)
@@ -76,7 +77,7 @@ func (c *completer) item(ctx context.Context, cand candidate) (CompletionItem, e
7677
kind = protocol.ConstantCompletion
7778
case *types.Var:
7879
if _, ok := obj.Type().(*types.Struct); ok {
79-
detail = "struct{...}" // for anonymous structs
80+
detail = "struct{...}" // for anonymous unaliased struct types
8081
} else if obj.IsField() {
8182
var err error
8283
detail, err = golang.FormatVarType(ctx, c.snapshot, c.pkg, obj, c.qf, c.mq)
@@ -94,12 +95,9 @@ func (c *completer) item(ctx context.Context, cand candidate) (CompletionItem, e
9495
break
9596
}
9697
case *types.Func:
97-
sig, ok := obj.Type().Underlying().(*types.Signature)
98-
if !ok {
99-
break
100-
}
101-
kind = protocol.FunctionCompletion
102-
if sig != nil && sig.Recv() != nil {
98+
if obj.Type().(*types.Signature).Recv() == nil {
99+
kind = protocol.FunctionCompletion
100+
} else {
103101
kind = protocol.MethodCompletion
104102
}
105103
case *types.PkgName:
@@ -414,7 +412,14 @@ func inferableTypeParams(sig *types.Signature) map[*types.TypeParam]bool {
414412
}
415413
case *types.TypeParam:
416414
free[t] = true
417-
case *types.Basic, *types.Named:
415+
case *aliases.Alias:
416+
visit(aliases.Unalias(t))
417+
case *types.Named:
418+
targs := t.TypeArgs()
419+
for i := 0; i < targs.Len(); i++ {
420+
visit(targs.At(i))
421+
}
422+
case *types.Basic:
418423
// nop
419424
default:
420425
panic(t)

gopls/internal/golang/completion/keywords.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (c *completer) addKeywordCompletions() {
6363
// If we are at the file scope, only offer decl keywords. We don't
6464
// get *ast.Idents at the file scope because non-keyword identifiers
6565
// turn into *ast.BadDecl, not *ast.Ident.
66-
if len(c.path) == 1 || isASTFile(c.path[1]) {
66+
if len(c.path) == 1 || is[*ast.File](c.path[1]) {
6767
c.addKeywordItems(seen, stdScore, TYPE, CONST, VAR, FUNC, IMPORT)
6868
return
6969
} else if _, ok := c.path[0].(*ast.Ident); !ok {

0 commit comments

Comments
 (0)