diff options
author | Matthew Dempsky <mdempsky@google.com> | 2021-04-21 18:22:35 -0700 |
---|---|---|
committer | Matthew Dempsky <mdempsky@google.com> | 2021-04-22 21:23:59 +0000 |
commit | f7afdfd48383c4f0ea8653ea9f8c7b9a3d93abee (patch) | |
tree | 0cb2a09d6cf70f1e9d070b24a72add0b16c4d3aa /src/go/types/expr.go | |
parent | cfe5d79c5c2c9888a0e56e089dca99e405a225b9 (diff) | |
download | go-f7afdfd48383c4f0ea8653ea9f8c7b9a3d93abee.tar.gz go-f7afdfd48383c4f0ea8653ea9f8c7b9a3d93abee.zip |
go/types: cleanup and fix Checker.index
A couple minor spec compliance issues: constant, typed index operands
must still be representable as type "int", but should also be recorded
as their original type.
Fixes #45667.
Change-Id: Iefeb29f20a8e48350af83a62c9ae0e92198c5ef7
Reviewed-on: https://go-review.googlesource.com/c/go/+/312591
Trust: Matthew Dempsky <mdempsky@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src/go/types/expr.go')
-rw-r--r-- | src/go/types/expr.go | 56 |
1 files changed, 36 insertions, 20 deletions
diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 57523e1d0f..b4eea229b8 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -1012,19 +1012,7 @@ func (check *Checker) index(index ast.Expr, max int64) (typ Type, val int64) { var x operand check.expr(&x, index) - if x.mode == invalid { - return - } - - // an untyped constant must be representable as Int - check.convertUntyped(&x, Typ[Int]) - if x.mode == invalid { - return - } - - // the index must be of integer type - if !isInteger(x.typ) { - check.invalidArg(&x, _InvalidIndex, "index %s must be integer", &x) + if !check.isValidIndex(&x, _InvalidIndex, "index", false) { return } @@ -1032,12 +1020,6 @@ func (check *Checker) index(index ast.Expr, max int64) (typ Type, val int64) { return x.typ, -1 } - // a constant index i must be in bounds - if constant.Sign(x.val) < 0 { - check.invalidArg(&x, _InvalidIndex, "index %s must not be negative", &x) - return - } - v, valid := constant.Int64Val(constant.ToInt(x.val)) if !valid || max >= 0 && v >= max { check.errorf(&x, _InvalidIndex, "index %s is out of bounds", &x) @@ -1045,7 +1027,41 @@ func (check *Checker) index(index ast.Expr, max int64) (typ Type, val int64) { } // 0 <= v [ && v < max ] - return Typ[Int], v + return x.typ, v +} + +func (check *Checker) isValidIndex(x *operand, code errorCode, what string, allowNegative bool) bool { + if x.mode == invalid { + return false + } + + // spec: "a constant index that is untyped is given type int" + check.convertUntyped(x, Typ[Int]) + if x.mode == invalid { + return false + } + + // spec: "the index x must be of integer type or an untyped constant" + if !isInteger(x.typ) { + check.invalidArg(x, code, "%s %s must be integer", what, x) + return false + } + + if x.mode == constant_ { + // spec: "a constant index must be non-negative ..." + if !allowNegative && constant.Sign(x.val) < 0 { + check.invalidArg(x, code, "%s %s must not be negative", what, x) + return false + } + + // spec: "... and representable by a value of type int" + if !representableConst(x.val, check, Typ[Int], &x.val) { + check.invalidArg(x, code, "%s %s overflows int", what, x) + return false + } + } + + return true } // indexElts checks the elements (elts) of an array or slice composite literal |