Example #1
0
// 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
}
Example #2
0
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
}
Example #3
0
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
}