@@ -35,6 +35,10 @@ type pkgReader struct {
3535
3636 // laterFns holds functions that need to be invoked at the end of
3737 // import reading.
38+ //
39+ // TODO(mdempsky): Is it safe to have a single "later" slice or do
40+ // we need to have multiple passes? See comments on CL 386002 and
41+ // go.dev/issue/52104.
3842 laterFns []func ()
3943 // laterFors is used in case of 'type A B' to ensure that B is processed before A.
4044 laterFors map [types.Type ]int
@@ -158,12 +162,11 @@ type reader struct {
158162// A readerDict holds the state for type parameters that parameterize
159163// the current unified IR element.
160164type readerDict struct {
161- // bounds is a slice of typeInfos corresponding to the underlying
162- // bounds of the element's type parameters.
163- bounds []typeInfo
165+ rtbounds []typeInfo // contains constraint types for each parameter in rtparams
166+ rtparams []* types.TypeParam // contains receiver type parameters for an element
164167
165- // tparams is a slice of the constructed TypeParams for the element.
166- tparams []* types.TypeParam
168+ tbounds [] typeInfo // contains constraint types for each parameter in tparams
169+ tparams []* types.TypeParam // contains type parameters for an element
167170
168171 // derived is a slice of types derived from tparams, which may be
169172 // instantiated while reading the current element.
@@ -353,7 +356,11 @@ func (r *reader) doTyp() (res types.Type) {
353356 return name .Type ()
354357
355358 case pkgbits .TypeTypeParam :
356- return r .dict .tparams [r .Len ()]
359+ n := r .Len ()
360+ if n < len (r .dict .rtbounds ) {
361+ return r .dict .rtparams [n ]
362+ }
363+ return r .dict .tparams [n - len (r .dict .rtbounds )]
357364
358365 case pkgbits .TypeArray :
359366 len := int64 (r .Uint64 ())
@@ -534,7 +541,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
534541 pos := r .pos ()
535542 var tparams []* types.TypeParam
536543 if r .Version ().Has (pkgbits .AliasTypeParamNames ) {
537- tparams = r .typeParamNames ()
544+ tparams = r .typeParamNames (false )
538545 }
539546 typ := r .typ ()
540547 declare (aliases .New (pos , objPkg , objName , typ , tparams ))
@@ -547,8 +554,15 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
547554
548555 case pkgbits .ObjFunc :
549556 pos := r .pos ()
550- tparams := r .typeParamNames ()
551- sig := r .signature (nil , nil , tparams )
557+ var rtparams []* types.TypeParam
558+ var recv * types.Var
559+ if r .Version ().Has (pkgbits .GenericMethods ) && r .Bool () {
560+ r .selector ()
561+ rtparams = r .typeParamNames (true )
562+ recv = r .param ()
563+ }
564+ tparams := r .typeParamNames (false )
565+ sig := r .signature (recv , rtparams , tparams )
552566 declare (types .NewFunc (pos , objPkg , objName , sig ))
553567
554568 case pkgbits .ObjType :
@@ -558,7 +572,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
558572 named := types .NewNamed (obj , nil , nil )
559573 declare (obj )
560574
561- named .SetTypeParams (r .typeParamNames ())
575+ named .SetTypeParams (r .typeParamNames (false ))
562576
563577 setUnderlying := func (underlying types.Type ) {
564578 // If the underlying type is an interface, we need to
@@ -638,9 +652,20 @@ func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
638652 errorf ("unexpected object with %v implicit type parameter(s)" , implicits )
639653 }
640654
641- dict .bounds = make ([]typeInfo , r .Len ())
642- for i := range dict .bounds {
643- dict .bounds [i ] = r .typInfo ()
655+ nreceivers := 0
656+ if r .Version ().Has (pkgbits .GenericMethods ) && r .Bool () {
657+ nreceivers = r .Len ()
658+ }
659+ nexplicits := r .Len ()
660+
661+ dict .rtbounds = make ([]typeInfo , nreceivers )
662+ for i := range dict .rtbounds {
663+ dict .rtbounds [i ] = r .typInfo ()
664+ }
665+
666+ dict .tbounds = make ([]typeInfo , nexplicits )
667+ for i := range dict .tbounds {
668+ dict .tbounds [i ] = r .typInfo ()
644669 }
645670
646671 dict .derived = make ([]derivedInfo , r .Len ())
@@ -659,15 +684,24 @@ func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
659684 return & dict
660685}
661686
662- func (r * reader ) typeParamNames () []* types.TypeParam {
687+ func (r * reader ) typeParamNames (isGenMeth bool ) []* types.TypeParam {
663688 r .Sync (pkgbits .SyncTypeParamNames )
664689
665- // Note: This code assumes it only processes objects without
666- // implement type parameters. This is currently fine, because
667- // reader is only used to read in exported declarations, which are
668- // always package scoped.
690+ // Note: This code assumes there are no implicit type parameters.
691+ // This is fine since it only reads exported declarations, which
692+ // never have implicits.
669693
670- if len (r .dict .bounds ) == 0 {
694+ var in []typeInfo
695+ var out * []* types.TypeParam
696+ if isGenMeth {
697+ in = r .dict .rtbounds
698+ out = & r .dict .rtparams
699+ } else {
700+ in = r .dict .tbounds
701+ out = & r .dict .tparams
702+ }
703+
704+ if len (in ) == 0 {
671705 return nil
672706 }
673707
@@ -676,48 +710,42 @@ func (r *reader) typeParamNames() []*types.TypeParam {
676710 // create all the TypeNames and TypeParams, then we construct and
677711 // set the bound type.
678712
679- r .dict .tparams = make ([]* types.TypeParam , len (r .dict .bounds ))
680- for i := range r .dict .bounds {
713+ // We have to save tparams outside of the closure, because typeParamNames
714+ // can be called multiple times with the same dictionary instance.
715+ tparams := make ([]* types.TypeParam , len (in ))
716+ * out = tparams
717+
718+ for i := range in {
681719 pos := r .pos ()
682720 pkg , name := r .localIdent ()
683721
684722 tname := types .NewTypeName (pos , pkg , name , nil )
685- r . dict . tparams [i ] = types .NewTypeParam (tname , nil )
723+ tparams [i ] = types .NewTypeParam (tname , nil )
686724 }
687725
688- typs := make ([]types.Type , len (r .dict .bounds ))
689- for i , bound := range r .dict .bounds {
690- typs [i ] = r .p .typIdx (bound , r .dict )
726+ // The reader dictionary will continue mutating before we have time
727+ // to call delayed functions; make a local copy of the constraints.
728+ types := make ([]types.Type , len (in ))
729+ for i , info := range in {
730+ types [i ] = r .p .typIdx (info , r .dict )
691731 }
692732
693- // TODO(mdempsky): This is subtle, elaborate further.
694- //
695- // We have to save tparams outside of the closure, because
696- // typeParamNames() can be called multiple times with the same
697- // dictionary instance.
698- //
699- // Also, this needs to happen later to make sure SetUnderlying has
700- // been called.
701- //
702- // TODO(mdempsky): Is it safe to have a single "later" slice or do
703- // we need to have multiple passes? See comments on CL 386002 and
704- // go.dev/issue/52104.
705- tparams := r .dict .tparams
733+ // This needs to happen later to make sure SetUnderlying has been called.
706734 r .p .later (func () {
707- for i , typ := range typs {
735+ for i , typ := range types {
708736 tparams [i ].SetConstraint (typ )
709737 }
710738 })
711739
712- return r . dict . tparams
740+ return tparams
713741}
714742
715743func (r * reader ) method () * types.Func {
716744 r .Sync (pkgbits .SyncMethod )
717745 pos := r .pos ()
718746 pkg , name := r .selector ()
719747
720- rparams := r .typeParamNames ()
748+ rparams := r .typeParamNames (false )
721749 sig := r .signature (r .param (), rparams , nil )
722750
723751 _ = r .pos () // TODO(mdempsky): Remove; this is a hacker for linker.go.
0 commit comments