@@ -18,6 +18,8 @@ import (
1818 "go/types"
1919 "io"
2020 "sort"
21+
22+ "golang.org/x/tools/internal/typeparams"
2123)
2224
2325type intReader struct {
@@ -41,6 +43,21 @@ func (r *intReader) uint64() uint64 {
4143 return i
4244}
4345
46+ // Keep this in sync with constants in iexport.go.
47+ const (
48+ iexportVersionGo1_11 = 0
49+ iexportVersionPosCol = 1
50+ // TODO: before release, change this back to 2.
51+ iexportVersionGenerics = iexportVersionPosCol
52+
53+ iexportVersionCurrent = iexportVersionGenerics
54+ )
55+
56+ type ident struct {
57+ pkg string
58+ name string
59+ }
60+
4461const predeclReserved = 32
4562
4663type itag uint64
@@ -56,6 +73,9 @@ const (
5673 signatureType
5774 structType
5875 interfaceType
76+ typeParamType
77+ instType
78+ unionType
5979)
6080
6181// IImportData imports a package from the serialized package data
@@ -101,9 +121,13 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
101121
102122 version = int64 (r .uint64 ())
103123 switch version {
104- case currentVersion , 0 :
124+ case /* iexportVersionGenerics, */ iexportVersionPosCol , iexportVersionGo1_11 :
105125 default :
106- errorf ("unknown iexport format version %d" , version )
126+ if version > iexportVersionGenerics {
127+ errorf ("unstable iexport format version %d, just rebuild compiler and std library" , version )
128+ } else {
129+ errorf ("unknown iexport format version %d" , version )
130+ }
107131 }
108132
109133 sLen := int64 (r .uint64 ())
@@ -115,8 +139,9 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
115139 r .Seek (sLen + dLen , io .SeekCurrent )
116140
117141 p := iimporter {
118- ipath : path ,
119- version : int (version ),
142+ exportVersion : version ,
143+ ipath : path ,
144+ version : int (version ),
120145
121146 stringData : stringData ,
122147 stringCache : make (map [uint64 ]string ),
@@ -125,6 +150,9 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
125150 declData : declData ,
126151 pkgIndex : make (map [* types.Package ]map [string ]uint64 ),
127152 typCache : make (map [uint64 ]types.Type ),
153+ // Separate map for typeparams, keyed by their package and unique
154+ // name (name with subscript).
155+ tparamIndex : make (map [ident ]types.Type ),
128156
129157 fake : fakeFileSet {
130158 fset : fset ,
@@ -216,16 +244,18 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
216244}
217245
218246type iimporter struct {
219- ipath string
220- version int
247+ exportVersion int64
248+ ipath string
249+ version int
221250
222251 stringData []byte
223252 stringCache map [uint64 ]string
224253 pkgCache map [uint64 ]* types.Package
225254
226- declData []byte
227- pkgIndex map [* types.Package ]map [string ]uint64
228- typCache map [uint64 ]types.Type
255+ declData []byte
256+ pkgIndex map [* types.Package ]map [string ]uint64
257+ typCache map [uint64 ]types.Type
258+ tparamIndex map [ident ]types.Type
229259
230260 fake fakeFileSet
231261 interfaceList []* types.Interface
@@ -315,17 +345,27 @@ func (r *importReader) obj(name string) {
315345
316346 r .declare (types .NewConst (pos , r .currPkg , name , typ , val ))
317347
318- case 'F' :
348+ case 'F' , 'G' :
349+ var tparams []* typeparams.TypeParam
350+ if tag == 'G' {
351+ tparams = r .tparamList ()
352+ }
319353 sig := r .signature (nil )
320-
354+ typeparams . SetForSignature ( sig , tparams )
321355 r .declare (types .NewFunc (pos , r .currPkg , name , sig ))
322356
323- case 'T' :
357+ case 'T' , 'U' :
324358 // Types can be recursive. We need to setup a stub
325359 // declaration before recursing.
326360 obj := types .NewTypeName (pos , r .currPkg , name , nil )
327361 named := types .NewNamed (obj , nil , nil )
362+ // Declare obj before calling r.tparamList, so the new type name is recognized
363+ // if used in the constraint of one of its own typeparams (see #48280).
328364 r .declare (obj )
365+ if tag == 'U' {
366+ tparams := r .tparamList ()
367+ typeparams .SetForNamed (named , tparams )
368+ }
329369
330370 underlying := r .p .typAt (r .uint64 (), named ).Underlying ()
331371 named .SetUnderlying (underlying )
@@ -337,10 +377,46 @@ func (r *importReader) obj(name string) {
337377 recv := r .param ()
338378 msig := r .signature (recv )
339379
380+ // If the receiver has any targs, set those as the
381+ // rparams of the method (since those are the
382+ // typeparams being used in the method sig/body).
383+ targs := typeparams .NamedTypeArgs (baseType (msig .Recv ().Type ()))
384+ if len (targs ) > 0 {
385+ rparams := make ([]* typeparams.TypeParam , len (targs ))
386+ for i := range rparams {
387+ rparams [i ], _ = targs [i ].(* typeparams.TypeParam )
388+ }
389+ typeparams .SetRecvTypeParams (msig , rparams )
390+ }
391+
340392 named .AddMethod (types .NewFunc (mpos , r .currPkg , mname , msig ))
341393 }
342394 }
343395
396+ case 'P' :
397+ // We need to "declare" a typeparam in order to have a name that
398+ // can be referenced recursively (if needed) in the type param's
399+ // bound.
400+ if r .p .exportVersion < iexportVersionGenerics {
401+ errorf ("unexpected type param type" )
402+ }
403+ name0 , sub := parseSubscript (name )
404+ tn := types .NewTypeName (pos , r .currPkg , name0 , nil )
405+ t := typeparams .NewTypeParam (tn , nil )
406+ if sub == 0 {
407+ errorf ("missing subscript" )
408+ }
409+
410+ // TODO(rfindley): can we use a different, stable ID?
411+ // t.SetId(sub)
412+
413+ // To handle recursive references to the typeparam within its
414+ // bound, save the partial type in tparamIndex before reading the bounds.
415+ id := ident {r .currPkg .Name (), name }
416+ r .p .tparamIndex [id ] = t
417+
418+ typeparams .SetTypeParamConstraint (t , r .typ ())
419+
344420 case 'V' :
345421 typ := r .typ ()
346422
@@ -618,6 +694,49 @@ func (r *importReader) doType(base *types.Named) types.Type {
618694 typ := newInterface (methods , embeddeds )
619695 r .p .interfaceList = append (r .p .interfaceList , typ )
620696 return typ
697+
698+ case typeParamType :
699+ if r .p .exportVersion < iexportVersionGenerics {
700+ errorf ("unexpected type param type" )
701+ }
702+ pkg , name := r .qualifiedIdent ()
703+ id := ident {pkg .Name (), name }
704+ if t , ok := r .p .tparamIndex [id ]; ok {
705+ // We're already in the process of importing this typeparam.
706+ return t
707+ }
708+ // Otherwise, import the definition of the typeparam now.
709+ r .p .doDecl (pkg , name )
710+ return r .p .tparamIndex [id ]
711+
712+ case instType :
713+ if r .p .exportVersion < iexportVersionGenerics {
714+ errorf ("unexpected instantiation type" )
715+ }
716+ // pos does not matter for instances: they are positioned on the original
717+ // type.
718+ _ = r .pos ()
719+ len := r .uint64 ()
720+ targs := make ([]types.Type , len )
721+ for i := range targs {
722+ targs [i ] = r .typ ()
723+ }
724+ baseType := r .typ ()
725+ // The imported instantiated type doesn't include any methods, so
726+ // we must always use the methods of the base (orig) type.
727+ // TODO provide a non-nil *Environment
728+ t , _ := typeparams .Instantiate (nil , baseType , targs , false )
729+ return t
730+
731+ case unionType :
732+ if r .p .exportVersion < iexportVersionGenerics {
733+ errorf ("unexpected instantiation type" )
734+ }
735+ terms := make ([]* typeparams.Term , r .uint64 ())
736+ for i := range terms {
737+ terms [i ] = typeparams .NewTerm (r .bool (), r .typ ())
738+ }
739+ return typeparams .NewUnion (terms )
621740 }
622741}
623742
@@ -632,6 +751,20 @@ func (r *importReader) signature(recv *types.Var) *types.Signature {
632751 return types .NewSignature (recv , params , results , variadic )
633752}
634753
754+ func (r * importReader ) tparamList () []* typeparams.TypeParam {
755+ n := r .uint64 ()
756+ if n == 0 {
757+ return nil
758+ }
759+ xs := make ([]* typeparams.TypeParam , n )
760+ for i := range xs {
761+ // Note: the standard library importer is tolerant of nil types here,
762+ // though would panic in SetTypeParams.
763+ xs [i ] = r .typ ().(* typeparams.TypeParam )
764+ }
765+ return xs
766+ }
767+
635768func (r * importReader ) paramList () * types.Tuple {
636769 xs := make ([]* types.Var , r .uint64 ())
637770 for i := range xs {
@@ -674,3 +807,33 @@ func (r *importReader) byte() byte {
674807 }
675808 return x
676809}
810+
811+ func baseType (typ types.Type ) * types.Named {
812+ // pointer receivers are never types.Named types
813+ if p , _ := typ .(* types.Pointer ); p != nil {
814+ typ = p .Elem ()
815+ }
816+ // receiver base types are always (possibly generic) types.Named types
817+ n , _ := typ .(* types.Named )
818+ return n
819+ }
820+
821+ func parseSubscript (name string ) (string , uint64 ) {
822+ // Extract the subscript value from the type param name. We export
823+ // and import the subscript value, so that all type params have
824+ // unique names.
825+ sub := uint64 (0 )
826+ startsub := - 1
827+ for i , r := range name {
828+ if '₀' <= r && r < '₀' + 10 {
829+ if startsub == - 1 {
830+ startsub = i
831+ }
832+ sub = sub * 10 + uint64 (r - '₀' )
833+ }
834+ }
835+ if startsub >= 0 {
836+ name = name [:startsub ]
837+ }
838+ return name , sub
839+ }
0 commit comments