// rawExpr typechecks expression e and initializes x with the expression // value or type. If an error occurred, x.mode is set to invalid. // If hint != nil, it is the type of a composite literal element. // iota >= 0 indicates that the expression is part of a constant declaration. // cycleOk indicates whether it is ok for a type expression to refer to itself. // func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycleOk bool) { if trace { c := "" if cycleOk { c = " тиБ" } check.trace(e.Pos(), "%s%s", e, c) defer check.untrace("=> %s", x) } // record final type of x if untyped, notify clients of type otherwise defer check.callExpr(x) switch e := e.(type) { case *ast.BadExpr: goto Error // error was reported before case *ast.Ident: if e.Name == "_" { check.invalidOp(e.Pos(), "cannot use _ as value or type") goto Error } obj := check.lookup(e) if obj == nil { goto Error // error was reported before } check.object(obj, cycleOk) switch obj := obj.(type) { case *Package: check.errorf(e.Pos(), "use of package %s not in selector", obj.Name) goto Error case *Const: if obj.typ == Typ[Invalid] { goto Error } x.mode = constant if obj == universeIota { if iota < 0 { check.invalidAST(e.Pos(), "cannot use iota outside constant declaration") goto Error } x.val = exact.MakeInt64(int64(iota)) } else { x.val = obj.val // may be nil if we don't know the constant value } case *TypeName: x.mode = typexpr if !cycleOk && obj.typ.Underlying() == nil { check.errorf(obj.spec.Pos(), "illegal cycle in declaration of %s", obj.Name) x.expr = e x.typ = Typ[Invalid] return // don't goto Error - need x.mode == typexpr } case *Var: x.mode = variable case *Func: x.mode = value default: unreachable() } x.typ = obj.Type() case *ast.Ellipsis: // ellipses are handled explicitly where they are legal // (array composite literals and parameter lists) check.errorf(e.Pos(), "invalid use of '...'") goto Error case *ast.BasicLit: x.setConst(e.Kind, e.Value) if x.mode == invalid { check.invalidAST(e.Pos(), "invalid literal %v", e.Value) goto Error } case *ast.FuncLit: if sig, ok := check.typ(e.Type, false).(*Signature); ok { x.mode = value x.typ = sig check.later(nil, sig, e.Body) } else { check.invalidAST(e.Pos(), "invalid function literal %s", e) goto Error } case *ast.CompositeLit: typ := hint openArray := false if e.Type != nil { // [...]T array types may only appear with composite literals. // Check for them here so we don't have to handle ... in general. typ = nil if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil { if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil { // We have an "open" [...]T array type. // Create a new ArrayType with unknown length (-1) // and finish setting it up after analyzing the literal. typ = &Array{len: -1, elt: check.typ(atyp.Elt, cycleOk)} openArray = true } } if typ == nil { typ = check.typ(e.Type, false) } } if typ == nil { check.errorf(e.Pos(), "missing type in composite literal") goto Error } switch utyp := typ.Deref().Underlying().(type) { case *Struct: if len(e.Elts) == 0 { break } fields := utyp.fields if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok { // all elements must have keys visited := make([]bool, len(fields)) for _, e := range e.Elts { kv, _ := e.(*ast.KeyValueExpr) if kv == nil { check.errorf(e.Pos(), "mixture of field:value and value elements in struct literal") continue } key, _ := kv.Key.(*ast.Ident) if key == nil { check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key) continue } i := utyp.fieldIndex(check.pkg, key.Name) if i < 0 { check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name) continue } // 0 <= i < len(fields) if visited[i] { check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name) continue } visited[i] = true check.expr(x, kv.Value, nil, iota) check.register(key, fields[i]) etyp := fields[i].typ if !check.assignment(x, etyp) { if x.mode != invalid { check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp) } continue } } } else { // no element must have a key for i, e := range e.Elts { if kv, _ := e.(*ast.KeyValueExpr); kv != nil { check.errorf(kv.Pos(), "mixture of field:value and value elements in struct literal") continue } check.expr(x, e, nil, iota) if i >= len(fields) { check.errorf(x.pos(), "too many values in struct literal") break // cannot continue } // i < len(fields) etyp := fields[i].typ if !check.assignment(x, etyp) { if x.mode != invalid { check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp) } continue } } if len(e.Elts) < len(fields) { check.errorf(e.Rbrace, "too few values in struct literal") // ok to continue } } case *Array: n := check.indexedElts(e.Elts, utyp.elt, utyp.len, iota) // if we have an "open" [...]T array, set the length now that we know it if openArray { utyp.len = n } case *Slice: check.indexedElts(e.Elts, utyp.elt, -1, iota) case *Map: visited := make(map[interface{}]bool, len(e.Elts)) for _, e := range e.Elts { kv, _ := e.(*ast.KeyValueExpr) if kv == nil { check.errorf(e.Pos(), "missing key in map literal") continue } check.compositeLitKey(kv.Key) check.expr(x, kv.Key, nil, iota) if !check.assignment(x, utyp.key) { if x.mode != invalid { check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.key) } continue } if x.mode == constant { if visited[x.val] { check.errorf(x.pos(), "duplicate key %s in map literal", x.val) continue } visited[x.val] = true } check.expr(x, kv.Value, utyp.elt, iota) if !check.assignment(x, utyp.elt) { if x.mode != invalid { check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.elt) } continue } } default: check.errorf(e.Pos(), "%s is not a valid composite literal type", typ) goto Error } x.mode = value x.typ = typ case *ast.ParenExpr: check.rawExpr(x, e.X, nil, iota, cycleOk) case *ast.SelectorExpr: sel := e.Sel.Name // If the identifier refers to a package, handle everything here // so we don't need a "package" mode for operands: package names // can only appear in qualified identifiers which are mapped to // selector expressions. if ident, ok := e.X.(*ast.Ident); ok { if pkg, ok := check.lookup(ident).(*Package); ok { exp := pkg.scope.Lookup(sel) if exp == nil { check.errorf(e.Pos(), "%s not declared by package %s", sel, ident) goto Error } else if !ast.IsExported(exp.Name()) { // gcimported package scopes contain non-exported // objects such as types used in partially exported // objects - do not accept them check.errorf(e.Pos(), "%s not exported by package %s", sel, ident) goto Error } check.register(e.Sel, exp) // Simplified version of the code for *ast.Idents: // - imported packages use types.Scope and types.Objects // - imported objects are always fully initialized switch exp := exp.(type) { case *Const: assert(exp.Val != nil) x.mode = constant x.typ = exp.typ x.val = exp.val case *TypeName: x.mode = typexpr x.typ = exp.typ case *Var: x.mode = variable x.typ = exp.typ case *Func: x.mode = value x.typ = exp.typ default: unreachable() } x.expr = e return } } check.exprOrType(x, e.X, iota, false) if x.mode == invalid { goto Error } res := lookupField(x.typ, check.pkg, sel) utyp := x.typ.Underlying() if res.mode == invalid { check.invalidOp(e.Pos(), "%s has no single field or method %s", x, sel) goto Error } if x.mode == typexpr { // method expression sig, ok := res.typ.(*Signature) if !ok { check.invalidOp(e.Pos(), "%s has no method %s", x, sel) goto Error } // the receiver type becomes the type of the first function // argument of the method expression's function type // TODO(gri) at the moment, method sets don't correctly track // pointer vs non-pointer receivers => typechecker is too lenient var params []*Var if sig.params != nil { params = sig.params.vars } x.mode = value m := x.typ.Deref().(*Named).methods.Lookup(check.pkg, sel) check.register(e.Sel, m) x.typ = &Signature{ params: NewTuple(append([]*Var{{typ: x.typ}}, params...)...), results: sig.results, isVariadic: sig.isVariadic, } } else { // regular selector x.mode = res.mode if res.index == nil { // method var method Object if t, ok := x.typ.Deref().(*Named); ok { method = t.methods.Lookup(check.pkg, sel) } if method == nil { if t, ok := utyp.Deref().(*Interface); ok { method = t.methods.Lookup(check.pkg, sel) } } if method != nil { check.register(e.Sel, method) } else if false { // TODO(sqs): fix this - it occurs when we aren't propagating the methods of an embedded interface. fmt.Printf("nil method: %s", e.Sel) } } else { // field if s, ok := utyp.Deref().(*Struct); ok { check.register(e.Sel, s.Field(res.index[0])) } } x.typ = res.typ } case *ast.IndexExpr: check.expr(x, e.X, nil, iota) if x.mode == invalid { goto Error } valid := false length := int64(-1) // valid if >= 0 switch typ := x.typ.Underlying().(type) { case *Basic: if isString(typ) { valid = true if x.mode == constant { length = int64(len(exact.StringVal(x.val))) } // an indexed string always yields a byte value // (not a constant) even if the string and the // index are constant x.mode = value x.typ = Typ[Byte] } case *Array: valid = true length = typ.len if x.mode != variable { x.mode = value } x.typ = typ.elt case *Pointer: if typ, _ := typ.base.Underlying().(*Array); typ != nil { valid = true length = typ.len x.mode = variable x.typ = typ.elt } case *Slice: valid = true x.mode = variable x.typ = typ.elt case *Map: var key operand check.expr(&key, e.Index, nil, iota) if !check.assignment(&key, typ.key) { if key.mode != invalid { check.invalidOp(key.pos(), "cannot use %s as map index of type %s", &key, typ.key) } goto Error } x.mode = valueok x.typ = typ.elt x.expr = e return } if !valid { check.invalidOp(x.pos(), "cannot index %s", x) goto Error } if e.Index == nil { check.invalidAST(e.Pos(), "missing index expression for %s", x) return } check.index(e.Index, length, iota) // ok to continue case *ast.SliceExpr: check.expr(x, e.X, nil, iota) if x.mode == invalid { goto Error } valid := false length := int64(-1) // valid if >= 0 switch typ := x.typ.Underlying().(type) { case *Basic: if isString(typ) { valid = true if x.mode == constant { length = int64(len(exact.StringVal(x.val))) + 1 // +1 for slice } // a sliced string always yields a string value // of the same type as the original string (not // a constant) even if the string and the indices // are constant x.mode = value // x.typ doesn't change, but if it is an untyped // string it becomes string (see also issue 4913). if typ.kind == UntypedString { x.typ = Typ[String] } } case *Array: valid = true length = typ.len + 1 // +1 for slice if x.mode != variable { check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x) goto Error } x.typ = &Slice{elt: typ.elt} case *Pointer: if typ, _ := typ.base.Underlying().(*Array); typ != nil { valid = true length = typ.len + 1 // +1 for slice x.mode = variable x.typ = &Slice{elt: typ.elt} } case *Slice: valid = true x.mode = variable // x.typ doesn't change } if !valid { check.invalidOp(x.pos(), "cannot slice %s", x) goto Error } lo := int64(0) if e.Low != nil { if i, ok := check.index(e.Low, length, iota); ok && i >= 0 { lo = i } } hi := int64(-1) if e.High != nil { if i, ok := check.index(e.High, length, iota); ok && i >= 0 { hi = i } } else if length >= 0 { hi = length } if lo >= 0 && hi >= 0 && lo > hi { check.errorf(e.Low.Pos(), "inverted slice range: %d > %d", lo, hi) // ok to continue } case *ast.TypeAssertExpr: check.expr(x, e.X, nil, iota) if x.mode == invalid { goto Error } var T *Interface if T, _ = x.typ.Underlying().(*Interface); T == nil { check.invalidOp(x.pos(), "%s is not an interface", x) goto Error } // x.(type) expressions are handled explicitly in type switches if e.Type == nil { check.errorf(e.Pos(), "use of .(type) outside type switch") goto Error } typ := check.typ(e.Type, false) if typ == Typ[Invalid] { goto Error } if method, wrongType := missingMethod(typ, T); method != nil { var msg string if wrongType { msg = "%s cannot have dynamic type %s (wrong type for method %s)" } else { msg = "%s cannot have dynamic type %s (missing method %s)" } check.errorf(e.Type.Pos(), msg, x, typ, method.name) // ok to continue } x.mode = valueok x.expr = e x.typ = typ case *ast.CallExpr: check.exprOrType(x, e.Fun, iota, false) if x.mode == invalid { goto Error } else if x.mode == typexpr { check.conversion(x, e, x.typ, iota) } else if sig, ok := x.typ.Underlying().(*Signature); ok { // check parameters // If we have a trailing ... at the end of the parameter // list, the last argument must match the parameter type // []T of a variadic function parameter x ...T. passSlice := false if e.Ellipsis.IsValid() { if sig.isVariadic { passSlice = true } else { check.errorf(e.Ellipsis, "cannot use ... in call to %s", e.Fun) // ok to continue } } // If we have a single argument that is a function call // we need to handle it separately. Determine if this // is the case without checking the argument. var call *ast.CallExpr if len(e.Args) == 1 { call, _ = unparen(e.Args[0]).(*ast.CallExpr) } n := 0 // parameter count if call != nil { // We have a single argument that is a function call. check.expr(x, call, nil, -1) if x.mode == invalid { goto Error // TODO(gri): we can do better } if t, ok := x.typ.(*Tuple); ok { // multiple result values n = t.Len() for i := 0; i < n; i++ { obj := t.At(i) x.mode = value x.expr = nil // TODO(gri) can we do better here? (for good error messages) x.typ = obj.typ check.argument(sig, i, nil, x, passSlice && i+1 == n) } } else { // single result value n = 1 check.argument(sig, 0, nil, x, passSlice) } } else { // We don't have a single argument or it is not a function call. n = len(e.Args) for i, arg := range e.Args { check.argument(sig, i, arg, x, passSlice && i+1 == n) } } // determine if we have enough arguments if sig.isVariadic { // a variadic function accepts an "empty" // last argument: count one extra n++ } if n < sig.params.Len() { check.errorf(e.Fun.Pos(), "too few arguments in call to %s", e.Fun) // ok to continue } // determine result switch sig.results.Len() { case 0: x.mode = novalue case 1: x.mode = value x.typ = sig.results.vars[0].typ default: x.mode = value x.typ = sig.results } } else if bin, ok := x.typ.(*Builtin); ok { check.builtin(x, e, bin, iota) } else { check.invalidOp(x.pos(), "cannot call non-function %s", x) goto Error } case *ast.StarExpr: check.exprOrType(x, e.X, iota, true) switch x.mode { case invalid: goto Error case typexpr: x.typ = &Pointer{base: x.typ} default: if typ, ok := x.typ.Underlying().(*Pointer); ok { x.mode = variable x.typ = typ.base } else { check.invalidOp(x.pos(), "cannot indirect %s", x) goto Error } } case *ast.UnaryExpr: check.expr(x, e.X, nil, iota) if x.mode == invalid { goto Error } check.unary(x, e.Op) if x.mode == invalid { goto Error } case *ast.BinaryExpr: check.binary(x, e.X, e.Y, e.Op, iota) if x.mode == invalid { goto Error } case *ast.KeyValueExpr: // key:value expressions are handled in composite literals check.invalidAST(e.Pos(), "no key:value expected") goto Error case *ast.ArrayType: if e.Len != nil { check.expr(x, e.Len, nil, iota) if x.mode == invalid { goto Error } if x.mode != constant { if x.mode != invalid { check.errorf(x.pos(), "array length %s must be constant", x) } goto Error } if !x.isInteger() { check.errorf(x.pos(), "array length %s must be integer", x) goto Error } n, ok := exact.Int64Val(x.val) if !ok || n < 0 { check.errorf(x.pos(), "invalid array length %s", x) goto Error } x.typ = &Array{len: n, elt: check.typ(e.Elt, cycleOk)} } else { x.typ = &Slice{elt: check.typ(e.Elt, true)} } x.mode = typexpr case *ast.StructType: x.mode = typexpr fields, tags := check.collectFields(e.Fields, cycleOk) x.typ = &Struct{fields: fields, tags: tags} case *ast.FuncType: params, isVariadic := check.collectParams(e.Params, true) results, _ := check.collectParams(e.Results, false) x.mode = typexpr x.typ = &Signature{recv: nil, params: NewTuple(params...), results: NewTuple(results...), isVariadic: isVariadic} case *ast.InterfaceType: x.mode = typexpr x.typ = &Interface{methods: check.collectMethods(e.Methods)} case *ast.MapType: x.mode = typexpr x.typ = &Map{key: check.typ(e.Key, true), elt: check.typ(e.Value, true)} case *ast.ChanType: x.mode = typexpr x.typ = &Chan{dir: e.Dir, elt: check.typ(e.Value, true)} default: if debug { check.dump("expr = %v (%T)", e, e) } unreachable() } // everything went well x.expr = e return Error: x.mode = invalid x.expr = e }
// 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 }