Skip to content

Commit 054c06d

Browse files
committed
gopls: rationalize "deref" helpers
This change (part of the types.Alias audit) defines two helper functions for dealing with pointer types: 1. internal/typeparams.MustDeref (formerly go/ssa.mustDeref) is the type equivalent of a LOAD instruction. 2. internal/typesinternal.Unpointer strips off a Pointer constructor (possibly wrapped in an Alias). The golang.Deref function, which recursively strips off Pointer and Named constructors, is a meaningless operation. It has been replaced in all cases by Unpointer + Unalias. There are far too many functions called 'deref' with subtle variations in their behavior. I plan to standardize x/tools on few common idioms. (There is more to do.) Updates golang/go#65294 Change-Id: I502bab95e8d954715784b7e35ec801f4be4bc959 Reviewed-on: https://go-review.googlesource.com/c/tools/+/565476 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]> Reviewed-by: Tim King <[email protected]>
1 parent a4d9215 commit 054c06d

File tree

18 files changed

+100
-62
lines changed

18 files changed

+100
-62
lines changed

go/ssa/builder.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ func (b *builder) builtin(fn *Function, obj *types.Builtin, args []ast.Expr, typ
328328
}
329329

330330
case "new":
331-
return emitNew(fn, mustDeref(typ), pos, "new")
331+
return emitNew(fn, typeparams.MustDeref(typ), pos, "new")
332332

333333
case "len", "cap":
334334
// Special case: len or cap of an array or *array is
@@ -419,7 +419,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
419419
wantAddr := true
420420
v := b.receiver(fn, e.X, wantAddr, escaping, sel)
421421
index := sel.index[len(sel.index)-1]
422-
fld := fieldOf(mustDeref(v.Type()), index) // v is an addr.
422+
fld := fieldOf(typeparams.MustDeref(v.Type()), index) // v is an addr.
423423

424424
// Due to the two phases of resolving AssignStmt, a panic from x.f = p()
425425
// when x is nil is required to come after the side-effects of
@@ -468,7 +468,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
468468
v.setType(et)
469469
return fn.emit(v)
470470
}
471-
return &lazyAddress{addr: emit, t: mustDeref(et), pos: e.Lbrack, expr: e}
471+
return &lazyAddress{addr: emit, t: typeparams.MustDeref(et), pos: e.Lbrack, expr: e}
472472

473473
case *ast.StarExpr:
474474
return &address{addr: b.expr(fn, e.X), pos: e.Star, expr: e}

go/ssa/create.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *
259259
obj := scope.Lookup(name)
260260
memberFromObject(p, obj, nil, "")
261261
if obj, ok := obj.(*types.TypeName); ok {
262+
// No Unalias: aliases should not duplicate methods.
262263
if named, ok := obj.Type().(*types.Named); ok {
263264
for i, n := 0, named.NumMethods(); i < n; i++ {
264265
memberFromObject(p, named.Method(i), nil, "")

go/ssa/emit.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"go/ast"
1212
"go/token"
1313
"go/types"
14+
15+
"golang.org/x/tools/internal/typeparams"
1416
)
1517

1618
// emitAlloc emits to f a new Alloc instruction allocating a variable
@@ -64,7 +66,7 @@ func emitLocalVar(f *Function, v *types.Var) *Alloc {
6466
// new temporary, and returns the value so defined.
6567
func emitLoad(f *Function, addr Value) *UnOp {
6668
v := &UnOp{Op: token.MUL, X: addr}
67-
v.setType(mustDeref(addr.Type()))
69+
v.setType(typeparams.MustDeref(addr.Type()))
6870
f.emit(v)
6971
return v
7072
}
@@ -414,7 +416,7 @@ func emitTypeCoercion(f *Function, v Value, typ types.Type) Value {
414416
// emitStore emits to f an instruction to store value val at location
415417
// addr, applying implicit conversions as required by assignability rules.
416418
func emitStore(f *Function, addr, val Value, pos token.Pos) *Store {
417-
typ := mustDeref(addr.Type())
419+
typ := typeparams.MustDeref(addr.Type())
418420
s := &Store{
419421
Addr: addr,
420422
Val: emitConv(f, val, typ),

go/ssa/func.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"io"
1515
"os"
1616
"strings"
17+
18+
"golang.org/x/tools/internal/typeparams"
1719
)
1820

1921
// Like ObjectOf, but panics instead of returning nil.
@@ -531,7 +533,7 @@ func WriteFunction(buf *bytes.Buffer, f *Function) {
531533
if len(f.Locals) > 0 {
532534
buf.WriteString("# Locals:\n")
533535
for i, l := range f.Locals {
534-
fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, l.Name(), relType(mustDeref(l.Type()), from))
536+
fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, l.Name(), relType(typeparams.MustDeref(l.Type()), from))
535537
}
536538
}
537539
writeSignature(buf, from, f.Name(), f.Signature)

go/ssa/lift.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ import (
4343
"go/token"
4444
"math/big"
4545
"os"
46+
47+
"golang.org/x/tools/internal/typeparams"
4648
)
4749

4850
// If true, show diagnostic information at each step of lifting.
@@ -465,7 +467,7 @@ func liftAlloc(df domFrontier, alloc *Alloc, newPhis newPhiMap, fresh *int) bool
465467
*fresh++
466468

467469
phi.pos = alloc.Pos()
468-
phi.setType(mustDeref(alloc.Type()))
470+
phi.setType(typeparams.MustDeref(alloc.Type()))
469471
phi.block = v
470472
if debugLifting {
471473
fmt.Fprintf(os.Stderr, "\tplace %s = %s at block %s\n", phi.Name(), phi, v)
@@ -510,7 +512,7 @@ func replaceAll(x, y Value) {
510512
func renamed(renaming []Value, alloc *Alloc) Value {
511513
v := renaming[alloc.index]
512514
if v == nil {
513-
v = zeroConst(mustDeref(alloc.Type()))
515+
v = zeroConst(typeparams.MustDeref(alloc.Type()))
514516
renaming[alloc.index] = v
515517
}
516518
return v

go/ssa/lvalue.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"go/ast"
1212
"go/token"
1313
"go/types"
14+
15+
"golang.org/x/tools/internal/typeparams"
1416
)
1517

1618
// An lvalue represents an assignable location that may appear on the
@@ -52,7 +54,7 @@ func (a *address) address(fn *Function) Value {
5254
}
5355

5456
func (a *address) typ() types.Type {
55-
return mustDeref(a.addr.Type())
57+
return typeparams.MustDeref(a.addr.Type())
5658
}
5759

5860
// An element is an lvalue represented by m[k], the location of an

go/ssa/print.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"strings"
1818

1919
"golang.org/x/tools/go/types/typeutil"
20+
"golang.org/x/tools/internal/typeparams"
2021
)
2122

2223
// relName returns the name of v relative to i.
@@ -94,7 +95,7 @@ func (v *Alloc) String() string {
9495
op = "new"
9596
}
9697
from := v.Parent().relPkg()
97-
return fmt.Sprintf("%s %s (%s)", op, relType(mustDeref(v.Type()), from), v.Comment)
98+
return fmt.Sprintf("%s %s (%s)", op, relType(typeparams.MustDeref(v.Type()), from), v.Comment)
9899
}
99100

100101
func (v *Phi) String() string {
@@ -260,7 +261,7 @@ func (v *MakeChan) String() string {
260261
func (v *FieldAddr) String() string {
261262
// Be robust against a bad index.
262263
name := "?"
263-
if fld := fieldOf(mustDeref(v.X.Type()), v.Field); fld != nil {
264+
if fld := fieldOf(typeparams.MustDeref(v.X.Type()), v.Field); fld != nil {
264265
name = fld.Name()
265266
}
266267
return fmt.Sprintf("&%s.%s [#%d]", relName(v.X, v), name, v.Field)
@@ -449,7 +450,7 @@ func WritePackage(buf *bytes.Buffer, p *Package) {
449450

450451
case *Global:
451452
fmt.Fprintf(buf, " var %-*s %s\n",
452-
maxname, name, relType(mustDeref(mem.Type()), from))
453+
maxname, name, relType(typeparams.MustDeref(mem.Type()), from))
453454
}
454455
}
455456

go/ssa/util.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,6 @@ func deref(typ types.Type) (types.Type, bool) {
115115
return typ, false
116116
}
117117

118-
// mustDeref returns the element type of a type with a pointer core type.
119-
// Panics on failure.
120-
func mustDeref(typ types.Type) types.Type {
121-
if et, ok := deref(typ); ok {
122-
return et
123-
}
124-
panic("cannot dereference type " + typ.String())
125-
}
126-
127118
// recvType returns the receiver type of method obj.
128119
func recvType(obj *types.Func) types.Type {
129120
return obj.Type().(*types.Signature).Recv().Type()

gopls/internal/golang/completion/completion.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ import (
3737
goplsastutil "golang.org/x/tools/gopls/internal/util/astutil"
3838
"golang.org/x/tools/gopls/internal/util/safetoken"
3939
"golang.org/x/tools/gopls/internal/util/typesutil"
40+
"golang.org/x/tools/internal/aliases"
4041
"golang.org/x/tools/internal/event"
4142
"golang.org/x/tools/internal/fuzzy"
4243
"golang.org/x/tools/internal/imports"
4344
"golang.org/x/tools/internal/typeparams"
45+
"golang.org/x/tools/internal/typesinternal"
4446
)
4547

4648
// A CompletionItem represents a possible completion suggested by the algorithm.
@@ -1585,7 +1587,7 @@ func (c *completer) lexical(ctx context.Context) error {
15851587
}
15861588

15871589
if c.inference.objType != nil {
1588-
if named, _ := golang.Deref(c.inference.objType).(*types.Named); named != nil {
1590+
if named, ok := aliases.Unalias(typesinternal.Unpointer(c.inference.objType)).(*types.Named); ok {
15891591
// If we expected a named type, check the type's package for
15901592
// completion items. This is useful when the current file hasn't
15911593
// imported the type's package yet.
@@ -1651,14 +1653,14 @@ func (c *completer) injectType(ctx context.Context, t types.Type) {
16511653
return
16521654
}
16531655

1654-
t = golang.Deref(t)
1656+
t = typesinternal.Unpointer(t)
16551657

16561658
// If we have an expected type and it is _not_ a named type, handle
16571659
// it specially. Non-named types like "[]int" will never be
16581660
// considered via a lexical search, so we need to directly inject
16591661
// them. Also allow generic types since lexical search does not
16601662
// infer instantiated versions of them.
1661-
if named, _ := t.(*types.Named); named == nil || named.TypeParams().Len() > 0 {
1663+
if named, ok := aliases.Unalias(t).(*types.Named); !ok || named.TypeParams().Len() > 0 {
16621664
// If our expected type is "[]int", this will add a literal
16631665
// candidate of "[]int{}".
16641666
c.literal(ctx, t, nil)
@@ -1896,7 +1898,7 @@ func enclosingCompositeLiteral(path []ast.Node, pos token.Pos, info *types.Info)
18961898

18971899
clInfo := compLitInfo{
18981900
cl: n,
1899-
clType: golang.Deref(tv.Type).Underlying(),
1901+
clType: typesinternal.Unpointer(tv.Type).Underlying(),
19001902
}
19011903

19021904
var (

gopls/internal/golang/completion/literal.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ import (
1414
"golang.org/x/tools/gopls/internal/golang"
1515
"golang.org/x/tools/gopls/internal/golang/completion/snippet"
1616
"golang.org/x/tools/gopls/internal/protocol"
17+
"golang.org/x/tools/internal/aliases"
1718
"golang.org/x/tools/internal/event"
19+
"golang.org/x/tools/internal/typesinternal"
1820
)
1921

2022
// literal generates composite literal, function literal, and make()
@@ -49,10 +51,11 @@ func (c *completer) literal(ctx context.Context, literalType types.Type, imp *im
4951
//
5052
// don't offer "mySlice{}" since we have already added a candidate
5153
// of "[]int{}".
52-
if _, named := literalType.(*types.Named); named && expType != nil {
53-
if _, named := golang.Deref(expType).(*types.Named); !named {
54-
return
55-
}
54+
if is[*types.Named](aliases.Unalias(literalType)) &&
55+
expType != nil &&
56+
!is[*types.Named](aliases.Unalias(typesinternal.Unpointer(expType))) {
57+
58+
return
5659
}
5760

5861
// Check if an object of type literalType would match our expected type.
@@ -589,3 +592,8 @@ func (c *completer) typeParamInScope(tp *types.TypeParam) bool {
589592
_, foundObj := scope.LookupParent(obj.Name(), c.pos)
590593
return obj == foundObj
591594
}
595+
596+
func is[T any](x any) bool {
597+
_, ok := x.(T)
598+
return ok
599+
}

0 commit comments

Comments
 (0)