// For len(x) and cap(x) we need to know if x contains any function calls or
// receive operations. Save/restore current setting and set hasCallOrRecv to
// false for the evaluation of x so that we can check it afterwards.
- // Note: We must do this _before_ calling unpack because unpack evaluates the
- // first argument before we even call arg(x, 0)!
+ // Note: We must do this _before_ calling exprList because exprList evaluates
+ // all arguments.
if id == _Len || id == _Cap {
defer func(b bool) {
check.hasCallOrRecv = b
}
// determine actual arguments
- var arg getter
+ var arg func(*operand, int) // TODO(gri) remove use of arg getter in favor of using xlist directly
nargs := len(call.Args)
switch id {
default:
// make argument getter
- arg, nargs, _ = unpack(func(x *operand, i int) { check.multiExpr(x, call.Args[i]) }, nargs, false)
- if arg == nil {
- return
- }
+ xlist, _ := check.exprList(call.Args, false)
+ arg = func(x *operand, i int) { *x = *xlist[i]; x.typ = expand(x.typ) }
+ nargs = len(xlist)
// evaluate first argument, if present
if nargs > 0 {
arg(x, 0)
// of S and the respective parameter passing rules apply."
S := x.typ
var T Type
- if s, _ := S.Underlying().(*Slice); s != nil {
+ if s := asSlice(S); s != nil {
T = s.elem
} else {
check.invalidArg(x, _InvalidAppend, "%s is not a slice", x)
// check general case by creating custom signature
sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature
sig.variadic = true
- check.arguments(x, call, sig, func(x *operand, i int) {
- // only evaluate arguments that have not been evaluated before
- if i < len(alist) {
- *x = alist[i]
- return
- }
- arg(x, i)
- }, nargs)
+ var xlist []*operand
+ // convert []operand to []*operand
+ for i := range alist {
+ xlist = append(xlist, &alist[i])
+ }
+ for i := len(alist); i < nargs; i++ {
+ var x operand
+ arg(&x, i)
+ xlist = append(xlist, &x)
+ }
+ check.arguments(call, sig, xlist) // discard result (we know the result type)
// ok to continue even if check.arguments reported errors
x.mode = value
mode := invalid
var typ Type
var val constant.Value
- switch typ = implicitArrayDeref(x.typ.Underlying()); t := typ.(type) {
+ switch typ = implicitArrayDeref(optype(x.typ)); t := typ.(type) {
case *Basic:
if isString(t) && id == _Len {
if x.mode == constant_ {
if id == _Len {
mode = value
}
+
+ case *Sum:
+ if t.is(func(t Type) bool {
+ switch t := under(t).(type) {
+ case *Basic:
+ if isString(t) && id == _Len {
+ return true
+ }
+ case *Array, *Slice, *Chan:
+ return true
+ case *Map:
+ if id == _Len {
+ return true
+ }
+ }
+ return false
+ }) {
+ mode = value
+ }
}
if mode == invalid && typ != Typ[Invalid] {
case _Close:
// close(c)
- c, _ := x.typ.Underlying().(*Chan)
+ c := asChan(x.typ)
if c == nil {
check.invalidArg(x, _InvalidClose, "%s is not a channel", x)
return
}
// the argument types must be of floating-point type
- if !isFloat(x.typ) {
+ f := func(x Type) Type {
+ if t := asBasic(x); t != nil {
+ switch t.kind {
+ case Float32:
+ return Typ[Complex64]
+ case Float64:
+ return Typ[Complex128]
+ case UntypedFloat:
+ return Typ[UntypedComplex]
+ }
+ }
+ return nil
+ }
+ resTyp := check.applyTypeFunc(f, x.typ)
+ if resTyp == nil {
check.invalidArg(x, _InvalidComplex, "arguments have type %s, expected floating-point", x.typ)
return
}
x.mode = value
}
- // determine result type
- var res BasicKind
- switch x.typ.Underlying().(*Basic).kind {
- case Float32:
- res = Complex64
- case Float64:
- res = Complex128
- case UntypedFloat:
- res = UntypedComplex
- default:
- unreachable()
- }
- resTyp := Typ[res]
-
if check.Types != nil && x.mode != constant_ {
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ, x.typ))
}
case _Copy:
// copy(x, y []T) int
var dst Type
- if t, _ := x.typ.Underlying().(*Slice); t != nil {
+ if t := asSlice(x.typ); t != nil {
dst = t.elem
}
return
}
var src Type
- switch t := y.typ.Underlying().(type) {
+ switch t := optype(y.typ).(type) {
case *Basic:
if isString(y.typ) {
src = universeByte
case _Delete:
// delete(m, k)
- m, _ := x.typ.Underlying().(*Map)
+ m := asMap(x.typ)
if m == nil {
check.invalidArg(x, _InvalidDelete, "%s is not a map", x)
return
}
// the argument must be of complex type
- if !isComplex(x.typ) {
+ f := func(x Type) Type {
+ if t := asBasic(x); t != nil {
+ switch t.kind {
+ case Complex64:
+ return Typ[Float32]
+ case Complex128:
+ return Typ[Float64]
+ case UntypedComplex:
+ return Typ[UntypedFloat]
+ }
+ }
+ return nil
+ }
+ resTyp := check.applyTypeFunc(f, x.typ)
+ if resTyp == nil {
code := _InvalidImag
if id == _Real {
code = _InvalidReal
x.mode = value
}
- // determine result type
- var res BasicKind
- switch x.typ.Underlying().(*Basic).kind {
- case Complex64:
- res = Float32
- case Complex128:
- res = Float64
- case UntypedComplex:
- res = UntypedFloat
- default:
- unreachable()
- }
- resTyp := Typ[res]
-
if check.Types != nil && x.mode != constant_ {
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ))
}
// make(T, n, m)
// (no argument evaluated yet)
arg0 := call.Args[0]
- T := check.typ(arg0)
+ T := check.varType(arg0)
if T == Typ[Invalid] {
return
}
- var min int // minimum number of arguments
- switch T.Underlying().(type) {
- case *Slice:
- min = 2
- case *Map, *Chan:
- min = 1
- default:
+ min, max := -1, 10
+ var valid func(t Type) bool
+ valid = func(t Type) bool {
+ var m int
+ switch t := optype(t).(type) {
+ case *Slice:
+ m = 2
+ case *Map, *Chan:
+ m = 1
+ case *Sum:
+ return t.is(valid)
+ default:
+ return false
+ }
+ if m > min {
+ min = m
+ }
+ if m+1 < max {
+ max = m + 1
+ }
+ return true
+ }
+
+ if !valid(T) {
check.invalidArg(arg0, _InvalidMake, "cannot make %s; type must be slice, map, or channel", arg0)
return
}
- if nargs < min || min+1 < nargs {
- check.errorf(call, _WrongArgCount, "%v expects %d or %d arguments; found %d", call, min, min+1, nargs)
+ if nargs < min || max < nargs {
+ if min == max {
+ check.errorf(call, _WrongArgCount, "%v expects %d arguments; found %d", call, min, nargs)
+ } else {
+ check.errorf(call, _WrongArgCount, "%v expects %d or %d arguments; found %d", call, min, max, nargs)
+ }
return
}
+
types := []Type{T}
var sizes []int64 // constant integer arguments, if any
for _, arg := range call.Args[1:] {
case _New:
// new(T)
// (no argument evaluated yet)
- T := check.typ(call.Args[0])
+ T := check.varType(call.Args[0])
if T == Typ[Invalid] {
return
}
case _Alignof:
// unsafe.Alignof(x T) uintptr
+ if asTypeParam(x.typ) != nil {
+ check.invalidOp(call, _Todo, "unsafe.Alignof undefined for %s", x)
+ return
+ }
check.assignment(x, nil, "argument to unsafe.Alignof")
if x.mode == invalid {
return
case _Sizeof:
// unsafe.Sizeof(x T) uintptr
+ if asTypeParam(x.typ) != nil {
+ check.invalidOp(call, _Todo, "unsafe.Sizeof undefined for %s", x)
+ return
+ }
check.assignment(x, nil, "argument to unsafe.Sizeof")
if x.mode == invalid {
return
return true
}
+// applyTypeFunc applies f to x. If x is a type parameter,
+// the result is a type parameter constrained by an new
+// interface bound. The type bounds for that interface
+// are computed by applying f to each of the type bounds
+// of x. If any of these applications of f return nil,
+// applyTypeFunc returns nil.
+// If x is not a type parameter, the result is f(x).
+func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
+ if tp := asTypeParam(x); tp != nil {
+ // Test if t satisfies the requirements for the argument
+ // type and collect possible result types at the same time.
+ var rtypes []Type
+ if !tp.Bound().is(func(x Type) bool {
+ if r := f(x); r != nil {
+ rtypes = append(rtypes, r)
+ return true
+ }
+ return false
+ }) {
+ return nil
+ }
+
+ // construct a suitable new type parameter
+ tpar := NewTypeName(token.NoPos, nil /* = Universe pkg */, "<type parameter>", nil)
+ ptyp := check.NewTypeParam(tpar, 0, &emptyInterface) // assigns type to tpar as a side-effect
+ tsum := NewSum(rtypes)
+ ptyp.bound = &Interface{types: tsum, allMethods: markComplete, allTypes: tsum}
+
+ return ptyp
+ }
+
+ return f(x)
+}
+
// makeSig makes a signature for the given argument and result types.
// Default types are used for untyped arguments, and res may be nil.
func makeSig(res Type, args ...Type) *Signature {
//
func implicitArrayDeref(typ Type) Type {
if p, ok := typ.(*Pointer); ok {
- if a, ok := p.base.Underlying().(*Array); ok {
+ if a := asArray(p.base); a != nil {
return a
}
}