mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.typeparams] go/types: import expr changes from dev.go2go
This change imports assignments.go, builtins.go, call.go, conversions.go, and expr.go from the dev.go2go branch. Changes from dev.go2go: - Update error positions and codes. - Fix some failing tests due to error message changes. - Fix a bug in exprInternal where normal IndexExpr checking wasn't proceeding in the case of a non-generic indexed func. - Fix the type of the second operand in commaerr expressions to be universeError. We should add tests in a later CL. This code was mostly reviewed, but call.go and expr.go were marked incomplete. Additionally, these two files had notably diverged from types2, requiring further understanding. The dev.go2go branch significantly simplified the type checking of arguments, resulting in the removal of the _InvalidDotDotDot operand error code. Change-Id: Iba2cef95e17bfaa6da6d4eb94c2e2ce1c691ac44 Reviewed-on: https://go-review.googlesource.com/c/go/+/282193 Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org> Trust: Robert Griesemer <gri@golang.org> Trust: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
822aeacd9e
commit
81cd99858d
10 changed files with 837 additions and 427 deletions
|
|
@ -26,7 +26,9 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
|
||||||
case constant_, variable, mapindex, value, commaok, commaerr:
|
case constant_, variable, mapindex, value, commaok, commaerr:
|
||||||
// ok
|
// ok
|
||||||
default:
|
default:
|
||||||
unreachable()
|
// we may get here because of other problems (issue #39634, crash 12)
|
||||||
|
check.errorf(x, 0, "cannot assign %s to %s in %s", x, T, context)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if isUntyped(x.typ) {
|
if isUntyped(x.typ) {
|
||||||
|
|
@ -66,6 +68,11 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
|
||||||
}
|
}
|
||||||
// x.typ is typed
|
// x.typ is typed
|
||||||
|
|
||||||
|
// A generic (non-instantiated) function value cannot be assigned to a variable.
|
||||||
|
if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
|
||||||
|
check.errorf(x, 0, "cannot use generic function %s without instantiation in %s", x, context)
|
||||||
|
}
|
||||||
|
|
||||||
// spec: "If a left-hand side is the blank identifier, any typed or
|
// spec: "If a left-hand side is the blank identifier, any typed or
|
||||||
// non-constant value except for the predeclared identifier nil may
|
// non-constant value except for the predeclared identifier nil may
|
||||||
// be assigned to it."
|
// be assigned to it."
|
||||||
|
|
@ -148,6 +155,7 @@ func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
|
||||||
|
|
||||||
func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
|
func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
|
||||||
if x.mode == invalid || x.typ == Typ[Invalid] {
|
if x.mode == invalid || x.typ == Typ[Invalid] {
|
||||||
|
check.useLHS(lhs)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,25 +229,27 @@ func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
|
||||||
|
|
||||||
// If returnPos is valid, initVars is called to type-check the assignment of
|
// If returnPos is valid, initVars is called to type-check the assignment of
|
||||||
// return expressions, and returnPos is the position of the return statement.
|
// return expressions, and returnPos is the position of the return statement.
|
||||||
func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
|
func (check *Checker) initVars(lhs []*Var, origRHS []ast.Expr, returnPos token.Pos) {
|
||||||
l := len(lhs)
|
rhs, commaOk := check.exprList(origRHS, len(lhs) == 2 && !returnPos.IsValid())
|
||||||
get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
|
|
||||||
if get == nil || l != r {
|
if len(lhs) != len(rhs) {
|
||||||
// invalidate lhs and use rhs
|
// invalidate lhs
|
||||||
for _, obj := range lhs {
|
for _, obj := range lhs {
|
||||||
if obj.typ == nil {
|
if obj.typ == nil {
|
||||||
obj.typ = Typ[Invalid]
|
obj.typ = Typ[Invalid]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if get == nil {
|
// don't report an error if we already reported one
|
||||||
return // error reported by unpack
|
for _, x := range rhs {
|
||||||
}
|
if x.mode == invalid {
|
||||||
check.useGetter(get, r)
|
|
||||||
if returnPos.IsValid() {
|
|
||||||
check.errorf(atPos(returnPos), _WrongResultCount, "wrong number of return values (want %d, got %d)", l, r)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
check.errorf(rhs[0], _WrongAssignCount, "cannot initialize %d variables with %d values", l, r)
|
}
|
||||||
|
if returnPos.IsValid() {
|
||||||
|
check.errorf(atPos(returnPos), _WrongResultCount, "wrong number of return values (want %d, got %d)", len(lhs), len(rhs))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
check.errorf(rhs[0], _WrongAssignCount, "cannot initialize %d variables with %d values", len(lhs), len(rhs))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,50 +258,46 @@ func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos)
|
||||||
context = "return statement"
|
context = "return statement"
|
||||||
}
|
}
|
||||||
|
|
||||||
var x operand
|
|
||||||
if commaOk {
|
if commaOk {
|
||||||
var a [2]Type
|
var a [2]Type
|
||||||
for i := range a {
|
for i := range a {
|
||||||
get(&x, i)
|
a[i] = check.initVar(lhs[i], rhs[i], context)
|
||||||
a[i] = check.initVar(lhs[i], &x, context)
|
|
||||||
}
|
}
|
||||||
check.recordCommaOkTypes(rhs[0], a)
|
check.recordCommaOkTypes(origRHS[0], a)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, lhs := range lhs {
|
for i, lhs := range lhs {
|
||||||
get(&x, i)
|
check.initVar(lhs, rhs[i], context)
|
||||||
check.initVar(lhs, &x, context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
|
func (check *Checker) assignVars(lhs, origRHS []ast.Expr) {
|
||||||
l := len(lhs)
|
rhs, commaOk := check.exprList(origRHS, len(lhs) == 2)
|
||||||
get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2)
|
|
||||||
if get == nil {
|
if len(lhs) != len(rhs) {
|
||||||
check.useLHS(lhs...)
|
check.useLHS(lhs...)
|
||||||
return // error reported by unpack
|
// don't report an error if we already reported one
|
||||||
|
for _, x := range rhs {
|
||||||
|
if x.mode == invalid {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if l != r {
|
}
|
||||||
check.useGetter(get, r)
|
check.errorf(rhs[0], _WrongAssignCount, "cannot assign %d values to %d variables", len(rhs), len(lhs))
|
||||||
check.errorf(rhs[0], _WrongAssignCount, "cannot assign %d values to %d variables", r, l)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var x operand
|
|
||||||
if commaOk {
|
if commaOk {
|
||||||
var a [2]Type
|
var a [2]Type
|
||||||
for i := range a {
|
for i := range a {
|
||||||
get(&x, i)
|
a[i] = check.assignVar(lhs[i], rhs[i])
|
||||||
a[i] = check.assignVar(lhs[i], &x)
|
|
||||||
}
|
}
|
||||||
check.recordCommaOkTypes(rhs[0], a)
|
check.recordCommaOkTypes(origRHS[0], a)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, lhs := range lhs {
|
for i, lhs := range lhs {
|
||||||
get(&x, i)
|
check.assignVar(lhs, rhs[i])
|
||||||
check.assignVar(lhs, &x)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
// For len(x) and cap(x) we need to know if x contains any function calls or
|
// 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
|
// receive operations. Save/restore current setting and set hasCallOrRecv to
|
||||||
// false for the evaluation of x so that we can check it afterwards.
|
// 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
|
// Note: We must do this _before_ calling exprList because exprList evaluates
|
||||||
// first argument before we even call arg(x, 0)!
|
// all arguments.
|
||||||
if id == _Len || id == _Cap {
|
if id == _Len || id == _Cap {
|
||||||
defer func(b bool) {
|
defer func(b bool) {
|
||||||
check.hasCallOrRecv = b
|
check.hasCallOrRecv = b
|
||||||
|
|
@ -41,15 +41,14 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine actual arguments
|
// 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)
|
nargs := len(call.Args)
|
||||||
switch id {
|
switch id {
|
||||||
default:
|
default:
|
||||||
// make argument getter
|
// make argument getter
|
||||||
arg, nargs, _ = unpack(func(x *operand, i int) { check.multiExpr(x, call.Args[i]) }, nargs, false)
|
xlist, _ := check.exprList(call.Args, false)
|
||||||
if arg == nil {
|
arg = func(x *operand, i int) { *x = *xlist[i]; x.typ = expand(x.typ) }
|
||||||
return
|
nargs = len(xlist)
|
||||||
}
|
|
||||||
// evaluate first argument, if present
|
// evaluate first argument, if present
|
||||||
if nargs > 0 {
|
if nargs > 0 {
|
||||||
arg(x, 0)
|
arg(x, 0)
|
||||||
|
|
@ -84,7 +83,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
// of S and the respective parameter passing rules apply."
|
// of S and the respective parameter passing rules apply."
|
||||||
S := x.typ
|
S := x.typ
|
||||||
var T Type
|
var T Type
|
||||||
if s, _ := S.Underlying().(*Slice); s != nil {
|
if s := asSlice(S); s != nil {
|
||||||
T = s.elem
|
T = s.elem
|
||||||
} else {
|
} else {
|
||||||
check.invalidArg(x, _InvalidAppend, "%s is not a slice", x)
|
check.invalidArg(x, _InvalidAppend, "%s is not a slice", x)
|
||||||
|
|
@ -121,14 +120,17 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
// check general case by creating custom signature
|
// check general case by creating custom signature
|
||||||
sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature
|
sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature
|
||||||
sig.variadic = true
|
sig.variadic = true
|
||||||
check.arguments(x, call, sig, func(x *operand, i int) {
|
var xlist []*operand
|
||||||
// only evaluate arguments that have not been evaluated before
|
// convert []operand to []*operand
|
||||||
if i < len(alist) {
|
for i := range alist {
|
||||||
*x = alist[i]
|
xlist = append(xlist, &alist[i])
|
||||||
return
|
|
||||||
}
|
}
|
||||||
arg(x, i)
|
for i := len(alist); i < nargs; i++ {
|
||||||
}, nargs)
|
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
|
// ok to continue even if check.arguments reported errors
|
||||||
|
|
||||||
x.mode = value
|
x.mode = value
|
||||||
|
|
@ -143,7 +145,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
mode := invalid
|
mode := invalid
|
||||||
var typ Type
|
var typ Type
|
||||||
var val constant.Value
|
var val constant.Value
|
||||||
switch typ = implicitArrayDeref(x.typ.Underlying()); t := typ.(type) {
|
switch typ = implicitArrayDeref(optype(x.typ)); t := typ.(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(t) && id == _Len {
|
if isString(t) && id == _Len {
|
||||||
if x.mode == constant_ {
|
if x.mode == constant_ {
|
||||||
|
|
@ -176,6 +178,25 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
if id == _Len {
|
if id == _Len {
|
||||||
mode = value
|
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] {
|
if mode == invalid && typ != Typ[Invalid] {
|
||||||
|
|
@ -196,7 +217,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
|
|
||||||
case _Close:
|
case _Close:
|
||||||
// close(c)
|
// close(c)
|
||||||
c, _ := x.typ.Underlying().(*Chan)
|
c := asChan(x.typ)
|
||||||
if c == nil {
|
if c == nil {
|
||||||
check.invalidArg(x, _InvalidClose, "%s is not a channel", x)
|
check.invalidArg(x, _InvalidClose, "%s is not a channel", x)
|
||||||
return
|
return
|
||||||
|
|
@ -271,7 +292,21 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
}
|
}
|
||||||
|
|
||||||
// the argument types must be of floating-point type
|
// 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)
|
check.invalidArg(x, _InvalidComplex, "arguments have type %s, expected floating-point", x.typ)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -283,20 +318,6 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
x.mode = value
|
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_ {
|
if check.Types != nil && x.mode != constant_ {
|
||||||
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ, x.typ))
|
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ, x.typ))
|
||||||
}
|
}
|
||||||
|
|
@ -306,7 +327,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
case _Copy:
|
case _Copy:
|
||||||
// copy(x, y []T) int
|
// copy(x, y []T) int
|
||||||
var dst Type
|
var dst Type
|
||||||
if t, _ := x.typ.Underlying().(*Slice); t != nil {
|
if t := asSlice(x.typ); t != nil {
|
||||||
dst = t.elem
|
dst = t.elem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,7 +337,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var src Type
|
var src Type
|
||||||
switch t := y.typ.Underlying().(type) {
|
switch t := optype(y.typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(y.typ) {
|
if isString(y.typ) {
|
||||||
src = universeByte
|
src = universeByte
|
||||||
|
|
@ -343,7 +364,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
|
|
||||||
case _Delete:
|
case _Delete:
|
||||||
// delete(m, k)
|
// delete(m, k)
|
||||||
m, _ := x.typ.Underlying().(*Map)
|
m := asMap(x.typ)
|
||||||
if m == nil {
|
if m == nil {
|
||||||
check.invalidArg(x, _InvalidDelete, "%s is not a map", x)
|
check.invalidArg(x, _InvalidDelete, "%s is not a map", x)
|
||||||
return
|
return
|
||||||
|
|
@ -389,7 +410,21 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
}
|
}
|
||||||
|
|
||||||
// the argument must be of complex type
|
// 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
|
code := _InvalidImag
|
||||||
if id == _Real {
|
if id == _Real {
|
||||||
code = _InvalidReal
|
code = _InvalidReal
|
||||||
|
|
@ -409,20 +444,6 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
x.mode = value
|
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_ {
|
if check.Types != nil && x.mode != constant_ {
|
||||||
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ))
|
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ))
|
||||||
}
|
}
|
||||||
|
|
@ -434,25 +455,47 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
// make(T, n, m)
|
// make(T, n, m)
|
||||||
// (no argument evaluated yet)
|
// (no argument evaluated yet)
|
||||||
arg0 := call.Args[0]
|
arg0 := call.Args[0]
|
||||||
T := check.typ(arg0)
|
T := check.varType(arg0)
|
||||||
if T == Typ[Invalid] {
|
if T == Typ[Invalid] {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var min int // minimum number of arguments
|
min, max := -1, 10
|
||||||
switch T.Underlying().(type) {
|
var valid func(t Type) bool
|
||||||
|
valid = func(t Type) bool {
|
||||||
|
var m int
|
||||||
|
switch t := optype(t).(type) {
|
||||||
case *Slice:
|
case *Slice:
|
||||||
min = 2
|
m = 2
|
||||||
case *Map, *Chan:
|
case *Map, *Chan:
|
||||||
min = 1
|
m = 1
|
||||||
|
case *Sum:
|
||||||
|
return t.is(valid)
|
||||||
default:
|
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)
|
check.invalidArg(arg0, _InvalidMake, "cannot make %s; type must be slice, map, or channel", arg0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if nargs < min || min+1 < nargs {
|
if nargs < min || max < nargs {
|
||||||
check.errorf(call, _WrongArgCount, "%v expects %d or %d arguments; found %d", call, min, min+1, 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
types := []Type{T}
|
types := []Type{T}
|
||||||
var sizes []int64 // constant integer arguments, if any
|
var sizes []int64 // constant integer arguments, if any
|
||||||
for _, arg := range call.Args[1:] {
|
for _, arg := range call.Args[1:] {
|
||||||
|
|
@ -475,7 +518,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
case _New:
|
case _New:
|
||||||
// new(T)
|
// new(T)
|
||||||
// (no argument evaluated yet)
|
// (no argument evaluated yet)
|
||||||
T := check.typ(call.Args[0])
|
T := check.varType(call.Args[0])
|
||||||
if T == Typ[Invalid] {
|
if T == Typ[Invalid] {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -545,6 +588,10 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
|
|
||||||
case _Alignof:
|
case _Alignof:
|
||||||
// unsafe.Alignof(x T) uintptr
|
// unsafe.Alignof(x T) uintptr
|
||||||
|
if asTypeParam(x.typ) != nil {
|
||||||
|
check.invalidOp(call, 0, "unsafe.Alignof undefined for %s", x)
|
||||||
|
return
|
||||||
|
}
|
||||||
check.assignment(x, nil, "argument to unsafe.Alignof")
|
check.assignment(x, nil, "argument to unsafe.Alignof")
|
||||||
if x.mode == invalid {
|
if x.mode == invalid {
|
||||||
return
|
return
|
||||||
|
|
@ -602,6 +649,10 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
|
|
||||||
case _Sizeof:
|
case _Sizeof:
|
||||||
// unsafe.Sizeof(x T) uintptr
|
// unsafe.Sizeof(x T) uintptr
|
||||||
|
if asTypeParam(x.typ) != nil {
|
||||||
|
check.invalidOp(call, 0, "unsafe.Sizeof undefined for %s", x)
|
||||||
|
return
|
||||||
|
}
|
||||||
check.assignment(x, nil, "argument to unsafe.Sizeof")
|
check.assignment(x, nil, "argument to unsafe.Sizeof")
|
||||||
if x.mode == invalid {
|
if x.mode == invalid {
|
||||||
return
|
return
|
||||||
|
|
@ -657,6 +708,40 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
return true
|
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.
|
// makeSig makes a signature for the given argument and result types.
|
||||||
// Default types are used for untyped arguments, and res may be nil.
|
// Default types are used for untyped arguments, and res may be nil.
|
||||||
func makeSig(res Type, args ...Type) *Signature {
|
func makeSig(res Type, args ...Type) *Signature {
|
||||||
|
|
@ -678,7 +763,7 @@ func makeSig(res Type, args ...Type) *Signature {
|
||||||
//
|
//
|
||||||
func implicitArrayDeref(typ Type) Type {
|
func implicitArrayDeref(typ Type) Type {
|
||||||
if p, ok := typ.(*Pointer); ok {
|
if p, ok := typ.(*Pointer); ok {
|
||||||
if a, ok := p.base.Underlying().(*Array); ok {
|
if a := asArray(p.base); a != nil {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
// REVIEW INCOMPLETE
|
||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
@ -13,45 +14,73 @@ import (
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
// TODO(rFindley) this has diverged a bit from types2. Bring it up to date.
|
||||||
check.exprOrType(x, e.Fun)
|
// If call == nil, the "call" was an index expression, and orig is of type *ast.IndexExpr.
|
||||||
|
func (check *Checker) call(x *operand, call *ast.CallExpr, orig ast.Expr) exprKind {
|
||||||
|
assert(orig != nil)
|
||||||
|
if call != nil {
|
||||||
|
assert(call == orig)
|
||||||
|
check.exprOrType(x, call.Fun)
|
||||||
|
} else {
|
||||||
|
// We must have an index expression.
|
||||||
|
// x has already been set up (evaluation of orig.X).
|
||||||
|
// Set up fake call so we can use its fields below.
|
||||||
|
expr := orig.(*ast.IndexExpr)
|
||||||
|
call = &ast.CallExpr{Fun: expr.X, Lparen: expr.Lbrack, Args: []ast.Expr{expr.Index}, Rparen: expr.Rbrack, Brackets: true}
|
||||||
|
}
|
||||||
|
|
||||||
switch x.mode {
|
switch x.mode {
|
||||||
case invalid:
|
case invalid:
|
||||||
check.use(e.Args...)
|
check.use(call.Args...)
|
||||||
x.mode = invalid
|
x.expr = orig
|
||||||
x.expr = e
|
|
||||||
return statement
|
return statement
|
||||||
|
|
||||||
case typexpr:
|
case typexpr:
|
||||||
// conversion
|
// conversion or type instantiation
|
||||||
T := x.typ
|
T := x.typ
|
||||||
x.mode = invalid
|
x.mode = invalid
|
||||||
switch n := len(e.Args); n {
|
if isGeneric(T) {
|
||||||
|
// type instantiation
|
||||||
|
x.typ = check.typ(call)
|
||||||
|
if x.typ != Typ[Invalid] {
|
||||||
|
x.mode = typexpr
|
||||||
|
}
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
// conversion
|
||||||
|
switch n := len(call.Args); n {
|
||||||
case 0:
|
case 0:
|
||||||
check.errorf(inNode(e, e.Rparen), _WrongArgCount, "missing argument in conversion to %s", T)
|
check.errorf(inNode(call, call.Rparen), _WrongArgCount, "missing argument in conversion to %s", T)
|
||||||
case 1:
|
case 1:
|
||||||
check.expr(x, e.Args[0])
|
check.expr(x, call.Args[0])
|
||||||
if x.mode != invalid {
|
if x.mode != invalid {
|
||||||
if e.Ellipsis.IsValid() {
|
if call.Ellipsis.IsValid() {
|
||||||
check.errorf(e.Args[0], _BadDotDotDotSyntax, "invalid use of ... in conversion to %s", T)
|
check.errorf(call.Args[0], _BadDotDotDotSyntax, "invalid use of ... in conversion to %s", T)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if t := asInterface(T); t != nil {
|
||||||
|
check.completeInterface(token.NoPos, t)
|
||||||
|
if t.IsConstraint() {
|
||||||
|
check.errorf(call, 0, "cannot use interface %s in conversion (contains type list or is comparable)", T)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
check.conversion(x, T)
|
check.conversion(x, T)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
check.use(e.Args...)
|
check.use(call.Args...)
|
||||||
check.errorf(e.Args[n-1], _WrongArgCount, "too many arguments in conversion to %s", T)
|
check.errorf(call.Args[n-1], _WrongArgCount, "too many arguments in conversion to %s", T)
|
||||||
}
|
}
|
||||||
x.expr = e
|
x.expr = orig
|
||||||
return conversion
|
return conversion
|
||||||
|
|
||||||
case builtin:
|
case builtin:
|
||||||
id := x.id
|
id := x.id
|
||||||
if !check.builtin(x, e, id) {
|
if !check.builtin(x, call, id) {
|
||||||
x.mode = invalid
|
x.mode = invalid
|
||||||
}
|
}
|
||||||
x.expr = e
|
x.expr = orig
|
||||||
// a non-constant result implies a function call
|
// a non-constant result implies a function call
|
||||||
if x.mode != invalid && x.mode != constant_ {
|
if x.mode != invalid && x.mode != constant_ {
|
||||||
check.hasCallOrRecv = true
|
check.hasCallOrRecv = true
|
||||||
|
|
@ -62,20 +91,111 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
||||||
// function/method call
|
// function/method call
|
||||||
cgocall := x.mode == cgofunc
|
cgocall := x.mode == cgofunc
|
||||||
|
|
||||||
sig, _ := x.typ.Underlying().(*Signature)
|
sig := asSignature(x.typ)
|
||||||
if sig == nil {
|
if sig == nil {
|
||||||
check.invalidOp(x, _InvalidCall, "cannot call non-function %s", x)
|
check.invalidOp(x, _InvalidCall, "cannot call non-function %s", x)
|
||||||
x.mode = invalid
|
x.mode = invalid
|
||||||
x.expr = e
|
x.expr = orig
|
||||||
return statement
|
return statement
|
||||||
}
|
}
|
||||||
|
|
||||||
arg, n, _ := unpack(func(x *operand, i int) { check.multiExpr(x, e.Args[i]) }, len(e.Args), false)
|
// evaluate arguments
|
||||||
if arg != nil {
|
args, ok := check.exprOrTypeList(call.Args)
|
||||||
check.arguments(x, e, sig, arg, n)
|
if ok && call.Brackets && len(args) > 0 && args[0].mode != typexpr {
|
||||||
} else {
|
check.errorf(args[0], _NotAType, "%s is not a type", args[0])
|
||||||
x.mode = invalid
|
ok = false
|
||||||
}
|
}
|
||||||
|
if !ok {
|
||||||
|
x.mode = invalid
|
||||||
|
x.expr = orig
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
// instantiate function if needed
|
||||||
|
if n := len(args); n > 0 && len(sig.tparams) > 0 && args[0].mode == typexpr {
|
||||||
|
// If the first argument is a type, assume we have explicit type arguments.
|
||||||
|
|
||||||
|
// check number of type arguments
|
||||||
|
// TODO(rFindley)
|
||||||
|
// if !check.conf.InferFromConstraints && n != len(sig.tparams) || n > len(sig.tparams) {
|
||||||
|
if n != len(sig.tparams) || n > len(sig.tparams) {
|
||||||
|
check.errorf(args[n-1], 0, "got %d type arguments but want %d", n, len(sig.tparams))
|
||||||
|
x.mode = invalid
|
||||||
|
x.expr = orig
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect types
|
||||||
|
targs := make([]Type, n)
|
||||||
|
// TODO(rFindley) positioner?
|
||||||
|
poslist := make([]token.Pos, n)
|
||||||
|
for i, a := range args {
|
||||||
|
if a.mode != typexpr {
|
||||||
|
// error was reported earlier
|
||||||
|
x.mode = invalid
|
||||||
|
x.expr = orig
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
targs[i] = a.typ
|
||||||
|
poslist[i] = a.Pos()
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we don't have enough type arguments, use constraint type inference
|
||||||
|
var inferred bool
|
||||||
|
if n < len(sig.tparams) {
|
||||||
|
var failed int
|
||||||
|
targs, failed = check.inferB(sig.tparams, targs)
|
||||||
|
if targs == nil {
|
||||||
|
// error was already reported
|
||||||
|
x.mode = invalid
|
||||||
|
x.expr = orig
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
if failed >= 0 {
|
||||||
|
// at least one type argument couldn't be inferred
|
||||||
|
assert(targs[failed] == nil)
|
||||||
|
tpar := sig.tparams[failed]
|
||||||
|
ppos := check.fset.Position(tpar.pos).String()
|
||||||
|
check.errorf(inNode(call, call.Rparen), 0, "cannot infer %s (%s) (%s)", tpar.name, ppos, targs)
|
||||||
|
x.mode = invalid
|
||||||
|
x.expr = orig
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
// all type arguments were inferred sucessfully
|
||||||
|
if debug {
|
||||||
|
for _, targ := range targs {
|
||||||
|
assert(targ != nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n = len(targs)
|
||||||
|
inferred = true
|
||||||
|
}
|
||||||
|
assert(n == len(sig.tparams))
|
||||||
|
|
||||||
|
// instantiate function signature
|
||||||
|
for i, typ := range targs {
|
||||||
|
// some positions may be missing if types are inferred
|
||||||
|
var pos token.Pos
|
||||||
|
if i < len(poslist) {
|
||||||
|
pos = poslist[i]
|
||||||
|
}
|
||||||
|
check.ordinaryType(atPos(pos), typ)
|
||||||
|
}
|
||||||
|
res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature)
|
||||||
|
assert(res.tparams == nil) // signature is not generic anymore
|
||||||
|
if inferred {
|
||||||
|
check.recordInferred(orig, targs, res)
|
||||||
|
}
|
||||||
|
x.typ = res
|
||||||
|
x.mode = value
|
||||||
|
x.expr = orig
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach here, orig must have been a regular call, not an index expression.
|
||||||
|
assert(!call.Brackets)
|
||||||
|
|
||||||
|
sig = check.arguments(call, sig, args)
|
||||||
|
|
||||||
// determine result
|
// determine result
|
||||||
switch sig.results.Len() {
|
switch sig.results.Len() {
|
||||||
|
|
@ -92,180 +212,253 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
||||||
x.mode = value
|
x.mode = value
|
||||||
x.typ = sig.results
|
x.typ = sig.results
|
||||||
}
|
}
|
||||||
|
x.expr = call
|
||||||
x.expr = e
|
|
||||||
check.hasCallOrRecv = true
|
check.hasCallOrRecv = true
|
||||||
|
|
||||||
|
// if type inference failed, a parametrized result must be invalidated
|
||||||
|
// (operands cannot have a parametrized type)
|
||||||
|
if x.mode == value && len(sig.tparams) > 0 && isParameterized(sig.tparams, x.typ) {
|
||||||
|
x.mode = invalid
|
||||||
|
}
|
||||||
|
|
||||||
return statement
|
return statement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// useGetter is like use, but takes a getter instead of a list of expressions.
|
// exprOrTypeList returns a list of operands and reports an error if the
|
||||||
// It should be called instead of use if a getter is present to avoid repeated
|
// list contains a mix of values and types (ignoring invalid operands).
|
||||||
// evaluation of the first argument (since the getter was likely obtained via
|
func (check *Checker) exprOrTypeList(elist []ast.Expr) (xlist []*operand, ok bool) {
|
||||||
// unpack, which may have evaluated the first argument already).
|
ok = true
|
||||||
func (check *Checker) useGetter(get getter, n int) {
|
|
||||||
|
switch len(elist) {
|
||||||
|
case 0:
|
||||||
|
// nothing to do
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// single (possibly comma-ok) value or type, or function returning multiple values
|
||||||
|
e := elist[0]
|
||||||
var x operand
|
var x operand
|
||||||
for i := 0; i < n; i++ {
|
check.multiExprOrType(&x, e)
|
||||||
get(&x, i)
|
if t, ok := x.typ.(*Tuple); ok && x.mode != invalid && x.mode != typexpr {
|
||||||
|
// multiple values
|
||||||
|
xlist = make([]*operand, t.Len())
|
||||||
|
for i, v := range t.vars {
|
||||||
|
xlist[i] = &operand{mode: value, expr: e, typ: v.typ}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
check.instantiatedOperand(&x)
|
||||||
|
|
||||||
|
// exactly one (possibly invalid or comma-ok) value or type
|
||||||
|
xlist = []*operand{&x}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// multiple (possibly invalid) values or types
|
||||||
|
xlist = make([]*operand, len(elist))
|
||||||
|
ntypes := 0
|
||||||
|
for i, e := range elist {
|
||||||
|
var x operand
|
||||||
|
check.exprOrType(&x, e)
|
||||||
|
xlist[i] = &x
|
||||||
|
switch x.mode {
|
||||||
|
case invalid:
|
||||||
|
ntypes = len(xlist) // make 'if' condition fail below (no additional error in this case)
|
||||||
|
case typexpr:
|
||||||
|
ntypes++
|
||||||
|
check.instantiatedOperand(&x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if 0 < ntypes && ntypes < len(xlist) {
|
||||||
|
check.errorf(xlist[0], 0, "mix of value and type expressions")
|
||||||
|
ok = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, unpack
|
|
||||||
// calls the incoming getter for the first operand. If that operand is
|
|
||||||
// invalid, unpack returns (nil, 0, false). Otherwise, if that 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. The third result value reports if it
|
|
||||||
// is indeed the comma-ok case. In all other cases, the incoming getter and
|
|
||||||
// operand count are returned unchanged, and the third result value is false.
|
|
||||||
//
|
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
// If the returned 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, bool) {
|
|
||||||
if n != 1 {
|
|
||||||
// zero or multiple values
|
|
||||||
return get, n, false
|
|
||||||
}
|
|
||||||
// possibly result of an n-valued function call or comma,ok value
|
|
||||||
var x0 operand
|
|
||||||
get(&x0, 0)
|
|
||||||
if x0.mode == invalid {
|
|
||||||
return nil, 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
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(), false
|
|
||||||
}
|
|
||||||
|
|
||||||
if x0.mode == mapindex || x0.mode == commaok || x0.mode == commaerr {
|
|
||||||
// comma-ok value
|
|
||||||
if allowCommaOk {
|
|
||||||
a := [2]Type{x0.typ, Typ[UntypedBool]}
|
|
||||||
if x0.mode == commaerr {
|
|
||||||
a[1] = universeError
|
|
||||||
}
|
|
||||||
return func(x *operand, i int) {
|
|
||||||
x.mode = value
|
|
||||||
x.expr = x0.expr
|
|
||||||
x.typ = a[i]
|
|
||||||
}, 2, true
|
|
||||||
}
|
|
||||||
x0.mode = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// single value
|
|
||||||
return func(x *operand, i int) {
|
|
||||||
if i != 0 {
|
|
||||||
unreachable()
|
|
||||||
}
|
|
||||||
*x = x0
|
|
||||||
}, 1, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 getter, n int) {
|
|
||||||
if call.Ellipsis.IsValid() {
|
|
||||||
// last argument is of the form x...
|
|
||||||
if !sig.variadic {
|
|
||||||
check.errorf(atPos(call.Ellipsis), _NonVariadicDotDotDot, "cannot use ... in call to non-variadic %s", call.Fun)
|
|
||||||
check.useGetter(arg, n)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(call.Args) == 1 && n > 1 {
|
|
||||||
|
func (check *Checker) exprList(elist []ast.Expr, allowCommaOk bool) (xlist []*operand, commaOk bool) {
|
||||||
|
switch len(elist) {
|
||||||
|
case 0:
|
||||||
|
// nothing to do
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// single (possibly comma-ok) value, or function returning multiple values
|
||||||
|
e := elist[0]
|
||||||
|
var x operand
|
||||||
|
check.multiExpr(&x, e)
|
||||||
|
if t, ok := x.typ.(*Tuple); ok && x.mode != invalid {
|
||||||
|
// multiple values
|
||||||
|
xlist = make([]*operand, t.Len())
|
||||||
|
for i, v := range t.vars {
|
||||||
|
xlist[i] = &operand{mode: value, expr: e, typ: v.typ}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// exactly one (possibly invalid or comma-ok) value
|
||||||
|
xlist = []*operand{&x}
|
||||||
|
if allowCommaOk && (x.mode == mapindex || x.mode == commaok || x.mode == commaerr) {
|
||||||
|
x.mode = value
|
||||||
|
x2 := &operand{mode: value, expr: e, typ: Typ[UntypedBool]}
|
||||||
|
if x.mode == commaerr {
|
||||||
|
x2.typ = universeError
|
||||||
|
}
|
||||||
|
xlist = append(xlist, x2)
|
||||||
|
commaOk = true
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// multiple (possibly invalid) values
|
||||||
|
xlist = make([]*operand, len(elist))
|
||||||
|
for i, e := range elist {
|
||||||
|
var x operand
|
||||||
|
check.expr(&x, e)
|
||||||
|
xlist[i] = &x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, args []*operand) (rsig *Signature) {
|
||||||
|
rsig = sig
|
||||||
|
|
||||||
|
// TODO(gri) try to eliminate this extra verification loop
|
||||||
|
for _, a := range args {
|
||||||
|
switch a.mode {
|
||||||
|
case typexpr:
|
||||||
|
check.errorf(a, 0, "%s used as value", a)
|
||||||
|
return
|
||||||
|
case invalid:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function call argument/parameter count requirements
|
||||||
|
//
|
||||||
|
// | standard call | dotdotdot call |
|
||||||
|
// --------------+------------------+----------------+
|
||||||
|
// standard func | nargs == npars | invalid |
|
||||||
|
// --------------+------------------+----------------+
|
||||||
|
// variadic func | nargs >= npars-1 | nargs == npars |
|
||||||
|
// --------------+------------------+----------------+
|
||||||
|
|
||||||
|
nargs := len(args)
|
||||||
|
npars := sig.params.Len()
|
||||||
|
ddd := call.Ellipsis.IsValid()
|
||||||
|
|
||||||
|
// set up parameters
|
||||||
|
sigParams := sig.params // adjusted for variadic functions (may be nil for empty parameter lists!)
|
||||||
|
adjusted := false // indicates if sigParams is different from t.params
|
||||||
|
if sig.variadic {
|
||||||
|
if ddd {
|
||||||
|
// variadic_func(a, b, c...)
|
||||||
|
if len(call.Args) == 1 && nargs > 1 {
|
||||||
// f()... is not permitted if f() is multi-valued
|
// f()... is not permitted if f() is multi-valued
|
||||||
check.errorf(atPos(call.Ellipsis), _InvalidDotDotDotOperand, "cannot use ... with %d-valued %s", n, call.Args[0])
|
check.errorf(inNode(call, call.Ellipsis), _InvalidDotDotDot, "cannot use ... with %d-valued %s", nargs, call.Args[0])
|
||||||
check.useGetter(arg, n)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// variadic_func(a, b, c)
|
||||||
|
if nargs >= npars-1 {
|
||||||
|
// Create custom parameters for arguments: keep
|
||||||
|
// the first npars-1 parameters and add one for
|
||||||
|
// each argument mapping to the ... parameter.
|
||||||
|
vars := make([]*Var, npars-1) // npars > 0 for variadic functions
|
||||||
|
copy(vars, sig.params.vars)
|
||||||
|
last := sig.params.vars[npars-1]
|
||||||
|
typ := last.typ.(*Slice).elem
|
||||||
|
for len(vars) < nargs {
|
||||||
|
vars = append(vars, NewParam(last.pos, last.pkg, last.name, typ))
|
||||||
}
|
}
|
||||||
|
sigParams = NewTuple(vars...) // possibly nil!
|
||||||
// evaluate arguments
|
adjusted = true
|
||||||
context := check.sprintf("argument to %s", call.Fun)
|
npars = nargs
|
||||||
for i := 0; i < n; i++ {
|
} else {
|
||||||
arg(x, i)
|
// nargs < npars-1
|
||||||
if x.mode != invalid {
|
npars-- // for correct error message below
|
||||||
var ellipsis token.Pos
|
|
||||||
if i == n-1 && call.Ellipsis.IsValid() {
|
|
||||||
ellipsis = call.Ellipsis
|
|
||||||
}
|
}
|
||||||
check.argument(sig, i, x, ellipsis, context)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if ddd {
|
||||||
|
// standard_func(a, b, c...)
|
||||||
|
check.errorf(inNode(call, call.Ellipsis), _NonVariadicDotDotDot, "cannot use ... in call to non-variadic %s", call.Fun)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// standard_func(a, b, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check argument count
|
// check argument count
|
||||||
if sig.variadic {
|
|
||||||
// a variadic function accepts an "empty"
|
|
||||||
// last argument: count one extra
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
if n < sig.params.Len() {
|
|
||||||
check.errorf(inNode(call, call.Rparen), _WrongArgCount, "too few arguments in call to %s", call.Fun)
|
|
||||||
// ok to continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// argument checks passing of argument x to the i'th parameter of the given signature.
|
|
||||||
// If ellipsis is valid, the argument is followed by ... at that position in the call.
|
|
||||||
func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token.Pos, context string) {
|
|
||||||
check.singleValue(x)
|
|
||||||
if x.mode == invalid {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
n := sig.params.Len()
|
|
||||||
|
|
||||||
// determine parameter type
|
|
||||||
var typ Type
|
|
||||||
switch {
|
switch {
|
||||||
case i < n:
|
case nargs < npars:
|
||||||
typ = sig.params.vars[i].typ
|
check.errorf(inNode(call, call.Rparen), _WrongArgCount, "not enough arguments in call to %s", call.Fun)
|
||||||
case sig.variadic:
|
return
|
||||||
typ = sig.params.vars[n-1].typ
|
case nargs > npars:
|
||||||
|
check.errorf(args[npars], _WrongArgCount, "too many arguments in call to %s", call.Fun) // report at first extra argument
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// infer type arguments and instantiate signature if necessary
|
||||||
|
if len(sig.tparams) > 0 {
|
||||||
|
// TODO(gri) provide position information for targs so we can feed
|
||||||
|
// it to the instantiate call for better error reporting
|
||||||
|
targs, failed := check.infer(sig.tparams, sigParams, args)
|
||||||
|
if targs == nil {
|
||||||
|
return // error already reported
|
||||||
|
}
|
||||||
|
if failed >= 0 {
|
||||||
|
// Some type arguments couldn't be inferred. Use
|
||||||
|
// bounds type inference to try to make progress.
|
||||||
|
// TODO(rFindley)
|
||||||
|
/*
|
||||||
|
if check.conf.InferFromConstraints {
|
||||||
|
targs, failed = check.inferB(sig.tparams, targs)
|
||||||
|
if targs == nil {
|
||||||
|
return // error already reported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if failed >= 0 {
|
||||||
|
// at least one type argument couldn't be inferred
|
||||||
|
assert(targs[failed] == nil)
|
||||||
|
tpar := sig.tparams[failed]
|
||||||
|
ppos := check.fset.Position(tpar.pos).String()
|
||||||
|
check.errorf(inNode(call, call.Rparen), 0, "cannot infer %s (%s) (%s)", tpar.name, ppos, targs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// all type arguments were inferred sucessfully
|
||||||
if debug {
|
if debug {
|
||||||
if _, ok := typ.(*Slice); !ok {
|
for _, targ := range targs {
|
||||||
check.dump("%v: expected unnamed slice type, got %s", sig.params.vars[n-1].Pos(), typ)
|
assert(targ != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
check.errorf(x, _WrongArgCount, "too many arguments")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ellipsis.IsValid() {
|
// compute result signature
|
||||||
if i != n-1 {
|
rsig = check.instantiate(call.Pos(), sig, targs, nil).(*Signature)
|
||||||
check.errorf(atPos(ellipsis), _MisplacedDotDotDot, "can only use ... with matching parameter")
|
assert(rsig.tparams == nil) // signature is not generic anymore
|
||||||
return
|
check.recordInferred(call, targs, rsig)
|
||||||
|
|
||||||
|
// Optimization: Only if the parameter list was adjusted do we
|
||||||
|
// need to compute it from the adjusted list; otherwise we can
|
||||||
|
// simply use the result signature's parameter list.
|
||||||
|
if adjusted {
|
||||||
|
sigParams = check.subst(call.Pos(), sigParams, makeSubstMap(sig.tparams, targs)).(*Tuple)
|
||||||
|
} else {
|
||||||
|
sigParams = rsig.params
|
||||||
}
|
}
|
||||||
// argument is of the form x... and x is single-valued
|
|
||||||
if _, ok := x.typ.Underlying().(*Slice); !ok && x.typ != Typ[UntypedNil] { // see issue #18268
|
|
||||||
check.errorf(x, _InvalidDotDotDotOperand, "cannot use %s as parameter of type %s", x, typ)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if sig.variadic && i >= n-1 {
|
|
||||||
// use the variadic parameter slice's element type
|
|
||||||
typ = typ.(*Slice).elem
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check.assignment(x, typ, context)
|
// check arguments
|
||||||
|
// TODO(gri) Possible optimization (may be tricky): We could avoid
|
||||||
|
// checking arguments from which we inferred type arguments.
|
||||||
|
for i, a := range args {
|
||||||
|
check.assignment(a, sigParams.vars[i].typ, check.sprintf("argument to %s", call.Fun))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var cgoPrefixes = [...]string{
|
var cgoPrefixes = [...]string{
|
||||||
|
|
@ -368,7 +561,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||||
x.typ = exp.typ
|
x.typ = exp.typ
|
||||||
x.id = exp.id
|
x.id = exp.id
|
||||||
default:
|
default:
|
||||||
check.dump("unexpected object %v", exp)
|
check.dump("%v: unexpected object %v", e.Sel.Pos(), exp)
|
||||||
unreachable()
|
unreachable()
|
||||||
}
|
}
|
||||||
x.expr = e
|
x.expr = e
|
||||||
|
|
@ -381,6 +574,8 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check.instantiatedOperand(x)
|
||||||
|
|
||||||
obj, index, indirect = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
|
obj, index, indirect = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -390,8 +585,20 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||||
case indirect:
|
case indirect:
|
||||||
check.errorf(e.Sel, _InvalidMethodExpr, "cannot call pointer method %s on %s", sel, x.typ)
|
check.errorf(e.Sel, _InvalidMethodExpr, "cannot call pointer method %s on %s", sel, x.typ)
|
||||||
default:
|
default:
|
||||||
// Check if capitalization of sel matters and provide better error
|
var why string
|
||||||
// message in that case.
|
if tpar := asTypeParam(x.typ); tpar != nil {
|
||||||
|
// Type parameter bounds don't specify fields, so don't mention "field".
|
||||||
|
switch obj := tpar.Bound().obj.(type) {
|
||||||
|
case nil:
|
||||||
|
why = check.sprintf("type bound for %s has no method %s", x.typ, sel)
|
||||||
|
case *TypeName:
|
||||||
|
why = check.sprintf("interface %s has no method %s", obj.name, sel)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
why = check.sprintf("type %s has no field or method %s", x.typ, sel)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if capitalization of sel matters and provide better error message in that case.
|
||||||
if len(sel) > 0 {
|
if len(sel) > 0 {
|
||||||
var changeCase string
|
var changeCase string
|
||||||
if r := rune(sel[0]); unicode.IsUpper(r) {
|
if r := rune(sel[0]); unicode.IsUpper(r) {
|
||||||
|
|
@ -400,11 +607,11 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||||
changeCase = string(unicode.ToUpper(r)) + sel[1:]
|
changeCase = string(unicode.ToUpper(r)) + sel[1:]
|
||||||
}
|
}
|
||||||
if obj, _, _ = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil {
|
if obj, _, _ = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil {
|
||||||
check.errorf(e.Sel, _MissingFieldOrMethod, "%s.%s undefined (type %s has no field or method %s, but does have %s)", x.expr, sel, x.typ, sel, changeCase)
|
why += ", but does have " + changeCase
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check.errorf(e.Sel, _MissingFieldOrMethod, "%s.%s undefined (type %s has no field or method %s)", x.expr, sel, x.typ, sel)
|
|
||||||
|
check.errorf(e.Sel, _MissingFieldOrMethod, "%s.%s undefined (%s)", x.expr, sel, why)
|
||||||
}
|
}
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
@ -412,6 +619,43 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||||
// methods may not have a fully set up signature yet
|
// methods may not have a fully set up signature yet
|
||||||
if m, _ := obj.(*Func); m != nil {
|
if m, _ := obj.(*Func); m != nil {
|
||||||
check.objDecl(m, nil)
|
check.objDecl(m, nil)
|
||||||
|
// If m has a parameterized receiver type, infer the type parameter
|
||||||
|
// values from the actual receiver provided and then substitute the
|
||||||
|
// type parameters in the signature accordingly.
|
||||||
|
// TODO(gri) factor this code out
|
||||||
|
sig := m.typ.(*Signature)
|
||||||
|
if len(sig.rparams) > 0 {
|
||||||
|
// The method may have a pointer receiver, but the actually provided receiver
|
||||||
|
// may be a (hopefully addressable) non-pointer value, or vice versa. Here we
|
||||||
|
// only care about inferring receiver type parameters; to make the inference
|
||||||
|
// work, match up pointer-ness of receiver and argument.
|
||||||
|
arg := x
|
||||||
|
if ptrRecv := isPointer(sig.recv.typ); ptrRecv != isPointer(arg.typ) {
|
||||||
|
copy := *arg
|
||||||
|
if ptrRecv {
|
||||||
|
copy.typ = NewPointer(arg.typ)
|
||||||
|
} else {
|
||||||
|
copy.typ = arg.typ.(*Pointer).base
|
||||||
|
}
|
||||||
|
arg = ©
|
||||||
|
}
|
||||||
|
targs, failed := check.infer(sig.rparams, NewTuple(sig.recv), []*operand{arg})
|
||||||
|
if failed >= 0 {
|
||||||
|
// We may reach here if there were other errors (see issue #40056).
|
||||||
|
// check.infer will report a follow-up error.
|
||||||
|
// TODO(gri) avoid the follow-up error or provide better explanation.
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
// Don't modify m. Instead - for now - make a copy of m and use that instead.
|
||||||
|
// (If we modify m, some tests will fail; possibly because the m is in use.)
|
||||||
|
// TODO(gri) investigate and provide a correct explanation here
|
||||||
|
copy := *m
|
||||||
|
copy.typ = check.subst(e.Pos(), m.typ, makeSubstMap(sig.rparams, targs))
|
||||||
|
obj = ©
|
||||||
|
}
|
||||||
|
// TODO(gri) we also need to do substitution for parameterized interface methods
|
||||||
|
// (this breaks code in testdata/linalg.go2 at the moment)
|
||||||
|
// 12/20/2019: Is this TODO still correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
if x.mode == typexpr {
|
if x.mode == typexpr {
|
||||||
|
|
@ -434,7 +678,8 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||||
}
|
}
|
||||||
x.mode = value
|
x.mode = value
|
||||||
x.typ = &Signature{
|
x.typ = &Signature{
|
||||||
params: NewTuple(append([]*Var{NewVar(token.NoPos, check.pkg, "", x.typ)}, params...)...),
|
tparams: sig.tparams,
|
||||||
|
params: NewTuple(append([]*Var{NewVar(token.NoPos, check.pkg, "_", x.typ)}, params...)...),
|
||||||
results: sig.results,
|
results: sig.results,
|
||||||
variadic: sig.variadic,
|
variadic: sig.variadic,
|
||||||
}
|
}
|
||||||
|
|
@ -458,7 +703,14 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||||
// addressability, should we report the type &(x.typ) instead?
|
// addressability, should we report the type &(x.typ) instead?
|
||||||
check.recordSelection(e, MethodVal, x.typ, obj, index, indirect)
|
check.recordSelection(e, MethodVal, x.typ, obj, index, indirect)
|
||||||
|
|
||||||
if debug {
|
// TODO(gri) The verification pass below is disabled for now because
|
||||||
|
// method sets don't match method lookup in some cases.
|
||||||
|
// For instance, if we made a copy above when creating a
|
||||||
|
// custom method for a parameterized received type, the
|
||||||
|
// method set method doesn't match (no copy there). There
|
||||||
|
/// may be other situations.
|
||||||
|
disabled := true
|
||||||
|
if !disabled && debug {
|
||||||
// Verify that LookupFieldOrMethod and MethodSet.Lookup agree.
|
// Verify that LookupFieldOrMethod and MethodSet.Lookup agree.
|
||||||
// TODO(gri) This only works because we call LookupFieldOrMethod
|
// TODO(gri) This only works because we call LookupFieldOrMethod
|
||||||
// _before_ calling NewMethodSet: LookupFieldOrMethod completes
|
// _before_ calling NewMethodSet: LookupFieldOrMethod completes
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ func (check *Checker) conversion(x *operand, T Type) {
|
||||||
switch {
|
switch {
|
||||||
case constArg && isConstType(T):
|
case constArg && isConstType(T):
|
||||||
// constant conversion
|
// constant conversion
|
||||||
switch t := T.Underlying().(*Basic); {
|
switch t := asBasic(T); {
|
||||||
case representableConst(x.val, check, t, &x.val):
|
case representableConst(x.val, check, t, &x.val):
|
||||||
ok = true
|
ok = true
|
||||||
case isInteger(x.typ) && isString(t):
|
case isInteger(x.typ) && isString(t):
|
||||||
|
|
@ -87,8 +87,8 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
|
||||||
|
|
||||||
// "x's type and T have identical underlying types if tags are ignored"
|
// "x's type and T have identical underlying types if tags are ignored"
|
||||||
V := x.typ
|
V := x.typ
|
||||||
Vu := V.Underlying()
|
Vu := under(V)
|
||||||
Tu := T.Underlying()
|
Tu := under(T)
|
||||||
if check.identicalIgnoreTags(Vu, Tu) {
|
if check.identicalIgnoreTags(Vu, Tu) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -97,14 +97,14 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
|
||||||
// have identical underlying types if tags are ignored"
|
// have identical underlying types if tags are ignored"
|
||||||
if V, ok := V.(*Pointer); ok {
|
if V, ok := V.(*Pointer); ok {
|
||||||
if T, ok := T.(*Pointer); ok {
|
if T, ok := T.(*Pointer); ok {
|
||||||
if check.identicalIgnoreTags(V.base.Underlying(), T.base.Underlying()) {
|
if check.identicalIgnoreTags(under(V.base), under(T.base)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// "x's type and T are both integer or floating point types"
|
// "x's type and T are both integer or floating point types"
|
||||||
if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) {
|
if isIntegerOrFloat(V) && isIntegerOrFloat(T) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,27 +137,27 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func isUintptr(typ Type) bool {
|
func isUintptr(typ Type) bool {
|
||||||
t, ok := typ.Underlying().(*Basic)
|
t := asBasic(typ)
|
||||||
return ok && t.kind == Uintptr
|
return t != nil && t.kind == Uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
func isUnsafePointer(typ Type) bool {
|
func isUnsafePointer(typ Type) bool {
|
||||||
// TODO(gri): Is this (typ.Underlying() instead of just typ) correct?
|
// TODO(gri): Is this asBasic() instead of typ.(*Basic) correct?
|
||||||
|
// (The former calls under(), while the latter doesn't.)
|
||||||
// The spec does not say so, but gc claims it is. See also
|
// The spec does not say so, but gc claims it is. See also
|
||||||
// issue 6326.
|
// issue 6326.
|
||||||
t, ok := typ.Underlying().(*Basic)
|
t := asBasic(typ)
|
||||||
return ok && t.kind == UnsafePointer
|
return t != nil && t.kind == UnsafePointer
|
||||||
}
|
}
|
||||||
|
|
||||||
func isPointer(typ Type) bool {
|
func isPointer(typ Type) bool {
|
||||||
_, ok := typ.Underlying().(*Pointer)
|
return asPointer(typ) != nil
|
||||||
return ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isBytesOrRunes(typ Type) bool {
|
func isBytesOrRunes(typ Type) bool {
|
||||||
if s, ok := typ.(*Slice); ok {
|
if s := asSlice(typ); s != nil {
|
||||||
t, ok := s.elem.Underlying().(*Basic)
|
t := asBasic(s.elem)
|
||||||
return ok && (t.kind == Byte || t.kind == Rune)
|
return t != nil && (t.kind == Byte || t.kind == Rune)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -753,52 +753,12 @@ const (
|
||||||
_NonVariadicDotDotDot
|
_NonVariadicDotDotDot
|
||||||
|
|
||||||
// _MisplacedDotDotDot occurs when a "..." is used somewhere other than the
|
// _MisplacedDotDotDot occurs when a "..." is used somewhere other than the
|
||||||
// final argument to a function call.
|
// final argument in a function declaration.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// func printArgs(args ...int) {
|
// func f(...int, int)
|
||||||
// for _, a := range args {
|
|
||||||
// println(a)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func f() {
|
|
||||||
// a := []int{1,2,3}
|
|
||||||
// printArgs(0, a...)
|
|
||||||
// }
|
|
||||||
_MisplacedDotDotDot
|
_MisplacedDotDotDot
|
||||||
|
|
||||||
// _InvalidDotDotDotOperand occurs when a "..." operator is applied to a
|
|
||||||
// single-valued operand.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// func printArgs(args ...int) {
|
|
||||||
// for _, a := range args {
|
|
||||||
// println(a)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func f() {
|
|
||||||
// a := 1
|
|
||||||
// printArgs(a...)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// func args() (int, int) {
|
|
||||||
// return 1, 2
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func printArgs(args ...int) {
|
|
||||||
// for _, a := range args {
|
|
||||||
// println(a)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func g() {
|
|
||||||
// printArgs(args()...)
|
|
||||||
// }
|
|
||||||
_InvalidDotDotDotOperand
|
|
||||||
|
|
||||||
// _InvalidDotDotDot occurs when a "..." is used in a non-variadic built-in
|
// _InvalidDotDotDot occurs when a "..." is used in a non-variadic built-in
|
||||||
// function.
|
// function.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -155,9 +155,9 @@ func TestEvalPos(t *testing.T) {
|
||||||
import "io"
|
import "io"
|
||||||
type R = io.Reader
|
type R = io.Reader
|
||||||
func _() {
|
func _() {
|
||||||
/* interface{R}.Read => , func(interface{io.Reader}, p []byte) (n int, err error) */
|
/* interface{R}.Read => , func(_ interface{io.Reader}, p []byte) (n int, err error) */
|
||||||
_ = func() {
|
_ = func() {
|
||||||
/* interface{io.Writer}.Write => , func(interface{io.Writer}, p []byte) (n int, err error) */
|
/* interface{io.Writer}.Write => , func(_ interface{io.Writer}, p []byte) (n int, err error) */
|
||||||
type io interface {} // must not shadow io in line above
|
type io interface {} // must not shadow io in line above
|
||||||
}
|
}
|
||||||
type R interface {} // must not shadow R in first line of this function body
|
type R interface {} // must not shadow R in first line of this function body
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
// REVIEW INCOMPLETE
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
@ -99,8 +100,8 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) {
|
||||||
return
|
return
|
||||||
|
|
||||||
case token.ARROW:
|
case token.ARROW:
|
||||||
typ, ok := x.typ.Underlying().(*Chan)
|
typ := asChan(x.typ)
|
||||||
if !ok {
|
if typ == nil {
|
||||||
check.invalidOp(x, _InvalidReceive, "cannot receive from non-channel %s", x)
|
check.invalidOp(x, _InvalidReceive, "cannot receive from non-channel %s", x)
|
||||||
x.mode = invalid
|
x.mode = invalid
|
||||||
return
|
return
|
||||||
|
|
@ -122,7 +123,7 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if x.mode == constant_ {
|
if x.mode == constant_ {
|
||||||
typ := x.typ.Underlying().(*Basic)
|
typ := asBasic(x.typ)
|
||||||
var prec uint
|
var prec uint
|
||||||
if isUnsigned(typ) {
|
if isUnsigned(typ) {
|
||||||
prec = uint(check.conf.sizeof(typ) * 8)
|
prec = uint(check.conf.sizeof(typ) * 8)
|
||||||
|
|
@ -461,7 +462,7 @@ func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) {
|
||||||
// If the new type is not final and still untyped, just
|
// If the new type is not final and still untyped, just
|
||||||
// update the recorded type.
|
// update the recorded type.
|
||||||
if !final && isUntyped(typ) {
|
if !final && isUntyped(typ) {
|
||||||
old.typ = typ.Underlying().(*Basic)
|
old.typ = asBasic(typ)
|
||||||
check.untyped[x] = old
|
check.untyped[x] = old
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -512,6 +513,7 @@ func (check *Checker) convertUntyped(x *operand, target Type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) canConvertUntyped(x *operand, target Type) error {
|
func (check *Checker) canConvertUntyped(x *operand, target Type) error {
|
||||||
|
target = expand(target)
|
||||||
if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
|
if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -744,7 +746,7 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
x.expr = e // for better error message
|
x.expr = e // for better error message
|
||||||
}
|
}
|
||||||
check.representable(x, x.typ.Underlying().(*Basic))
|
check.representable(x, asBasic(x.typ))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -889,7 +891,7 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o
|
||||||
if x.mode == constant_ && y.mode == constant_ {
|
if x.mode == constant_ && y.mode == constant_ {
|
||||||
xval := x.val
|
xval := x.val
|
||||||
yval := y.val
|
yval := y.val
|
||||||
typ := x.typ.Underlying().(*Basic)
|
typ := asBasic(x.typ)
|
||||||
// force integer division of integer operands
|
// force integer division of integer operands
|
||||||
if op == token.QUO && isInteger(typ) {
|
if op == token.QUO && isInteger(typ) {
|
||||||
op = token.QUO_ASSIGN
|
op = token.QUO_ASSIGN
|
||||||
|
|
@ -1028,7 +1030,7 @@ const (
|
||||||
//
|
//
|
||||||
func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
|
func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
if trace {
|
if trace {
|
||||||
check.trace(e.Pos(), "%s", e)
|
check.trace(e.Pos(), "expr %s", e)
|
||||||
check.indent++
|
check.indent++
|
||||||
defer func() {
|
defer func() {
|
||||||
check.indent--
|
check.indent--
|
||||||
|
|
@ -1133,7 +1135,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
// We have an "open" [...]T array type.
|
// We have an "open" [...]T array type.
|
||||||
// Create a new ArrayType with unknown length (-1)
|
// Create a new ArrayType with unknown length (-1)
|
||||||
// and finish setting it up after analyzing the literal.
|
// and finish setting it up after analyzing the literal.
|
||||||
typ = &Array{len: -1, elem: check.typ(atyp.Elt)}
|
typ = &Array{len: -1, elem: check.varType(atyp.Elt)}
|
||||||
base = typ
|
base = typ
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -1144,7 +1146,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
case hint != nil:
|
case hint != nil:
|
||||||
// no composite literal type present - use hint (element type of enclosing type)
|
// no composite literal type present - use hint (element type of enclosing type)
|
||||||
typ = hint
|
typ = hint
|
||||||
base, _ = deref(typ.Underlying()) // *T implies &T{}
|
base, _ = deref(under(typ)) // *T implies &T{}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// TODO(gri) provide better error messages depending on context
|
// TODO(gri) provide better error messages depending on context
|
||||||
|
|
@ -1152,7 +1154,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
switch utyp := base.Underlying().(type) {
|
switch utyp := optype(base).(type) {
|
||||||
case *Struct:
|
case *Struct:
|
||||||
if len(e.Elts) == 0 {
|
if len(e.Elts) == 0 {
|
||||||
break
|
break
|
||||||
|
|
@ -1280,7 +1282,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
duplicate := false
|
duplicate := false
|
||||||
// if the key is of interface type, the type is also significant when checking for duplicates
|
// if the key is of interface type, the type is also significant when checking for duplicates
|
||||||
xkey := keyVal(x.val)
|
xkey := keyVal(x.val)
|
||||||
if _, ok := utyp.key.Underlying().(*Interface); ok {
|
if asInterface(utyp.key) != nil {
|
||||||
for _, vtyp := range visited[xkey] {
|
for _, vtyp := range visited[xkey] {
|
||||||
if check.identical(vtyp, x.typ) {
|
if check.identical(vtyp, x.typ) {
|
||||||
duplicate = true
|
duplicate = true
|
||||||
|
|
@ -1332,15 +1334,31 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
check.selector(x, e)
|
check.selector(x, e)
|
||||||
|
|
||||||
case *ast.IndexExpr:
|
case *ast.IndexExpr:
|
||||||
check.expr(x, e.X)
|
check.exprOrType(x, e.X)
|
||||||
if x.mode == invalid {
|
if x.mode == invalid {
|
||||||
check.use(e.Index)
|
check.use(e.Index)
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if x.mode == typexpr {
|
||||||
|
// type instantiation
|
||||||
|
x.mode = invalid
|
||||||
|
x.typ = check.varType(e)
|
||||||
|
if x.typ != Typ[Invalid] {
|
||||||
|
x.mode = typexpr
|
||||||
|
}
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.mode == value {
|
||||||
|
if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
|
||||||
|
return check.call(x, nil, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
valid := false
|
valid := false
|
||||||
length := int64(-1) // valid if >= 0
|
length := int64(-1) // valid if >= 0
|
||||||
switch typ := x.typ.Underlying().(type) {
|
switch typ := optype(x.typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(typ) {
|
if isString(typ) {
|
||||||
valid = true
|
valid = true
|
||||||
|
|
@ -1363,7 +1381,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
x.typ = typ.elem
|
x.typ = typ.elem
|
||||||
|
|
||||||
case *Pointer:
|
case *Pointer:
|
||||||
if typ, _ := typ.base.Underlying().(*Array); typ != nil {
|
if typ := asArray(typ.base); typ != nil {
|
||||||
valid = true
|
valid = true
|
||||||
length = typ.len
|
length = typ.len
|
||||||
x.mode = variable
|
x.mode = variable
|
||||||
|
|
@ -1384,6 +1402,82 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
x.typ = typ.elem
|
x.typ = typ.elem
|
||||||
x.expr = e
|
x.expr = e
|
||||||
return expression
|
return expression
|
||||||
|
|
||||||
|
case *Sum:
|
||||||
|
// A sum type can be indexed if all of the sum's types
|
||||||
|
// support indexing and have the same index and element
|
||||||
|
// type. Special rules apply for maps in the sum type.
|
||||||
|
var tkey, telem Type // key is for map types only
|
||||||
|
nmaps := 0 // number of map types in sum type
|
||||||
|
if typ.is(func(t Type) bool {
|
||||||
|
var e Type
|
||||||
|
switch t := under(t).(type) {
|
||||||
|
case *Basic:
|
||||||
|
if isString(t) {
|
||||||
|
e = universeByte
|
||||||
|
}
|
||||||
|
case *Array:
|
||||||
|
e = t.elem
|
||||||
|
case *Pointer:
|
||||||
|
if t := asArray(t.base); t != nil {
|
||||||
|
e = t.elem
|
||||||
|
}
|
||||||
|
case *Slice:
|
||||||
|
e = t.elem
|
||||||
|
case *Map:
|
||||||
|
// If there are multiple maps in the sum type,
|
||||||
|
// they must have identical key types.
|
||||||
|
// TODO(gri) We may be able to relax this rule
|
||||||
|
// but it becomes complicated very quickly.
|
||||||
|
if tkey != nil && !Identical(t.key, tkey) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
tkey = t.key
|
||||||
|
e = t.elem
|
||||||
|
nmaps++
|
||||||
|
case *TypeParam:
|
||||||
|
check.errorf(x, 0, "type of %s contains a type parameter - cannot index (implementation restriction)", x)
|
||||||
|
case *instance:
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
if e == nil || telem != nil && !Identical(e, telem) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
telem = e
|
||||||
|
return true
|
||||||
|
}) {
|
||||||
|
// If there are maps, the index expression must be assignable
|
||||||
|
// to the map key type (as for simple map index expressions).
|
||||||
|
if nmaps > 0 {
|
||||||
|
var key operand
|
||||||
|
check.expr(&key, e.Index)
|
||||||
|
check.assignment(&key, tkey, "map index")
|
||||||
|
// ok to continue even if indexing failed - map element type is known
|
||||||
|
|
||||||
|
// If there are only maps, we are done.
|
||||||
|
if nmaps == len(typ.types) {
|
||||||
|
x.mode = mapindex
|
||||||
|
x.typ = telem
|
||||||
|
x.expr = e
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise we have mix of maps and other types. For
|
||||||
|
// now we require that the map key be an integer type.
|
||||||
|
// TODO(gri) This is probably not good enough.
|
||||||
|
valid = isInteger(tkey)
|
||||||
|
// avoid 2nd indexing error if indexing failed above
|
||||||
|
if !valid && key.mode == invalid {
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
x.mode = value // map index expressions are not addressable
|
||||||
|
} else {
|
||||||
|
// no maps
|
||||||
|
valid = true
|
||||||
|
x.mode = variable
|
||||||
|
}
|
||||||
|
x.typ = telem
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !valid {
|
if !valid {
|
||||||
|
|
@ -1396,6 +1490,13 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In pathological (invalid) cases (e.g.: type T1 [][[]T1{}[0][0]]T0)
|
||||||
|
// the element type may be accessed before it's set. Make sure we have
|
||||||
|
// a valid type.
|
||||||
|
if x.typ == nil {
|
||||||
|
x.typ = Typ[Invalid]
|
||||||
|
}
|
||||||
|
|
||||||
check.index(e.Index, length)
|
check.index(e.Index, length)
|
||||||
// ok to continue
|
// ok to continue
|
||||||
|
|
||||||
|
|
@ -1408,7 +1509,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
|
|
||||||
valid := false
|
valid := false
|
||||||
length := int64(-1) // valid if >= 0
|
length := int64(-1) // valid if >= 0
|
||||||
switch typ := x.typ.Underlying().(type) {
|
switch typ := optype(x.typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(typ) {
|
if isString(typ) {
|
||||||
if e.Slice3 {
|
if e.Slice3 {
|
||||||
|
|
@ -1436,7 +1537,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
x.typ = &Slice{elem: typ.elem}
|
x.typ = &Slice{elem: typ.elem}
|
||||||
|
|
||||||
case *Pointer:
|
case *Pointer:
|
||||||
if typ, _ := typ.base.Underlying().(*Array); typ != nil {
|
if typ := asArray(typ.base); typ != nil {
|
||||||
valid = true
|
valid = true
|
||||||
length = typ.len
|
length = typ.len
|
||||||
x.typ = &Slice{elem: typ.elem}
|
x.typ = &Slice{elem: typ.elem}
|
||||||
|
|
@ -1445,6 +1546,10 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
case *Slice:
|
case *Slice:
|
||||||
valid = true
|
valid = true
|
||||||
// x.typ doesn't change
|
// x.typ doesn't change
|
||||||
|
|
||||||
|
case *Sum, *TypeParam:
|
||||||
|
check.errorf(x, 0, "generic slice expressions not yet implemented")
|
||||||
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
if !valid {
|
if !valid {
|
||||||
|
|
@ -1505,11 +1610,12 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
if x.mode == invalid {
|
if x.mode == invalid {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
xtyp, _ := x.typ.Underlying().(*Interface)
|
xtyp, _ := under(x.typ).(*Interface)
|
||||||
if xtyp == nil {
|
if xtyp == nil {
|
||||||
check.invalidOp(x, _InvalidAssert, "%s is not an interface", x)
|
check.invalidOp(x, _InvalidAssert, "%s is not an interface", x)
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
check.ordinaryType(x, xtyp)
|
||||||
// x.(type) expressions are handled explicitly in type switches
|
// x.(type) expressions are handled explicitly in type switches
|
||||||
if e.Type == nil {
|
if e.Type == nil {
|
||||||
// Don't use invalidAST because this can occur in the AST produced by
|
// Don't use invalidAST because this can occur in the AST produced by
|
||||||
|
|
@ -1517,7 +1623,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
check.error(e, _BadTypeKeyword, "use of .(type) outside type switch")
|
check.error(e, _BadTypeKeyword, "use of .(type) outside type switch")
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
T := check.typ(e.Type)
|
T := check.varType(e.Type)
|
||||||
if T == Typ[Invalid] {
|
if T == Typ[Invalid] {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
@ -1526,7 +1632,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
x.typ = T
|
x.typ = T
|
||||||
|
|
||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
return check.call(x, e)
|
return check.call(x, e, e)
|
||||||
|
|
||||||
case *ast.StarExpr:
|
case *ast.StarExpr:
|
||||||
check.exprOrType(x, e.X)
|
check.exprOrType(x, e.X)
|
||||||
|
|
@ -1536,7 +1642,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
case typexpr:
|
case typexpr:
|
||||||
x.typ = &Pointer{base: x.typ}
|
x.typ = &Pointer{base: x.typ}
|
||||||
default:
|
default:
|
||||||
if typ, ok := x.typ.Underlying().(*Pointer); ok {
|
if typ := asPointer(x.typ); typ != nil {
|
||||||
x.mode = variable
|
x.mode = variable
|
||||||
x.typ = typ.base
|
x.typ = typ.base
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1637,6 +1743,77 @@ func (check *Checker) typeAssertion(at positioner, x *operand, xtyp *Interface,
|
||||||
check.errorf(at, _ImpossibleAssert, "%s cannot have dynamic type %s (%s)", x, T, msg)
|
check.errorf(at, _ImpossibleAssert, "%s cannot have dynamic type %s (%s)", x, T, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// expr typechecks expression e and initializes x with the expression value.
|
||||||
|
// The result must be a single value.
|
||||||
|
// If an error occurred, x.mode is set to invalid.
|
||||||
|
//
|
||||||
|
func (check *Checker) expr(x *operand, e ast.Expr) {
|
||||||
|
check.rawExpr(x, e, nil)
|
||||||
|
check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
|
||||||
|
check.singleValue(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiExpr is like expr but the result may also be a multi-value.
|
||||||
|
func (check *Checker) multiExpr(x *operand, e ast.Expr) {
|
||||||
|
check.rawExpr(x, e, nil)
|
||||||
|
check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiExprOrType is like multiExpr but the result may also be a type.
|
||||||
|
func (check *Checker) multiExprOrType(x *operand, e ast.Expr) {
|
||||||
|
check.rawExpr(x, e, nil)
|
||||||
|
check.exclude(x, 1<<novalue|1<<builtin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// exprWithHint typechecks expression e and initializes x with the expression value;
|
||||||
|
// hint is the type of a composite literal element.
|
||||||
|
// If an error occurred, x.mode is set to invalid.
|
||||||
|
//
|
||||||
|
func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
|
||||||
|
assert(hint != nil)
|
||||||
|
check.rawExpr(x, e, hint)
|
||||||
|
check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
|
||||||
|
check.singleValue(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// exprOrType typechecks expression or type e and initializes x with the expression value or type.
|
||||||
|
// If an error occurred, x.mode is set to invalid.
|
||||||
|
//
|
||||||
|
func (check *Checker) exprOrType(x *operand, e ast.Expr) {
|
||||||
|
check.rawExpr(x, e, nil)
|
||||||
|
check.exclude(x, 1<<novalue)
|
||||||
|
check.singleValue(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// exclude reports an error if x.mode is in modeset and sets x.mode to invalid.
|
||||||
|
// The modeset may contain any of 1<<novalue, 1<<builtin, 1<<typexpr.
|
||||||
|
func (check *Checker) exclude(x *operand, modeset uint) {
|
||||||
|
if modeset&(1<<x.mode) != 0 {
|
||||||
|
var msg string
|
||||||
|
var code errorCode
|
||||||
|
switch x.mode {
|
||||||
|
case novalue:
|
||||||
|
if modeset&(1<<typexpr) != 0 {
|
||||||
|
msg = "%s used as value"
|
||||||
|
} else {
|
||||||
|
msg = "%s used as value or type"
|
||||||
|
}
|
||||||
|
code = _TooManyValues
|
||||||
|
case builtin:
|
||||||
|
msg = "%s must be called"
|
||||||
|
code = _UncalledBuiltin
|
||||||
|
case typexpr:
|
||||||
|
msg = "%s is not an expression"
|
||||||
|
code = _NotAnExpr
|
||||||
|
default:
|
||||||
|
unreachable()
|
||||||
|
}
|
||||||
|
check.errorf(x, code, msg, x)
|
||||||
|
x.mode = invalid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// singleValue reports an error if x describes a tuple and sets x.mode to invalid.
|
||||||
func (check *Checker) singleValue(x *operand) {
|
func (check *Checker) singleValue(x *operand) {
|
||||||
if x.mode == value {
|
if x.mode == value {
|
||||||
// tuple types are never named - no need for underlying type below
|
// tuple types are never named - no need for underlying type below
|
||||||
|
|
@ -1647,73 +1824,3 @@ func (check *Checker) singleValue(x *operand) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// expr typechecks expression e and initializes x with the expression value.
|
|
||||||
// The result must be a single value.
|
|
||||||
// If an error occurred, x.mode is set to invalid.
|
|
||||||
//
|
|
||||||
func (check *Checker) expr(x *operand, e ast.Expr) {
|
|
||||||
check.multiExpr(x, e)
|
|
||||||
check.singleValue(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// multiExpr is like expr but the result may be a multi-value.
|
|
||||||
func (check *Checker) multiExpr(x *operand, e ast.Expr) {
|
|
||||||
check.rawExpr(x, e, nil)
|
|
||||||
var msg string
|
|
||||||
var code errorCode
|
|
||||||
switch x.mode {
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
case novalue:
|
|
||||||
msg = "%s used as value"
|
|
||||||
code = _TooManyValues
|
|
||||||
case builtin:
|
|
||||||
msg = "%s must be called"
|
|
||||||
code = _UncalledBuiltin
|
|
||||||
case typexpr:
|
|
||||||
msg = "%s is not an expression"
|
|
||||||
code = _NotAnExpr
|
|
||||||
}
|
|
||||||
check.errorf(x, code, msg, x)
|
|
||||||
x.mode = invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
// exprWithHint typechecks expression e and initializes x with the expression value;
|
|
||||||
// hint is the type of a composite literal element.
|
|
||||||
// If an error occurred, x.mode is set to invalid.
|
|
||||||
//
|
|
||||||
func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
|
|
||||||
assert(hint != nil)
|
|
||||||
check.rawExpr(x, e, hint)
|
|
||||||
check.singleValue(x)
|
|
||||||
var msg string
|
|
||||||
var code errorCode
|
|
||||||
switch x.mode {
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
case novalue:
|
|
||||||
msg = "%s used as value"
|
|
||||||
code = _TooManyValues
|
|
||||||
case builtin:
|
|
||||||
msg = "%s must be called"
|
|
||||||
code = _UncalledBuiltin
|
|
||||||
case typexpr:
|
|
||||||
msg = "%s is not an expression"
|
|
||||||
code = _NotAnExpr
|
|
||||||
}
|
|
||||||
check.errorf(x, code, msg, x)
|
|
||||||
x.mode = invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
// exprOrType typechecks expression or type e and initializes x with the expression value or type.
|
|
||||||
// If an error occurred, x.mode is set to invalid.
|
|
||||||
//
|
|
||||||
func (check *Checker) exprOrType(x *operand, e ast.Expr) {
|
|
||||||
check.rawExpr(x, e, nil)
|
|
||||||
check.singleValue(x)
|
|
||||||
if x.mode == novalue {
|
|
||||||
check.errorf(x, _NotAnExpr, "%s used as value or type", x)
|
|
||||||
x.mode = invalid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
6
src/go/types/testdata/builtins.src
vendored
6
src/go/types/testdata/builtins.src
vendored
|
|
@ -25,11 +25,11 @@ func append1() {
|
||||||
_ = append(s, b)
|
_ = append(s, b)
|
||||||
_ = append(s, x /* ERROR cannot use x */ )
|
_ = append(s, x /* ERROR cannot use x */ )
|
||||||
_ = append(s, s /* ERROR cannot use s */ )
|
_ = append(s, s /* ERROR cannot use s */ )
|
||||||
_ = append(s... /* ERROR can only use ... with matching parameter */ )
|
_ = append(s...) /* ERROR not enough arguments */
|
||||||
_ = append(s, b, s... /* ERROR can only use ... with matching parameter */ )
|
_ = append(s, b, s /* ERROR too many arguments */ ...)
|
||||||
_ = append(s, 1, 2, 3)
|
_ = append(s, 1, 2, 3)
|
||||||
_ = append(s, 1, 2, 3, x /* ERROR cannot use x */ , 5, 6, 6)
|
_ = append(s, 1, 2, 3, x /* ERROR cannot use x */ , 5, 6, 6)
|
||||||
_ = append(s, 1, 2, s... /* ERROR can only use ... with matching parameter */ )
|
_ = append(s, 1, 2 /* ERROR too many arguments */, s...)
|
||||||
_ = append([]interface{}(nil), 1, 2, "foo", x, 3.1425, false)
|
_ = append([]interface{}(nil), 1, 2, "foo", x, 3.1425, false)
|
||||||
|
|
||||||
type S []byte
|
type S []byte
|
||||||
|
|
|
||||||
22
src/go/types/testdata/expr3.src
vendored
22
src/go/types/testdata/expr3.src
vendored
|
|
@ -492,26 +492,26 @@ func _calls() {
|
||||||
f1(0)
|
f1(0)
|
||||||
f1(x)
|
f1(x)
|
||||||
f1(10.0)
|
f1(10.0)
|
||||||
f1() /* ERROR "too few arguments" */
|
f1() /* ERROR "not enough arguments" */
|
||||||
f1(x, y /* ERROR "too many arguments" */ )
|
f1(x, y /* ERROR "too many arguments" */ )
|
||||||
f1(s /* ERROR "cannot use .* in argument" */ )
|
f1(s /* ERROR "cannot use .* in argument" */ )
|
||||||
f1(x ... /* ERROR "cannot use ..." */ )
|
f1(x ... /* ERROR "cannot use ..." */ )
|
||||||
f1(g0 /* ERROR "used as value" */ ())
|
f1(g0 /* ERROR "used as value" */ ())
|
||||||
f1(g1())
|
f1(g1())
|
||||||
f1(g2 /* ERROR "cannot use g2" */ /* ERROR "too many arguments" */ ())
|
f1(g2 /* ERROR "too many arguments" */ ())
|
||||||
|
|
||||||
f2() /* ERROR "too few arguments" */
|
f2() /* ERROR "not enough arguments" */
|
||||||
f2(3.14) /* ERROR "too few arguments" */
|
f2(3.14) /* ERROR "not enough arguments" */
|
||||||
f2(3.14, "foo")
|
f2(3.14, "foo")
|
||||||
f2(x /* ERROR "cannot use .* in argument" */ , "foo")
|
f2(x /* ERROR "cannot use .* in argument" */ , "foo")
|
||||||
f2(g0 /* ERROR "used as value" */ ())
|
f2(g0 /* ERROR "used as value" */ ())
|
||||||
f2(g1 /* ERROR "cannot use .* in argument" */ ()) /* ERROR "too few arguments" */
|
f2(g1()) /* ERROR "not enough arguments" */
|
||||||
f2(g2())
|
f2(g2())
|
||||||
|
|
||||||
fs() /* ERROR "too few arguments" */
|
fs() /* ERROR "not enough arguments" */
|
||||||
fs(g0 /* ERROR "used as value" */ ())
|
fs(g0 /* ERROR "used as value" */ ())
|
||||||
fs(g1 /* ERROR "cannot use .* in argument" */ ())
|
fs(g1 /* ERROR "cannot use .* in argument" */ ())
|
||||||
fs(g2 /* ERROR "cannot use .* in argument" */ /* ERROR "too many arguments" */ ())
|
fs(g2 /* ERROR "too many arguments" */ ())
|
||||||
fs(gs())
|
fs(gs())
|
||||||
|
|
||||||
fv()
|
fv()
|
||||||
|
|
@ -519,7 +519,7 @@ func _calls() {
|
||||||
fv(s /* ERROR "cannot use .* in argument" */ )
|
fv(s /* ERROR "cannot use .* in argument" */ )
|
||||||
fv(s...)
|
fv(s...)
|
||||||
fv(x /* ERROR "cannot use" */ ...)
|
fv(x /* ERROR "cannot use" */ ...)
|
||||||
fv(1, s... /* ERROR "can only use ... with matching parameter" */ )
|
fv(1, s /* ERROR "too many arguments" */ ...)
|
||||||
fv(gs /* ERROR "cannot use .* in argument" */ ())
|
fv(gs /* ERROR "cannot use .* in argument" */ ())
|
||||||
fv(gs /* ERROR "cannot use .* in argument" */ ()...)
|
fv(gs /* ERROR "cannot use .* in argument" */ ()...)
|
||||||
|
|
||||||
|
|
@ -528,7 +528,7 @@ func _calls() {
|
||||||
t.fm(1, 2.0, x)
|
t.fm(1, 2.0, x)
|
||||||
t.fm(s /* ERROR "cannot use .* in argument" */ )
|
t.fm(s /* ERROR "cannot use .* in argument" */ )
|
||||||
t.fm(g1())
|
t.fm(g1())
|
||||||
t.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
|
t.fm(1, s /* ERROR "too many arguments" */ ...)
|
||||||
t.fm(gs /* ERROR "cannot use .* in argument" */ ())
|
t.fm(gs /* ERROR "cannot use .* in argument" */ ())
|
||||||
t.fm(gs /* ERROR "cannot use .* in argument" */ ()...)
|
t.fm(gs /* ERROR "cannot use .* in argument" */ ()...)
|
||||||
|
|
||||||
|
|
@ -536,7 +536,7 @@ func _calls() {
|
||||||
T.fm(t, 1, 2.0, x)
|
T.fm(t, 1, 2.0, x)
|
||||||
T.fm(t, s /* ERROR "cannot use .* in argument" */ )
|
T.fm(t, s /* ERROR "cannot use .* in argument" */ )
|
||||||
T.fm(t, g1())
|
T.fm(t, g1())
|
||||||
T.fm(t, 1, s... /* ERROR "can only use ... with matching parameter" */ )
|
T.fm(t, 1, s /* ERROR "too many arguments" */ ...)
|
||||||
T.fm(t, gs /* ERROR "cannot use .* in argument" */ ())
|
T.fm(t, gs /* ERROR "cannot use .* in argument" */ ())
|
||||||
T.fm(t, gs /* ERROR "cannot use .* in argument" */ ()...)
|
T.fm(t, gs /* ERROR "cannot use .* in argument" */ ()...)
|
||||||
|
|
||||||
|
|
@ -545,7 +545,7 @@ func _calls() {
|
||||||
i.fm(1, 2.0, x)
|
i.fm(1, 2.0, x)
|
||||||
i.fm(s /* ERROR "cannot use .* in argument" */ )
|
i.fm(s /* ERROR "cannot use .* in argument" */ )
|
||||||
i.fm(g1())
|
i.fm(g1())
|
||||||
i.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
|
i.fm(1, s /* ERROR "too many arguments" */ ...)
|
||||||
i.fm(gs /* ERROR "cannot use .* in argument" */ ())
|
i.fm(gs /* ERROR "cannot use .* in argument" */ ())
|
||||||
i.fm(gs /* ERROR "cannot use .* in argument" */ ()...)
|
i.fm(gs /* ERROR "cannot use .* in argument" */ ()...)
|
||||||
|
|
||||||
|
|
|
||||||
2
src/go/types/testdata/stmt0.src
vendored
2
src/go/types/testdata/stmt0.src
vendored
|
|
@ -86,7 +86,7 @@ func assignments1() {
|
||||||
|
|
||||||
g := func(int, bool){}
|
g := func(int, bool){}
|
||||||
var m map[int]int
|
var m map[int]int
|
||||||
g(m[0]) /* ERROR "too few arguments" */
|
g(m[0]) /* ERROR "not enough arguments" */
|
||||||
|
|
||||||
// assignments to _
|
// assignments to _
|
||||||
_ = nil /* ERROR "use of untyped nil" */
|
_ = nil /* ERROR "use of untyped nil" */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue