]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: fix export/import of constants with typeparam type
authorDan Scales <danscales@google.com>
Wed, 2 Jun 2021 07:03:25 +0000 (00:03 -0700)
committerDan Scales <danscales@google.com>
Wed, 2 Jun 2021 23:10:42 +0000 (23:10 +0000)
A constant will have a TYPEPARAM type if it appears in a place where it
must match that typeparam type (e.g. in a binary operation with a
variable of that typeparam type). If so, then we must write out its
actual constant kind as well, so its constant val can be read in
properly during import.

Fixed some export/import tests which were casting some untyped constants
to avoid this problem.

Change-Id: I285ad8f1c8febbe526769c96e6b27acbd23050f0
Reviewed-on: https://go-review.googlesource.com/c/go/+/324189
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
src/cmd/compile/internal/typecheck/iexport.go
src/cmd/compile/internal/typecheck/iimport.go
test/typeparam/fact.go
test/typeparam/factimp.dir/a.go
test/typeparam/listimp.dir/a.go

index d83f385fcbf19a1664db82cfc4e9959c34da2641..66c356ee7c8c1952beb4d72cae22ff2f66fc06ba 100644 (file)
@@ -1061,26 +1061,50 @@ func constTypeOf(typ *types.Type) constant.Kind {
 }
 
 func (w *exportWriter) value(typ *types.Type, v constant.Value) {
-       ir.AssertValidTypeForConst(typ, v)
        w.typ(typ)
+       var kind constant.Kind
+       var valType *types.Type
+
+       if typ.Kind() == types.TTYPEPARAM {
+               // A constant will have a TYPEPARAM type if it appears in a place
+               // where it must match that typeparam type (e.g. in a binary
+               // operation with a variable of that typeparam type). If so, then
+               // we must write out its actual constant kind as well, so its
+               // constant val can be read in properly during import.
+               kind = v.Kind()
+               w.int64(int64(kind))
+
+               switch kind {
+               case constant.Int:
+                       valType = types.Types[types.TINT64]
+               case constant.Float:
+                       valType = types.Types[types.TFLOAT64]
+               case constant.Complex:
+                       valType = types.Types[types.TCOMPLEX128]
+               }
+       } else {
+               ir.AssertValidTypeForConst(typ, v)
+               kind = constTypeOf(typ)
+               valType = typ
+       }
 
-       // Each type has only one admissible constant representation,
-       // so we could type switch directly on v.U here. However,
-       // switching on the type increases symmetry with import logic
-       // and provides a useful consistency check.
+       // Each type has only one admissible constant representation, so we could
+       // type switch directly on v.Kind() here. However, switching on the type
+       // (in the non-typeparam case) increases symmetry with import logic and
+       // provides a useful consistency check.
 
-       switch constTypeOf(typ) {
+       switch kind {
        case constant.Bool:
                w.bool(constant.BoolVal(v))
        case constant.String:
                w.string(constant.StringVal(v))
        case constant.Int:
-               w.mpint(v, typ)
+               w.mpint(v, valType)
        case constant.Float:
-               w.mpfloat(v, typ)
+               w.mpfloat(v, valType)
        case constant.Complex:
-               w.mpfloat(constant.Real(v), typ)
-               w.mpfloat(constant.Imag(v), typ)
+               w.mpfloat(constant.Real(v), valType)
+               w.mpfloat(constant.Imag(v), valType)
        }
 }
 
index 4c31e47378aad163ee1ed5c0f1092cd54e787459..96107b657b624c139cefdbcaa226105b6ee81b4c 100644 (file)
@@ -400,19 +400,39 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name {
 }
 
 func (p *importReader) value(typ *types.Type) constant.Value {
-       switch constTypeOf(typ) {
+       var kind constant.Kind
+       var valType *types.Type
+
+       if typ.Kind() == types.TTYPEPARAM {
+               // If a constant had a typeparam type, then we wrote out its
+               // actual constant kind as well.
+               kind = constant.Kind(p.int64())
+               switch kind {
+               case constant.Int:
+                       valType = types.Types[types.TINT64]
+               case constant.Float:
+                       valType = types.Types[types.TFLOAT64]
+               case constant.Complex:
+                       valType = types.Types[types.TCOMPLEX128]
+               }
+       } else {
+               kind = constTypeOf(typ)
+               valType = typ
+       }
+
+       switch kind {
        case constant.Bool:
                return constant.MakeBool(p.bool())
        case constant.String:
                return constant.MakeString(p.string())
        case constant.Int:
                var i big.Int
-               p.mpint(&i, typ)
+               p.mpint(&i, valType)
                return constant.Make(&i)
        case constant.Float:
-               return p.float(typ)
+               return p.float(valType)
        case constant.Complex:
-               return makeComplex(p.float(typ), p.float(typ))
+               return makeComplex(p.float(valType), p.float(valType))
        }
 
        base.Fatalf("unexpected value type: %v", typ)
index 16b2adf6fb71557566a4c23312d30885ad457c1d..ea86ae3e028a60f81de5a109a59eb59b1c56b511 100644 (file)
@@ -9,10 +9,10 @@ package main
 import "fmt"
 
 func fact[T interface { type int, int64, float64 }](n T) T {
-       if n == T(1) {
-               return T(1)
+       if n == 1 {
+               return 1
        }
-       return n * fact(n - T(1))
+       return n * fact(n - 1)
 }
 
 func main() {
index e11575e66e5adaf6b50e3f7ad3ef46f9e3d868ab..355247438296cbc9e15a993c1ad769a594c74780 100644 (file)
@@ -5,8 +5,8 @@
 package a
 
 func Fact[T interface { type int, int64, float64 }](n T) T {
-       if n == T(1) {
-               return T(1)
+       if n == 1 {
+               return 1
        }
-       return n * Fact(n - T(1))
+       return n * Fact(n - 1)
 }
index a4118a0e819b5fb89f7464562cca321001291ad1..0a4634b7be4517c12862cb929dbdf7d0c2df5649 100644 (file)
@@ -42,11 +42,10 @@ type ListNum[T OrderedNum] struct {
 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) {
+                if p.Val > max && p.Val < Clip {
                         max = p.Val
                 }
         }