]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: disallow real, imag, complex on type parameters
authorRobert Griesemer <gri@golang.org>
Mon, 31 Jan 2022 23:12:53 +0000 (15:12 -0800)
committerRobert Griesemer <gri@golang.org>
Tue, 1 Feb 2022 01:07:25 +0000 (01:07 +0000)
We can type-check these fine but the API implications are unclear.

Fixes #50912.
For #50937.

Change-Id: If29bbb4a257ff6a85e3bfcd4755fd8f90c80fb87
Reviewed-on: https://go-review.googlesource.com/c/go/+/382116
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/types2/builtins.go
src/cmd/compile/internal/types2/testdata/fixedbugs/issue50912.go2 [new file with mode: 0644]
src/go/types/builtins.go
src/go/types/testdata/fixedbugs/issue50912.go2 [new file with mode: 0644]
test/typeparam/absdiff2.go
test/typeparam/absdiff3.go
test/typeparam/absdiffimp2.dir/a.go

index cea4fd36318cd149fb5a6bbfe9923c3204f7aefa..c2f955ce8c70a2409a91c3c59111c9a4838b7c04 100644 (file)
@@ -309,7 +309,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                        }
                        return nil
                }
-               resTyp := check.applyTypeFunc(f, x.typ)
+               resTyp := check.applyTypeFunc(f, x, id)
                if resTyp == nil {
                        check.errorf(x, invalidArg+"arguments have type %s, expected floating-point", x.typ)
                        return
@@ -437,7 +437,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                        }
                        return nil
                }
-               resTyp := check.applyTypeFunc(f, x.typ)
+               resTyp := check.applyTypeFunc(f, x, id)
                if resTyp == nil {
                        check.errorf(x, invalidArg+"argument has type %s, expected complex type", x.typ)
                        return
@@ -800,8 +800,8 @@ func hasVarSize(t Type) bool {
 // of x. If any of these applications of f return nil,
 // applyTypeFunc returns nil.
 // If x is not a type parameter, the result is f(x).
-func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
-       if tp, _ := x.(*TypeParam); tp != nil {
+func (check *Checker) applyTypeFunc(f func(Type) Type, x *operand, id builtinId) Type {
+       if tp, _ := x.typ.(*TypeParam); tp != nil {
                // Test if t satisfies the requirements for the argument
                // type and collect possible result types at the same time.
                var terms []*Term
@@ -818,17 +818,23 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
                        return nil
                }
 
+               // We can type-check this fine but we're introducing a synthetic
+               // type parameter for the result. It's not clear what the API
+               // implications are here. Report an error for 1.18 but continue
+               // type-checking.
+               check.softErrorf(x, "%s not supported as argument to %s for go1.18 (see issue #50937)", x, predeclaredFuncs[id].name)
+
                // Construct a suitable new type parameter for the result type.
                // The type parameter is placed in the current package so export/import
                // works as expected.
-               tpar := NewTypeName(nopos, check.pkg, "<type parameter>", nil)
+               tpar := NewTypeName(nopos, check.pkg, tp.obj.name, nil)
                ptyp := check.newTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect
                ptyp.index = tp.index
 
                return ptyp
        }
 
-       return f(x)
+       return f(x.typ)
 }
 
 // makeSig makes a signature for the given argument and result types.
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50912.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50912.go2
new file mode 100644 (file)
index 0000000..f161925
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2022 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 p
+
+func Real[P ~complex128](x P) {
+       _ = real(x /* ERROR not supported */ )
+}
+
+func Imag[P ~complex128](x P) {
+       _ = imag(x /* ERROR not supported */ )
+}
+
+func Complex[P ~float64](x P) {
+       _ = complex(x /* ERROR not supported */ , 0)
+       _ = complex(0 /* ERROR not supported */ , x)
+       _ = complex(x /* ERROR not supported */ , x)
+}
index 35a2d1ae2e6799c82fabc7d1d750b8897a852685..f9aece225b2abe3d3b9a4221ccddb683404ba715 100644 (file)
@@ -314,7 +314,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                        }
                        return nil
                }
-               resTyp := check.applyTypeFunc(f, x.typ)
+               resTyp := check.applyTypeFunc(f, x, id)
                if resTyp == nil {
                        check.invalidArg(x, _InvalidComplex, "arguments have type %s, expected floating-point", x.typ)
                        return
@@ -442,7 +442,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                        }
                        return nil
                }
-               resTyp := check.applyTypeFunc(f, x.typ)
+               resTyp := check.applyTypeFunc(f, x, id)
                if resTyp == nil {
                        code := _InvalidImag
                        if id == _Real {
@@ -809,8 +809,8 @@ func hasVarSize(t Type) bool {
 // of x. If any of these applications of f return nil,
 // applyTypeFunc returns nil.
 // If x is not a type parameter, the result is f(x).
-func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
-       if tp, _ := x.(*TypeParam); tp != nil {
+func (check *Checker) applyTypeFunc(f func(Type) Type, x *operand, id builtinId) Type {
+       if tp, _ := x.typ.(*TypeParam); tp != nil {
                // Test if t satisfies the requirements for the argument
                // type and collect possible result types at the same time.
                var terms []*Term
@@ -827,17 +827,34 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
                        return nil
                }
 
+               // We can type-check this fine but we're introducing a synthetic
+               // type parameter for the result. It's not clear what the API
+               // implications are here. Report an error for 1.18 (see #50912),
+               // but continue type-checking.
+               var code errorCode
+               switch id {
+               case _Real:
+                       code = _InvalidReal
+               case _Imag:
+                       code = _InvalidImag
+               case _Complex:
+                       code = _InvalidComplex
+               default:
+                       unreachable()
+               }
+               check.softErrorf(x, code, "%s not supported as argument to %s for go1.18 (see issue #50937)", x, predeclaredFuncs[id].name)
+
                // Construct a suitable new type parameter for the result type.
                // The type parameter is placed in the current package so export/import
                // works as expected.
-               tpar := NewTypeName(token.NoPos, check.pkg, "<type parameter>", nil)
+               tpar := NewTypeName(token.NoPos, check.pkg, tp.obj.name, nil)
                ptyp := check.newTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect
                ptyp.index = tp.index
 
                return ptyp
        }
 
-       return f(x)
+       return f(x.typ)
 }
 
 // makeSig makes a signature for the given argument and result types.
diff --git a/src/go/types/testdata/fixedbugs/issue50912.go2 b/src/go/types/testdata/fixedbugs/issue50912.go2
new file mode 100644 (file)
index 0000000..f161925
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2022 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 p
+
+func Real[P ~complex128](x P) {
+       _ = real(x /* ERROR not supported */ )
+}
+
+func Imag[P ~complex128](x P) {
+       _ = imag(x /* ERROR not supported */ )
+}
+
+func Complex[P ~float64](x P) {
+       _ = complex(x /* ERROR not supported */ , 0)
+       _ = complex(0 /* ERROR not supported */ , x)
+       _ = complex(x /* ERROR not supported */ , x)
+}
index 2d82c4721ce8ac765512fd7a9a7696c82e0d2f02..36de8ff2c9ab3065ba55264a8aa33e30dc0ecb1c 100644 (file)
@@ -66,9 +66,25 @@ type complexAbs[T Complex] struct {
        Value T
 }
 
+func realimag(x any) (re, im float64) {
+       switch z := x.(type) {
+       case complex64:
+               re = float64(real(z))
+               im = float64(imag(z))
+       case complex128:
+               re = real(z)
+               im = imag(z)
+       default:
+               panic("unknown complex type")
+       }
+       return
+}
+
 func (a complexAbs[T]) Abs() T {
-       r := float64(real(a.Value))
-       i := float64(imag(a.Value))
+       // TODO use direct conversion instead of realimag once #50937 is fixed
+       r, i := realimag(a.Value)
+       // r := float64(real(a.Value))
+       // i := float64(imag(a.Value))
        d := math.Sqrt(r*r + i*i)
        return T(complex(d, 0))
 }
index 3ca03fe26f8f38401b659cb20ea7644724246028..99fa6f11ab503a04d605d7dd04495ca4e83c4291 100644 (file)
@@ -43,9 +43,25 @@ type Complex interface {
        ~complex64 | ~complex128
 }
 
+func realimag(x any) (re, im float64) {
+       switch z := x.(type) {
+       case complex64:
+               re = float64(real(z))
+               im = float64(imag(z))
+       case complex128:
+               re = real(z)
+               im = imag(z)
+       default:
+               panic("unknown complex type")
+       }
+       return
+}
+
 func ComplexAbs[T Complex](a T) T {
-       r := float64(real(a))
-       i := float64(imag(a))
+       // TODO use direct conversion instead of realimag once #50937 is fixed
+       r, i := realimag(a)
+       // r := float64(real(a))
+       // i := float64(imag(a))
        d := math.Sqrt(r*r + i*i)
        return T(complex(d, 0))
 }
index 302b69b97664f94c256dd79ce6829cd4d9db8a81..43493e1430d4f23f81735833666428e12f5d5eb0 100644 (file)
@@ -60,9 +60,25 @@ type complexAbs[T Complex] struct {
        Value T
 }
 
+func realimag(x any) (re, im float64) {
+       switch z := x.(type) {
+       case complex64:
+               re = float64(real(z))
+               im = float64(imag(z))
+       case complex128:
+               re = real(z)
+               im = imag(z)
+       default:
+               panic("unknown complex type")
+       }
+       return
+}
+
 func (a complexAbs[T]) Abs() T {
-       r := float64(real(a.Value))
-       i := float64(imag(a.Value))
+       // TODO use direct conversion instead of realimag once #50937 is fixed
+       r, i := realimag(a.Value)
+       // r := float64(real(a.Value))
+       // i := float64(imag(a.Value))
        d := math.Sqrt(r*r + i*i)
        return T(complex(d, 0))
 }