@@ -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 }
0 commit comments