Skip to content

Commit c99edec

Browse files
timothy-kingGo LUCI
authored and
Go LUCI
committed
gopls/internal/golang/completion: add alias support for literals
Derived from https://go.dev/cl/603935. Change-Id: I1a75562da194a8e5cc532f1b52fbc1f9d9b2907a Reviewed-on: https://go-review.googlesource.com/c/tools/+/619478 Reviewed-by: Alan Donovan <adonovan@google.com> Commit-Queue: Tim King <taking@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent bfe3046 commit c99edec

File tree

2 files changed

+38
-17
lines changed

2 files changed

+38
-17
lines changed

gopls/internal/golang/completion/literal.go

+29-17
Original file line numberDiff line numberDiff line change
@@ -517,28 +517,30 @@ func (c *completer) typeNameSnippet(literalType types.Type, qf types.Qualifier)
517517
var (
518518
snip snippet.Builder
519519
typeName string
520-
// TODO(adonovan): think more about aliases.
521-
// They should probably be treated more like Named.
522-
named, _ = types.Unalias(literalType).(*types.Named)
520+
pnt, _ = literalType.(typesinternal.NamedOrAlias) // = *Named | *Alias
523521
)
524522

525-
if named != nil && named.Obj() != nil && named.TypeParams().Len() > 0 && !c.fullyInstantiated(named) {
523+
tparams := typesinternal.TypeParams(pnt)
524+
if tparams.Len() > 0 && !c.fullyInstantiated(pnt) {
525+
// tparams.Len() > 0 implies pnt != nil.
526+
// Inv: pnt is not "error" or "unsafe.Pointer", so pnt.Obj() != nil and has a Pkg().
527+
526528
// We are not "fully instantiated" meaning we have type params that must be specified.
527-
if pkg := qf(named.Obj().Pkg()); pkg != "" {
529+
if pkg := qf(pnt.Obj().Pkg()); pkg != "" {
528530
typeName = pkg + "."
529531
}
530532

531533
// We do this to get "someType" instead of "someType[T]".
532-
typeName += named.Obj().Name()
534+
typeName += pnt.Obj().Name()
533535
snip.WriteText(typeName + "[")
534536

535537
if c.opts.placeholders {
536-
for i := 0; i < named.TypeParams().Len(); i++ {
538+
for i := 0; i < tparams.Len(); i++ {
537539
if i > 0 {
538540
snip.WriteText(", ")
539541
}
540542
snip.WritePlaceholder(func(snip *snippet.Builder) {
541-
snip.WriteText(types.TypeString(named.TypeParams().At(i), qf))
543+
snip.WriteText(types.TypeString(tparams.At(i), qf))
542544
})
543545
}
544546
} else {
@@ -557,25 +559,35 @@ func (c *completer) typeNameSnippet(literalType types.Type, qf types.Qualifier)
557559

558560
// fullyInstantiated reports whether all of t's type params have
559561
// specified type args.
560-
func (c *completer) fullyInstantiated(t *types.Named) bool {
561-
tps := t.TypeParams()
562-
tas := t.TypeArgs()
562+
func (c *completer) fullyInstantiated(t typesinternal.NamedOrAlias) bool {
563+
targs := typesinternal.TypeArgs(t)
564+
tparams := typesinternal.TypeParams(t)
563565

564-
if tps.Len() != tas.Len() {
566+
if tparams.Len() != targs.Len() {
565567
return false
566568
}
567569

568-
for i := 0; i < tas.Len(); i++ {
569-
// TODO(adonovan) think about generic aliases.
570-
switch ta := types.Unalias(tas.At(i)).(type) {
570+
for i := 0; i < targs.Len(); i++ {
571+
targ := targs.At(i)
572+
573+
// The expansion of an alias can have free type parameters,
574+
// whether or not the alias itself has type parameters:
575+
//
576+
// func _[K comparable]() {
577+
// type Set = map[K]bool // free(Set) = {K}
578+
// type MapTo[V] = map[K]V // free(Map[foo]) = {V}
579+
// }
580+
//
581+
// So, we must Unalias.
582+
switch targ := types.Unalias(targ).(type) {
571583
case *types.TypeParam:
572584
// A *TypeParam only counts as specified if it is currently in
573585
// scope (i.e. we are in a generic definition).
574-
if !c.typeParamInScope(ta) {
586+
if !c.typeParamInScope(targ) {
575587
return false
576588
}
577589
case *types.Named:
578-
if !c.fullyInstantiated(ta) {
590+
if !c.fullyInstantiated(targ) {
579591
return false
580592
}
581593
}

gopls/internal/test/marker/testdata/completion/alias.txt

+9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ func takesGeneric[a int | string](s[a]) {
2626
takesGeneric() //@rank(")", tpInScopeLit),snippet(")", tpInScopeLit, "s[a]{\\}")
2727
}
2828

29+
func _() {
30+
s[int]{} //@item(tpInstLit, "s[int]{}", "", "var")
31+
takesGeneric[int]() //@rank(")", tpInstLit),snippet(")", tpInstLit, "s[int]{\\}")
32+
33+
"s[...]{}" //@item(tpUninstLit, "s[...]{}", "", "var")
34+
takesGeneric() //@rank(")", tpUninstLit),snippet(")", tpUninstLit, "s[${1:}]{\\}")
35+
}
36+
37+
2938
type myType int //@item(flType, "myType", "int", "type")
3039

3140
type myt[T int] myType //@item(aflType, "myt[T]", "int", "type")

0 commit comments

Comments
 (0)