mirror of
https://github.com/golang/go
synced 2024-11-19 00:34:40 -07:00
go.tools/go/types: built-in calls of the form builtin(f())
- factor out argument extraction logic - cleaned up error handling in builtin.go (no need for goto's anymore) - lots of additional test cases - various cleanups, better documentation Fixes golang/go#5795. R=adonovan CC=golang-dev https://golang.org/cl/14312044
This commit is contained in:
parent
6af036a659
commit
5d0990f591
@ -13,48 +13,48 @@ import (
|
||||
"code.google.com/p/go.tools/go/exact"
|
||||
)
|
||||
|
||||
// builtin typechecks a call to a built-in and returns the result via x.
|
||||
// If the call has type errors, the returned x is marked as invalid.
|
||||
// builtin type-checks a call to the built-in specified by id and
|
||||
// returns true if the call is valid, with *x holding the result;
|
||||
// but x.expr is not set. If the call is invalid, the result is
|
||||
// false, and *x is undefined.
|
||||
//
|
||||
func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
args := call.Args
|
||||
|
||||
// declare before goto's
|
||||
var arg0 ast.Expr // first argument, if present
|
||||
func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ bool) {
|
||||
// determine actual arguments
|
||||
var arg getter
|
||||
nargs := len(call.Args)
|
||||
switch id {
|
||||
default:
|
||||
// make argument getter
|
||||
arg, nargs = unpack(func(x *operand, i int) { check.expr(x, call.Args[i]) }, nargs, false)
|
||||
// evaluate first argument, if present
|
||||
if nargs > 0 {
|
||||
arg(x, 0)
|
||||
if x.mode == invalid {
|
||||
return
|
||||
}
|
||||
}
|
||||
case _Make, _New, _Offsetof, _Trace:
|
||||
// arguments requires special handling
|
||||
}
|
||||
|
||||
// check argument count
|
||||
n := len(args)
|
||||
msg := ""
|
||||
bin := predeclaredFuncs[id]
|
||||
if n < bin.nargs {
|
||||
msg = "not enough"
|
||||
} else if !bin.variadic && n > bin.nargs {
|
||||
msg = "too many"
|
||||
}
|
||||
if msg != "" {
|
||||
check.invalidOp(call.Pos(), "%s arguments for %s (expected %d, found %d)", msg, 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)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
{
|
||||
msg := ""
|
||||
if nargs < bin.nargs {
|
||||
msg = "not enough"
|
||||
} else if !bin.variadic && nargs > bin.nargs {
|
||||
msg = "too many"
|
||||
}
|
||||
if msg != "" {
|
||||
check.invalidOp(call.Rparen, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch id {
|
||||
case _Append:
|
||||
// append(s S, x ...T) S where T is the element type of S
|
||||
// append(s S, x ...T) S, where T is the element type of S
|
||||
// spec: "The variadic function append appends zero or more values x to s of type
|
||||
// S, which must be a slice type, and returns the resulting slice, also of type S.
|
||||
// The values x are passed to a parameter of type ...T where T is the element type
|
||||
@ -65,7 +65,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
T = s.elt
|
||||
} else {
|
||||
check.invalidArg(x.pos(), "%s is not a slice", x)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
|
||||
// remember arguments that have been evaluated already
|
||||
@ -74,16 +74,15 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
// spec: "As a special case, append also accepts a first argument assignable
|
||||
// to type []byte with a second argument of string type followed by ... .
|
||||
// This form appends the bytes of the string.
|
||||
if n == 2 && call.Ellipsis.IsValid() && x.isAssignableTo(check.conf, NewSlice(Typ[Byte])) {
|
||||
check.expr(x, args[1])
|
||||
if nargs == 2 && call.Ellipsis.IsValid() && x.isAssignableTo(check.conf, NewSlice(Typ[Byte])) {
|
||||
arg(x, 1)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
if isString(x.typ) {
|
||||
x.mode = value
|
||||
x.typ = S
|
||||
x.expr = call
|
||||
return
|
||||
break
|
||||
}
|
||||
alist = append(alist, *x)
|
||||
// fallthrough
|
||||
@ -98,13 +97,15 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
*x = alist[i]
|
||||
return
|
||||
}
|
||||
check.expr(x, args[i])
|
||||
})
|
||||
arg(x, i)
|
||||
}, nargs)
|
||||
|
||||
x.mode = value
|
||||
x.typ = S
|
||||
|
||||
case _Cap, _Len:
|
||||
// cap(x)
|
||||
// len(x)
|
||||
mode := invalid
|
||||
var val exact.Value
|
||||
switch typ := implicitArrayDeref(x.typ.Underlying()).(type) {
|
||||
@ -124,7 +125,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
// 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) {
|
||||
if !check.containsCallsOrReceives(x.expr) {
|
||||
mode = constant
|
||||
val = exact.MakeInt64(typ.len)
|
||||
}
|
||||
@ -140,78 +141,82 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
|
||||
if mode == invalid {
|
||||
check.invalidArg(x.pos(), "%s for %s", x, bin.name)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
x.mode = mode
|
||||
x.typ = Typ[Int]
|
||||
x.val = val
|
||||
|
||||
case _Close:
|
||||
ch, ok := x.typ.Underlying().(*Chan)
|
||||
if !ok {
|
||||
// close(c)
|
||||
c, _ := x.typ.Underlying().(*Chan)
|
||||
if c == nil {
|
||||
check.invalidArg(x.pos(), "%s is not a channel", x)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
if ch.dir&ast.SEND == 0 {
|
||||
if c.dir&ast.SEND == 0 {
|
||||
check.invalidArg(x.pos(), "%s must not be a receive-only channel", x)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
x.mode = novalue
|
||||
|
||||
case _Complex:
|
||||
// complex(x, y realT) complexT
|
||||
if !check.complexArg(x) {
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
|
||||
var y operand
|
||||
check.expr(&y, args[1])
|
||||
arg(&y, 1)
|
||||
if y.mode == invalid {
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
if !check.complexArg(&y) {
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
|
||||
check.convertUntyped(x, y.typ)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
check.convertUntyped(&y, x.typ)
|
||||
if y.mode == invalid {
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
|
||||
if !IsIdentical(x.typ, y.typ) {
|
||||
check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
|
||||
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 {
|
||||
realT := x.typ.Underlying().(*Basic)
|
||||
complexT := Typ[Invalid]
|
||||
switch realT.kind {
|
||||
case Float32:
|
||||
x.typ = Typ[Complex64]
|
||||
complexT = Typ[Complex64]
|
||||
case Float64:
|
||||
x.typ = Typ[Complex128]
|
||||
complexT = Typ[Complex128]
|
||||
case UntypedInt, UntypedRune, UntypedFloat:
|
||||
if x.mode == constant {
|
||||
typ = defaultType(typ).(*Basic)
|
||||
x.typ = Typ[UntypedComplex]
|
||||
realT = defaultType(realT).(*Basic)
|
||||
complexT = 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]
|
||||
realT = Typ[Float64]
|
||||
complexT = Typ[Complex128]
|
||||
}
|
||||
default:
|
||||
check.invalidArg(x.pos(), "float32 or float64 arguments expected")
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
x.typ = complexT
|
||||
|
||||
if x.mode != constant {
|
||||
// The arguments have now their final types, which at run-
|
||||
@ -220,21 +225,23 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
// 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)
|
||||
check.updateExprType(x.expr, realT, true)
|
||||
check.updateExprType(y.expr, realT, true)
|
||||
}
|
||||
|
||||
case _Copy:
|
||||
var y operand
|
||||
check.expr(&y, args[1])
|
||||
if y.mode == invalid {
|
||||
goto Error
|
||||
}
|
||||
|
||||
var dst, src Type
|
||||
if t, ok := x.typ.Underlying().(*Slice); ok {
|
||||
// copy(x, y []T) int
|
||||
var dst Type
|
||||
if t, _ := x.typ.Underlying().(*Slice); t != nil {
|
||||
dst = t.elt
|
||||
}
|
||||
|
||||
var y operand
|
||||
arg(&y, 1)
|
||||
if y.mode == invalid {
|
||||
return
|
||||
}
|
||||
var src Type
|
||||
switch t := y.typ.Underlying().(type) {
|
||||
case *Basic:
|
||||
if isString(y.typ) {
|
||||
@ -246,37 +253,40 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
|
||||
if dst == nil || src == nil {
|
||||
check.invalidArg(x.pos(), "copy expects slice arguments; found %s and %s", x, &y)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
return
|
||||
}
|
||||
|
||||
x.mode = value
|
||||
x.typ = Typ[Int]
|
||||
|
||||
case _Delete:
|
||||
m, ok := x.typ.Underlying().(*Map)
|
||||
if !ok {
|
||||
// delete(m, k)
|
||||
m, _ := x.typ.Underlying().(*Map)
|
||||
if m == nil {
|
||||
check.invalidArg(x.pos(), "%s is not a map", x)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
check.expr(x, args[1])
|
||||
arg(x, 1) // k
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
if !x.isAssignableTo(check.conf, m.key) {
|
||||
check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
x.mode = novalue
|
||||
|
||||
case _Imag, _Real:
|
||||
// imag(complexT) realT
|
||||
// real(complexT) realT
|
||||
if !isComplex(x.typ) {
|
||||
check.invalidArg(x.pos(), "%s must be a complex number", x)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
if x.mode == constant {
|
||||
if id == _Real {
|
||||
@ -301,94 +311,107 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
x.typ = Typ[k]
|
||||
|
||||
case _Make:
|
||||
resultTyp := check.typ(arg0, nil, false)
|
||||
if resultTyp == Typ[Invalid] {
|
||||
goto Error
|
||||
// make(T, n)
|
||||
// make(T, n, m)
|
||||
// (no argument evaluated yet)
|
||||
arg0 := call.Args[0]
|
||||
T := check.typ(arg0, nil, false)
|
||||
if T == Typ[Invalid] {
|
||||
return
|
||||
}
|
||||
var min int // minimum number of arguments
|
||||
switch resultTyp.Underlying().(type) {
|
||||
switch T.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
|
||||
return
|
||||
}
|
||||
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
|
||||
if nargs < min || min+1 < nargs {
|
||||
check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, nargs)
|
||||
return
|
||||
}
|
||||
var sizes []int64 // constant integer arguments, if any
|
||||
for _, arg := range args[1:] {
|
||||
for _, arg := range call.Args[1:] {
|
||||
if s, ok := check.index(arg, -1); ok && s >= 0 {
|
||||
sizes = append(sizes, s)
|
||||
}
|
||||
}
|
||||
if len(sizes) == 2 && sizes[0] > sizes[1] {
|
||||
check.invalidArg(args[1].Pos(), "length and capacity swapped")
|
||||
check.invalidArg(call.Args[1].Pos(), "length and capacity swapped")
|
||||
// safe to continue
|
||||
}
|
||||
x.mode = variable
|
||||
x.typ = resultTyp
|
||||
x.typ = T
|
||||
|
||||
case _New:
|
||||
resultTyp := check.typ(arg0, nil, false)
|
||||
if resultTyp == Typ[Invalid] {
|
||||
goto Error
|
||||
// new(T)
|
||||
// (no argument evaluated yet)
|
||||
T := check.typ(call.Args[0], nil, false)
|
||||
if T == Typ[Invalid] {
|
||||
return
|
||||
}
|
||||
x.mode = variable
|
||||
x.typ = &Pointer{base: resultTyp}
|
||||
x.typ = &Pointer{base: T}
|
||||
|
||||
case _Panic:
|
||||
x.mode = novalue
|
||||
|
||||
case _Print, _Println:
|
||||
for _, arg := range args {
|
||||
check.expr(x, arg)
|
||||
case _Panic, _Print, _Println:
|
||||
// panic(x interface{})
|
||||
// print(x, y, ...)
|
||||
// println(x, y, ...)
|
||||
for i := 1; i < nargs; i++ {
|
||||
arg(x, i)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
// TODO(gri) arguments must be assignable to _
|
||||
}
|
||||
x.mode = novalue
|
||||
|
||||
case _Recover:
|
||||
// recover() interface{}
|
||||
x.mode = value
|
||||
x.typ = new(Interface)
|
||||
|
||||
case _Alignof:
|
||||
// unsafe.Alignof(x T) uintptr, where x must be a variable
|
||||
x.mode = constant
|
||||
x.val = exact.MakeInt64(check.conf.alignof(x.typ))
|
||||
x.typ = Typ[Uintptr]
|
||||
|
||||
case _Offsetof:
|
||||
arg, ok := unparen(arg0).(*ast.SelectorExpr)
|
||||
if !ok {
|
||||
// unsafe.Offsetof(x T) uintptr, where x must be a selector
|
||||
// (no argument evaluated yet)
|
||||
arg0 := call.Args[0]
|
||||
selx, _ := unparen(arg0).(*ast.SelectorExpr)
|
||||
if selx == nil {
|
||||
check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0)
|
||||
goto Error
|
||||
check.rawExpr(x, arg0, nil) // evaluate to avoid spurious "declared but not used" errors
|
||||
return
|
||||
}
|
||||
check.expr(x, arg.X)
|
||||
check.expr(x, selx.X)
|
||||
if x.mode == invalid {
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
base := derefStructPtr(x.typ)
|
||||
sel := arg.Sel.Name
|
||||
obj, index, indirect := LookupFieldOrMethod(base, check.pkg, arg.Sel.Name)
|
||||
sel := selx.Sel.Name
|
||||
obj, index, indirect := LookupFieldOrMethod(base, check.pkg, sel)
|
||||
switch obj.(type) {
|
||||
case nil:
|
||||
check.invalidArg(x.pos(), "%s has no single field %s", base, sel)
|
||||
goto Error
|
||||
return
|
||||
case *Func:
|
||||
check.invalidArg(arg0.Pos(), "%s is a method value", arg0)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
if indirect {
|
||||
check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, base)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(gri) Should we pass x.typ instead of base (and indirect report if derefStructPtr indirected)?
|
||||
check.recordSelection(arg, FieldVal, base, obj, index, false)
|
||||
check.recordSelection(selx, FieldVal, base, obj, index, false)
|
||||
|
||||
offs := check.conf.offsetof(base, index)
|
||||
x.mode = constant
|
||||
@ -396,6 +419,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
x.typ = Typ[Uintptr]
|
||||
|
||||
case _Sizeof:
|
||||
// unsafe.Sizeof(x T) uintptr
|
||||
x.mode = constant
|
||||
x.val = exact.MakeInt64(check.conf.sizeof(x.typ))
|
||||
x.typ = Typ[Uintptr]
|
||||
@ -406,11 +430,11 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
// 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
|
||||
return
|
||||
}
|
||||
if x.val.Kind() != exact.Bool {
|
||||
check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x)
|
||||
goto Error
|
||||
return
|
||||
}
|
||||
if !exact.BoolVal(x.val) {
|
||||
check.errorf(call.Pos(), "%s failed", call)
|
||||
@ -422,15 +446,15 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
// 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 {
|
||||
// (no argument evaluated yet)
|
||||
if nargs == 0 {
|
||||
check.dump("%s: trace() without arguments", call.Pos())
|
||||
x.mode = novalue
|
||||
x.expr = call
|
||||
return
|
||||
break
|
||||
}
|
||||
var t operand
|
||||
x1 := x
|
||||
for _, arg := range args {
|
||||
for _, arg := range call.Args {
|
||||
check.rawExpr(x1, arg, nil) // 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
|
||||
@ -440,24 +464,22 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||
unreachable()
|
||||
}
|
||||
|
||||
x.expr = call
|
||||
return
|
||||
|
||||
Error:
|
||||
x.mode = invalid
|
||||
x.expr = call
|
||||
return true
|
||||
}
|
||||
|
||||
// makeSig returns the signature for the given parameter and result types.
|
||||
func makeSig(result Type, params ...Type) *Signature {
|
||||
list := make([]*Var, len(params))
|
||||
for i, param := range params {
|
||||
// makeSig makes a signature for the given argument and result types.
|
||||
// res may be nil.
|
||||
func makeSig(res Type, args ...Type) *Signature {
|
||||
list := make([]*Var, len(args))
|
||||
for i, param := range args {
|
||||
list[i] = NewVar(token.NoPos, nil, "", param)
|
||||
}
|
||||
return &Signature{
|
||||
params: NewTuple(list...),
|
||||
results: NewTuple(NewVar(token.NoPos, nil, "", result)),
|
||||
params := NewTuple(list...)
|
||||
var result *Tuple
|
||||
if res != nil {
|
||||
result = NewTuple(NewVar(token.NoPos, nil, "", res))
|
||||
}
|
||||
return &Signature{params: params, results: result}
|
||||
}
|
||||
|
||||
// implicitArrayDeref returns A if typ is of the form *A and A is an array;
|
||||
|
120
go/types/call.go
120
go/types/call.go
@ -49,7 +49,10 @@ func (check *checker) call(x *operand, e *ast.CallExpr) exprKind {
|
||||
|
||||
case builtin:
|
||||
id := x.id
|
||||
check.builtin(x, e, id)
|
||||
if !check.builtin(x, e, id) {
|
||||
x.mode = invalid
|
||||
}
|
||||
x.expr = e
|
||||
return predeclaredFuncs[id].kind
|
||||
|
||||
default:
|
||||
@ -62,7 +65,8 @@ func (check *checker) call(x *operand, e *ast.CallExpr) exprKind {
|
||||
return statement
|
||||
}
|
||||
|
||||
check.arguments(x, e, sig, func(x *operand, i int) { check.expr(x, e.Args[i]) })
|
||||
arg, n := unpack(func(x *operand, i int) { check.expr(x, e.Args[i]) }, len(e.Args), false)
|
||||
check.arguments(x, e, sig, arg, n)
|
||||
|
||||
// determine result
|
||||
switch sig.results.Len() {
|
||||
@ -81,9 +85,88 @@ func (check *checker) call(x *operand, e *ast.CallExpr) exprKind {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(gri) use unpack for assignment checking as well.
|
||||
|
||||
// A getter sets x as the i'th operand, where 0 <= i < n and n is the total
|
||||
// number of operands (context-specific, and maintained elsewhere). A getter
|
||||
// type-checks the i'th operand; the details of the actual check are getter-
|
||||
// specific.
|
||||
type getter func(x *operand, i int)
|
||||
|
||||
// unpack takes a getter get and a number of operands n. If n == 1 and the
|
||||
// first operand is a function call, or a comma,ok expression and allowCommaOk
|
||||
// is set, the result is a new getter and operand count providing access to the
|
||||
// function results, or comma,ok values, respectively. In all other cases, the
|
||||
// incoming getter and operand count are returned unchanged. In other words,
|
||||
// if there's exactly one operand that - after type-checking by calling get -
|
||||
// stands for multiple operands, the resulting getter provides access to those
|
||||
// operands instead.
|
||||
//
|
||||
// Note that unpack may call get(..., 0); but if the result getter is called
|
||||
// at most once for a given operand index i (including i == 0), that operand
|
||||
// is guaranteed to cause only one call of the incoming getter with that i.
|
||||
//
|
||||
func unpack(get getter, n int, allowCommaOk bool) (getter, int) {
|
||||
if n == 1 {
|
||||
// possibly result of an n-valued function call or comma,ok value
|
||||
var x0 operand
|
||||
get(&x0, 0)
|
||||
if x0.mode == invalid {
|
||||
return func(x *operand, i int) {
|
||||
if i != 0 {
|
||||
unreachable()
|
||||
}
|
||||
// i == 0
|
||||
x.mode = invalid
|
||||
}, 1
|
||||
}
|
||||
|
||||
if t, ok := x0.typ.(*Tuple); ok {
|
||||
// result of an n-valued function call
|
||||
return func(x *operand, i int) {
|
||||
x.mode = value
|
||||
x.expr = x0.expr
|
||||
x.typ = t.At(i).typ
|
||||
}, t.Len()
|
||||
}
|
||||
|
||||
if x0.mode == valueok {
|
||||
// comma-ok value
|
||||
if allowCommaOk {
|
||||
return func(x *operand, i int) {
|
||||
switch i {
|
||||
case 0:
|
||||
x.mode = value
|
||||
x.expr = x0.expr
|
||||
x.typ = x0.typ
|
||||
case 1:
|
||||
x.mode = value
|
||||
x.expr = x0.expr
|
||||
x.typ = Typ[UntypedBool]
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
}, 2
|
||||
}
|
||||
x0.mode = value
|
||||
}
|
||||
|
||||
// single value
|
||||
return func(x *operand, i int) {
|
||||
if i != 0 {
|
||||
unreachable()
|
||||
}
|
||||
*x = x0
|
||||
}, 1
|
||||
}
|
||||
|
||||
// zero or multiple values
|
||||
return get, n
|
||||
}
|
||||
|
||||
// arguments checks argument passing for the call with the given signature.
|
||||
// The arg function provides the operand for the i'th argument.
|
||||
func (check *checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg func(*operand, int)) {
|
||||
func (check *checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg func(*operand, int), n int) {
|
||||
passSlice := false
|
||||
if call.Ellipsis.IsValid() {
|
||||
// last argument is of the form x...
|
||||
@ -96,35 +179,10 @@ func (check *checker) arguments(x *operand, call *ast.CallExpr, sig *Signature,
|
||||
}
|
||||
|
||||
// evaluate arguments
|
||||
n := len(call.Args) // argument count
|
||||
if n == 1 {
|
||||
// single argument but possibly a multi-valued function call
|
||||
arg(x, 0)
|
||||
for i := 0; i < n; i++ {
|
||||
arg(x, i)
|
||||
if x.mode != invalid {
|
||||
if t, ok := x.typ.(*Tuple); ok {
|
||||
// argument is multi-valued function call
|
||||
n = t.Len()
|
||||
expr := call.Args[0]
|
||||
for i := 0; i < n; i++ {
|
||||
x.mode = value
|
||||
x.expr = expr
|
||||
x.typ = t.At(i).typ
|
||||
check.argument(sig, i, x, passSlice && i == n-1)
|
||||
}
|
||||
} else {
|
||||
// single value
|
||||
check.argument(sig, 0, x, passSlice)
|
||||
}
|
||||
} else {
|
||||
n = sig.params.Len() // avoid additional argument length errors below
|
||||
}
|
||||
} else {
|
||||
// zero or multiple arguments
|
||||
for i := range call.Args {
|
||||
arg(x, i)
|
||||
if x.mode != invalid {
|
||||
check.argument(sig, i, x, passSlice && i == n-1)
|
||||
}
|
||||
check.argument(sig, i, x, passSlice && i == n-1)
|
||||
}
|
||||
}
|
||||
|
||||
|
487
go/types/testdata/builtins.src
vendored
487
go/types/testdata/builtins.src
vendored
@ -8,16 +8,18 @@ package builtins
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func _append1() {
|
||||
func f0() {}
|
||||
|
||||
func append1() {
|
||||
var b byte
|
||||
var x int
|
||||
var s []byte
|
||||
_ = append /* ERROR "argument" */ ()
|
||||
_ = append("foo" /* ERROR "not a slice" */ )
|
||||
_ = append(nil /* ERROR "not a slice" */ , s)
|
||||
_ = append(x /* ERROR "not a slice" */ , s)
|
||||
_ = append() // ERROR not enough arguments
|
||||
_ = append("foo" /* ERROR not a slice */ )
|
||||
_ = append(nil /* ERROR not a slice */ , s)
|
||||
_ = append(x /* ERROR not a slice */ , s)
|
||||
_ = append(s)
|
||||
append /* ERROR "not used" */ (s)
|
||||
append /* ERROR not used */ (s)
|
||||
|
||||
_ = append(s, b)
|
||||
_ = append(s, x /* ERROR cannot pass argument x */ )
|
||||
@ -47,7 +49,7 @@ func _append1() {
|
||||
}
|
||||
|
||||
// from the spec
|
||||
func _append2() {
|
||||
func append2() {
|
||||
s0 := []int{0, 0}
|
||||
s1 := append(s0, 2) // append a single element s1 == []int{0, 0, 2}
|
||||
s2 := append(s1, 3, 5, 7) // append multiple elements s2 == []int{0, 0, 2, 3, 5, 7}
|
||||
@ -63,50 +65,83 @@ func _append2() {
|
||||
_ = s4
|
||||
}
|
||||
|
||||
func _cap() {
|
||||
func append3() {
|
||||
f1 := func() (s []int) { return }
|
||||
f2 := func() (s []int, x int) { return }
|
||||
f3 := func() (s []int, x, y int) { return }
|
||||
f5 := func() (s []interface{}, x int, y float32, z string, b bool) { return }
|
||||
ff := func() (int, float32) { return 0, 0 }
|
||||
_ = append(f0 /* ERROR used as value */ ())
|
||||
_ = append(f1())
|
||||
_ = append(f2())
|
||||
_ = append(f3())
|
||||
_ = append(f5())
|
||||
_ = append(ff /* ERROR not a slice */ ()) // TODO(gri) better error message
|
||||
}
|
||||
|
||||
func cap1() {
|
||||
var a [10]bool
|
||||
var p *[20]int
|
||||
var c chan string
|
||||
_ = cap /* ERROR "argument" */ ()
|
||||
_ = cap /* ERROR "argument" */ (1, 2)
|
||||
_ = cap(42 /* ERROR "invalid" */)
|
||||
_ = cap() // ERROR not enough arguments
|
||||
_ = cap(1, 2) // ERROR too many arguments
|
||||
_ = cap(42 /* ERROR invalid */)
|
||||
const _3 = cap(a)
|
||||
assert(_3 == 10)
|
||||
const _4 = cap(p)
|
||||
assert(_4 == 20)
|
||||
_ = cap(c)
|
||||
cap /* ERROR "not used" */ (c)
|
||||
cap /* ERROR not used */ (c)
|
||||
|
||||
// issue 4744
|
||||
type T struct{ a [10]int }
|
||||
const _ = cap(((*T)(nil)).a)
|
||||
}
|
||||
|
||||
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 cap2() {
|
||||
f1a := func() (a [10]int) { return }
|
||||
f1s := func() (s []int) { return }
|
||||
f2 := func() (s []int, x int) { return }
|
||||
_ = cap(f0 /* ERROR used as value */ ())
|
||||
_ = cap(f1a())
|
||||
_ = cap(f1s())
|
||||
_ = cap(f2()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func _complex() {
|
||||
func close1() {
|
||||
var c chan int
|
||||
var r <-chan int
|
||||
close() // ERROR not enough arguments
|
||||
close(1, 2) // ERROR too many arguments
|
||||
close(42 /* ERROR not a channel */)
|
||||
close(r /* ERROR receive-only channel */)
|
||||
close(c)
|
||||
_ = close /* ERROR used as value */ (c)
|
||||
}
|
||||
|
||||
func close2() {
|
||||
f1 := func() (ch chan int) { return }
|
||||
f2 := func() (ch chan int, x int) { return }
|
||||
close(f0 /* ERROR used as value */ ())
|
||||
close(f1())
|
||||
close(f2()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func complex1() {
|
||||
var i32 int32
|
||||
var f32 float32
|
||||
var f64 float64
|
||||
var c64 complex64
|
||||
_ = complex /* ERROR "argument" */ ()
|
||||
_ = complex /* ERROR "argument" */ (1)
|
||||
_ = complex(true /* ERROR "invalid argument" */ , 0)
|
||||
_ = complex(i32 /* ERROR "invalid argument" */ , 0)
|
||||
_ = complex("foo" /* ERROR "invalid argument" */ , 0)
|
||||
_ = complex(c64 /* ERROR "invalid argument" */ , 0)
|
||||
_ = complex(0, true /* ERROR "invalid argument" */ )
|
||||
_ = complex(0, i32 /* ERROR "invalid argument" */ )
|
||||
_ = complex(0, "foo" /* ERROR "invalid argument" */ )
|
||||
_ = complex(0, c64 /* ERROR "invalid argument" */ )
|
||||
_ = complex() // ERROR not enough arguments
|
||||
_ = complex(1) // ERROR not enough arguments
|
||||
_ = complex(true /* ERROR invalid argument */ , 0)
|
||||
_ = complex(i32 /* ERROR invalid argument */ , 0)
|
||||
_ = complex("foo" /* ERROR invalid argument */ , 0)
|
||||
_ = complex(c64 /* ERROR invalid argument */ , 0)
|
||||
_ = complex(0, true /* ERROR invalid argument */ )
|
||||
_ = complex(0, i32 /* ERROR invalid argument */ )
|
||||
_ = complex(0, "foo" /* ERROR invalid argument */ )
|
||||
_ = complex(0, c64 /* ERROR invalid argument */ )
|
||||
_ = complex(f32, f32)
|
||||
_ = complex(f32, 1)
|
||||
_ = complex(f32, 1.0)
|
||||
@ -115,17 +150,17 @@ func _complex() {
|
||||
_ = complex(f64, 1)
|
||||
_ = complex(f64, 1.0)
|
||||
_ = complex(f64, 'a')
|
||||
_ = complex(f32 /* ERROR "mismatched types" */, f64)
|
||||
_ = complex(f64 /* ERROR "mismatched types" */, f32)
|
||||
_ = complex(f32 /* ERROR mismatched types */, f64)
|
||||
_ = complex(f64 /* ERROR mismatched types */, f32)
|
||||
_ = complex(1, 1)
|
||||
_ = complex(1, 1.1)
|
||||
_ = complex(1, 'a')
|
||||
complex /* ERROR "not used" */ (1, 2)
|
||||
complex /* ERROR not used */ (1, 2)
|
||||
|
||||
var _ complex64 = complex(f32, f32)
|
||||
var _ complex64 = complex /* ERROR "cannot initialize" */ (f64, f64)
|
||||
var _ complex64 = complex /* ERROR cannot initialize */ (f64, f64)
|
||||
|
||||
var _ complex128 = complex /* ERROR "cannot initialize" */ (f32, f32)
|
||||
var _ complex128 = complex /* ERROR cannot initialize */ (f32, f32)
|
||||
var _ complex128 = complex(f64, f64)
|
||||
|
||||
// untyped constants
|
||||
@ -134,22 +169,32 @@ func _complex() {
|
||||
const _ complex64 = complex(1, 0)
|
||||
const _ complex128 = complex(1, 0)
|
||||
|
||||
const _ int = complex /* ERROR "int" */ (1.1, 0)
|
||||
const _ float32 = complex /* ERROR "float32" */ (1, 2)
|
||||
const _ int = complex /* ERROR int */ (1.1, 0)
|
||||
const _ float32 = complex /* ERROR float32 */ (1, 2)
|
||||
|
||||
// untyped values
|
||||
var s uint
|
||||
_ = complex(1 /* ERROR "integer" */ <<s, 0)
|
||||
const _ = complex /* ERROR "not constant" */ (1 /* ERROR "integer" */ <<s, 0)
|
||||
var _ int = complex /* ERROR "cannot initialize" */ (1 /* ERROR "integer" */ <<s, 0)
|
||||
_ = complex(1 /* ERROR integer */ <<s, 0)
|
||||
const _ = complex /* ERROR not constant */ (1 /* ERROR integer */ <<s, 0)
|
||||
var _ int = complex /* ERROR cannot initialize */ (1 /* ERROR integer */ <<s, 0)
|
||||
}
|
||||
|
||||
func _copy() {
|
||||
copy /* ERROR "not enough arguments" */ ()
|
||||
copy /* ERROR "not enough arguments" */ ("foo")
|
||||
copy([ /* ERROR "copy expects slice arguments" */ ...]int{}, []int{})
|
||||
copy([ /* ERROR "copy expects slice arguments" */ ]int{}, [...]int{})
|
||||
copy([ /* ERROR "different element types" */ ]int8{}, "foo")
|
||||
func complex2() {
|
||||
f1 := func() (x float32) { return }
|
||||
f2 := func() (x, y float32) { return }
|
||||
f3 := func() (x, y, z float32) { return }
|
||||
_ = complex(f0 /* ERROR used as value */ ())
|
||||
_ = complex(f1()) // ERROR not enough arguments
|
||||
_ = complex(f2())
|
||||
_ = complex(f3()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func copy1() {
|
||||
copy() // ERROR not enough arguments
|
||||
copy("foo") // ERROR not enough arguments
|
||||
copy([ /* ERROR copy expects slice arguments */ ...]int{}, []int{})
|
||||
copy([ /* ERROR copy expects slice arguments */ ]int{}, [...]int{})
|
||||
copy([ /* ERROR different element types */ ]int8{}, "foo")
|
||||
|
||||
// spec examples
|
||||
var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
|
||||
@ -161,26 +206,47 @@ func _copy() {
|
||||
_, _, _ = n1, n2, n3
|
||||
}
|
||||
|
||||
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 copy2() {
|
||||
f1 := func() (a []int) { return }
|
||||
f2 := func() (a, b []int) { return }
|
||||
f3 := func() (a, b, c []int) { return }
|
||||
copy(f0 /* ERROR used as value */ ())
|
||||
copy(f1()) // ERROR not enough arguments
|
||||
copy(f2())
|
||||
copy(f3()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func _imag() {
|
||||
func delete1() {
|
||||
var m map[string]int
|
||||
var s string
|
||||
delete() // ERROR not enough arguments
|
||||
delete(1) // ERROR not enough arguments
|
||||
delete(1, 2, 3) // ERROR too many arguments
|
||||
delete(m, 0 /* ERROR not assignable */)
|
||||
delete(m, s)
|
||||
_ = delete /* ERROR used as value */ (m, s)
|
||||
}
|
||||
|
||||
func delete2() {
|
||||
f1 := func() (m map[string]int) { return }
|
||||
f2 := func() (m map[string]int, k string) { return }
|
||||
f3 := func() (m map[string]int, k string, x float32) { return }
|
||||
delete(f0 /* ERROR used as value */ ())
|
||||
delete(f1()) // ERROR not enough arguments
|
||||
delete(f2())
|
||||
delete(f3()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func imag1() {
|
||||
var f32 float32
|
||||
var f64 float64
|
||||
var c64 complex64
|
||||
var c128 complex128
|
||||
_ = imag /* ERROR "argument" */ ()
|
||||
_ = imag /* ERROR "argument" */ (1, 2)
|
||||
_ = imag(10 /* ERROR "must be a complex number" */)
|
||||
_ = imag(2.7182818 /* ERROR "must be a complex number" */)
|
||||
_ = imag("foo" /* ERROR "must be a complex number" */)
|
||||
_ = imag() // ERROR not enough arguments
|
||||
_ = imag(1, 2) // ERROR too many arguments
|
||||
_ = imag(10 /* ERROR must be a complex number */)
|
||||
_ = imag(2.7182818 /* ERROR must be a complex number */)
|
||||
_ = imag("foo" /* ERROR must be a complex number */)
|
||||
const _5 = imag(1 + 2i)
|
||||
assert(_5 == 2)
|
||||
f32 = _5
|
||||
@ -189,20 +255,28 @@ func _imag() {
|
||||
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)
|
||||
f32 = imag /* ERROR cannot assign */ (c128)
|
||||
f64 = imag /* ERROR cannot assign */ (c64)
|
||||
imag /* ERROR not used */ (c64)
|
||||
_, _ = f32, f64
|
||||
}
|
||||
|
||||
func _len() {
|
||||
func imag2() {
|
||||
f1 := func() (x complex128) { return }
|
||||
f2 := func() (x, y complex128) { return }
|
||||
_ = imag(f0 /* ERROR used as value */ ())
|
||||
_ = imag(f1())
|
||||
_ = imag(f2()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func len1() {
|
||||
const c = "foobar"
|
||||
var a [10]bool
|
||||
var p *[20]int
|
||||
var m map[string]complex128
|
||||
_ = len /* ERROR "argument" */ ()
|
||||
_ = len /* ERROR "argument" */ (1, 2)
|
||||
_ = len(42 /* ERROR "invalid" */)
|
||||
_ = len() // ERROR not enough arguments
|
||||
_ = len(1, 2) // ERROR too many arguments
|
||||
_ = len(42 /* ERROR invalid */)
|
||||
const _3 = len(c)
|
||||
assert(_3 == 6)
|
||||
const _4 = len(a)
|
||||
@ -210,54 +284,62 @@ func _len() {
|
||||
const _5 = len(p)
|
||||
assert(_5 == 20)
|
||||
_ = len(m)
|
||||
len /* ERROR "not used" */ (c)
|
||||
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)])
|
||||
const n = len /* ERROR not constant */ (hash[recover()][len(t)])
|
||||
assert(n == 10) // ok because n has unknown value and no error is reported
|
||||
var ch <-chan int
|
||||
const nn = len /* ERROR "not constant" */ (hash[<-ch][len(t)])
|
||||
const nn = len /* ERROR not constant */ (hash[<-ch][len(t)])
|
||||
|
||||
// issue 4744
|
||||
type T struct{ a [10]int }
|
||||
const _ = len(((*T)(nil)).a)
|
||||
}
|
||||
|
||||
func _make() {
|
||||
func len2() {
|
||||
f1 := func() (x []int) { return }
|
||||
f2 := func() (x, y []int) { return }
|
||||
_ = len(f0 /* ERROR used as value */ ())
|
||||
_ = len(f1())
|
||||
_ = len(f2()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func make1() {
|
||||
var n int
|
||||
var m float32
|
||||
var s uint
|
||||
|
||||
_ = make /* ERROR "argument" */ ()
|
||||
_ = make(1 /* ERROR "not a type" */)
|
||||
_ = make(int /* ERROR "cannot make" */)
|
||||
_ = make() // ERROR not enough arguments
|
||||
_ = make(1 /* ERROR not a type */)
|
||||
_ = make(int /* ERROR cannot make */)
|
||||
|
||||
// slices
|
||||
_ = make/* ERROR "arguments" */ ([]int)
|
||||
_ = make/* ERROR "arguments" */ ([]int, 2, 3, 4)
|
||||
_ = make([]int, int /* ERROR "not an expression" */)
|
||||
_ = make([]int, 10, float32 /* ERROR "not an expression" */)
|
||||
_ = make([]int, "foo" /* ERROR "cannot convert" */)
|
||||
_ = make([]int, 10, 2.3 /* ERROR "overflows" */)
|
||||
_ = make/* ERROR arguments */ ([]int)
|
||||
_ = make/* ERROR arguments */ ([]int, 2, 3, 4)
|
||||
_ = make([]int, int /* ERROR not an expression */)
|
||||
_ = make([]int, 10, float32 /* ERROR not an expression */)
|
||||
_ = make([]int, "foo" /* ERROR cannot convert */)
|
||||
_ = make([]int, 10, 2.3 /* ERROR overflows */)
|
||||
_ = make([]int, 5, 10.0)
|
||||
_ = make([]int, 0i)
|
||||
_ = make([]int, 1.0)
|
||||
_ = make([]int, 1.0<<s)
|
||||
_ = make([]int, 1.1 /* ERROR "int" */ <<s)
|
||||
_ = make([]int, - /* ERROR "must not be negative" */ 1, 10)
|
||||
_ = make([]int, 0, - /* ERROR "must not be negative" */ 1)
|
||||
_ = make([]int, - /* ERROR "must not be negative" */ 1, - /* ERROR "must not be negative" */ 1)
|
||||
_ = make([]int, 1 /* ERROR "overflows" */ <<100, 1 /* ERROR "overflows" */ <<100)
|
||||
_ = make([]int, 10 /* ERROR "length and capacity swapped" */ , 9)
|
||||
_ = make([]int, 1 /* ERROR "overflows" */ <<100, 12345)
|
||||
_ = make([]int, m /* ERROR "must be integer" */ )
|
||||
_ = make([]int, 1.1 /* ERROR int */ <<s)
|
||||
_ = make([]int, - /* ERROR must not be negative */ 1, 10)
|
||||
_ = make([]int, 0, - /* ERROR must not be negative */ 1)
|
||||
_ = make([]int, - /* ERROR must not be negative */ 1, - /* ERROR must not be negative */ 1)
|
||||
_ = make([]int, 1 /* ERROR overflows */ <<100, 1 /* ERROR overflows */ <<100)
|
||||
_ = make([]int, 10 /* ERROR length and capacity swapped */ , 9)
|
||||
_ = make([]int, 1 /* ERROR overflows */ <<100, 12345)
|
||||
_ = make([]int, m /* ERROR must be integer */ )
|
||||
|
||||
// maps
|
||||
_ = make /* ERROR "arguments" */ (map[int]string, 10, 20)
|
||||
_ = make(map[int]float32, int /* ERROR "not an expression" */)
|
||||
_ = make(map[int]float32, "foo" /* ERROR "cannot convert" */)
|
||||
_ = make /* ERROR arguments */ (map[int]string, 10, 20)
|
||||
_ = make(map[int]float32, int /* ERROR not an expression */)
|
||||
_ = make(map[int]float32, "foo" /* ERROR cannot convert */)
|
||||
_ = make(map[int]float32, 10)
|
||||
_ = make(map[int]float32, n)
|
||||
_ = make(map[int]float32, int64(n))
|
||||
@ -265,65 +347,111 @@ func _make() {
|
||||
_ = make(map[string]bool, 10.0<<s)
|
||||
|
||||
// channels
|
||||
_ = make /* ERROR "arguments" */ (chan int, 10, 20)
|
||||
_ = make(chan int, int /* ERROR "not an expression" */)
|
||||
_ = make(chan<- int, "foo" /* ERROR "cannot convert" */)
|
||||
_ = make /* ERROR arguments */ (chan int, 10, 20)
|
||||
_ = make(chan int, int /* ERROR not an expression */)
|
||||
_ = make(chan<- int, "foo" /* ERROR cannot convert */)
|
||||
_ = make(<-chan float64, 10)
|
||||
_ = make(chan chan int, n)
|
||||
_ = make(chan string, int64(n))
|
||||
_ = make(chan bool, 10.0)
|
||||
_ = make(chan bool, 10.0<<s)
|
||||
|
||||
make /* ERROR "not used" */ ([]int, 10)
|
||||
make /* ERROR not used */ ([]int, 10)
|
||||
}
|
||||
|
||||
func _new() {
|
||||
_ = new /* ERROR "argument" */ ()
|
||||
_ = new /* ERROR "argument" */ (1, 2)
|
||||
_ = new("foo" /* ERROR "not a type" */)
|
||||
func make2() {
|
||||
f1 /* ERROR not used */ := func() (x []int) { return }
|
||||
_ = make(f0 /* ERROR not a type */ ())
|
||||
_ = make(f1 /* ERROR not a type */ ())
|
||||
}
|
||||
|
||||
func new1() {
|
||||
_ = new() // ERROR not enough arguments
|
||||
_ = new(1, 2) // ERROR too many arguments
|
||||
_ = new("foo" /* ERROR not a type */)
|
||||
p := new(float64)
|
||||
_ = new(struct{ x, y int })
|
||||
q := new(*float64)
|
||||
_ = *p == **q
|
||||
new /* ERROR "not used" */ (int)
|
||||
new /* ERROR not used */ (int)
|
||||
}
|
||||
|
||||
func _panic() {
|
||||
panic /* ERROR "arguments" */ ()
|
||||
panic /* ERROR "arguments" */ (1, 2)
|
||||
func new2() {
|
||||
f1 /* ERROR not used */ := func() (x []int) { return }
|
||||
_ = new(f0 /* ERROR not a type */ ())
|
||||
_ = new(f1 /* ERROR not a type */ ())
|
||||
}
|
||||
|
||||
func panic1() {
|
||||
panic() // ERROR not enough arguments
|
||||
panic(1, 2) // ERROR too many arguments
|
||||
panic(0)
|
||||
panic("foo")
|
||||
panic(false)
|
||||
panic(1<<1000) // TODO(gri) argument should be assignable to _
|
||||
_ = panic /* ERROR used as value */ (0)
|
||||
}
|
||||
|
||||
func _print() {
|
||||
func panic2() {
|
||||
f1 := func() (x int) { return }
|
||||
f2 := func() (x, y int) { return }
|
||||
panic(f0 /* ERROR used as value */ ())
|
||||
panic(f1())
|
||||
panic(f2()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func print1() {
|
||||
print()
|
||||
print(1)
|
||||
print(1, 2)
|
||||
print("foo")
|
||||
print(2.718281828)
|
||||
print(false)
|
||||
print(1<<1000, 1<<1000) // TODO(gri) arguments should be assignable to _
|
||||
_ = print /* ERROR used as value */ ()
|
||||
}
|
||||
|
||||
func _println() {
|
||||
func print2() {
|
||||
f1 := func() (x int) { return }
|
||||
f2 := func() (x, y int) { return }
|
||||
f3 := func() (x int, y float32, z string) { return }
|
||||
print(f0 /* ERROR used as value */ ())
|
||||
print(f1())
|
||||
print(f2())
|
||||
print(f3())
|
||||
}
|
||||
|
||||
func println1() {
|
||||
println()
|
||||
println(1)
|
||||
println(1, 2)
|
||||
println("foo")
|
||||
println(2.718281828)
|
||||
println(false)
|
||||
println(1<<1000, 1<<1000) // TODO(gri) arguments should be assignable to _
|
||||
_ = println /* ERROR used as value */ ()
|
||||
}
|
||||
|
||||
func _real() {
|
||||
func println2() {
|
||||
f1 := func() (x int) { return }
|
||||
f2 := func() (x, y int) { return }
|
||||
f3 := func() (x int, y float32, z string) { return }
|
||||
println(f0 /* ERROR used as value */ ())
|
||||
println(f1())
|
||||
println(f2())
|
||||
println(f3())
|
||||
}
|
||||
|
||||
func real1() {
|
||||
var f32 float32
|
||||
var f64 float64
|
||||
var c64 complex64
|
||||
var c128 complex128
|
||||
_ = real /* ERROR "argument" */ ()
|
||||
_ = real /* ERROR "argument" */ (1, 2)
|
||||
_ = real(10 /* ERROR "must be a complex number" */)
|
||||
_ = real(2.7182818 /* ERROR "must be a complex number" */)
|
||||
_ = real("foo" /* ERROR "must be a complex number" */)
|
||||
_ = real() // ERROR not enough arguments
|
||||
_ = real(1, 2) // ERROR too many arguments
|
||||
_ = real(10 /* ERROR must be a complex number */)
|
||||
_ = real(2.7182818 /* ERROR must be a complex number */)
|
||||
_ = real("foo" /* ERROR must be a complex number */)
|
||||
const _5 = real(1 + 2i)
|
||||
assert(_5 == 1)
|
||||
f32 = _5
|
||||
@ -332,18 +460,34 @@ func _real() {
|
||||
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)
|
||||
f32 = real /* ERROR cannot assign */ (c128)
|
||||
f64 = real /* ERROR cannot assign */ (c64)
|
||||
real /* ERROR not used */ (c64)
|
||||
_, _ = f32, f64
|
||||
}
|
||||
|
||||
func _recover() {
|
||||
func real2() {
|
||||
f1 := func() (x complex128) { return }
|
||||
f2 := func() (x, y complex128) { return }
|
||||
_ = real(f0 /* ERROR used as value */ ())
|
||||
_ = real(f1())
|
||||
_ = real(f2()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func recover1() {
|
||||
_ = recover()
|
||||
_ = recover /* ERROR "argument" */ (10)
|
||||
_ = recover(10) // ERROR too many arguments
|
||||
recover()
|
||||
}
|
||||
|
||||
func recover2() {
|
||||
f1 := func() (x int) { return }
|
||||
f2 := func() (x, y int) { return }
|
||||
_ = recover(f0 /* ERROR used as value */ ())
|
||||
_ = recover(f1()) // ERROR too many arguments
|
||||
_ = recover(f2()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
// assuming types.DefaultPtrSize == 8
|
||||
type S0 struct{ // offset
|
||||
a bool // 0
|
||||
@ -366,14 +510,14 @@ type S2 struct{ // offset
|
||||
|
||||
func (S2) m() {}
|
||||
|
||||
func _Alignof() {
|
||||
func Alignof1() {
|
||||
var x int
|
||||
_ = unsafe /* ERROR "argument" */ .Alignof()
|
||||
_ = unsafe /* ERROR "argument" */ .Alignof(1, 2)
|
||||
_ = unsafe.Alignof(int /* ERROR "not an expression" */)
|
||||
_ = unsafe.Alignof() // ERROR not enough arguments
|
||||
_ = unsafe.Alignof(1, 2) // ERROR too many arguments
|
||||
_ = unsafe.Alignof(int /* ERROR not an expression */)
|
||||
_ = unsafe.Alignof(42)
|
||||
_ = unsafe.Alignof(new(struct{}))
|
||||
unsafe /* ERROR "not used" */ .Alignof(x)
|
||||
unsafe /* ERROR not used */ .Alignof(x)
|
||||
|
||||
var y S0
|
||||
assert(unsafe.Alignof(y.a) == 1)
|
||||
@ -383,16 +527,24 @@ func _Alignof() {
|
||||
assert(unsafe.Alignof(y.e) == 8)
|
||||
}
|
||||
|
||||
func _Offsetof() {
|
||||
func Alignof2() {
|
||||
f1 := func() (x int32) { return }
|
||||
f2 := func() (x, y int32) { return }
|
||||
_ = unsafe.Alignof(f0 /* ERROR used as value */ ())
|
||||
assert(unsafe.Alignof(f1()) == 4)
|
||||
_ = unsafe.Alignof(f2()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
func Offsetof1() {
|
||||
var x struct{ f int }
|
||||
_ = unsafe /* ERROR "argument" */ .Offsetof()
|
||||
_ = unsafe /* ERROR "argument" */ .Offsetof(1, 2)
|
||||
_ = unsafe.Offsetof(int /* ERROR "not a selector expression" */)
|
||||
_ = unsafe.Offsetof(x /* ERROR "not a selector expression" */)
|
||||
_ = unsafe.Offsetof() // ERROR not enough arguments
|
||||
_ = unsafe.Offsetof(1, 2) // ERROR too many arguments
|
||||
_ = unsafe.Offsetof(int /* ERROR not a selector expression */)
|
||||
_ = unsafe.Offsetof(x /* ERROR not a selector expression */)
|
||||
_ = unsafe.Offsetof(x.f)
|
||||
_ = unsafe.Offsetof((x.f))
|
||||
_ = unsafe.Offsetof((((((((x))).f)))))
|
||||
unsafe /* ERROR "not used" */ .Offsetof(x.f)
|
||||
unsafe /* ERROR not used */ .Offsetof(x.f)
|
||||
|
||||
var y0 S0
|
||||
assert(unsafe.Offsetof(y0.a) == 0)
|
||||
@ -423,18 +575,26 @@ func _Offsetof() {
|
||||
|
||||
var y2 S2
|
||||
assert(unsafe.Offsetof(y2.S1) == 0)
|
||||
_ = unsafe.Offsetof(y2 /* ERROR "embedded via a pointer" */ .x)
|
||||
_ = unsafe.Offsetof(y2 /* ERROR "method value" */ .m)
|
||||
_ = unsafe.Offsetof(y2 /* ERROR embedded via a pointer */ .x)
|
||||
_ = unsafe.Offsetof(y2 /* ERROR method value */ .m)
|
||||
}
|
||||
|
||||
func _Sizeof() {
|
||||
func Offsetof2() {
|
||||
f1 := func() (x int32) { return }
|
||||
f2 := func() (x, y int32) { return }
|
||||
_ = unsafe.Offsetof(f0 /* ERROR not a selector expression */ ())
|
||||
_ = unsafe.Offsetof(f1 /* ERROR not a selector expression */ ())
|
||||
_ = unsafe.Offsetof(f2 /* ERROR not a selector expression */ ())
|
||||
}
|
||||
|
||||
func Sizeof1() {
|
||||
var x int
|
||||
_ = unsafe /* ERROR "argument" */ .Sizeof()
|
||||
_ = unsafe /* ERROR "argument" */ .Sizeof(1, 2)
|
||||
_ = unsafe.Sizeof(int /* ERROR "not an expression" */)
|
||||
_ = unsafe.Sizeof() // ERROR not enough arguments
|
||||
_ = unsafe.Sizeof(1, 2) // ERROR too many arguments
|
||||
_ = unsafe.Sizeof(int /* ERROR not an expression */)
|
||||
_ = unsafe.Sizeof(42)
|
||||
_ = unsafe.Sizeof(new(complex128))
|
||||
unsafe /* ERROR "not used" */ .Sizeof(x)
|
||||
unsafe /* ERROR not used */ .Sizeof(x)
|
||||
|
||||
// basic types have size guarantees
|
||||
assert(unsafe.Sizeof(byte(0)) == 1)
|
||||
@ -474,21 +634,56 @@ func _Sizeof() {
|
||||
assert(unsafe.Sizeof(T{}) == 12)
|
||||
}
|
||||
|
||||
// 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)
|
||||
func Sizeof2() {
|
||||
f1 := func() (x int64) { return }
|
||||
f2 := func() (x, y int64) { return }
|
||||
_ = unsafe.Sizeof(f0 /* ERROR used as value */ ())
|
||||
assert(unsafe.Sizeof(f1()) == 8)
|
||||
_ = unsafe.Sizeof(f2()) // ERROR too many arguments
|
||||
}
|
||||
|
||||
// self-testing only
|
||||
func _trace() {
|
||||
func assert1() {
|
||||
var x int
|
||||
assert() /* ERROR not enough arguments */
|
||||
assert(1, 2) /* ERROR too many arguments */
|
||||
assert("foo" /* ERROR boolean constant */ )
|
||||
assert(x /* ERROR boolean constant */)
|
||||
assert(true)
|
||||
assert /* ERROR failed */ (false)
|
||||
_ = assert(true)
|
||||
}
|
||||
|
||||
func assert2() {
|
||||
f1 := func() (x bool) { return }
|
||||
f2 := func() (x bool) { return }
|
||||
assert(f0 /* ERROR used as value */ ())
|
||||
assert(f1 /* ERROR boolean constant */ ())
|
||||
assert(f2 /* ERROR boolean constant */ ())
|
||||
}
|
||||
|
||||
// self-testing only
|
||||
func trace1() {
|
||||
// Uncomment the code below to test trace - will produce console output
|
||||
// _ = trace /* ERROR "no value" */ ()
|
||||
// _ = trace /* ERROR no value */ ()
|
||||
// _ = trace(1)
|
||||
// _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
|
||||
}
|
||||
|
||||
func trace2() {
|
||||
f1 := func() (x int) { return }
|
||||
f2 := func() (x int, y string) { return }
|
||||
f3 := func() (x int, y string, z []int) { return }
|
||||
_ = f1
|
||||
_ = f2
|
||||
_ = f3
|
||||
// Uncomment the code below to test trace - will produce console output
|
||||
// trace(f0())
|
||||
// trace(f1())
|
||||
// trace(f2())
|
||||
// trace(f3())
|
||||
// trace(f0(), 1)
|
||||
// trace(f1(), 1, 2)
|
||||
// trace(f2(), 1, 2, 3)
|
||||
// trace(f3(), 1, 2, 3, 4)
|
||||
}
|
||||
|
2
go/types/testdata/expr3.src
vendored
2
go/types/testdata/expr3.src
vendored
@ -383,7 +383,7 @@ func _calls() {
|
||||
f2(3.14) /* ERROR "too few arguments" */
|
||||
f2(3.14, "foo")
|
||||
f2(x /* ERROR "cannot pass" */ , "foo")
|
||||
f2(g0 /* ERROR "used as value" */ ())
|
||||
f2(g0 /* ERROR "used as value" */ ()) /* ERROR "too few arguments" */
|
||||
f2(g1 /* ERROR "cannot pass" */ ()) /* ERROR "too few arguments" */
|
||||
f2(g2())
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user