Commit 7c03cd32 authored by Robert Griesemer's avatar Robert Griesemer

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
parent 48af64b2
......@@ -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]
}
......@@ -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 }
......
......@@ -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]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment