mirror of
https://github.com/golang/go
synced 2024-11-20 05:04:43 -07:00
exp/type/staging: implemented recent spec changes
Also: - type-checking receivers - get rid of some multiple errors at the same position R=rsc, minux.ma CC=golang-dev https://golang.org/cl/6709061
This commit is contained in:
parent
48af64b295
commit
7c03cd32b6
@ -204,13 +204,27 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
|
||||
check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, n)
|
||||
goto Error
|
||||
}
|
||||
var sizes []interface{} // constant integer arguments, if any
|
||||
for _, arg := range args[1:] {
|
||||
check.expr(x, arg, nil, iota)
|
||||
if !x.isInteger() {
|
||||
if x.isInteger() {
|
||||
if x.mode == constant {
|
||||
if isNegConst(x.val) {
|
||||
check.invalidArg(x.pos(), "%s must not be negative", x)
|
||||
// safe to continue
|
||||
} else {
|
||||
sizes = append(sizes, x.val) // x.val >= 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
check.invalidArg(x.pos(), "%s must be an integer", x)
|
||||
// safe to continue
|
||||
}
|
||||
}
|
||||
if len(sizes) == 2 && compareConst(sizes[0], sizes[1], token.GTR) {
|
||||
check.invalidArg(args[1].Pos(), "length and capacity swapped")
|
||||
// safe to continue
|
||||
}
|
||||
x.mode = variable
|
||||
x.typ = typ0
|
||||
|
||||
|
@ -179,7 +179,8 @@ func (check *checker) ident(name *ast.Ident, cycleOk bool) {
|
||||
ftyp := check.typ(fdecl.Type, cycleOk).(*Signature)
|
||||
obj.Type = ftyp
|
||||
if fdecl.Recv != nil {
|
||||
// TODO(gri) handle method receiver
|
||||
// TODO(gri) is this good enough for the receiver?
|
||||
check.collectFields(token.FUNC, fdecl.Recv, true)
|
||||
}
|
||||
check.stmt(fdecl.Body)
|
||||
|
||||
|
@ -398,38 +398,31 @@ func (check *checker) binary(x, y *operand, op token.Token, hint Type) {
|
||||
}
|
||||
|
||||
// index checks an index expression for validity. If length >= 0, it is the upper
|
||||
// bound for the index. The result is a valid constant index >= 0, or a negative
|
||||
// value.
|
||||
// bound for the index. The result is a valid integer constant, or nil.
|
||||
//
|
||||
func (check *checker) index(index ast.Expr, length int64, iota int) int64 {
|
||||
func (check *checker) index(index ast.Expr, length int64, iota int) interface{} {
|
||||
var x operand
|
||||
var i int64 // index value, valid if >= 0
|
||||
|
||||
check.expr(&x, index, nil, iota)
|
||||
if !x.isInteger() {
|
||||
check.errorf(x.pos(), "index %s must be integer", &x)
|
||||
return -1
|
||||
return nil
|
||||
}
|
||||
if x.mode != constant {
|
||||
return -1 // we cannot check more
|
||||
return nil // we cannot check more
|
||||
}
|
||||
// x.mode == constant and the index value must be >= 0
|
||||
if isNegConst(x.val) {
|
||||
check.errorf(x.pos(), "index %s must not be negative", &x)
|
||||
return -1
|
||||
return nil
|
||||
}
|
||||
var ok bool
|
||||
if i, ok = x.val.(int64); !ok {
|
||||
// index value doesn't fit into an int64
|
||||
i = length // trigger out of bounds check below if we know length (>= 0)
|
||||
}
|
||||
|
||||
if length >= 0 && i >= length {
|
||||
// x.val >= 0
|
||||
if length >= 0 && compareConst(x.val, length, token.GEQ) {
|
||||
check.errorf(x.pos(), "index %s is out of bounds (>= %d)", &x, length)
|
||||
return -1
|
||||
return nil
|
||||
}
|
||||
|
||||
return i
|
||||
return x.val
|
||||
}
|
||||
|
||||
func (check *checker) callRecord(x *operand) {
|
||||
@ -672,18 +665,20 @@ func (check *checker) exprOrType(x *operand, e ast.Expr, hint Type, iota int, cy
|
||||
goto Error
|
||||
}
|
||||
|
||||
var lo int64
|
||||
var lo interface{} = zeroConst
|
||||
if e.Low != nil {
|
||||
lo = check.index(e.Low, length, iota)
|
||||
}
|
||||
|
||||
var hi int64 = length
|
||||
var hi interface{}
|
||||
if e.High != nil {
|
||||
hi = check.index(e.High, length, iota)
|
||||
} else if length >= 0 {
|
||||
hi = length
|
||||
}
|
||||
|
||||
if hi >= 0 && lo > hi {
|
||||
check.errorf(e.Low.Pos(), "inverted slice range: %d > %d", lo, hi)
|
||||
if lo != nil && hi != nil && compareConst(lo, hi, token.GTR) {
|
||||
check.errorf(e.Low.Pos(), "inverted slice range: %v > %v", lo, hi)
|
||||
// ok to continue
|
||||
}
|
||||
|
||||
@ -747,6 +742,8 @@ func (check *checker) exprOrType(x *operand, e ast.Expr, hint Type, iota int, cy
|
||||
case *ast.StarExpr:
|
||||
check.exprOrType(x, e.X, hint, iota, true)
|
||||
switch x.mode {
|
||||
case invalid:
|
||||
// ignore - error reported before
|
||||
case novalue:
|
||||
check.errorf(x.pos(), "%s used as value or type", x)
|
||||
goto Error
|
||||
@ -840,13 +837,16 @@ Error:
|
||||
func (check *checker) expr(x *operand, e ast.Expr, hint Type, iota int) {
|
||||
check.exprOrType(x, e, hint, iota, false)
|
||||
switch x.mode {
|
||||
case invalid:
|
||||
// ignore - error reported before
|
||||
case novalue:
|
||||
check.errorf(x.pos(), "%s used as value", x)
|
||||
x.mode = invalid
|
||||
case typexpr:
|
||||
check.errorf(x.pos(), "%s is not an expression", x)
|
||||
x.mode = invalid
|
||||
default:
|
||||
return
|
||||
}
|
||||
x.mode = invalid
|
||||
}
|
||||
|
||||
// typ is like exprOrType but also checks that e represents a type (rather than a value).
|
||||
@ -855,13 +855,15 @@ func (check *checker) expr(x *operand, e ast.Expr, hint Type, iota int) {
|
||||
func (check *checker) typ(e ast.Expr, cycleOk bool) Type {
|
||||
var x operand
|
||||
check.exprOrType(&x, e, nil, -1, cycleOk)
|
||||
switch {
|
||||
case x.mode == novalue:
|
||||
switch x.mode {
|
||||
case invalid:
|
||||
// ignore - error reported before
|
||||
case novalue:
|
||||
check.errorf(x.pos(), "%s used as type", &x)
|
||||
x.typ = Typ[Invalid]
|
||||
case x.mode != typexpr:
|
||||
case typexpr:
|
||||
return x.typ
|
||||
default:
|
||||
check.errorf(x.pos(), "%s is not a type", &x)
|
||||
x.typ = Typ[Invalid]
|
||||
}
|
||||
return x.typ
|
||||
return Typ[Invalid]
|
||||
}
|
||||
|
141
src/pkg/exp/types/staging/testdata/builtins.src
vendored
141
src/pkg/exp/types/staging/testdata/builtins.src
vendored
@ -68,11 +68,11 @@ func _imag() {
|
||||
var f64 float64
|
||||
var c64 complex64
|
||||
var c128 complex128
|
||||
_0 := imag /* ERROR "argument" */ ()
|
||||
_1 := imag /* ERROR "argument" */ (1, 2)
|
||||
_2 := imag(10 /* ERROR "must be a complex number" */)
|
||||
_3 := imag(2.7182818 /* ERROR "must be a complex number" */)
|
||||
_4 := imag("foo" /* ERROR "must be a complex number" */)
|
||||
_ = imag /* ERROR "argument" */ ()
|
||||
_ = imag /* ERROR "argument" */ (1, 2)
|
||||
_ = imag(10 /* ERROR "must be a complex number" */)
|
||||
_ = imag(2.7182818 /* ERROR "must be a complex number" */)
|
||||
_ = imag("foo" /* ERROR "must be a complex number" */)
|
||||
const _5 = imag(1 + 2i)
|
||||
assert(_5 == 2)
|
||||
f32 = _5
|
||||
@ -92,16 +92,16 @@ func _len() {
|
||||
var p *[20]int
|
||||
var s []int
|
||||
var m map[string]complex128
|
||||
_0 := len /* ERROR "argument" */ ()
|
||||
_1 := len /* ERROR "argument" */ (1, 2)
|
||||
_2 := len(42 /* ERROR "invalid" */)
|
||||
_ = len /* ERROR "argument" */ ()
|
||||
_ = len /* ERROR "argument" */ (1, 2)
|
||||
_ = len(42 /* ERROR "invalid" */)
|
||||
const _3 = len(c)
|
||||
assert(_3 == 6)
|
||||
const _4 = len(a)
|
||||
assert(_4 == 10)
|
||||
const _5 = len(p)
|
||||
assert(_5 == 20)
|
||||
_6 := len(m)
|
||||
_ = len(m)
|
||||
len /* ERROR "not used" */ (c)
|
||||
|
||||
// esoteric case
|
||||
@ -111,54 +111,59 @@ func _len() {
|
||||
assert /* ERROR "failed" */ (n == 10)
|
||||
var ch <-chan int
|
||||
const nn = len /* ERROR "not constant" */ (hash[<-ch][len(t)])
|
||||
_7 := nn // TODO(gri) remove this once unused constants get type-checked
|
||||
_ = nn // TODO(gri) remove this once unused constants get type-checked
|
||||
}
|
||||
|
||||
func _make() {
|
||||
n := 0
|
||||
|
||||
_0 := make /* ERROR "argument" */ ()
|
||||
_1 := make(1 /* ERROR "not a type" */)
|
||||
_2 := make(int /* ERROR "cannot make" */)
|
||||
_ = make /* ERROR "argument" */ ()
|
||||
_ = make(1 /* ERROR "not a type" */)
|
||||
_ = make(int /* ERROR "cannot make" */)
|
||||
|
||||
// slices
|
||||
_3 := make/* ERROR "arguments" */ ([]int)
|
||||
_4 := make/* ERROR "arguments" */ ([]int, 2, 3, 4)
|
||||
_5 := make([]int, int /* ERROR "not an expression" */)
|
||||
_6 := make([]int, 10, float32 /* ERROR "not an expression" */)
|
||||
_7 := make([]int, "foo" /* ERROR "must be an integer" */)
|
||||
_8 := make([]int, 10, 2.3 /* ERROR "must be an integer" */)
|
||||
_9 := make([]int, 5, 10.0)
|
||||
_10 := make([]int, 0i)
|
||||
_11 := make([]int, -1, 1<<100) // out-of-range constants lead to run-time errors
|
||||
_ = make/* ERROR "arguments" */ ([]int)
|
||||
_ = make/* ERROR "arguments" */ ([]int, 2, 3, 4)
|
||||
_ = make([]int, int /* ERROR "not an expression" */)
|
||||
_ = make([]int, 10, float32 /* ERROR "not an expression" */)
|
||||
_ = make([]int, "foo" /* ERROR "must be an integer" */)
|
||||
_ = make([]int, 10, 2.3 /* ERROR "must be an integer" */)
|
||||
_ = make([]int, 5, 10.0)
|
||||
_ = make([]int, 0i)
|
||||
_ = make([]int, - /* ERROR "must not be negative" */ 1, 10)
|
||||
_ = make([]int, 0, - /* ERROR "must not be negative" */ 1)
|
||||
_ = make([]int, - /* ERROR "must not be negative" */ 1, - /* ERROR "must not be negative" */ 1)
|
||||
_ = make([]int, 1<<100, 1<<100) // run-time panic
|
||||
_ = make([]int, 1 /* ERROR "length and capacity swapped" */ <<100 + 1, 1<<100)
|
||||
_ = make([]int, 1 /* ERROR "length and capacity swapped" */ <<100, 12345)
|
||||
|
||||
// maps
|
||||
_12 := make /* ERROR "arguments" */ (map[int]string, 10, 20)
|
||||
_13 := make(map[int]float32, int /* ERROR "not an expression" */)
|
||||
_14 := make(map[int]float32, "foo" /* ERROR "must be an integer" */)
|
||||
_15 := make(map[int]float32, 10)
|
||||
_16 := make(map[int]float32, n)
|
||||
_17 := make(map[int]float32, int64(n))
|
||||
_ = make /* ERROR "arguments" */ (map[int]string, 10, 20)
|
||||
_ = make(map[int]float32, int /* ERROR "not an expression" */)
|
||||
_ = make(map[int]float32, "foo" /* ERROR "must be an integer" */)
|
||||
_ = make(map[int]float32, 10)
|
||||
_ = make(map[int]float32, n)
|
||||
_ = make(map[int]float32, int64(n))
|
||||
|
||||
// channels
|
||||
_22 := make /* ERROR "arguments" */ (chan int, 10, 20)
|
||||
_23 := make(chan int, int /* ERROR "not an expression" */)
|
||||
_24 := make(chan<- int, "foo" /* ERROR "must be an integer" */)
|
||||
_25 := make(<-chan float64, 10)
|
||||
_26 := make(chan chan int, n)
|
||||
_27 := make(chan string, int64(n))
|
||||
_ = make /* ERROR "arguments" */ (chan int, 10, 20)
|
||||
_ = make(chan int, int /* ERROR "not an expression" */)
|
||||
_ = make(chan<- int, "foo" /* ERROR "must be an integer" */)
|
||||
_ = make(<-chan float64, 10)
|
||||
_ = make(chan chan int, n)
|
||||
_ = make(chan string, int64(n))
|
||||
|
||||
make /* ERROR "not used" */ ([]int, 10)
|
||||
}
|
||||
|
||||
func _new() {
|
||||
_0 := new /* ERROR "argument" */ ()
|
||||
_1 := new /* ERROR "argument" */ (1, 2)
|
||||
_3 := new("foo" /* ERROR "not a type" */)
|
||||
_4 := new(float64)
|
||||
_5 := new(struct{ x, y int })
|
||||
_6 := new(*float64)
|
||||
_7 := *_4 == **_6
|
||||
_ = new /* ERROR "argument" */ ()
|
||||
_ = new /* ERROR "argument" */ (1, 2)
|
||||
_ = new("foo" /* ERROR "not a type" */)
|
||||
p := new(float64)
|
||||
_ = new(struct{ x, y int })
|
||||
q := new(*float64)
|
||||
_ = *p == **q
|
||||
new /* ERROR "not used" */ (int)
|
||||
}
|
||||
|
||||
@ -167,11 +172,11 @@ func _real() {
|
||||
var f64 float64
|
||||
var c64 complex64
|
||||
var c128 complex128
|
||||
_0 := real /* ERROR "argument" */ ()
|
||||
_1 := real /* ERROR "argument" */ (1, 2)
|
||||
_2 := real(10 /* ERROR "must be a complex number" */)
|
||||
_3 := real(2.7182818 /* ERROR "must be a complex number" */)
|
||||
_4 := real("foo" /* ERROR "must be a complex number" */)
|
||||
_ = real /* ERROR "argument" */ ()
|
||||
_ = real /* ERROR "argument" */ (1, 2)
|
||||
_ = real(10 /* ERROR "must be a complex number" */)
|
||||
_ = real(2.7182818 /* ERROR "must be a complex number" */)
|
||||
_ = real("foo" /* ERROR "must be a complex number" */)
|
||||
const _5 = real(1 + 2i)
|
||||
assert(_5 == 1)
|
||||
f32 = _5
|
||||
@ -186,40 +191,40 @@ func _real() {
|
||||
}
|
||||
|
||||
func _recover() {
|
||||
_0 := recover()
|
||||
_1 := recover /* ERROR "argument" */ (10)
|
||||
_ = recover()
|
||||
_ = recover /* ERROR "argument" */ (10)
|
||||
recover()
|
||||
}
|
||||
|
||||
func _Alignof() {
|
||||
var x int
|
||||
_0 := unsafe /* ERROR "argument" */ .Alignof()
|
||||
_1 := unsafe /* ERROR "argument" */ .Alignof(1, 2)
|
||||
_3 := unsafe.Alignof(int /* ERROR "not an expression" */)
|
||||
_4 := unsafe.Alignof(42)
|
||||
_5 := unsafe.Alignof(new(struct{}))
|
||||
_ = unsafe /* ERROR "argument" */ .Alignof()
|
||||
_ = unsafe /* ERROR "argument" */ .Alignof(1, 2)
|
||||
_ = unsafe.Alignof(int /* ERROR "not an expression" */)
|
||||
_ = unsafe.Alignof(42)
|
||||
_ = unsafe.Alignof(new(struct{}))
|
||||
unsafe /* ERROR "not used" */ .Alignof(x)
|
||||
}
|
||||
|
||||
func _Offsetof() {
|
||||
var x struct{ f int }
|
||||
_0 := unsafe /* ERROR "argument" */ .Offsetof()
|
||||
_1 := unsafe /* ERROR "argument" */ .Offsetof(1, 2)
|
||||
_2 := unsafe.Offsetof(int /* ERROR "not an expression" */)
|
||||
_3 := unsafe.Offsetof(x /* ERROR "not a selector" */)
|
||||
_4 := unsafe.Offsetof(x.f)
|
||||
_5 := unsafe.Offsetof((x.f))
|
||||
_6 := unsafe.Offsetof((((((((x))).f)))))
|
||||
_ = unsafe /* ERROR "argument" */ .Offsetof()
|
||||
_ = unsafe /* ERROR "argument" */ .Offsetof(1, 2)
|
||||
_ = unsafe.Offsetof(int /* ERROR "not an expression" */)
|
||||
_ = unsafe.Offsetof(x /* ERROR "not a selector" */)
|
||||
_ = unsafe.Offsetof(x.f)
|
||||
_ = unsafe.Offsetof((x.f))
|
||||
_ = unsafe.Offsetof((((((((x))).f)))))
|
||||
unsafe /* ERROR "not used" */ .Offsetof(x.f)
|
||||
}
|
||||
|
||||
func _Sizeof() {
|
||||
var x int
|
||||
_0 := unsafe /* ERROR "argument" */ .Sizeof()
|
||||
_1 := unsafe /* ERROR "argument" */ .Sizeof(1, 2)
|
||||
_2 := unsafe.Sizeof(int /* ERROR "not an expression" */)
|
||||
_3 := unsafe.Sizeof(42)
|
||||
_4 := unsafe.Sizeof(new(complex128))
|
||||
_ = unsafe /* ERROR "argument" */ .Sizeof()
|
||||
_ = unsafe /* ERROR "argument" */ .Sizeof(1, 2)
|
||||
_ = unsafe.Sizeof(int /* ERROR "not an expression" */)
|
||||
_ = unsafe.Sizeof(42)
|
||||
_ = unsafe.Sizeof(new(complex128))
|
||||
unsafe /* ERROR "not used" */ .Sizeof(x)
|
||||
|
||||
// basic types have size guarantees
|
||||
@ -252,7 +257,7 @@ func _assert() {
|
||||
// self-testing only
|
||||
func _trace() {
|
||||
// Uncomment the code below to test trace - will produce console output
|
||||
// _0 := trace /* ERROR "no value" */ ()
|
||||
// _1 := trace(1)
|
||||
// _2 := trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
|
||||
// _ = trace /* ERROR "no value" */ ()
|
||||
// _ = trace(1)
|
||||
// _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
const pi = 3.1415
|
||||
|
||||
type (
|
||||
N undeclared /* ERROR "undeclared" */ /* ERROR "not a type" */
|
||||
N undeclared /* ERROR "undeclared" */
|
||||
B bool
|
||||
I int32
|
||||
A [10]P
|
||||
@ -41,7 +41,7 @@ type (
|
||||
|
||||
|
||||
type (
|
||||
p1 pi /* ERROR "no field or method foo" */ /* ERROR "not a type" */ .foo
|
||||
p1 pi /* ERROR "no field or method foo" */ .foo
|
||||
p2 unsafe.Pointer
|
||||
)
|
||||
|
||||
|
@ -26,7 +26,7 @@ var (
|
||||
array []byte
|
||||
iface interface{}
|
||||
|
||||
blank _ /* ERROR "cannot use _" */ /* ERROR "not a type" */
|
||||
blank _ /* ERROR "cannot use _" */
|
||||
)
|
||||
|
||||
// Global variables with initialization
|
||||
@ -63,8 +63,8 @@ var (
|
||||
t12 complex64 = -(u + *t11) / *&v
|
||||
t13 int = a /* ERROR "shifted operand" */ << d
|
||||
t14 int = i << j /* ERROR "must be unsigned" */
|
||||
t15 math /* ERROR "not in selector" */ /* ERROR "not a type" */
|
||||
t16 math /* ERROR "not a type" */ .xxx /* ERROR "unexported" */
|
||||
t15 math /* ERROR "not in selector" */
|
||||
t16 math.xxx /* ERROR "unexported" */
|
||||
t17 math /* ERROR "not a type" */ .Pi
|
||||
t18 float64 = math.Pi * 10.0
|
||||
t19 int = t1 /* ERROR "cannot call" */ ()
|
||||
|
@ -28,9 +28,10 @@ type T2 struct {
|
||||
func (undeclared /* ERROR "undeclared" */) m() {}
|
||||
func (x *undeclared /* ERROR "undeclared" */) m() {}
|
||||
|
||||
func (pi /* ERROR "not a type" */) m1() {}
|
||||
func (x pi /* ERROR "not a type" */) m2() {}
|
||||
func (x *pi /* ERROR "not a type" */) m3() {}
|
||||
// TODO(gri) try to get rid of double error reporting here
|
||||
func (pi /* ERROR "not a type" */ /* ERROR "not a type" */) m1() {}
|
||||
func (x pi /* ERROR "not a type" */ /* ERROR "not a type" */) m2() {}
|
||||
func (x *pi /* ERROR "not a type" */ /* ERROR "cannot indirect" */) m3() {} // TODO(gri) not closing the last /* comment crashes the system
|
||||
|
||||
// Blank types.
|
||||
type _ struct { m int }
|
||||
|
5
src/pkg/exp/types/staging/testdata/expr3.src
vendored
5
src/pkg/exp/types/staging/testdata/expr3.src
vendored
@ -88,6 +88,11 @@ func indexes() {
|
||||
_ = s[1 : 2]
|
||||
_ = s[2 /* ERROR "inverted slice range" */ : 1]
|
||||
_ = s[2 :]
|
||||
_ = s[: 1<<100]
|
||||
_ = s[1<<100 :]
|
||||
_ = s[1<<100 : 1<<100]
|
||||
_ = s[1 /* ERROR "inverted slice range" */ <<100+1 : 1<<100]
|
||||
_ = s[1 /* ERROR "inverted slice range" */ <<100+1 : 10]
|
||||
|
||||
var t string
|
||||
_ = t[- /* ERROR "index .* negative" */ 1]
|
||||
|
Loading…
Reference in New Issue
Block a user