--- /dev/null
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements typechecking of builtin function calls.
+
+package types
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+// 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
+ var typ0 Type
+
+ // 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:
+ // argument must be a type
+ typ0 = underlying(check.typ(arg0, false))
+ if typ0 == Typ[Invalid] {
+ goto Error
+ }
+ case _Trace:
+ // _Trace implementation does the work
+ default:
+ // argument must be an expression
+ check.expr(x, arg0, nil, iota)
+ if x.mode == invalid {
+ goto Error
+ }
+ typ0 = underlying(x.typ)
+ }
+ }
+
+ switch id {
+ case _Append:
+ s, ok := typ0.(*Slice)
+ if !ok {
+ check.invalidArg(x.pos(), "%s is not a typed slice", x)
+ goto Error
+ }
+ 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 = s
+
+ case _Cap, _Len:
+ mode := invalid
+ var val interface{}
+ switch typ := implicitDeref(typ0).(type) {
+ case *Basic:
+ if isString(typ) && id == _Len {
+ if x.mode == constant {
+ mode = constant
+ val = int64(len(x.val.(string)))
+ } else {
+ mode = value
+ }
+ }
+
+ case *Array:
+ mode = value
+ if !containsCallsOrReceives(arg0) {
+ mode = constant
+ val = 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 := typ0.(*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:
+ var y operand
+ check.expr(&y, args[1], nil, iota)
+ if y.mode == invalid {
+ goto Error
+ }
+ // TODO(gri) handle complex(a, b) like (a + toImag(b))
+ unimplemented()
+
+ case _Copy:
+ // TODO(gri) implements checks
+ unimplemented()
+ x.mode = value
+ x.typ = Typ[Int]
+
+ case _Delete:
+ m, ok := typ0.(*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(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(typ0) {
+ check.invalidArg(x.pos(), "%s must be a complex number", x)
+ goto Error
+ }
+ if x.mode == constant {
+ // nothing to do for x.val == 0
+ if !isZeroConst(x.val) {
+ c := x.val.(complex)
+ if id == _Real {
+ x.val = c.re
+ } else {
+ x.val = c.im
+ }
+ }
+ } else {
+ x.mode = value
+ }
+ k := Invalid
+ switch typ0.(*Basic).Kind {
+ case Complex64:
+ k = Float32
+ case Complex128:
+ k = Float64
+ case UntypedComplex:
+ k = UntypedFloat
+ default:
+ unreachable()
+ }
+ x.typ = Typ[k]
+
+ case _Make:
+ var min int // minimum number of arguments
+ switch typ0.(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
+ }
+ for _, arg := range args[1:] {
+ check.expr(x, arg, nil, iota)
+ if !x.isInteger() {
+ check.invalidArg(x.pos(), "%s must be an integer", x)
+ // safe to continue
+ }
+ }
+ x.mode = variable
+ x.typ = typ0
+
+ case _New:
+ x.mode = variable
+ x.typ = &Pointer{Base: typ0}
+
+ case _Panic, _Print, _Println:
+ x.mode = novalue
+
+ case _Recover:
+ x.mode = value
+ x.typ = emptyInterface
+
+ case _Alignof:
+ x.mode = constant
+ x.typ = Typ[Uintptr]
+ // For now we return 1 always as it satisfies the spec's alignment guarantees.
+ // TODO(gri) Extend typechecker API so that platform-specific values can be
+ // provided.
+ x.val = int64(1)
+
+ case _Offsetof:
+ if _, ok := unparen(x.expr).(*ast.SelectorExpr); !ok {
+ check.invalidArg(x.pos(), "%s is not a selector", x)
+ goto Error
+ }
+ x.mode = constant
+ x.typ = Typ[Uintptr]
+ // because of the size guarantees for basic types (> 0 for some),
+ // returning 0 is only correct if two distinct non-zero size
+ // structs can have the same address (the spec permits that)
+ x.val = int64(0)
+
+ case _Sizeof:
+ // basic types with specified sizes have size guarantees; for all others we use 0
+ var size int64
+ if typ, ok := typ0.(*Basic); ok {
+ size = typ.Size
+ }
+ x.mode = constant
+ x.typ = Typ[Uintptr]
+ x.val = size
+
+ 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(typ0) {
+ check.invalidArg(x.pos(), "%s is not a boolean constant", x)
+ goto Error
+ }
+ pred, ok := x.val.(bool)
+ if !ok {
+ check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x)
+ goto Error
+ }
+ if !pred {
+ 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.exprOrType(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
+}
+
+// implicitDeref returns A if typ is of the form *A and A is an array;
+// otherwise it returns typ.
+//
+func implicitDeref(typ Type) Type {
+ if p, ok := typ.(*Pointer); ok {
+ if a, ok := underlying(p.Base).(*Array); ok {
+ return a
+ }
+ }
+ return typ
+}
+
+// containsCallsOrReceives returns true if the expression x contains
+// function calls or channel receives; it returns false otherwise.
+//
+func containsCallsOrReceives(x ast.Expr) bool {
+ res := false
+ ast.Inspect(x, func(x ast.Node) bool {
+ switch x := x.(type) {
+ case *ast.CallExpr:
+ res = true
+ return false
+ case *ast.UnaryExpr:
+ if x.Op == token.ARROW {
+ res = true
+ return false
+ }
+ }
+ return true
+ })
+ return res
+}
+
+// unparen removes any parentheses surrounding an expression and returns
+// the naked expression.
+//
+func unparen(x ast.Expr) ast.Expr {
+ if p, ok := x.(*ast.ParenExpr); ok {
+ return unparen(p.X)
+ }
+ return x
+}
--- /dev/null
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// builtin calls
+
+package builtins
+
+import "unsafe"
+
+func _append() {
+ var x int
+ var s []byte
+ _0 := append /* ERROR "argument" */ ()
+ _1 := append("foo" /* ERROR "not a typed slice" */)
+ _2 := append(nil /* ERROR "not a typed slice" */, s)
+ _3 := append(x /* ERROR "not a typed slice" */, s)
+ _4 := append(s)
+ append /* ERROR "not used" */ (s)
+}
+
+func _cap() {
+ var a [10]bool
+ var p *[20]int
+ var s []int
+ var c chan string
+ _0 := cap /* ERROR "argument" */ ()
+ _1 := cap /* ERROR "argument" */ (1, 2)
+ _2 := cap(42 /* ERROR "invalid" */)
+ const _3 = cap(a)
+ assert(_3 == 10)
+ const _4 = cap(p)
+ assert(_4 == 20)
+ _5 := cap(c)
+ cap /* ERROR "not used" */ (c)
+}
+
+func _close() {
+ var c chan int
+ var r <-chan int
+ close /* ERROR "argument" */ ()
+ close /* ERROR "argument" */ (1, 2)
+ close(42 /* ERROR "not a channel" */)
+ close(r /* ERROR "receive-only channel" */)
+ close(c)
+}
+
+func _complex() {
+ _0 := complex /* ERROR "argument" */ ()
+ _1 := complex /* ERROR "argument" */ (1)
+ _2 := complex(1, 2)
+ // TODO(gri) add tests checking types
+ complex /* ERROR "not used" */ (1, 2)
+}
+
+func _delete() {
+ var m map[string]int
+ var s string
+ delete /* ERROR "argument" */ ()
+ delete /* ERROR "argument" */ (1)
+ delete /* ERROR "argument" */ (1, 2, 3)
+ delete(m, 0 /* ERROR "not assignable" */)
+ delete(m, s)
+}
+
+func _imag() {
+ var f32 float32
+ var f64 float64
+ var c64 complex64
+ var c128 complex128
+ _0 := imag /* ERROR "argument" */ ()
+ _1 := imag /* ERROR "argument" */ (1, 2)
+ _2 := imag(10 /* ERROR "must be a complex number" */)
+ _3 := imag(2.7182818 /* ERROR "must be a complex number" */)
+ _4 := imag("foo" /* ERROR "must be a complex number" */)
+ const _5 = imag(1 + 2i)
+ assert(_5 == 2)
+ f32 = _5
+ f64 = _5
+ const _6 = imag(0i)
+ assert(_6 == 0)
+ f32 = imag(c64)
+ f64 = imag(c128)
+ f32 = imag /* ERROR "cannot assign" */ (c128)
+ f64 = imag /* ERROR "cannot assign" */ (c64)
+ imag /* ERROR "not used" */ (c64)
+}
+
+func _len() {
+ const c = "foobar"
+ var a [10]bool
+ var p *[20]int
+ var s []int
+ var m map[string]complex128
+ _0 := len /* ERROR "argument" */ ()
+ _1 := len /* ERROR "argument" */ (1, 2)
+ _2 := len(42 /* ERROR "invalid" */)
+ const _3 = len(c)
+ assert(_3 == 6)
+ const _4 = len(a)
+ assert(_4 == 10)
+ const _5 = len(p)
+ assert(_5 == 20)
+ _6 := len(m)
+ len /* ERROR "not used" */ (c)
+
+ // esoteric case
+ var t string
+ var hash map[interface{}][]*[10]int
+ const n = len /* ERROR "not constant" */ (hash[recover()][len(t)])
+ assert /* ERROR "failed" */ (n == 10)
+ var ch <-chan int
+ const nn = len /* ERROR "not constant" */ (hash[<-ch][len(t)])
+ _7 := nn // TODO(gri) remove this once unused constants get type-checked
+}
+
+func _make() {
+ n := 0
+
+ _0 := make /* ERROR "argument" */ ()
+ _1 := make(1 /* ERROR "not a type" */)
+ _2 := make(int /* ERROR "cannot make" */)
+
+ // slices
+ _3 := make/* ERROR "arguments" */ ([]int)
+ _4 := make/* ERROR "arguments" */ ([]int, 2, 3, 4)
+ _5 := make([]int, int /* ERROR "not an expression" */)
+ _6 := make([]int, 10, float32 /* ERROR "not an expression" */)
+ _7 := make([]int, "foo" /* ERROR "must be an integer" */)
+ _8 := make([]int, 10, 2.3 /* ERROR "must be an integer" */)
+ _9 := make([]int, 5, 10.0)
+ _10 := make([]int, 0i)
+ _11 := make([]int, -1, 1<<100) // out-of-range constants lead to run-time errors
+
+ // maps
+ _12 := make /* ERROR "arguments" */ (map[int]string, 10, 20)
+ _13 := make(map[int]float32, int /* ERROR "not an expression" */)
+ _14 := make(map[int]float32, "foo" /* ERROR "must be an integer" */)
+ _15 := make(map[int]float32, 10)
+ _16 := make(map[int]float32, n)
+ _17 := make(map[int]float32, int64(n))
+
+ // channels
+ _22 := make /* ERROR "arguments" */ (chan int, 10, 20)
+ _23 := make(chan int, int /* ERROR "not an expression" */)
+ _24 := make(chan<- int, "foo" /* ERROR "must be an integer" */)
+ _25 := make(<-chan float64, 10)
+ _26 := make(chan chan int, n)
+ _27 := make(chan string, int64(n))
+
+ make /* ERROR "not used" */ ([]int, 10)
+}
+
+func _new() {
+ _0 := new /* ERROR "argument" */ ()
+ _1 := new /* ERROR "argument" */ (1, 2)
+ _3 := new("foo" /* ERROR "not a type" */)
+ _4 := new(float64)
+ _5 := new(struct{ x, y int })
+ _6 := new(*float64)
+ _7 := *_4 == **_6
+ new /* ERROR "not used" */ (int)
+}
+
+func _real() {
+ var f32 float32
+ var f64 float64
+ var c64 complex64
+ var c128 complex128
+ _0 := real /* ERROR "argument" */ ()
+ _1 := real /* ERROR "argument" */ (1, 2)
+ _2 := real(10 /* ERROR "must be a complex number" */)
+ _3 := real(2.7182818 /* ERROR "must be a complex number" */)
+ _4 := real("foo" /* ERROR "must be a complex number" */)
+ const _5 = real(1 + 2i)
+ assert(_5 == 1)
+ f32 = _5
+ f64 = _5
+ const _6 = real(0i)
+ assert(_6 == 0)
+ f32 = real(c64)
+ f64 = real(c128)
+ f32 = real /* ERROR "cannot assign" */ (c128)
+ f64 = real /* ERROR "cannot assign" */ (c64)
+ real /* ERROR "not used" */ (c64)
+}
+
+func _recover() {
+ _0 := recover()
+ _1 := recover /* ERROR "argument" */ (10)
+ recover()
+}
+
+func _Alignof() {
+ var x int
+ _0 := unsafe /* ERROR "argument" */ .Alignof()
+ _1 := unsafe /* ERROR "argument" */ .Alignof(1, 2)
+ _3 := unsafe.Alignof(int /* ERROR "not an expression" */)
+ _4 := unsafe.Alignof(42)
+ _5 := unsafe.Alignof(new(struct{}))
+ unsafe /* ERROR "not used" */ .Alignof(x)
+}
+
+func _Offsetof() {
+ var x struct{ f int }
+ _0 := unsafe /* ERROR "argument" */ .Offsetof()
+ _1 := unsafe /* ERROR "argument" */ .Offsetof(1, 2)
+ _2 := unsafe.Offsetof(int /* ERROR "not an expression" */)
+ _3 := unsafe.Offsetof(x /* ERROR "not a selector" */)
+ _4 := unsafe.Offsetof(x.f)
+ _5 := unsafe.Offsetof((x.f))
+ _6 := unsafe.Offsetof((((((((x))).f)))))
+ unsafe /* ERROR "not used" */ .Offsetof(x.f)
+}
+
+func _Sizeof() {
+ var x int
+ _0 := unsafe /* ERROR "argument" */ .Sizeof()
+ _1 := unsafe /* ERROR "argument" */ .Sizeof(1, 2)
+ _2 := unsafe.Sizeof(int /* ERROR "not an expression" */)
+ _3 := unsafe.Sizeof(42)
+ _4 := unsafe.Sizeof(new(complex128))
+ unsafe /* ERROR "not used" */ .Sizeof(x)
+
+ // basic types have size guarantees
+ assert(unsafe.Sizeof(byte(0)) == 1)
+ assert(unsafe.Sizeof(uint8(0)) == 1)
+ assert(unsafe.Sizeof(int8(0)) == 1)
+ assert(unsafe.Sizeof(uint16(0)) == 2)
+ assert(unsafe.Sizeof(int16(0)) == 2)
+ assert(unsafe.Sizeof(uint32(0)) == 4)
+ assert(unsafe.Sizeof(int32(0)) == 4)
+ assert(unsafe.Sizeof(float32(0)) == 4)
+ assert(unsafe.Sizeof(uint64(0)) == 8)
+ assert(unsafe.Sizeof(int64(0)) == 8)
+ assert(unsafe.Sizeof(float64(0)) == 8)
+ assert(unsafe.Sizeof(complex64(0)) == 8)
+ assert(unsafe.Sizeof(complex128(0)) == 16)
+}
+
+// self-testing only
+func _assert() {
+ var x int
+ assert /* ERROR "argument" */ ()
+ assert /* ERROR "argument" */ (1, 2)
+ assert("foo" /* ERROR "boolean constant" */ )
+ assert(x /* ERROR "boolean constant" */)
+ assert(true)
+ assert /* ERROR "failed" */ (false)
+}
+
+// self-testing only
+func _trace() {
+ // Uncomment the code below to test trace - will produce console output
+ // _0 := trace /* ERROR "no value" */ ()
+ // _1 := trace(1)
+ // _2 := trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
+}