@@ -18,6 +18,8 @@ import (
18
18
"go/types"
19
19
"io"
20
20
"sort"
21
+
22
+ "golang.org/x/tools/internal/typeparams"
21
23
)
22
24
23
25
type intReader struct {
@@ -41,6 +43,21 @@ func (r *intReader) uint64() uint64 {
41
43
return i
42
44
}
43
45
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
+
44
61
const predeclReserved = 32
45
62
46
63
type itag uint64
@@ -56,6 +73,9 @@ const (
56
73
signatureType
57
74
structType
58
75
interfaceType
76
+ typeParamType
77
+ instType
78
+ unionType
59
79
)
60
80
61
81
// IImportData imports a package from the serialized package data
@@ -101,9 +121,13 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
101
121
102
122
version = int64 (r .uint64 ())
103
123
switch version {
104
- case currentVersion , 0 :
124
+ case /* iexportVersionGenerics, */ iexportVersionPosCol , iexportVersionGo1_11 :
105
125
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
+ }
107
131
}
108
132
109
133
sLen := int64 (r .uint64 ())
@@ -115,8 +139,9 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
115
139
r .Seek (sLen + dLen , io .SeekCurrent )
116
140
117
141
p := iimporter {
118
- ipath : path ,
119
- version : int (version ),
142
+ exportVersion : version ,
143
+ ipath : path ,
144
+ version : int (version ),
120
145
121
146
stringData : stringData ,
122
147
stringCache : make (map [uint64 ]string ),
@@ -125,6 +150,9 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
125
150
declData : declData ,
126
151
pkgIndex : make (map [* types.Package ]map [string ]uint64 ),
127
152
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 ),
128
156
129
157
fake : fakeFileSet {
130
158
fset : fset ,
@@ -216,16 +244,18 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data
216
244
}
217
245
218
246
type iimporter struct {
219
- ipath string
220
- version int
247
+ exportVersion int64
248
+ ipath string
249
+ version int
221
250
222
251
stringData []byte
223
252
stringCache map [uint64 ]string
224
253
pkgCache map [uint64 ]* types.Package
225
254
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
229
259
230
260
fake fakeFileSet
231
261
interfaceList []* types.Interface
@@ -315,17 +345,27 @@ func (r *importReader) obj(name string) {
315
345
316
346
r .declare (types .NewConst (pos , r .currPkg , name , typ , val ))
317
347
318
- case 'F' :
348
+ case 'F' , 'G' :
349
+ var tparams []* typeparams.TypeParam
350
+ if tag == 'G' {
351
+ tparams = r .tparamList ()
352
+ }
319
353
sig := r .signature (nil )
320
-
354
+ typeparams . SetForSignature ( sig , tparams )
321
355
r .declare (types .NewFunc (pos , r .currPkg , name , sig ))
322
356
323
- case 'T' :
357
+ case 'T' , 'U' :
324
358
// Types can be recursive. We need to setup a stub
325
359
// declaration before recursing.
326
360
obj := types .NewTypeName (pos , r .currPkg , name , nil )
327
361
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).
328
364
r .declare (obj )
365
+ if tag == 'U' {
366
+ tparams := r .tparamList ()
367
+ typeparams .SetForNamed (named , tparams )
368
+ }
329
369
330
370
underlying := r .p .typAt (r .uint64 (), named ).Underlying ()
331
371
named .SetUnderlying (underlying )
@@ -337,10 +377,46 @@ func (r *importReader) obj(name string) {
337
377
recv := r .param ()
338
378
msig := r .signature (recv )
339
379
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
+
340
392
named .AddMethod (types .NewFunc (mpos , r .currPkg , mname , msig ))
341
393
}
342
394
}
343
395
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
+
344
420
case 'V' :
345
421
typ := r .typ ()
346
422
@@ -618,6 +694,49 @@ func (r *importReader) doType(base *types.Named) types.Type {
618
694
typ := newInterface (methods , embeddeds )
619
695
r .p .interfaceList = append (r .p .interfaceList , typ )
620
696
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 )
621
740
}
622
741
}
623
742
@@ -632,6 +751,20 @@ func (r *importReader) signature(recv *types.Var) *types.Signature {
632
751
return types .NewSignature (recv , params , results , variadic )
633
752
}
634
753
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
+
635
768
func (r * importReader ) paramList () * types.Tuple {
636
769
xs := make ([]* types.Var , r .uint64 ())
637
770
for i := range xs {
@@ -674,3 +807,33 @@ func (r *importReader) byte() byte {
674
807
}
675
808
return x
676
809
}
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