mirror of
https://github.com/golang/go
synced 2024-11-26 16:07:00 -07:00
go/types, types2: disallow real, imag, complex on type parameters
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>
This commit is contained in:
parent
eab9a77a60
commit
4fea5935f5
@ -309,7 +309,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
resTyp := check.applyTypeFunc(f, x.typ)
|
resTyp := check.applyTypeFunc(f, x, id)
|
||||||
if resTyp == nil {
|
if resTyp == nil {
|
||||||
check.errorf(x, invalidArg+"arguments have type %s, expected floating-point", x.typ)
|
check.errorf(x, invalidArg+"arguments have type %s, expected floating-point", x.typ)
|
||||||
return
|
return
|
||||||
@ -437,7 +437,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
resTyp := check.applyTypeFunc(f, x.typ)
|
resTyp := check.applyTypeFunc(f, x, id)
|
||||||
if resTyp == nil {
|
if resTyp == nil {
|
||||||
check.errorf(x, invalidArg+"argument has type %s, expected complex type", x.typ)
|
check.errorf(x, invalidArg+"argument has type %s, expected complex type", x.typ)
|
||||||
return
|
return
|
||||||
@ -800,8 +800,8 @@ func hasVarSize(t Type) bool {
|
|||||||
// of x. If any of these applications of f return nil,
|
// of x. If any of these applications of f return nil,
|
||||||
// applyTypeFunc returns nil.
|
// applyTypeFunc returns nil.
|
||||||
// If x is not a type parameter, the result is f(x).
|
// If x is not a type parameter, the result is f(x).
|
||||||
func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
|
func (check *Checker) applyTypeFunc(f func(Type) Type, x *operand, id builtinId) Type {
|
||||||
if tp, _ := x.(*TypeParam); tp != nil {
|
if tp, _ := x.typ.(*TypeParam); tp != nil {
|
||||||
// Test if t satisfies the requirements for the argument
|
// Test if t satisfies the requirements for the argument
|
||||||
// type and collect possible result types at the same time.
|
// type and collect possible result types at the same time.
|
||||||
var terms []*Term
|
var terms []*Term
|
||||||
@ -818,17 +818,23 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
|
|||||||
return nil
|
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.
|
// Construct a suitable new type parameter for the result type.
|
||||||
// The type parameter is placed in the current package so export/import
|
// The type parameter is placed in the current package so export/import
|
||||||
// works as expected.
|
// 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 := check.newTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect
|
||||||
ptyp.index = tp.index
|
ptyp.index = tp.index
|
||||||
|
|
||||||
return ptyp
|
return ptyp
|
||||||
}
|
}
|
||||||
|
|
||||||
return f(x)
|
return f(x.typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeSig makes a signature for the given argument and result types.
|
// makeSig makes a signature for the given argument and result types.
|
||||||
|
19
src/cmd/compile/internal/types2/testdata/fixedbugs/issue50912.go2
vendored
Normal file
19
src/cmd/compile/internal/types2/testdata/fixedbugs/issue50912.go2
vendored
Normal file
@ -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)
|
||||||
|
}
|
@ -314,7 +314,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
resTyp := check.applyTypeFunc(f, x.typ)
|
resTyp := check.applyTypeFunc(f, x, id)
|
||||||
if resTyp == nil {
|
if resTyp == nil {
|
||||||
check.invalidArg(x, _InvalidComplex, "arguments have type %s, expected floating-point", x.typ)
|
check.invalidArg(x, _InvalidComplex, "arguments have type %s, expected floating-point", x.typ)
|
||||||
return
|
return
|
||||||
@ -442,7 +442,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
resTyp := check.applyTypeFunc(f, x.typ)
|
resTyp := check.applyTypeFunc(f, x, id)
|
||||||
if resTyp == nil {
|
if resTyp == nil {
|
||||||
code := _InvalidImag
|
code := _InvalidImag
|
||||||
if id == _Real {
|
if id == _Real {
|
||||||
@ -809,8 +809,8 @@ func hasVarSize(t Type) bool {
|
|||||||
// of x. If any of these applications of f return nil,
|
// of x. If any of these applications of f return nil,
|
||||||
// applyTypeFunc returns nil.
|
// applyTypeFunc returns nil.
|
||||||
// If x is not a type parameter, the result is f(x).
|
// If x is not a type parameter, the result is f(x).
|
||||||
func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
|
func (check *Checker) applyTypeFunc(f func(Type) Type, x *operand, id builtinId) Type {
|
||||||
if tp, _ := x.(*TypeParam); tp != nil {
|
if tp, _ := x.typ.(*TypeParam); tp != nil {
|
||||||
// Test if t satisfies the requirements for the argument
|
// Test if t satisfies the requirements for the argument
|
||||||
// type and collect possible result types at the same time.
|
// type and collect possible result types at the same time.
|
||||||
var terms []*Term
|
var terms []*Term
|
||||||
@ -827,17 +827,34 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
|
|||||||
return nil
|
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.
|
// Construct a suitable new type parameter for the result type.
|
||||||
// The type parameter is placed in the current package so export/import
|
// The type parameter is placed in the current package so export/import
|
||||||
// works as expected.
|
// 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 := check.newTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect
|
||||||
ptyp.index = tp.index
|
ptyp.index = tp.index
|
||||||
|
|
||||||
return ptyp
|
return ptyp
|
||||||
}
|
}
|
||||||
|
|
||||||
return f(x)
|
return f(x.typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeSig makes a signature for the given argument and result types.
|
// makeSig makes a signature for the given argument and result types.
|
||||||
|
19
src/go/types/testdata/fixedbugs/issue50912.go2
vendored
Normal file
19
src/go/types/testdata/fixedbugs/issue50912.go2
vendored
Normal file
@ -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)
|
||||||
|
}
|
@ -66,9 +66,25 @@ type complexAbs[T Complex] struct {
|
|||||||
Value T
|
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 {
|
func (a complexAbs[T]) Abs() T {
|
||||||
r := float64(real(a.Value))
|
// TODO use direct conversion instead of realimag once #50937 is fixed
|
||||||
i := float64(imag(a.Value))
|
r, i := realimag(a.Value)
|
||||||
|
// r := float64(real(a.Value))
|
||||||
|
// i := float64(imag(a.Value))
|
||||||
d := math.Sqrt(r*r + i*i)
|
d := math.Sqrt(r*r + i*i)
|
||||||
return T(complex(d, 0))
|
return T(complex(d, 0))
|
||||||
}
|
}
|
||||||
|
@ -43,9 +43,25 @@ type Complex interface {
|
|||||||
~complex64 | ~complex128
|
~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 {
|
func ComplexAbs[T Complex](a T) T {
|
||||||
r := float64(real(a))
|
// TODO use direct conversion instead of realimag once #50937 is fixed
|
||||||
i := float64(imag(a))
|
r, i := realimag(a)
|
||||||
|
// r := float64(real(a))
|
||||||
|
// i := float64(imag(a))
|
||||||
d := math.Sqrt(r*r + i*i)
|
d := math.Sqrt(r*r + i*i)
|
||||||
return T(complex(d, 0))
|
return T(complex(d, 0))
|
||||||
}
|
}
|
||||||
|
@ -60,9 +60,25 @@ type complexAbs[T Complex] struct {
|
|||||||
Value T
|
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 {
|
func (a complexAbs[T]) Abs() T {
|
||||||
r := float64(real(a.Value))
|
// TODO use direct conversion instead of realimag once #50937 is fixed
|
||||||
i := float64(imag(a.Value))
|
r, i := realimag(a.Value)
|
||||||
|
// r := float64(real(a.Value))
|
||||||
|
// i := float64(imag(a.Value))
|
||||||
d := math.Sqrt(r*r + i*i)
|
d := math.Sqrt(r*r + i*i)
|
||||||
return T(complex(d, 0))
|
return T(complex(d, 0))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user