]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: move to new export version, keep reading previous version
authorDan Scales <danscales@google.com>
Wed, 14 Apr 2021 16:34:17 +0000 (09:34 -0700)
committerDan Scales <danscales@google.com>
Fri, 21 May 2021 04:03:26 +0000 (04:03 +0000)
I added constants for the previous export versions, and for the final
generics export version. I also added a const for the current export
version. We can increment the current export version for unstable
changes in dev.typeparams, and eventally set it back to the generics
version (2) before release. Added the same constants in
typecheck/iexport.go, importer/iimport.go, and gcimporter/iimport.go,
must be kept in sync.

Put in the needed conditionals to be able to read old versions.

Added new export/import test listimp.dir.

Change-Id: I166d17d943e07951aa752562e952b067704aeeca
Reviewed-on: https://go-review.googlesource.com/c/go/+/319931
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/importer/iimport.go
src/cmd/compile/internal/typecheck/iexport.go
src/cmd/compile/internal/typecheck/iimport.go
src/go/internal/gcimporter/gcimporter_test.go
src/go/internal/gcimporter/iimport.go
test/typeparam/listimp.dir/a.go [new file with mode: 0644]
test/typeparam/listimp.dir/main.go [new file with mode: 0644]
test/typeparam/listimp.go [new file with mode: 0644]

index a4637ec34f90f0c26d0cfb9794b476eea82a60ba..37e5113435c5692dad58f63cd2e256b33e830653 100644 (file)
@@ -1,4 +1,3 @@
-// UNREVIEWED
 // Copyright 2018 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
@@ -42,6 +41,16 @@ func (r *intReader) uint64() uint64 {
        return i
 }
 
+// Keep this in sync with constants in iexport.go.
+const (
+       iexportVersionGo1_11   = 0
+       iexportVersionPosCol   = 1
+       iexportVersionGenerics = 2
+
+       // Start of the unstable series of versions, remove "+ n" before release.
+       iexportVersionCurrent = iexportVersionGenerics + 1
+)
+
 const predeclReserved = 32
 
 type itag uint64
@@ -68,7 +77,7 @@ const io_SeekCurrent = 1 // io.SeekCurrent (not defined in Go 1.4)
 // If the export data version is not recognized or the format is otherwise
 // compromised, an error is returned.
 func iImportData(imports map[string]*types2.Package, data []byte, path string) (_ int, pkg *types2.Package, err error) {
-       const currentVersion = 1
+       const currentVersion = iexportVersionCurrent
        version := int64(-1)
        defer func() {
                if e := recover(); e != nil {
@@ -84,9 +93,13 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) (
 
        version = int64(r.uint64())
        switch version {
-       case currentVersion, 0:
+       case currentVersion, iexportVersionPosCol, iexportVersionGo1_11:
        default:
-               errorf("unknown iexport format version %d", version)
+               if version > iexportVersionGenerics {
+                       errorf("unstable iexport format version %d, just rebuild compiler and std library", version)
+               } else {
+                       errorf("unknown iexport format version %d", version)
+               }
        }
 
        sLen := int64(r.uint64())
@@ -98,8 +111,9 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) (
        r.Seek(sLen+dLen, io_SeekCurrent)
 
        p := iimporter{
-               ipath:   path,
-               version: int(version),
+               exportVersion: version,
+               ipath:         path,
+               version:       int(version),
 
                stringData:   stringData,
                stringCache:  make(map[uint64]string),
@@ -178,8 +192,9 @@ func iImportData(imports map[string]*types2.Package, data []byte, path string) (
 }
 
 type iimporter struct {
-       ipath   string
-       version int
+       exportVersion int64
+       ipath         string
+       version       int
 
        stringData   []byte
        stringCache  map[uint64]string
@@ -294,14 +309,20 @@ func (r *importReader) obj(name string) {
                r.declare(types2.NewConst(pos, r.currPkg, name, typ, val))
 
        case 'F':
-               tparams := r.tparamList()
+               var tparams []*types2.TypeName
+               if r.p.exportVersion >= iexportVersionGenerics {
+                       tparams = r.tparamList()
+               }
                sig := r.signature(nil)
                sig.SetTParams(tparams)
 
                r.declare(types2.NewFunc(pos, r.currPkg, name, sig))
 
        case 'T':
-               tparams := r.tparamList()
+               var tparams []*types2.TypeName
+               if r.p.exportVersion >= iexportVersionGenerics {
+                       tparams = r.tparamList()
+               }
 
                // Types can be recursive. We need to setup a stub
                // declaration before recursing.
@@ -592,6 +613,9 @@ func (r *importReader) doType(base *types2.Named) types2.Type {
                return typ
 
        case typeParamType:
+               if r.p.exportVersion < iexportVersionGenerics {
+                       errorf("unexpected type param type")
+               }
                r.currPkg = r.pkg()
                pos := r.pos()
                name := r.string()
@@ -622,6 +646,9 @@ func (r *importReader) doType(base *types2.Named) types2.Type {
                return t
 
        case instType:
+               if r.p.exportVersion < iexportVersionGenerics {
+                       errorf("unexpected instantiation type")
+               }
                pos := r.pos()
                len := r.uint64()
                targs := make([]types2.Type, len)
index 11b9755148e0ea73970fc3caac2512c104d7c755..e6813adbf90eb60005541f64b169493a7162ce89 100644 (file)
@@ -223,9 +223,17 @@ import (
 )
 
 // Current indexed export format version. Increase with each format change.
-// 1: added column details to Pos
 // 0: Go1.11 encoding
-const iexportVersion = 1
+// 1: added column details to Pos
+// 2: added information for generic function/types (currently unstable)
+const (
+       iexportVersionGo1_11   = 0
+       iexportVersionPosCol   = 1
+       iexportVersionGenerics = 2
+
+       // Start of the unstable series of versions, remove "+ n" before release.
+       iexportVersionCurrent = iexportVersionGenerics + 1
+)
 
 // predeclReserved is the number of type offsets reserved for types
 // implicitly declared in the universe block.
@@ -297,7 +305,7 @@ func WriteExports(out *bufio.Writer) {
        // Assemble header.
        var hdr intWriter
        hdr.WriteByte('i')
-       hdr.uint64(iexportVersion)
+       hdr.uint64(iexportVersionCurrent)
        hdr.uint64(uint64(p.strings.Len()))
        hdr.uint64(dataLen)
 
index b6f227bb00eb71db8d6995fd4d152518c85187c4..778ce4be12ab96d2c1999dfe35d35384c49a5012 100644 (file)
@@ -121,8 +121,14 @@ func ReadImports(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintT
        ird := &intReader{in, pkg}
 
        version := ird.uint64()
-       if version != iexportVersion {
-               base.Errorf("import %q: unknown export format version %d", pkg.Path, version)
+       switch version {
+       case iexportVersionCurrent, iexportVersionPosCol, iexportVersionGo1_11:
+       default:
+               if version > iexportVersionGenerics {
+                       base.Errorf("import %q: unstable export format version %d, just recompile", pkg.Path, version)
+               } else {
+                       base.Errorf("import %q: unknown export format version %d", pkg.Path, version)
+               }
                base.ErrorExit()
        }
 
@@ -143,7 +149,8 @@ func ReadImports(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintT
        in.MustSeek(int64(sLen+dLen), os.SEEK_CUR)
 
        p := &iimporter{
-               ipkg: pkg,
+               exportVersion: version,
+               ipkg:          pkg,
 
                pkgCache:     map[uint64]*types.Pkg{},
                posBaseCache: map[uint64]*src.PosBase{},
@@ -212,7 +219,8 @@ func ReadImports(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintT
 }
 
 type iimporter struct {
-       ipkg *types.Pkg
+       exportVersion uint64
+       ipkg          *types.Pkg
 
        pkgCache     map[uint64]*types.Pkg
        posBaseCache map[uint64]*src.PosBase
@@ -314,7 +322,10 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name {
                return n
 
        case 'F':
-               tparams := r.tparamList()
+               var tparams []*types.Field
+               if r.p.exportVersion >= iexportVersionGenerics {
+                       tparams = r.tparamList()
+               }
                typ := r.signature(nil, tparams)
 
                n := importfunc(r.p.ipkg, pos, sym, typ)
@@ -322,7 +333,10 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name {
                return n
 
        case 'T':
-               rparams := r.typeList()
+               var rparams []*types.Type
+               if r.p.exportVersion >= iexportVersionGenerics {
+                       rparams = r.typeList()
+               }
 
                // Types can be recursive. We need to setup a stub
                // declaration before recursing.
@@ -738,6 +752,9 @@ func (r *importReader) typ1() *types.Type {
                return t
 
        case typeParamType:
+               if r.p.exportVersion < iexportVersionGenerics {
+                       base.Fatalf("unexpected type param type")
+               }
                r.setPkg()
                pos := r.pos()
                name := r.string()
@@ -761,6 +778,9 @@ func (r *importReader) typ1() *types.Type {
                return t
 
        case instType:
+               if r.p.exportVersion < iexportVersionGenerics {
+                       base.Fatalf("unexpected instantiation type")
+               }
                pos := r.pos()
                len := r.uint64()
                targs := make([]*types.Type, len)
index c010dc506e7caeee11468901c18983b22ccc76b1..286b8a63471e6851dd14d06dc8650e859adf881c 100644 (file)
@@ -139,7 +139,7 @@ func TestVersionHandling(t *testing.T) {
 
        // This package only handles gc export data.
        // Disable test until we put in the new export version.
-       if true || runtime.Compiler != "gc" {
+       if runtime.Compiler != "gc" {
                t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
        }
 
index 4416f5b2b92b06282ced9e2f2677bc6bbd8e5914..e003dc9767a387c384bee6968d8c6aec4c0a84e7 100644 (file)
@@ -40,6 +40,16 @@ func (r *intReader) uint64() uint64 {
        return i
 }
 
+// Keep this in sync with constants in iexport.go.
+const (
+       iexportVersionGo1_11   = 0
+       iexportVersionPosCol   = 1
+       iexportVersionGenerics = 2
+
+       // Start of the unstable series of versions, remove "+ n" before release.
+       iexportVersionCurrent = iexportVersionGenerics + 1
+)
+
 const predeclReserved = 32
 
 type itag uint64
@@ -64,7 +74,7 @@ const (
 // If the export data version is not recognized or the format is otherwise
 // compromised, an error is returned.
 func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
-       const currentVersion = 1
+       const currentVersion = iexportVersionCurrent
        version := int64(-1)
        defer func() {
                if e := recover(); e != nil {
@@ -80,9 +90,13 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
 
        version = int64(r.uint64())
        switch version {
-       case currentVersion, 0:
+       case currentVersion, iexportVersionPosCol, iexportVersionGo1_11:
        default:
-               errorf("unknown iexport format version %d", version)
+               if version > iexportVersionGenerics {
+                       errorf("unstable iexport format version %d, just rebuild compiler and std library", version)
+               } else {
+                       errorf("unknown iexport format version %d", version)
+               }
        }
 
        sLen := int64(r.uint64())
@@ -94,8 +108,9 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
        r.Seek(sLen+dLen, io.SeekCurrent)
 
        p := iimporter{
-               ipath:   path,
-               version: int(version),
+               exportVersion: version,
+               ipath:         path,
+               version:       int(version),
 
                stringData:  stringData,
                stringCache: make(map[uint64]string),
@@ -173,8 +188,9 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
 }
 
 type iimporter struct {
-       ipath   string
-       version int
+       exportVersion int64
+       ipath         string
+       version       int
 
        stringData  []byte
        stringCache map[uint64]string
@@ -273,19 +289,22 @@ func (r *importReader) obj(name string) {
                r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
 
        case 'F':
-               numTparams := r.uint64()
-               if numTparams > 0 {
-                       errorf("unexpected tparam")
-                       return
+               if r.p.exportVersion >= iexportVersionGenerics {
+                       numTparams := r.uint64()
+                       if numTparams > 0 {
+                               errorf("unexpected tparam")
+                       }
                }
                sig := r.signature(nil)
 
                r.declare(types.NewFunc(pos, r.currPkg, name, sig))
 
        case 'T':
-               numTparams := r.uint64()
-               if numTparams > 0 {
-                       errorf("unexpected tparam")
+               if r.p.exportVersion >= iexportVersionGenerics {
+                       numTparams := r.uint64()
+                       if numTparams > 0 {
+                               errorf("unexpected tparam")
+                       }
                }
 
                // Types can be recursive. We need to setup a stub
@@ -562,7 +581,7 @@ func (r *importReader) doType(base *types.Named) types.Type {
                return typ
 
        case typeParamType:
-               errorf("do not handle tparams yet")
+               errorf("do not handle type param types yet")
                return nil
 
        case instType:
diff --git a/test/typeparam/listimp.dir/a.go b/test/typeparam/listimp.dir/a.go
new file mode 100644 (file)
index 0000000..ea56975
--- /dev/null
@@ -0,0 +1,50 @@
+package a
+
+type Ordered interface {
+        type int, int8, int16, int32, int64,
+                uint, uint8, uint16, uint32, uint64, uintptr,
+                float32, float64,
+                string
+}
+
+// List is a linked list of ordered values of type T.
+type List[T Ordered] struct {
+        Next *List[T]
+        Val  T
+}
+
+func (l *List[T]) Largest() T {
+        var max T
+        for p := l; p != nil; p = p.Next {
+                if p.Val > max {
+                        max = p.Val
+                }
+        }
+        return max
+}
+
+type OrderedNum interface {
+        type int, int8, int16, int32, int64,
+                uint, uint8, uint16, uint32, uint64, uintptr,
+                float32, float64
+}
+
+// ListNum is a linked _List of ordered numeric values of type T.
+type ListNum[T OrderedNum] struct {
+        Next *ListNum[T]
+        Val  T
+}
+
+const Clip = 5
+
+// clippedLargest returns the largest in the list of OrderNums, but a max of 5.
+// TODO(danscales): fix export/import of an untype constant with typeparam type
+func (l *ListNum[T]) ClippedLargest() T {
+        var max T
+        for p := l; p != nil; p = p.Next {
+                if p.Val > max && p.Val < T(Clip) {
+                        max = p.Val
+                }
+        }
+        return max
+}
diff --git a/test/typeparam/listimp.dir/main.go b/test/typeparam/listimp.dir/main.go
new file mode 100644 (file)
index 0000000..4c1aa3e
--- /dev/null
@@ -0,0 +1,48 @@
+package main
+
+import (
+       "a"
+       "fmt"
+)
+
+func main() {
+        i3 := &a.List[int]{nil, 1}
+        i2 := &a.List[int]{i3, 3}
+        i1 := &a.List[int]{i2, 2}
+        if got, want := i1.Largest(), 3; got != want {
+                panic(fmt.Sprintf("got %d, want %d", got, want))
+        }
+
+        b3 := &a.List[byte]{nil, byte(1)}
+        b2 := &a.List[byte]{b3, byte(3)}
+        b1 := &a.List[byte]{b2, byte(2)}
+        if got, want := b1.Largest(), byte(3); got != want {
+                panic(fmt.Sprintf("got %d, want %d", got, want))
+        }
+
+        f3 := &a.List[float64]{nil, 13.5}
+        f2 := &a.List[float64]{f3, 1.2}
+        f1 := &a.List[float64]{f2, 4.5}
+        if got, want := f1.Largest(), 13.5; got != want {
+                panic(fmt.Sprintf("got %f, want %f", got, want))
+        }
+
+        s3 := &a.List[string]{nil, "dd"}
+        s2 := &a.List[string]{s3, "aa"}
+        s1 := &a.List[string]{s2, "bb"}
+        if got, want := s1.Largest(), "dd"; got != want {
+                panic(fmt.Sprintf("got %s, want %s", got, want))
+        }
+        j3 := &a.ListNum[int]{nil, 1}
+        j2 := &a.ListNum[int]{j3, 32}
+        j1 := &a.ListNum[int]{j2, 2}
+        if got, want := j1.ClippedLargest(), 2; got != want {
+                panic(fmt.Sprintf("got %d, want %d", got, want))
+        }
+        g3 := &a.ListNum[float64]{nil, 13.5}
+        g2 := &a.ListNum[float64]{g3, 1.2}
+        g1 := &a.ListNum[float64]{g2, 4.5}
+        if got, want := g1.ClippedLargest(), 4.5; got != want {
+                panic(fmt.Sprintf("got %f, want %f", got, want))
+        }
+}
diff --git a/test/typeparam/listimp.go b/test/typeparam/listimp.go
new file mode 100644 (file)
index 0000000..76930e5
--- /dev/null
@@ -0,0 +1,7 @@
+// rundir -G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored