mirror of https://github.com/golang/go.git
go/types: fix real(a) and imag(a) for untyped arguments
Fixes #11947. Change-Id: I6225f96b8dea0cecb097f9c7452a1aa80ae4476d Reviewed-on: https://go-review.googlesource.com/12939 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
a34b8cb733
commit
b9e4867e8d
|
|
@ -207,7 +207,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
return
|
||||
}
|
||||
|
||||
// Convert or check untyped arguments.
|
||||
// convert or check untyped arguments
|
||||
d := 0
|
||||
if isUntyped(x.typ) {
|
||||
d |= 1
|
||||
|
|
@ -231,7 +231,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
// 2) if one of them is not constant (possible because
|
||||
// it contains a shift that is yet untyped), convert
|
||||
// both of them to float64 since they must have the
|
||||
// same type to succeed
|
||||
// same type to succeed (this will result in an error
|
||||
// because shifts of floats are not permitted)
|
||||
if x.mode == constant_ && y.mode == constant_ {
|
||||
toFloat := func(x *operand) {
|
||||
if isNumeric(x.typ) && constant.Sign(constant.Imag(x.val)) == 0 {
|
||||
|
|
@ -243,6 +244,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
} else {
|
||||
check.convertUntyped(x, Typ[Float64])
|
||||
check.convertUntyped(&y, Typ[Float64])
|
||||
// x and y should be invalid now, but be conservative
|
||||
// and check below
|
||||
}
|
||||
}
|
||||
if x.mode == invalid || y.mode == invalid {
|
||||
|
|
@ -261,7 +264,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
return
|
||||
}
|
||||
|
||||
// if both arguments are constant, the result is a constant
|
||||
// if both arguments are constants, the result is a constant
|
||||
if x.mode == constant_ && y.mode == constant_ {
|
||||
x.val = constant.BinaryOp(x.val, token.ADD, constant.MakeImag(y.val))
|
||||
} else {
|
||||
|
|
@ -351,10 +354,35 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
case _Imag, _Real:
|
||||
// imag(complexT) floatT
|
||||
// real(complexT) floatT
|
||||
|
||||
// convert or check untyped argument
|
||||
if isUntyped(x.typ) {
|
||||
if x.mode == constant_ {
|
||||
// an untyped constant number can alway be considered
|
||||
// as a complex constant
|
||||
if isNumeric(x.typ) {
|
||||
x.typ = Typ[UntypedComplex]
|
||||
}
|
||||
} else {
|
||||
// an untyped non-constant argument may appear if
|
||||
// it contains a (yet untyped non-constant) shift
|
||||
// epression: convert it to complex128 which will
|
||||
// result in an error (shift of complex value)
|
||||
check.convertUntyped(x, Typ[Complex128])
|
||||
// x should be invalid now, but be conservative and check
|
||||
if x.mode == invalid {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the argument must be of complex type
|
||||
if !isComplex(x.typ) {
|
||||
check.invalidArg(x.pos(), "%s must be a complex number", x)
|
||||
check.invalidArg(x.pos(), "argument has type %s, expected complex type", x.typ)
|
||||
return
|
||||
}
|
||||
|
||||
// if the argument is a constant, the result is a constant
|
||||
if x.mode == constant_ {
|
||||
if id == _Real {
|
||||
x.val = constant.Real(x.val)
|
||||
|
|
@ -364,22 +392,26 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
} else {
|
||||
x.mode = value
|
||||
}
|
||||
var k BasicKind
|
||||
|
||||
// determine result type
|
||||
var res BasicKind
|
||||
switch x.typ.Underlying().(*Basic).kind {
|
||||
case Complex64:
|
||||
k = Float32
|
||||
res = Float32
|
||||
case Complex128:
|
||||
k = Float64
|
||||
res = Float64
|
||||
case UntypedComplex:
|
||||
k = UntypedFloat
|
||||
res = UntypedFloat
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
resTyp := Typ[res]
|
||||
|
||||
if check.Types != nil && x.mode != constant_ {
|
||||
check.recordBuiltinType(call.Fun, makeSig(Typ[k], x.typ))
|
||||
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ))
|
||||
}
|
||||
x.typ = Typ[k]
|
||||
|
||||
x.typ = resTyp
|
||||
|
||||
case _Make:
|
||||
// make(T, n)
|
||||
|
|
|
|||
|
|
@ -307,9 +307,10 @@ func imag1() {
|
|||
var c128 complex128
|
||||
_ = imag() // ERROR not enough arguments
|
||||
_ = imag(1, 2) // ERROR too many arguments
|
||||
_ = imag(10 /* ERROR must be a complex number */)
|
||||
_ = imag(2.7182818 /* ERROR must be a complex number */)
|
||||
_ = imag("foo" /* ERROR must be a complex number */)
|
||||
_ = imag(10)
|
||||
_ = imag(2.7182818)
|
||||
_ = imag("foo" /* ERROR expected complex */)
|
||||
_ = imag('a')
|
||||
const _5 = imag(1 + 2i)
|
||||
assert(_5 == 2)
|
||||
f32 = _5
|
||||
|
|
@ -331,8 +332,16 @@ func imag1() {
|
|||
f32 = imag(x64)
|
||||
f64 = imag(x128)
|
||||
|
||||
var s []complex64
|
||||
_ = imag(s... /* ERROR invalid use of \.\.\. */ )
|
||||
var a []complex64
|
||||
_ = imag(a... /* ERROR invalid use of \.\.\. */ )
|
||||
|
||||
// if argument is untyped, result is untyped
|
||||
const _ byte = imag(1.2 + 3i)
|
||||
const _ complex128 = imag(1.2 + 3i)
|
||||
|
||||
// lhs constant shift operands are typed as complex128
|
||||
var s uint
|
||||
_ = imag(1 /* ERROR must be integer */ << s)
|
||||
}
|
||||
|
||||
func imag2() {
|
||||
|
|
@ -579,9 +588,9 @@ func real1() {
|
|||
var c128 complex128
|
||||
_ = real() // ERROR not enough arguments
|
||||
_ = real(1, 2) // ERROR too many arguments
|
||||
_ = real(10 /* ERROR must be a complex number */)
|
||||
_ = real(2.7182818 /* ERROR must be a complex number */)
|
||||
_ = real("foo" /* ERROR must be a complex number */)
|
||||
_ = real(10)
|
||||
_ = real(2.7182818)
|
||||
_ = real("foo" /* ERROR expected complex */)
|
||||
const _5 = real(1 + 2i)
|
||||
assert(_5 == 1)
|
||||
f32 = _5
|
||||
|
|
@ -601,10 +610,18 @@ func real1() {
|
|||
var x128 C128
|
||||
f32 = imag(x64)
|
||||
f64 = imag(x128)
|
||||
|
||||
var s []complex64
|
||||
_ = real(s... /* ERROR invalid use of \.\.\. */ )
|
||||
_, _ = f32, f64
|
||||
|
||||
var a []complex64
|
||||
_ = real(a... /* ERROR invalid use of \.\.\. */ )
|
||||
|
||||
// if argument is untyped, result is untyped
|
||||
const _ byte = real(1 + 2.3i)
|
||||
const _ complex128 = real(1 + 2.3i)
|
||||
|
||||
// lhs constant shift operands are typed as complex128
|
||||
var s uint
|
||||
_ = real(1 /* ERROR must be integer */ << s)
|
||||
}
|
||||
|
||||
func real2() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue