// index checks an index/size expression arg for validity. // If length >= 0, it is the upper bound for arg. // TODO(gri): Do we need iota? func (check *checker) index(arg ast.Expr, length int64, iota int) (i int64, ok bool) { var x operand check.expr(&x, arg, nil, iota) // an untyped constant must be representable as Int check.convertUntyped(&x, Typ[Int]) if x.mode == invalid { return } // the index/size must be of integer type if !isInteger(x.typ) { check.invalidArg(x.pos(), "%s must be integer", &x) return } // a constant index/size i must be 0 <= i < length if x.mode == constant { if exact.Sign(x.val) < 0 { check.invalidArg(x.pos(), "%s must not be negative", &x) return } i, ok = exact.Int64Val(x.val) if !ok || length >= 0 && i >= length { check.errorf(x.pos(), "index %s is out of bounds", &x) return i, false } // 0 <= i [ && i < length ] return i, true } return -1, true }
func (check *checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token, iota int) { var y operand check.expr(x, lhs, nil, iota) check.expr(&y, rhs, nil, iota) if x.mode == invalid { return } if y.mode == invalid { x.mode = invalid x.expr = y.expr return } if isShift(op) { check.shift(x, &y, op) return } check.convertUntyped(x, y.typ) if x.mode == invalid { return } check.convertUntyped(&y, x.typ) if y.mode == invalid { x.mode = invalid return } if isComparison(op) { check.comparison(x, &y, op) return } if !IsIdentical(x.typ, y.typ) { // only report an error if we have valid types // (otherwise we had an error reported elsewhere already) if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] { check.invalidOp(x.pos(), "mismatched types %s and %s", x.typ, y.typ) } x.mode = invalid return } if !check.op(binaryOpPredicates, x, op) { x.mode = invalid return } if (op == token.QUO || op == token.REM) && y.mode == constant && exact.Sign(y.val) == 0 { check.invalidOp(y.pos(), "division by zero") x.mode = invalid return } if x.mode == constant && y.mode == constant { typ := underlying(x.typ).(*Basic) // force integer division of integer operands if op == token.QUO && isInteger(typ) { op = token.QUO_ASSIGN } x.val = exact.BinaryOp(x.val, op, y.val) // Typed constants must be representable in // their type after each constant operation. check.isRepresentable(x, typ) return } x.mode = value // x.typ is unchanged }
func isRepresentableConst(x exact.Value, ctxt *Context, as BasicKind) bool { switch x.Kind() { case exact.Unknown: return true case exact.Bool: return as == Bool || as == UntypedBool case exact.Int: if x, ok := exact.Int64Val(x); ok { switch as { case Int: var s = uint(ctxt.sizeof(Typ[as])) * 8 return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1 case Int8: const s = 8 return -1<<(s-1) <= x && x <= 1<<(s-1)-1 case Int16: const s = 16 return -1<<(s-1) <= x && x <= 1<<(s-1)-1 case Int32: const s = 32 return -1<<(s-1) <= x && x <= 1<<(s-1)-1 case Int64: return true case Uint, Uintptr: if s := uint(ctxt.sizeof(Typ[as])) * 8; s < 64 { return 0 <= x && x <= int64(1)<<s-1 } return 0 <= x case Uint8: const s = 8 return 0 <= x && x <= 1<<s-1 case Uint16: const s = 16 return 0 <= x && x <= 1<<s-1 case Uint32: const s = 32 return 0 <= x && x <= 1<<s-1 case Uint64: return 0 <= x case Float32: return true // TODO(gri) fix this case Float64: return true // TODO(gri) fix this case Complex64: return true // TODO(gri) fix this case Complex128: return true // TODO(gri) fix this case UntypedInt, UntypedFloat, UntypedComplex: return true } } n := exact.BitLen(x) switch as { case Uint, Uintptr: var s = uint(ctxt.sizeof(Typ[as])) * 8 return exact.Sign(x) >= 0 && n <= int(s) case Uint64: return exact.Sign(x) >= 0 && n <= 64 case Float32: return true // TODO(gri) fix this case Float64: return true // TODO(gri) fix this case Complex64: return true // TODO(gri) fix this case Complex128: return true // TODO(gri) fix this case UntypedInt, UntypedFloat, UntypedComplex: return true } case exact.Float: switch as { case Float32: return true // TODO(gri) fix this case Float64: return true // TODO(gri) fix this case Complex64: return true // TODO(gri) fix this case Complex128: return true // TODO(gri) fix this case UntypedFloat, UntypedComplex: return true } case exact.Complex: switch as { case Complex64: return true // TODO(gri) fix this case Complex128: return true // TODO(gri) fix this case UntypedComplex: return true } case exact.String: return as == String || as == UntypedString case exact.Nil: return as == UntypedNil || as == UnsafePointer default: unreachable() } return false }