go.tools/go/types: check 3-index slice expressions
R=adonovan CC=golang-dev https://golang.org/cl/13881043
This commit is contained in:
parent
b25f3012f3
commit
9d1c551b43
|
@ -405,7 +405,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("unreachable")
|
unreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
x.expr = call
|
x.expr = call
|
||||||
|
|
|
@ -745,11 +745,15 @@ func (check *checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token) {
|
||||||
// x.typ is unchanged
|
// x.typ is unchanged
|
||||||
}
|
}
|
||||||
|
|
||||||
// index checks an index/size expression arg for validity.
|
// index checks an index expression for validity.
|
||||||
// If length >= 0, it is the upper bound for arg.
|
// If max >= 0, it is the upper bound for index.
|
||||||
func (check *checker) index(arg ast.Expr, length int64) (i int64, ok bool) {
|
// If index is valid and the result i >= 0, then i is the constant value of index.
|
||||||
|
func (check *checker) index(index ast.Expr, max int64) (i int64, valid bool) {
|
||||||
var x operand
|
var x operand
|
||||||
check.expr(&x, arg)
|
check.expr(&x, index)
|
||||||
|
if x.mode == invalid {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// an untyped constant must be representable as Int
|
// an untyped constant must be representable as Int
|
||||||
check.convertUntyped(&x, Typ[Int])
|
check.convertUntyped(&x, Typ[Int])
|
||||||
|
@ -757,24 +761,24 @@ func (check *checker) index(arg ast.Expr, length int64) (i int64, ok bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// the index/size must be of integer type
|
// the index must be of integer type
|
||||||
if !isInteger(x.typ) {
|
if !isInteger(x.typ) {
|
||||||
check.invalidArg(x.pos(), "index %s must be integer", &x)
|
check.invalidArg(x.pos(), "index %s must be integer", &x)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// a constant index/size i must be 0 <= i < length
|
// a constant index i must be in bounds
|
||||||
if x.mode == constant {
|
if x.mode == constant {
|
||||||
if exact.Sign(x.val) < 0 {
|
if exact.Sign(x.val) < 0 {
|
||||||
check.invalidArg(x.pos(), "index %s must not be negative", &x)
|
check.invalidArg(x.pos(), "index %s must not be negative", &x)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i, ok = exact.Int64Val(x.val)
|
i, valid = exact.Int64Val(x.val)
|
||||||
if !ok || length >= 0 && i >= length {
|
if !valid || max >= 0 && i >= max {
|
||||||
check.errorf(x.pos(), "index %s is out of bounds", &x)
|
check.errorf(x.pos(), "index %s is out of bounds", &x)
|
||||||
return i, false
|
return i, false
|
||||||
}
|
}
|
||||||
// 0 <= i [ && i < length ]
|
// 0 <= i [ && i < max ]
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1144,7 +1148,7 @@ func (check *checker) expr0(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Index == nil {
|
if e.Index == nil {
|
||||||
check.invalidAST(e.Pos(), "missing index expression for %s", x)
|
check.invalidAST(e.Pos(), "missing index for %s", x)
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1162,17 +1166,17 @@ func (check *checker) expr0(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
switch typ := x.typ.Underlying().(type) {
|
switch typ := x.typ.Underlying().(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(typ) {
|
if isString(typ) {
|
||||||
|
if e.Slice3 {
|
||||||
|
check.invalidOp(x.pos(), "3-index slice of string")
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
valid = true
|
valid = true
|
||||||
if x.mode == constant {
|
if x.mode == constant {
|
||||||
length = int64(len(exact.StringVal(x.val))) + 1 // +1 for slice
|
length = int64(len(exact.StringVal(x.val)))
|
||||||
}
|
}
|
||||||
// a sliced string always yields a string value
|
// spec: "For untyped string operands the result
|
||||||
// of the same type as the original string (not
|
// is a non-constant value of type string."
|
||||||
// a constant) even if the string and the indices
|
|
||||||
// are constant
|
|
||||||
x.mode = value
|
x.mode = value
|
||||||
// x.typ doesn't change, but if it is an untyped
|
|
||||||
// string it becomes string (see also issue 4913).
|
|
||||||
if typ.kind == UntypedString {
|
if typ.kind == UntypedString {
|
||||||
x.typ = Typ[String]
|
x.typ = Typ[String]
|
||||||
}
|
}
|
||||||
|
@ -1180,7 +1184,7 @@ func (check *checker) expr0(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
|
|
||||||
case *Array:
|
case *Array:
|
||||||
valid = true
|
valid = true
|
||||||
length = typ.len + 1 // +1 for slice
|
length = typ.len
|
||||||
if x.mode != variable {
|
if x.mode != variable {
|
||||||
check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x)
|
check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x)
|
||||||
goto Error
|
goto Error
|
||||||
|
@ -1190,7 +1194,7 @@ func (check *checker) expr0(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
case *Pointer:
|
case *Pointer:
|
||||||
if typ, _ := typ.base.Underlying().(*Array); typ != nil {
|
if typ, _ := typ.base.Underlying().(*Array); typ != nil {
|
||||||
valid = true
|
valid = true
|
||||||
length = typ.len + 1 // +1 for slice
|
length = typ.len
|
||||||
x.mode = variable
|
x.mode = variable
|
||||||
x.typ = &Slice{elt: typ.elt}
|
x.typ = &Slice{elt: typ.elt}
|
||||||
}
|
}
|
||||||
|
@ -1206,25 +1210,50 @@ func (check *checker) expr0(x *operand, e ast.Expr, hint Type) exprKind {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
lo := int64(0)
|
// spec: "Only the first index may be omitted; it defaults to 0."
|
||||||
if e.Low != nil {
|
if e.Slice3 && (e.High == nil || e.Max == nil) {
|
||||||
if i, ok := check.index(e.Low, length); ok && i >= 0 {
|
check.errorf(e.Rbrack, "2nd and 3rd index required in 3-index slice")
|
||||||
lo = i
|
goto Error
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hi := int64(-1)
|
// check indices
|
||||||
if e.High != nil {
|
var ind [3]int64
|
||||||
if i, ok := check.index(e.High, length); ok && i >= 0 {
|
for i, expr := range []ast.Expr{e.Low, e.High, e.Max} {
|
||||||
hi = i
|
x := int64(-1)
|
||||||
|
switch {
|
||||||
|
case expr != nil:
|
||||||
|
// The "capacity" is only known statically for strings, arrays,
|
||||||
|
// and pointers to arrays, and it is the same as the length for
|
||||||
|
// those types.
|
||||||
|
max := int64(-1)
|
||||||
|
if length >= 0 {
|
||||||
|
max = length + 1
|
||||||
}
|
}
|
||||||
} else if length >= 0 {
|
if t, ok := check.index(expr, max); ok && t >= 0 {
|
||||||
hi = length
|
x = t
|
||||||
|
}
|
||||||
|
case i == 0:
|
||||||
|
// default is 0 for the first index
|
||||||
|
x = 0
|
||||||
|
case length >= 0:
|
||||||
|
// default is length (== capacity) otherwise
|
||||||
|
x = length
|
||||||
|
}
|
||||||
|
ind[i] = x
|
||||||
}
|
}
|
||||||
|
|
||||||
if lo >= 0 && hi >= 0 && lo > hi {
|
// constant indices must be in range
|
||||||
check.errorf(e.Low.Pos(), "inverted slice range: %d > %d", lo, hi)
|
// (check.index already checks that existing indices >= 0)
|
||||||
// ok to continue
|
L:
|
||||||
|
for i, x := range ind[:len(ind)-1] {
|
||||||
|
if x > 0 {
|
||||||
|
for _, y := range ind[i+1:] {
|
||||||
|
if y >= 0 && x > y {
|
||||||
|
check.errorf(e.Rbrack, "invalid slice indices: %d > %d", x, y)
|
||||||
|
break L // only report one error, ok to continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ast.TypeAssertExpr:
|
case *ast.TypeAssertExpr:
|
||||||
|
|
|
@ -82,7 +82,7 @@ func (check *checker) suspendedCall(keyword string, call *ast.CallExpr) {
|
||||||
case statement:
|
case statement:
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
panic("unreachable")
|
unreachable()
|
||||||
}
|
}
|
||||||
check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
|
check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,10 @@ func indexes() {
|
||||||
_ = a[- /* ERROR "negative" */ 1]
|
_ = a[- /* ERROR "negative" */ 1]
|
||||||
_ = a[- /* ERROR "negative" */ 1 :]
|
_ = a[- /* ERROR "negative" */ 1 :]
|
||||||
_ = a[: - /* ERROR "negative" */ 1]
|
_ = a[: - /* ERROR "negative" */ 1]
|
||||||
|
_ = a[::] /* ERROR "3-index slice" */
|
||||||
|
_ = a[0::] /* ERROR "3-index slice" */
|
||||||
|
_ = a[0::10] /* ERROR "3-index slice" */
|
||||||
|
_ = a[:10:10]
|
||||||
|
|
||||||
var a0 int
|
var a0 int
|
||||||
a0 = a[0]
|
a0 = a[0]
|
||||||
|
@ -34,6 +38,12 @@ func indexes() {
|
||||||
_ = a[11 /* ERROR "index .* out of bounds" */ :]
|
_ = a[11 /* ERROR "index .* out of bounds" */ :]
|
||||||
_ = a[: 11 /* ERROR "index .* out of bounds" */ ]
|
_ = a[: 11 /* ERROR "index .* out of bounds" */ ]
|
||||||
_ = a[: 1 /* ERROR "overflows" */ <<100]
|
_ = a[: 1 /* ERROR "overflows" */ <<100]
|
||||||
|
_ = a[:10:10]
|
||||||
|
_ = a[:11 /* ERROR "index .* out of bounds" */ :10]
|
||||||
|
_ = a[:10:11 /* ERROR "index .* out of bounds" */ ]
|
||||||
|
_ = a[10:0:10] /* ERROR "invalid slice indices" */
|
||||||
|
_ = a[0:10:0] /* ERROR "invalid slice indices" */
|
||||||
|
_ = a[10:0:0] /* ERROR "invalid slice indices" */
|
||||||
|
|
||||||
pa := &a
|
pa := &a
|
||||||
_ = pa[9]
|
_ = pa[9]
|
||||||
|
@ -45,6 +55,12 @@ func indexes() {
|
||||||
_ = pa[11 /* ERROR "index .* out of bounds" */ :]
|
_ = pa[11 /* ERROR "index .* out of bounds" */ :]
|
||||||
_ = pa[: 11 /* ERROR "index .* out of bounds" */ ]
|
_ = pa[: 11 /* ERROR "index .* out of bounds" */ ]
|
||||||
_ = pa[: 1 /* ERROR "overflows" */ <<100]
|
_ = pa[: 1 /* ERROR "overflows" */ <<100]
|
||||||
|
_ = pa[:10:10]
|
||||||
|
_ = pa[:11 /* ERROR "index .* out of bounds" */ :10]
|
||||||
|
_ = pa[:10:11 /* ERROR "index .* out of bounds" */ ]
|
||||||
|
_ = pa[10:0:10] /* ERROR "invalid slice indices" */
|
||||||
|
_ = pa[0:10:0] /* ERROR "invalid slice indices" */
|
||||||
|
_ = pa[10:0:0] /* ERROR "invalid slice indices" */
|
||||||
|
|
||||||
var b [0]int
|
var b [0]int
|
||||||
_ = b[0 /* ERROR "index .* out of bounds" */ ]
|
_ = b[0 /* ERROR "index .* out of bounds" */ ]
|
||||||
|
@ -52,6 +68,8 @@ func indexes() {
|
||||||
_ = b[0:]
|
_ = b[0:]
|
||||||
_ = b[:0]
|
_ = b[:0]
|
||||||
_ = b[0:0]
|
_ = b[0:0]
|
||||||
|
_ = b[0:0:0]
|
||||||
|
_ = b[1 /* ERROR "index .* out of bounds" */ :0:0]
|
||||||
|
|
||||||
var s []int
|
var s []int
|
||||||
_ = s[- /* ERROR "negative" */ 1]
|
_ = s[- /* ERROR "negative" */ 1]
|
||||||
|
@ -59,16 +77,23 @@ func indexes() {
|
||||||
_ = s[: - /* ERROR "negative" */ 1]
|
_ = s[: - /* ERROR "negative" */ 1]
|
||||||
_ = s[0]
|
_ = s[0]
|
||||||
_ = s[1:2]
|
_ = s[1:2]
|
||||||
_ = s[2 /* ERROR "inverted slice range" */ : 1]
|
_ = s[2:1] /* ERROR "invalid slice indices" */
|
||||||
_ = s[2:]
|
_ = s[2:]
|
||||||
_ = s[: 1 /* ERROR "overflows" */ <<100]
|
_ = s[: 1 /* ERROR "overflows" */ <<100]
|
||||||
_ = s[1 /* ERROR "overflows" */ <<100 :]
|
_ = s[1 /* ERROR "overflows" */ <<100 :]
|
||||||
_ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
|
_ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
|
||||||
|
_ = s[::] /* ERROR "3-index slice" */
|
||||||
|
_ = s[:10:10]
|
||||||
|
_ = s[10:0:10] /* ERROR "invalid slice indices" */
|
||||||
|
_ = s[0:10:0] /* ERROR "invalid slice indices" */
|
||||||
|
_ = s[10:0:0] /* ERROR "invalid slice indices" */
|
||||||
|
|
||||||
var t string
|
var t string
|
||||||
_ = t[- /* ERROR "negative" */ 1]
|
_ = t[- /* ERROR "negative" */ 1]
|
||||||
_ = t[- /* ERROR "negative" */ 1 :]
|
_ = t[- /* ERROR "negative" */ 1 :]
|
||||||
_ = t[: - /* ERROR "negative" */ 1]
|
_ = t[: - /* ERROR "negative" */ 1]
|
||||||
|
_ = t /* ERROR "3-index slice of string" */ [1:2:3]
|
||||||
|
_ = "foo" /* ERROR "3-index slice of string" */ [1:2:3]
|
||||||
var t0 byte
|
var t0 byte
|
||||||
t0 = t[0]
|
t0 = t[0]
|
||||||
_ = t0
|
_ = t0
|
||||||
|
|
Loading…
Reference in New Issue