aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2015-07-30 15:00:50 -0700
committerRobert Griesemer <gri@golang.org>2015-08-21 04:42:20 +0000
commit39e77bff85ddc9e862eccf0408968301955db977 (patch)
treec8aee702a0619e4a2e2d960adaa55acd6cb12b25 /src
parent80eca3a98b960bd612d0251137b93dfddbbb64de (diff)
downloadgo-39e77bff85ddc9e862eccf0408968301955db977.tar.xz
go/types: fix complex(a, b) for untyped arguments a, b
R=1.6 Fixes #11669. Change-Id: Id39e5401e991e46f014eb16b747f5d9b7b55b46a Reviewed-on: https://go-review.googlesource.com/12937 Reviewed-by: Alan Donovan <adonovan@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/go/types/builtins.go113
-rw-r--r--src/go/types/testdata/builtins.src19
2 files changed, 71 insertions, 61 deletions
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
index 47295914d0..d26e9a71a1 100644
--- a/src/go/types/builtins.go
+++ b/src/go/types/builtins.go
@@ -200,77 +200,93 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
}
case _Complex:
- // complex(x, y realT) complexT
- if !check.complexArg(x) {
- return
- }
-
+ // complex(x, y floatT) complexT
var y operand
arg(&y, 1)
if y.mode == invalid {
return
}
- if !check.complexArg(&y) {
- return
- }
- check.convertUntyped(x, y.typ)
- if x.mode == invalid {
- return
+ // Convert or check untyped arguments.
+ d := 0
+ if isUntyped(x.typ) {
+ d |= 1
}
- check.convertUntyped(&y, x.typ)
- if y.mode == invalid {
+ if isUntyped(y.typ) {
+ d |= 2
+ }
+ switch d {
+ case 0:
+ // x and y are typed => nothing to do
+ case 1:
+ // only x is untyped => convert to type of y
+ check.convertUntyped(x, y.typ)
+ case 2:
+ // only y is untyped => convert to type of x
+ check.convertUntyped(&y, x.typ)
+ case 3:
+ // x and y are untyped =>
+ // 1) if both are constants, convert them to untyped
+ // floating-point numbers if possible,
+ // 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
+ if x.mode == constant_ && y.mode == constant_ {
+ toFloat := func(x *operand) {
+ if isNumeric(x.typ) && constant.Sign(constant.Imag(x.val)) == 0 {
+ x.typ = Typ[UntypedFloat]
+ }
+ }
+ toFloat(x)
+ toFloat(&y)
+ } else {
+ check.convertUntyped(x, Typ[Float64])
+ check.convertUntyped(&y, Typ[Float64])
+ }
+ }
+ if x.mode == invalid || y.mode == invalid {
return
}
+ // both argument types must be identical
if !Identical(x.typ, y.typ) {
check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
return
}
+ // the argument types must be of floating-point type
+ if !isFloat(x.typ) {
+ check.invalidArg(x.pos(), "arguments have type %s, expected floating-point", x.typ)
+ return
+ }
+
+ // if both arguments are constant, 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 {
x.mode = value
}
- realT := x.typ
- complexT := Typ[Invalid]
- switch realT.Underlying().(*Basic).kind {
+ // determine result type
+ var res BasicKind
+ switch x.typ.Underlying().(*Basic).kind {
case Float32:
- complexT = Typ[Complex64]
+ res = Complex64
case Float64:
- complexT = Typ[Complex128]
- case UntypedInt, UntypedRune, UntypedFloat:
- if x.mode == constant_ {
- realT = defaultType(realT).(*Basic)
- complexT = Typ[UntypedComplex]
- } else {
- // untyped but not constant; probably because one
- // operand is a non-constant shift of untyped lhs
- realT = Typ[Float64]
- complexT = Typ[Complex128]
- }
+ res = Complex128
+ case UntypedFloat:
+ res = UntypedComplex
default:
- check.invalidArg(x.pos(), "float32 or float64 arguments expected")
- return
+ unreachable()
}
+ resTyp := Typ[res]
- x.typ = complexT
if check.Types != nil && x.mode != constant_ {
- check.recordBuiltinType(call.Fun, makeSig(complexT, realT, realT))
+ check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ, x.typ))
}
- if x.mode != constant_ {
- // The arguments have now their final types, which at run-
- // time will be materialized. Update the expression trees.
- // If the current types are untyped, the materialized type
- // is the respective default type.
- // (If the result is constant, the arguments are never
- // materialized and there is nothing to do.)
- check.updateExprType(x.expr, realT, true)
- check.updateExprType(y.expr, realT, true)
- }
+ x.typ = resTyp
case _Copy:
// copy(x, y []T) int
@@ -333,8 +349,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
}
case _Imag, _Real:
- // imag(complexT) realT
- // real(complexT) realT
+ // imag(complexT) floatT
+ // real(complexT) floatT
if !isComplex(x.typ) {
check.invalidArg(x.pos(), "%s must be a complex number", x)
return
@@ -616,12 +632,3 @@ func unparen(e ast.Expr) ast.Expr {
e = p.X
}
}
-
-func (check *Checker) complexArg(x *operand) bool {
- t, _ := x.typ.Underlying().(*Basic)
- if t != nil && (t.info&IsFloat != 0 || t.kind == UntypedInt || t.kind == UntypedRune) {
- return true
- }
- check.invalidArg(x.pos(), "%s must be a float32, float64, or an untyped non-complex numeric constant", x)
- return false
-}
diff --git a/src/go/types/testdata/builtins.src b/src/go/types/testdata/builtins.src
index 9eb551dc10..94eb6d771d 100644
--- a/src/go/types/testdata/builtins.src
+++ b/src/go/types/testdata/builtins.src
@@ -168,14 +168,14 @@ func complex1() {
var c128 complex128
_ = complex() // ERROR not enough arguments
_ = complex(1) // ERROR not enough arguments
- _ = complex(true /* ERROR invalid argument */ , 0)
- _ = complex(i32 /* ERROR invalid argument */ , 0)
- _ = complex("foo" /* ERROR invalid argument */ , 0)
- _ = complex(c64 /* ERROR invalid argument */ , 0)
- _ = complex(0, true /* ERROR invalid argument */ )
- _ = complex(0, i32 /* ERROR invalid argument */ )
- _ = complex(0, "foo" /* ERROR invalid argument */ )
- _ = complex(0, c64 /* ERROR invalid argument */ )
+ _ = complex(true /* ERROR mismatched types */ , 0)
+ _ = complex(i32 /* ERROR expected floating-point */ , 0)
+ _ = complex("foo" /* ERROR mismatched types */ , 0)
+ _ = complex(c64 /* ERROR expected floating-point */ , 0)
+ _ = complex(0 /* ERROR mismatched types */ , true)
+ _ = complex(0 /* ERROR expected floating-point */ , i32)
+ _ = complex(0 /* ERROR mismatched types */ , "foo")
+ _ = complex(0 /* ERROR expected floating-point */ , c64)
_ = complex(f32, f32)
_ = complex(f32, 1)
_ = complex(f32, 1.0)
@@ -202,6 +202,9 @@ func complex1() {
const _ float32 = complex(1, 0)
const _ complex64 = complex(1, 0)
const _ complex128 = complex(1, 0)
+ const _ = complex(0i, 0i)
+ const _ = complex(0i, 0)
+ const _ int = 1.0 + complex(1, 0i)
const _ int = complex /* ERROR int */ (1.1, 0)
const _ float32 = complex /* ERROR float32 */ (1, 2)