// 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 := underlying(x.typ).(*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(underlying(x.typ)).(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 := underlying(x.typ).(*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 := underlying(x.typ).(*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 := underlying(x.typ).(*Slice); ok { dst = t.Elt } switch t := underlying(y.typ).(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 := underlying(x.typ).(*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 underlying(x.typ).(*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 underlying(resultTyp).(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, QualifiedName{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(deref(x.typ), 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 }
// literalValue returns the value of the literal with the // dynamic type tag appropriate for l.Type(). func literalValue(l *ssa.Literal) value { if l.IsNil() { return zero(l.Type()) // typed nil } // By destination type: switch t := underlyingType(l.Type()).(type) { case *types.Basic: switch t.Kind { case types.Bool, types.UntypedBool: return exact.BoolVal(l.Value) case types.Int, types.UntypedInt: // Assume sizeof(int) is same on host and target. return int(l.Int64()) case types.Int8: return int8(l.Int64()) case types.Int16: return int16(l.Int64()) case types.Int32, types.UntypedRune: return int32(l.Int64()) case types.Int64: return l.Int64() case types.Uint: // Assume sizeof(uint) is same on host and target. return uint(l.Uint64()) case types.Uint8: return uint8(l.Uint64()) case types.Uint16: return uint16(l.Uint64()) case types.Uint32: return uint32(l.Uint64()) case types.Uint64: return l.Uint64() case types.Uintptr: // Assume sizeof(uintptr) is same on host and target. return uintptr(l.Uint64()) case types.Float32: return float32(l.Float64()) case types.Float64, types.UntypedFloat: return l.Float64() case types.Complex64: return complex64(l.Complex128()) case types.Complex128, types.UntypedComplex: return l.Complex128() case types.String, types.UntypedString: if l.Value.Kind() == exact.String { return exact.StringVal(l.Value) } return string(rune(l.Int64())) case types.UnsafePointer: panic("unsafe.Pointer literal") // not possible case types.UntypedNil: // nil was handled above. } case *types.Slice: switch et := underlyingType(t.Elt).(type) { case *types.Basic: switch et.Kind { case types.Byte: // string -> []byte var v []value for _, b := range []byte(exact.StringVal(l.Value)) { v = append(v, b) } return v case types.Rune: // string -> []rune var v []value for _, r := range []rune(exact.StringVal(l.Value)) { v = append(v, r) } return v } } } panic(fmt.Sprintf("literalValue: Value.(type)=%T Type()=%s", l.Value, l.Type())) }