blob: 2eec8d41ad18567f1fa0b4a1cb8dd802f83166c2 [file] [log] [blame] [edit]
// Copyright 2009 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.
package typecheck
import (
"fmt"
"go/constant"
"go/token"
"internal/types/errors"
"strings"
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
)
func tcShift(n, l, r ir.Node) (ir.Node, ir.Node, *types.Type) {
if l.Type() == nil || r.Type() == nil {
return l, r, nil
}
r = DefaultLit(r, types.Types[types.TUINT])
t := r.Type()
if !t.IsInteger() {
base.Errorf("invalid operation: %v (shift count type %v, must be integer)", n, r.Type())
return l, r, nil
}
t = l.Type()
if t != nil && t.Kind() != types.TIDEAL && !t.IsInteger() {
base.Errorf("invalid operation: %v (shift of type %v)", n, t)
return l, r, nil
}
// no DefaultLit for left
// the outer context gives the type
t = l.Type()
if (l.Type() == types.UntypedFloat || l.Type() == types.UntypedComplex) && r.Op() == ir.OLITERAL {
t = types.UntypedInt
}
return l, r, t
}
// tcArith typechecks operands of a binary arithmetic expression.
// The result of tcArith MUST be assigned back to original operands,
// t is the type of the expression, and should be set by the caller. e.g:
//
// n.X, n.Y, t = tcArith(n, op, n.X, n.Y)
// n.SetType(t)
func tcArith(n ir.Node, op ir.Op, l, r ir.Node) (ir.Node, ir.Node, *types.Type) {
l, r = defaultlit2(l, r, false)
if l.Type() == nil || r.Type() == nil {
return l, r, nil
}
t := l.Type()
if t.Kind() == types.TIDEAL {
t = r.Type()
}
aop := ir.OXXX
if n.Op().IsCmp() && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
// comparison is okay as long as one side is
// assignable to the other. convert so they have
// the same type.
//
// the only conversion that isn't a no-op is concrete == interface.
// in that case, check comparability of the concrete type.
// The conversion allocates, so only do it if the concrete type is huge.
converted := false
if r.Type().Kind() != types.TBLANK {
aop, _ = assignOp(l.Type(), r.Type())
if aop != ir.OXXX {
if r.Type().IsInterface() && !l.Type().IsInterface() && !types.IsComparable(l.Type()) {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type()))
return l, r, nil
}
types.CalcSize(l.Type())
if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Size() >= 1<<16 {
l = ir.NewConvExpr(base.Pos, aop, r.Type(), l)
l.SetTypecheck(1)
}
t = r.Type()
converted = true
}
}
if !converted && l.Type().Kind() != types.TBLANK {
aop, _ = assignOp(r.Type(), l.Type())
if aop != ir.OXXX {
if l.Type().IsInterface() && !r.Type().IsInterface() && !types.IsComparable(r.Type()) {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type()))
return l, r, nil
}
types.CalcSize(r.Type())
if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Size() >= 1<<16 {
r = ir.NewConvExpr(base.Pos, aop, l.Type(), r)
r.SetTypecheck(1)
}
t = l.Type()
}
}
}
if t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
l, r = defaultlit2(l, r, true)
if l.Type() == nil || r.Type() == nil {
return l, r, nil
}
if l.Type().IsInterface() == r.Type().IsInterface() || aop == 0 {
base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type())
return l, r, nil
}
}
if t.Kind() == types.TIDEAL {
t = mixUntyped(l.Type(), r.Type())
}
if dt := defaultType(t); !okfor[op][dt.Kind()] {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
return l, r, nil
}
// okfor allows any array == array, map == map, func == func.
// restrict to slice/map/func == nil and nil == slice/map/func.
if l.Type().IsArray() && !types.IsComparable(l.Type()) {
base.Errorf("invalid operation: %v (%v cannot be compared)", n, l.Type())
return l, r, nil
}
if l.Type().IsSlice() && !ir.IsNil(l) && !ir.IsNil(r) {
base.Errorf("invalid operation: %v (slice can only be compared to nil)", n)
return l, r, nil
}
if l.Type().IsMap() && !ir.IsNil(l) && !ir.IsNil(r) {
base.Errorf("invalid operation: %v (map can only be compared to nil)", n)
return l, r, nil
}
if l.Type().Kind() == types.TFUNC && !ir.IsNil(l) && !ir.IsNil(r) {
base.Errorf("invalid operation: %v (func can only be compared to nil)", n)
return l, r, nil
}
if l.Type().IsStruct() {
if f := types.IncomparableField(l.Type()); f != nil {
base.Errorf("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
return l, r, nil
}
}
return l, r, t
}
// The result of tcCompLit MUST be assigned back to n, e.g.
//
// n.Left = tcCompLit(n.Left)
func tcCompLit(n *ir.CompLitExpr) (res ir.Node) {
if base.EnableTrace && base.Flag.LowerT {
defer tracePrint("tcCompLit", n)(&res)
}
lno := base.Pos
defer func() {
base.Pos = lno
}()
ir.SetPos(n)
t := n.Type()
base.AssertfAt(t != nil, n.Pos(), "missing type in composite literal")
switch t.Kind() {
default:
base.Errorf("invalid composite literal type %v", t)
n.SetType(nil)
case types.TARRAY:
typecheckarraylit(t.Elem(), t.NumElem(), n.List, "array literal")
n.SetOp(ir.OARRAYLIT)
case types.TSLICE:
length := typecheckarraylit(t.Elem(), -1, n.List, "slice literal")
n.SetOp(ir.OSLICELIT)
n.Len = length
case types.TMAP:
for i3, l := range n.List {
ir.SetPos(l)
if l.Op() != ir.OKEY {
n.List[i3] = Expr(l)
base.Errorf("missing key in map literal")
continue
}
l := l.(*ir.KeyExpr)
r := l.Key
r = Expr(r)
l.Key = AssignConv(r, t.Key(), "map key")
r = l.Value
r = Expr(r)
l.Value = AssignConv(r, t.Elem(), "map value")
}
n.SetOp(ir.OMAPLIT)
case types.TSTRUCT:
// Need valid field offsets for Xoffset below.
types.CalcSize(t)
errored := false
if len(n.List) != 0 && nokeys(n.List) {
// simple list of variables
ls := n.List
for i, n1 := range ls {
ir.SetPos(n1)
n1 = Expr(n1)
ls[i] = n1
if i >= t.NumFields() {
if !errored {
base.Errorf("too many values in %v", n)
errored = true
}
continue
}
f := t.Field(i)
s := f.Sym
// Do the test for assigning to unexported fields.
// But if this is an instantiated function, then
// the function has already been typechecked. In
// that case, don't do the test, since it can fail
// for the closure structs created in
// walkClosure(), because the instantiated
// function is compiled as if in the source
// package of the generic function.
if !(ir.CurFunc != nil && strings.Contains(ir.CurFunc.Nname.Sym().Name, "[")) {
if s != nil && !types.IsExported(s.Name) && s.Pkg != types.LocalPkg {
base.Errorf("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
}
}
// No pushtype allowed here. Must name fields for that.
n1 = AssignConv(n1, f.Type, "field value")
ls[i] = ir.NewStructKeyExpr(base.Pos, f, n1)
}
if len(ls) < t.NumFields() {
base.Errorf("too few values in %v", n)
}
} else {
hash := make(map[string]bool)
// keyed list
ls := n.List
for i, n := range ls {
ir.SetPos(n)
sk, ok := n.(*ir.StructKeyExpr)
if !ok {
kv, ok := n.(*ir.KeyExpr)
if !ok {
if !errored {
base.Errorf("mixture of field:value and value initializers")
errored = true
}
ls[i] = Expr(n)
continue
}
sk = tcStructLitKey(t, kv)
if sk == nil {
continue
}
fielddup(sk.Sym().Name, hash)
}
// No pushtype allowed here. Tried and rejected.
sk.Value = Expr(sk.Value)
sk.Value = AssignConv(sk.Value, sk.Field.Type, "field value")
ls[i] = sk
}
}
n.SetOp(ir.OSTRUCTLIT)
}
return n
}
// tcStructLitKey typechecks an OKEY node that appeared within a
// struct literal.
func tcStructLitKey(typ *types.Type, kv *ir.KeyExpr) *ir.StructKeyExpr {
key := kv.Key
sym := key.Sym()
// An OXDOT uses the Sym field to hold
// the field to the right of the dot,
// so s will be non-nil, but an OXDOT
// is never a valid struct literal key.
if sym == nil || sym.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || sym.IsBlank() {
base.Errorf("invalid field name %v in struct initializer", key)
return nil
}
if f := Lookdot1(nil, sym, typ, typ.Fields(), 0); f != nil {
return ir.NewStructKeyExpr(kv.Pos(), f, kv.Value)
}
if ci := Lookdot1(nil, sym, typ, typ.Fields(), 2); ci != nil { // Case-insensitive lookup.
if visible(ci.Sym) {
base.Errorf("unknown field '%v' in struct literal of type %v (but does have %v)", sym, typ, ci.Sym)
} else if nonexported(sym) && sym.Name == ci.Sym.Name { // Ensure exactness before the suggestion.
base.Errorf("cannot refer to unexported field '%v' in struct literal of type %v", sym, typ)
} else {
base.Errorf("unknown field '%v' in struct literal of type %v", sym, typ)
}
return nil
}
var f *types.Field
p, _ := dotpath(sym, typ, &f, true)
if p == nil || f.IsMethod() {
base.Errorf("unknown field '%v' in struct literal of type %v", sym, typ)
return nil
}
// dotpath returns the parent embedded types in reverse order.
var ep []string
for ei := len(p) - 1; ei >= 0; ei-- {
ep = append(ep, p[ei].field.Sym.Name)
}
ep = append(ep, sym.Name)
base.Errorf("cannot use promoted field %v in struct literal of type %v", strings.Join(ep, "."), typ)
return nil
}
// tcConv typechecks an OCONV node.
func tcConv(n *ir.ConvExpr) ir.Node {
types.CheckSize(n.Type()) // ensure width is calculated for backend
n.X = Expr(n.X)
n.X = convlit1(n.X, n.Type(), true, nil)
t := n.X.Type()
if t == nil || n.Type() == nil {
n.SetType(nil)
return n
}
op, why := convertOp(n.X.Op() == ir.OLITERAL, t, n.Type())
if op == ir.OXXX {
// Due to //go:nointerface, we may be stricter than types2 here (#63333).
base.ErrorfAt(n.Pos(), errors.InvalidConversion, "cannot convert %L to type %v%s", n.X, n.Type(), why)
n.SetType(nil)
return n
}
n.SetOp(op)
switch n.Op() {
case ir.OCONVNOP:
if t.Kind() == n.Type().Kind() {
switch t.Kind() {
case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128:
// Floating point casts imply rounding and
// so the conversion must be kept.
n.SetOp(ir.OCONV)
}
}
// do not convert to []byte literal. See CL 125796.
// generated code and compiler memory footprint is better without it.
case ir.OSTR2BYTES:
// ok
case ir.OSTR2RUNES:
if n.X.Op() == ir.OLITERAL {
return stringtoruneslit(n)
}
case ir.OBYTES2STR:
if t.Elem() != types.ByteType && t.Elem() != types.Types[types.TUINT8] {
// If t is a slice of a user-defined byte type B (not uint8
// or byte), then add an extra CONVNOP from []B to []byte, so
// that the call to slicebytetostring() added in walk will
// typecheck correctly.
n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.ByteType), n.X)
n.X.SetTypecheck(1)
}
case ir.ORUNES2STR:
if t.Elem() != types.RuneType && t.Elem() != types.Types[types.TINT32] {
// If t is a slice of a user-defined rune type B (not uint32
// or rune), then add an extra CONVNOP from []B to []rune, so
// that the call to slicerunetostring() added in walk will
// typecheck correctly.
n.X = ir.NewConvExpr(n.X.Pos(), ir.OCONVNOP, types.NewSlice(types.RuneType), n.X)
n.X.SetTypecheck(1)
}
}
return n
}
// DotField returns a field selector expression that selects the
// index'th field of the given expression, which must be of struct or
// pointer-to-struct type.
func DotField(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
op, typ := ir.ODOT, x.Type()
if typ.IsPtr() {
op, typ = ir.ODOTPTR, typ.Elem()
}
if !typ.IsStruct() {
base.FatalfAt(pos, "DotField of non-struct: %L", x)
}
// TODO(mdempsky): This is the backend's responsibility.
types.CalcSize(typ)
field := typ.Field(index)
return dot(pos, field.Type, op, x, field)
}
func dot(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node, selection *types.Field) *ir.SelectorExpr {
n := ir.NewSelectorExpr(pos, op, x, selection.Sym)
n.Selection = selection
n.SetType(typ)
n.SetTypecheck(1)
return n
}
// XDotField returns an expression representing the field selection
// x.sym. If any implicit field selection are necessary, those are
// inserted too.
func XDotField(pos src.XPos, x ir.Node, sym *types.Sym) *ir.SelectorExpr {
n := Expr(ir.NewSelectorExpr(pos, ir.OXDOT, x, sym)).(*ir.SelectorExpr)
if n.Op() != ir.ODOT && n.Op() != ir.ODOTPTR {
base.FatalfAt(pos, "unexpected result op: %v (%v)", n.Op(), n)
}
return n
}
// XDotMethod returns an expression representing the method value
// x.sym (i.e., x is a value, not a type). If any implicit field
// selection are necessary, those are inserted too.
//
// If callee is true, the result is an ODOTMETH/ODOTINTER, otherwise
// an OMETHVALUE.
func XDotMethod(pos src.XPos, x ir.Node, sym *types.Sym, callee bool) *ir.SelectorExpr {
n := ir.NewSelectorExpr(pos, ir.OXDOT, x, sym)
if callee {
n = Callee(n).(*ir.SelectorExpr)
if n.Op() != ir.ODOTMETH && n.Op() != ir.ODOTINTER {
base.FatalfAt(pos, "unexpected result op: %v (%v)", n.Op(), n)
}
} else {
n = Expr(n).(*ir.SelectorExpr)
if n.Op() != ir.OMETHVALUE {
base.FatalfAt(pos, "unexpected result op: %v (%v)", n.Op(), n)
}
}
return n
}
// tcDot typechecks an OXDOT or ODOT node.
func tcDot(n *ir.SelectorExpr, top int) ir.Node {
if n.Op() == ir.OXDOT {
n = AddImplicitDots(n)
n.SetOp(ir.ODOT)
if n.X == nil {
n.SetType(nil)
return n
}
}
n.X = Expr(n.X)
n.X = DefaultLit(n.X, nil)
t := n.X.Type()
if t == nil {
base.UpdateErrorDot(ir.Line(n), fmt.Sprint(n.X), fmt.Sprint(n))
n.SetType(nil)
return n
}
if n.X.Op() == ir.OTYPE {
base.FatalfAt(n.Pos(), "use NewMethodExpr to construct OMETHEXPR")
}
if t.IsPtr() && !t.Elem().IsInterface() {
t = t.Elem()
if t == nil {
n.SetType(nil)
return n
}
n.SetOp(ir.ODOTPTR)
types.CheckSize(t)
}
if n.Sel.IsBlank() {
base.Errorf("cannot refer to blank field or method")
n.SetType(nil)
return n
}
if Lookdot(n, t, 0) == nil {
// Legitimate field or method lookup failed, try to explain the error
switch {
case t.IsEmptyInterface():
base.Errorf("%v undefined (type %v is interface with no methods)", n, n.X.Type())
case t.IsPtr() && t.Elem().IsInterface():
// Pointer to interface is almost always a mistake.
base.Errorf("%v undefined (type %v is pointer to interface, not interface)", n, n.X.Type())
case Lookdot(n, t, 1) != nil:
// Field or method matches by name, but it is not exported.
base.Errorf("%v undefined (cannot refer to unexported field or method %v)", n, n.Sel)
default:
if mt := Lookdot(n, t, 2); mt != nil && visible(mt.Sym) { // Case-insensitive lookup.
base.Errorf("%v undefined (type %v has no field or method %v, but does have %v)", n, n.X.Type(), n.Sel, mt.Sym)
} else {
base.Errorf("%v undefined (type %v has no field or method %v)", n, n.X.Type(), n.Sel)
}
}
n.SetType(nil)
return n
}
if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
n.SetOp(ir.OMETHVALUE)
n.SetType(NewMethodType(n.Type(), nil))
}
return n
}
// tcDotType typechecks an ODOTTYPE node.
func tcDotType(n *ir.TypeAssertExpr) ir.Node {
n.X = Expr(n.X)
n.X = DefaultLit(n.X, nil)
l := n.X
t := l.Type()
if t == nil {
n.SetType(nil)
return n
}
if !t.IsInterface() {
base.Errorf("invalid type assertion: %v (non-interface type %v on left)", n, t)
n.SetType(nil)
return n
}
base.AssertfAt(n.Type() != nil, n.Pos(), "missing type: %v", n)
if n.Type() != nil && !n.Type().IsInterface() {
why := ImplementsExplain(n.Type(), t)
if why != "" {
base.Fatalf("impossible type assertion:\n\t%s", why)
n.SetType(nil)
return n
}
}
return n
}
// tcITab typechecks an OITAB node.
func tcITab(n *ir.UnaryExpr) ir.Node {
n.X = Expr(n.X)
t := n.X.Type()
if t == nil {
n.SetType(nil)
return n
}
if !t.IsInterface() {
base.Fatalf("OITAB of %v", t)
}
n.SetType(types.NewPtr(types.Types[types.TUINTPTR]))
return n
}
// tcIndex typechecks an OINDEX node.
func tcIndex(n *ir.IndexExpr) ir.Node {
n.X = Expr(n.X)
n.X = DefaultLit(n.X, nil)
n.X = implicitstar(n.X)
l := n.X
n.Index = Expr(n.Index)
r := n.Index
t := l.Type()
if t == nil || r.Type() == nil {
n.SetType(nil)
return n
}
switch t.Kind() {
default:
base.Errorf("invalid operation: %v (type %v does not support indexing)", n, t)
n.SetType(nil)
return n
case types.TSTRING, types.TARRAY, types.TSLICE:
n.Index = indexlit(n.Index)
if t.IsString() {
n.SetType(types.ByteType)
} else {
n.SetType(t.Elem())
}
why := "string"
if t.IsArray() {
why = "array"
} else if t.IsSlice() {
why = "slice"
}
if n.Index.Type() != nil && !n.Index.Type().IsInteger() {
base.Errorf("non-integer %s index %v", why, n.Index)
return n
}
case types.TMAP:
n.Index = AssignConv(n.Index, t.Key(), "map index")
n.SetType(t.Elem())
n.SetOp(ir.OINDEXMAP)
n.Assigned = false
}
return n
}
// tcLenCap typechecks an OLEN or OCAP node.
func tcLenCap(n *ir.UnaryExpr) ir.Node {
n.X = Expr(n.X)
n.X = DefaultLit(n.X, nil)
n.X = implicitstar(n.X)
l := n.X
t := l.Type()
if t == nil {
n.SetType(nil)
return n
}
var ok bool
if n.Op() == ir.OLEN {
ok = okforlen[t.Kind()]
} else {
ok = okforcap[t.Kind()]
}
if !ok {
base.Errorf("invalid argument %L for %v", l, n.Op())
n.SetType(nil)
return n
}
n.SetType(types.Types[types.TINT])
return n
}
// tcUnsafeData typechecks an OUNSAFESLICEDATA or OUNSAFESTRINGDATA node.
func tcUnsafeData(n *ir.UnaryExpr) ir.Node {
n.X = Expr(n.X)
n.X = DefaultLit(n.X, nil)
l := n.X
t := l.Type()
if t == nil {
n.SetType(nil)
return n
}
var kind types.Kind
if n.Op() == ir.OUNSAFESLICEDATA {
kind = types.TSLICE
} else {
/* kind is string */
kind = types.TSTRING
}
if t.Kind() != kind {
base.Errorf("invalid argument %L for %v", l, n.Op())
n.SetType(nil)
return n
}
if kind == types.TSTRING {
t = types.ByteType
} else {
t = t.Elem()
}
n.SetType(types.NewPtr(t))
return n
}
// tcRecv typechecks an ORECV node.
func tcRecv(n *ir.UnaryExpr) ir.Node {
n.X = Expr(n.X)
n.X = DefaultLit(n.X, nil)
l := n.X
t := l.Type()
if t == nil {
n.SetType(nil)
return n
}
if !t.IsChan() {
base.Errorf("invalid operation: %v (receive from non-chan type %v)", n, t)
n.SetType(nil)
return n
}
if !t.ChanDir().CanRecv() {
base.Errorf("invalid operation: %v (receive from send-only type %v)", n, t)
n.SetType(nil)
return n
}
n.SetType(t.Elem())
return n
}
// tcSPtr typechecks an OSPTR node.
func tcSPtr(n *ir.UnaryExpr) ir.Node {
n.X = Expr(n.X)
t := n.X.Type()
if t == nil {
n.SetType(nil)
return n
}
if !t.IsSlice() && !t.IsString() {
base.Fatalf("OSPTR of %v", t)
}
if t.IsString() {
n.SetType(types.NewPtr(types.Types[types.TUINT8]))
} else {
n.SetType(types.NewPtr(t.Elem()))
}
return n
}
// tcSlice typechecks an OSLICE or OSLICE3 node.
func tcSlice(n *ir.SliceExpr) ir.Node {
n.X = DefaultLit(Expr(n.X), nil)
n.Low = indexlit(Expr(n.Low))
n.High = indexlit(Expr(n.High))
n.Max = indexlit(Expr(n.Max))
hasmax := n.Op().IsSlice3()
l := n.X
if l.Type() == nil {
n.SetType(nil)
return n
}
if l.Type().IsArray() {
if !ir.IsAddressable(n.X) {
base.Errorf("invalid operation %v (slice of unaddressable value)", n)
n.SetType(nil)
return n
}
addr := NodAddr(n.X)
addr.SetImplicit(true)
n.X = Expr(addr)
l = n.X
}
t := l.Type()
var tp *types.Type
if t.IsString() {
if hasmax {
base.Errorf("invalid operation %v (3-index slice of string)", n)
n.SetType(nil)
return n
}
n.SetType(t)
n.SetOp(ir.OSLICESTR)
} else if t.IsPtr() && t.Elem().IsArray() {
tp = t.Elem()
n.SetType(types.NewSlice(tp.Elem()))
types.CalcSize(n.Type())
if hasmax {
n.SetOp(ir.OSLICE3ARR)
} else {
n.SetOp(ir.OSLICEARR)
}
} else if t.IsSlice() {
n.SetType(t)
} else {
base.Errorf("cannot slice %v (type %v)", l, t)
n.SetType(nil)
return n
}
if n.Low != nil && !checksliceindex(n.Low) {
n.SetType(nil)
return n
}
if n.High != nil && !checksliceindex(n.High) {
n.SetType(nil)
return n
}
if n.Max != nil && !checksliceindex(n.Max) {
n.SetType(nil)
return n
}
return n
}
// tcSliceHeader typechecks an OSLICEHEADER node.
func tcSliceHeader(n *ir.SliceHeaderExpr) ir.Node {
// Errors here are Fatalf instead of Errorf because only the compiler
// can construct an OSLICEHEADER node.
// Components used in OSLICEHEADER that are supplied by parsed source code
// have already been typechecked in e.g. OMAKESLICE earlier.
t := n.Type()
if t == nil {
base.Fatalf("no type specified for OSLICEHEADER")
}
if !t.IsSlice() {
base.Fatalf("invalid type %v for OSLICEHEADER", n.Type())
}
if n.Ptr == nil || n.Ptr.Type() == nil || !n.Ptr.Type().IsUnsafePtr() {
base.Fatalf("need unsafe.Pointer for OSLICEHEADER")
}
n.Ptr = Expr(n.Ptr)
n.Len = DefaultLit(Expr(n.Len), types.Types[types.TINT])
n.Cap = DefaultLit(Expr(n.Cap), types.Types[types.TINT])
if ir.IsConst(n.Len, constant.Int) && ir.Int64Val(n.Len) < 0 {
base.Fatalf("len for OSLICEHEADER must be non-negative")
}
if ir.IsConst(n.Cap, constant.Int) && ir.Int64Val(n.Cap) < 0 {
base.Fatalf("cap for OSLICEHEADER must be non-negative")
}
if ir.IsConst(n.Len, constant.Int) && ir.IsConst(n.Cap, constant.Int) && constant.Compare(n.Len.Val(), token.GTR, n.Cap.Val()) {
base.Fatalf("len larger than cap for OSLICEHEADER")
}
return n
}
// tcStringHeader typechecks an OSTRINGHEADER node.
func tcStringHeader(n *ir.StringHeaderExpr) ir.Node {
t := n.Type()
if t == nil {
base.Fatalf("no type specified for OSTRINGHEADER")
}
if !t.IsString() {
base.Fatalf("invalid type %v for OSTRINGHEADER", n.Type())
}
if n.Ptr == nil || n.Ptr.Type() == nil || !n.Ptr.Type().IsUnsafePtr() {
base.Fatalf("need unsafe.Pointer for OSTRINGHEADER")
}
n.Ptr = Expr(n.Ptr)
n.Len = DefaultLit(Expr(n.Len), types.Types[types.TINT])
if ir.IsConst(n.Len, constant.Int) && ir.Int64Val(n.Len) < 0 {
base.Fatalf("len for OSTRINGHEADER must be non-negative")
}
return n
}
// tcStar typechecks an ODEREF node, which may be an expression or a type.
func tcStar(n *ir.StarExpr, top int) ir.Node {
n.X = typecheck(n.X, ctxExpr|ctxType)
l := n.X
t := l.Type()
if t == nil {
n.SetType(nil)
return n
}
// TODO(mdempsky): Remove (along with ctxType above) once I'm
// confident this code path isn't needed any more.
if l.Op() == ir.OTYPE {
base.Fatalf("unexpected type in deref expression: %v", l)
}
if !t.IsPtr() {
if top&(ctxExpr|ctxStmt) != 0 {
base.Errorf("invalid indirect of %L", n.X)
n.SetType(nil)
return n
}
base.Errorf("%v is not a type", l)
return n
}
n.SetType(t.Elem())
return n
}
// tcUnaryArith typechecks a unary arithmetic expression.
func tcUnaryArith(n *ir.UnaryExpr) ir.Node {
n.X = Expr(n.X)
l := n.X
t := l.Type()
if t == nil {
n.SetType(nil)
return n
}
if !okfor[n.Op()][defaultType(t).Kind()] {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(t))
n.SetType(nil)
return n
}
n.SetType(t)
return n
}