@@ -517,28 +517,30 @@ func (c *completer) typeNameSnippet(literalType types.Type, qf types.Qualifier)
517
517
var (
518
518
snip snippet.Builder
519
519
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
523
521
)
524
522
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
+
526
528
// 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 != "" {
528
530
typeName = pkg + "."
529
531
}
530
532
531
533
// We do this to get "someType" instead of "someType[T]".
532
- typeName += named .Obj ().Name ()
534
+ typeName += pnt .Obj ().Name ()
533
535
snip .WriteText (typeName + "[" )
534
536
535
537
if c .opts .placeholders {
536
- for i := 0 ; i < named . TypeParams () .Len (); i ++ {
538
+ for i := 0 ; i < tparams .Len (); i ++ {
537
539
if i > 0 {
538
540
snip .WriteText (", " )
539
541
}
540
542
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 ))
542
544
})
543
545
}
544
546
} else {
@@ -557,25 +559,35 @@ func (c *completer) typeNameSnippet(literalType types.Type, qf types.Qualifier)
557
559
558
560
// fullyInstantiated reports whether all of t's type params have
559
561
// 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 )
563
565
564
- if tps .Len () != tas .Len () {
566
+ if tparams .Len () != targs .Len () {
565
567
return false
566
568
}
567
569
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 ) {
571
583
case * types.TypeParam :
572
584
// A *TypeParam only counts as specified if it is currently in
573
585
// scope (i.e. we are in a generic definition).
574
- if ! c .typeParamInScope (ta ) {
586
+ if ! c .typeParamInScope (targ ) {
575
587
return false
576
588
}
577
589
case * types.Named :
578
- if ! c .fullyInstantiated (ta ) {
590
+ if ! c .fullyInstantiated (targ ) {
579
591
return false
580
592
}
581
593
}
0 commit comments