aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/go/types/builtins.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/go/types/builtins.go')
-rw-r--r--libgo/go/go/types/builtins.go184
1 files changed, 112 insertions, 72 deletions
diff --git a/libgo/go/go/types/builtins.go b/libgo/go/go/types/builtins.go
index 47295914d00..803264fb585 100644
--- a/libgo/go/go/types/builtins.go
+++ b/libgo/go/go/types/builtins.go
@@ -44,7 +44,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
switch id {
default:
// make argument getter
- arg, nargs, _ = unpack(func(x *operand, i int) { check.expr(x, call.Args[i]) }, nargs, false)
+ arg, nargs, _ = unpack(func(x *operand, i int) { check.multiExpr(x, call.Args[i]) }, nargs, false)
if arg == nil {
return
}
@@ -95,7 +95,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// spec: "As a special case, append also accepts a first argument assignable
// to type []byte with a second argument of string type followed by ... .
// This form appends the bytes of the string.
- if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check.conf, NewSlice(universeByte)) {
+ if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check.conf, NewSlice(universeByte), nil) {
arg(x, 1)
if x.mode == invalid {
return
@@ -200,77 +200,96 @@ 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
+ }
+ 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 (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 {
+ x.typ = Typ[UntypedFloat]
+ }
+ }
+ toFloat(x)
+ toFloat(&y)
+ } else {
+ check.convertUntyped(x, Typ[Float64])
+ check.convertUntyped(&y, Typ[Float64])
+ // x and y should be invalid now, but be conservative
+ // and check below
+ }
}
- check.convertUntyped(&y, x.typ)
- if y.mode == invalid {
+ 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 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))
+ x.val = constant.BinaryOp(constant.ToFloat(x.val), token.ADD, constant.MakeImag(constant.ToFloat(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
@@ -322,7 +341,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
return
}
- if !x.assignableTo(check.conf, m.key) {
+ if !x.assignableTo(check.conf, m.key, nil) {
check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key)
return
}
@@ -333,12 +352,37 @@ 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
+
+ // 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)
@@ -348,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)
@@ -423,8 +471,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
case _Panic:
// panic(x)
T := new(Interface)
- if !check.assignment(x, T) {
- assert(x.mode == invalid)
+ check.assignment(x, T, "argument to panic")
+ if x.mode == invalid {
return
}
@@ -443,8 +491,9 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
if i > 0 {
arg(x, i) // first argument already evaluated
}
- if !check.assignment(x, nil) {
- assert(x.mode == invalid)
+ check.assignment(x, nil, "argument to "+predeclaredFuncs[id].name)
+ if x.mode == invalid {
+ // TODO(gri) "use" all arguments?
return
}
params[i] = x.typ
@@ -466,8 +515,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
case _Alignof:
// unsafe.Alignof(x T) uintptr
- if !check.assignment(x, nil) {
- assert(x.mode == invalid)
+ check.assignment(x, nil, "argument to unsafe.Alignof")
+ if x.mode == invalid {
return
}
@@ -523,8 +572,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
case _Sizeof:
// unsafe.Sizeof(x T) uintptr
- if !check.assignment(x, nil) {
- assert(x.mode == invalid)
+ check.assignment(x, nil, "argument to unsafe.Sizeof")
+ if x.mode == invalid {
return
}
@@ -616,12 +665,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
-}