// number = int_lit [ "p" int_lit ] . // func (p *gcParser) parseNumber() (x operand) { x.mode = constant // mantissa mant := exact.MakeFromLiteral(p.parseInt(), token.INT) assert(mant != nil) if p.lit == "p" { // exponent (base 2) p.next() exp, err := strconv.ParseInt(p.parseInt(), 10, 0) if err != nil { p.error(err) } if exp < 0 { denom := exact.MakeInt64(1) denom = exact.Shift(denom, token.SHL, uint(-exp)) x.typ = Typ[UntypedFloat] x.val = exact.BinaryOp(mant, token.QUO, denom) return } if exp > 0 { mant = exact.Shift(mant, token.SHL, uint(exp)) } x.typ = Typ[UntypedFloat] x.val = mant return } x.typ = Typ[UntypedInt] x.val = mant return }
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 := x.typ.Underlying().(*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 }
// builtin typechecks a built-in call. The built-in type is bin, and iota is the current // value of iota or -1 if iota doesn't have a value in the current context. The result // of the call is returned via x. If the call has type errors, the returned x is marked // as invalid (x.mode == invalid). // func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *Builtin, iota int) { args := call.Args id := bin.id // declare before goto's var arg0 ast.Expr // first argument, if present // check argument count n := len(args) msg := "" if n < bin.nargs { msg = "not enough" } else if !bin.isVariadic && n > bin.nargs { msg = "too many" } if msg != "" { check.invalidOp(call.Pos(), msg+" arguments for %s (expected %d, found %d)", call, bin.nargs, n) goto Error } // common case: evaluate first argument if present; // if it is an expression, x has the expression value if n > 0 { arg0 = args[0] switch id { case _Make, _New, _Print, _Println, _Offsetof, _Trace: // respective cases below do the work default: // argument must be an expression check.expr(x, arg0, nil, iota) if x.mode == invalid { goto Error } } } switch id { case _Append: if _, ok := x.typ.Underlying().(*Slice); !ok { check.invalidArg(x.pos(), "%s is not a typed slice", x) goto Error } resultTyp := x.typ for _, arg := range args[1:] { check.expr(x, arg, nil, iota) if x.mode == invalid { goto Error } // TODO(gri) check assignability } x.mode = value x.typ = resultTyp case _Cap, _Len: mode := invalid var val exact.Value switch typ := implicitArrayDeref(x.typ.Underlying()).(type) { case *Basic: if isString(typ) && id == _Len { if x.mode == constant { mode = constant val = exact.MakeInt64(int64(len(exact.StringVal(x.val)))) } else { mode = value } } case *Array: mode = value // spec: "The expressions len(s) and cap(s) are constants // if the type of s is an array or pointer to an array and // the expression s does not contain channel receives or // function calls; in this case s is not evaluated." if !check.containsCallsOrReceives(arg0) { mode = constant val = exact.MakeInt64(typ.len) } case *Slice, *Chan: mode = value case *Map: if id == _Len { mode = value } } if mode == invalid { check.invalidArg(x.pos(), "%s for %s", x, bin.name) goto Error } x.mode = mode x.typ = Typ[Int] x.val = val case _Close: ch, ok := x.typ.Underlying().(*Chan) if !ok { check.invalidArg(x.pos(), "%s is not a channel", x) goto Error } if ch.dir&ast.SEND == 0 { check.invalidArg(x.pos(), "%s must not be a receive-only channel", x) goto Error } x.mode = novalue case _Complex: if !check.complexArg(x) { goto Error } var y operand check.expr(&y, args[1], nil, iota) if y.mode == invalid { goto Error } if !check.complexArg(&y) { goto Error } check.convertUntyped(x, y.typ) if x.mode == invalid { goto Error } check.convertUntyped(&y, x.typ) if y.mode == invalid { goto Error } if !IsIdentical(x.typ, y.typ) { check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ) goto Error } typ := x.typ.Underlying().(*Basic) if x.mode == constant && y.mode == constant { x.val = exact.BinaryOp(x.val, token.ADD, exact.MakeImag(y.val)) } else { x.mode = value } switch typ.kind { case Float32: x.typ = Typ[Complex64] case Float64: x.typ = Typ[Complex128] case UntypedInt, UntypedRune, UntypedFloat: if x.mode == constant { typ = defaultType(typ).(*Basic) x.typ = Typ[UntypedComplex] } else { // untyped but not constant; probably because one // operand is a non-constant shift of untyped lhs typ = Typ[Float64] x.typ = Typ[Complex128] } default: check.invalidArg(x.pos(), "float32 or float64 arguments expected") goto Error } 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(args[0], typ, true) check.updateExprType(args[1], typ, true) } case _Copy: var y operand check.expr(&y, args[1], nil, iota) if y.mode == invalid { goto Error } var dst, src Type if t, ok := x.typ.Underlying().(*Slice); ok { dst = t.elt } switch t := y.typ.Underlying().(type) { case *Basic: if isString(y.typ) { src = Typ[Byte] } case *Slice: src = t.elt } if dst == nil || src == nil { check.invalidArg(x.pos(), "copy expects slice arguments; found %s and %s", x, &y) goto Error } if !IsIdentical(dst, src) { check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src) goto Error } x.mode = value x.typ = Typ[Int] case _Delete: m, ok := x.typ.Underlying().(*Map) if !ok { check.invalidArg(x.pos(), "%s is not a map", x) goto Error } check.expr(x, args[1], nil, iota) if x.mode == invalid { goto Error } if !x.isAssignable(check.ctxt, m.key) { check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key) goto Error } x.mode = novalue case _Imag, _Real: if !isComplex(x.typ) { check.invalidArg(x.pos(), "%s must be a complex number", x) goto Error } if x.mode == constant { if id == _Real { x.val = exact.Real(x.val) } else { x.val = exact.Imag(x.val) } } else { x.mode = value } k := Invalid switch x.typ.Underlying().(*Basic).kind { case Complex64: k = Float32 case Complex128: k = Float64 case UntypedComplex: k = UntypedFloat default: unreachable() } x.typ = Typ[k] case _Make: resultTyp := check.typ(arg0, false) if resultTyp == Typ[Invalid] { goto Error } var min int // minimum number of arguments switch resultTyp.Underlying().(type) { case *Slice: min = 2 case *Map, *Chan: min = 1 default: check.invalidArg(arg0.Pos(), "cannot make %s; type must be slice, map, or channel", arg0) goto Error } if n := len(args); n < min || min+1 < n { check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, n) goto Error } var sizes []int64 // constant integer arguments, if any for _, arg := range args[1:] { if s, ok := check.index(arg, -1, iota); ok && s >= 0 { sizes = append(sizes, s) } } if len(sizes) == 2 && sizes[0] > sizes[1] { check.invalidArg(args[1].Pos(), "length and capacity swapped") // safe to continue } x.mode = variable x.typ = resultTyp case _New: resultTyp := check.typ(arg0, false) if resultTyp == Typ[Invalid] { goto Error } x.mode = variable x.typ = &Pointer{base: resultTyp} case _Panic: x.mode = novalue case _Print, _Println: for _, arg := range args { check.expr(x, arg, nil, -1) if x.mode == invalid { goto Error } } x.mode = novalue case _Recover: x.mode = value x.typ = new(Interface) case _Alignof: x.mode = constant x.val = exact.MakeInt64(check.ctxt.alignof(x.typ)) x.typ = Typ[Uintptr] case _Offsetof: arg, ok := unparen(arg0).(*ast.SelectorExpr) if !ok { check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0) goto Error } check.expr(x, arg.X, nil, -1) if x.mode == invalid { goto Error } sel := arg.Sel.Name res := lookupField(x.typ, check.pkg, arg.Sel.Name) if res.index == nil { check.invalidArg(x.pos(), "%s has no single field %s", x, sel) goto Error } offs := check.ctxt.offsetof(x.typ.Deref(), res.index) if offs < 0 { check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, x) goto Error } x.mode = constant x.val = exact.MakeInt64(offs) x.typ = Typ[Uintptr] case _Sizeof: x.mode = constant x.val = exact.MakeInt64(check.ctxt.sizeof(x.typ)) x.typ = Typ[Uintptr] case _Assert: // assert(pred) causes a typechecker error if pred is false. // The result of assert is the value of pred if there is no error. // Note: assert is only available in self-test mode. if x.mode != constant || !isBoolean(x.typ) { check.invalidArg(x.pos(), "%s is not a boolean constant", x) goto Error } if x.val.Kind() != exact.Bool { check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x) goto Error } if !exact.BoolVal(x.val) { check.errorf(call.Pos(), "%s failed", call) // compile-time assertion failure - safe to continue } case _Trace: // trace(x, y, z, ...) dumps the positions, expressions, and // values of its arguments. The result of trace is the value // of the first argument. // Note: trace is only available in self-test mode. if len(args) == 0 { check.dump("%s: trace() without arguments", call.Pos()) x.mode = novalue x.expr = call return } var t operand x1 := x for _, arg := range args { check.rawExpr(x1, arg, nil, iota, true) // permit trace for types, e.g.: new(trace(T)) check.dump("%s: %s", x1.pos(), x1) x1 = &t // use incoming x only for first argument } default: check.invalidAST(call.Pos(), "unknown builtin id %d", id) goto Error } x.expr = call return Error: x.mode = invalid x.expr = call }