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 ...@@ -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) check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, n)
goto Error goto Error
} }
var sizes []interface{} // constant integer arguments, if any
for _, arg := range args[1:] { for _, arg := range args[1:] {
check.expr(x, arg, nil, iota) 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) check.invalidArg(x.pos(), "%s must be an integer", x)
// safe to continue // 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.mode = variable
x.typ = typ0 x.typ = typ0
......
...@@ -179,7 +179,8 @@ func (check *checker) ident(name *ast.Ident, cycleOk bool) { ...@@ -179,7 +179,8 @@ func (check *checker) ident(name *ast.Ident, cycleOk bool) {
ftyp := check.typ(fdecl.Type, cycleOk).(*Signature) ftyp := check.typ(fdecl.Type, cycleOk).(*Signature)
obj.Type = ftyp obj.Type = ftyp
if fdecl.Recv != nil { 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) check.stmt(fdecl.Body)
......
...@@ -398,38 +398,31 @@ func (check *checker) binary(x, y *operand, op token.Token, hint Type) { ...@@ -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 // 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 // bound for the index. The result is a valid integer constant, or nil.
// value.
// //
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 x operand
var i int64 // index value, valid if >= 0
check.expr(&x, index, nil, iota) check.expr(&x, index, nil, iota)
if !x.isInteger() { if !x.isInteger() {
check.errorf(x.pos(), "index %s must be integer", &x) check.errorf(x.pos(), "index %s must be integer", &x)
return -1 return nil
} }
if x.mode != constant { 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 // x.mode == constant and the index value must be >= 0
if isNegConst(x.val) { if isNegConst(x.val) {
check.errorf(x.pos(), "index %s must not be negative", &x) check.errorf(x.pos(), "index %s must not be negative", &x)
return -1 return nil
} }
var ok bool // x.val >= 0
if i, ok = x.val.(int64); !ok { if length >= 0 && compareConst(x.val, length, token.GEQ) {
// 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 {
check.errorf(x.pos(), "index %s is out of bounds (>= %d)", &x, length) 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) { func (check *checker) callRecord(x *operand) {
...@@ -672,18 +665,20 @@ func (check *checker) exprOrType(x *operand, e ast.Expr, hint Type, iota int, cy ...@@ -672,18 +665,20 @@ func (check *checker) exprOrType(x *operand, e ast.Expr, hint Type, iota int, cy
goto Error goto Error
} }
var lo int64 var lo interface{} = zeroConst
if e.Low != nil { if e.Low != nil {
lo = check.index(e.Low, length, iota) lo = check.index(e.Low, length, iota)
} }
var hi int64 = length var hi interface{}
if e.High != nil { if e.High != nil {
hi = check.index(e.High, length, iota) hi = check.index(e.High, length, iota)
} else if length >= 0 {
hi = length
} }
if hi >= 0 && lo > hi { if lo != nil && hi != nil && compareConst(lo, hi, token.GTR) {
check.errorf(e.Low.Pos(), "inverted slice range: %d > %d", lo, hi) check.errorf(e.Low.Pos(), "inverted slice range: %v > %v", lo, hi)
// ok to continue // ok to continue
} }
...@@ -747,6 +742,8 @@ func (check *checker) exprOrType(x *operand, e ast.Expr, hint Type, iota int, cy ...@@ -747,6 +742,8 @@ func (check *checker) exprOrType(x *operand, e ast.Expr, hint Type, iota int, cy
case *ast.StarExpr: case *ast.StarExpr:
check.exprOrType(x, e.X, hint, iota, true) check.exprOrType(x, e.X, hint, iota, true)
switch x.mode { switch x.mode {
case invalid:
// ignore - error reported before
case novalue: case novalue:
check.errorf(x.pos(), "%s used as value or type", x) check.errorf(x.pos(), "%s used as value or type", x)
goto Error goto Error
...@@ -840,13 +837,16 @@ Error: ...@@ -840,13 +837,16 @@ Error:
func (check *checker) expr(x *operand, e ast.Expr, hint Type, iota int) { func (check *checker) expr(x *operand, e ast.Expr, hint Type, iota int) {
check.exprOrType(x, e, hint, iota, false) check.exprOrType(x, e, hint, iota, false)
switch x.mode { switch x.mode {
case invalid:
// ignore - error reported before
case novalue: case novalue:
check.errorf(x.pos(), "%s used as value", x) check.errorf(x.pos(), "%s used as value", x)
x.mode = invalid
case typexpr: case typexpr:
check.errorf(x.pos(), "%s is not an expression", x) 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). // 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) { ...@@ -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 { func (check *checker) typ(e ast.Expr, cycleOk bool) Type {
var x operand var x operand
check.exprOrType(&x, e, nil, -1, cycleOk) check.exprOrType(&x, e, nil, -1, cycleOk)
switch { switch x.mode {
case x.mode == novalue: case invalid:
// ignore - error reported before
case novalue:
check.errorf(x.pos(), "%s used as type", &x) check.errorf(x.pos(), "%s used as type", &x)
x.typ = Typ[Invalid] case typexpr:
case x.mode != typexpr: return x.typ
default:
check.errorf(x.pos(), "%s is not a type", &x) 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() { ...@@ -68,11 +68,11 @@ func _imag() {
var f64 float64 var f64 float64
var c64 complex64 var c64 complex64
var c128 complex128 var c128 complex128
_0 := imag /* ERROR "argument" */ () _ = imag /* ERROR "argument" */ ()
_1 := imag /* ERROR "argument" */ (1, 2) _ = imag /* ERROR "argument" */ (1, 2)
_2 := imag(10 /* ERROR "must be a complex number" */) _ = imag(10 /* ERROR "must be a complex number" */)
_3 := imag(2.7182818 /* ERROR "must be a complex number" */) _ = imag(2.7182818 /* ERROR "must be a complex number" */)
_4 := imag("foo" /* ERROR "must be a complex number" */) _ = imag("foo" /* ERROR "must be a complex number" */)
const _5 = imag(1 + 2i) const _5 = imag(1 + 2i)
assert(_5 == 2) assert(_5 == 2)
f32 = _5 f32 = _5
...@@ -92,16 +92,16 @@ func _len() { ...@@ -92,16 +92,16 @@ func _len() {
var p *[20]int var p *[20]int
var s []int var s []int
var m map[string]complex128 var m map[string]complex128
_0 := len /* ERROR "argument" */ () _ = len /* ERROR "argument" */ ()
_1 := len /* ERROR "argument" */ (1, 2) _ = len /* ERROR "argument" */ (1, 2)
_2 := len(42 /* ERROR "invalid" */) _ = len(42 /* ERROR "invalid" */)
const _3 = len(c) const _3 = len(c)
assert(_3 == 6) assert(_3 == 6)
const _4 = len(a) const _4 = len(a)
assert(_4 == 10) assert(_4 == 10)
const _5 = len(p) const _5 = len(p)
assert(_5 == 20) assert(_5 == 20)
_6 := len(m) _ = len(m)
len /* ERROR "not used" */ (c) len /* ERROR "not used" */ (c)
// esoteric case // esoteric case
...@@ -111,54 +111,59 @@ func _len() { ...@@ -111,54 +111,59 @@ func _len() {
assert /* ERROR "failed" */ (n == 10) assert /* ERROR "failed" */ (n == 10)
var ch <-chan int var ch <-chan int
const nn = len /* ERROR "not constant" */ (hash[<-ch][len(t)]) 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() { func _make() {
n := 0 n := 0
_0 := make /* ERROR "argument" */ () _ = make /* ERROR "argument" */ ()
_1 := make(1 /* ERROR "not a type" */) _ = make(1 /* ERROR "not a type" */)
_2 := make(int /* ERROR "cannot make" */) _ = make(int /* ERROR "cannot make" */)
// slices // slices
_3 := make/* ERROR "arguments" */ ([]int) _ = make/* ERROR "arguments" */ ([]int)
_4 := make/* ERROR "arguments" */ ([]int, 2, 3, 4) _ = make/* ERROR "arguments" */ ([]int, 2, 3, 4)
_5 := make([]int, int /* ERROR "not an expression" */) _ = make([]int, int /* ERROR "not an expression" */)
_6 := make([]int, 10, float32 /* ERROR "not an expression" */) _ = make([]int, 10, float32 /* ERROR "not an expression" */)
_7 := make([]int, "foo" /* ERROR "must be an integer" */) _ = make([]int, "foo" /* ERROR "must be an integer" */)
_8 := make([]int, 10, 2.3 /* ERROR "must be an integer" */) _ = make([]int, 10, 2.3 /* ERROR "must be an integer" */)
_9 := make([]int, 5, 10.0) _ = make([]int, 5, 10.0)
_10 := make([]int, 0i) _ = make([]int, 0i)
_11 := make([]int, -1, 1<<100) // out-of-range constants lead to run-time errors _ = 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 // maps
_12 := make /* ERROR "arguments" */ (map[int]string, 10, 20) _ = make /* ERROR "arguments" */ (map[int]string, 10, 20)
_13 := make(map[int]float32, int /* ERROR "not an expression" */) _ = make(map[int]float32, int /* ERROR "not an expression" */)
_14 := make(map[int]float32, "foo" /* ERROR "must be an integer" */) _ = make(map[int]float32, "foo" /* ERROR "must be an integer" */)
_15 := make(map[int]float32, 10) _ = make(map[int]float32, 10)
_16 := make(map[int]float32, n) _ = make(map[int]float32, n)
_17 := make(map[int]float32, int64(n)) _ = make(map[int]float32, int64(n))
// channels // channels
_22 := make /* ERROR "arguments" */ (chan int, 10, 20) _ = make /* ERROR "arguments" */ (chan int, 10, 20)
_23 := make(chan int, int /* ERROR "not an expression" */) _ = make(chan int, int /* ERROR "not an expression" */)
_24 := make(chan<- int, "foo" /* ERROR "must be an integer" */) _ = make(chan<- int, "foo" /* ERROR "must be an integer" */)
_25 := make(<-chan float64, 10) _ = make(<-chan float64, 10)
_26 := make(chan chan int, n) _ = make(chan chan int, n)
_27 := make(chan string, int64(n)) _ = make(chan string, int64(n))
make /* ERROR "not used" */ ([]int, 10) make /* ERROR "not used" */ ([]int, 10)
} }
func _new() { func _new() {
_0 := new /* ERROR "argument" */ () _ = new /* ERROR "argument" */ ()
_1 := new /* ERROR "argument" */ (1, 2) _ = new /* ERROR "argument" */ (1, 2)
_3 := new("foo" /* ERROR "not a type" */) _ = new("foo" /* ERROR "not a type" */)
_4 := new(float64) p := new(float64)
_5 := new(struct{ x, y int }) _ = new(struct{ x, y int })
_6 := new(*float64) q := new(*float64)
_7 := *_4 == **_6 _ = *p == **q
new /* ERROR "not used" */ (int) new /* ERROR "not used" */ (int)
} }
...@@ -167,11 +172,11 @@ func _real() { ...@@ -167,11 +172,11 @@ func _real() {
var f64 float64 var f64 float64
var c64 complex64 var c64 complex64
var c128 complex128 var c128 complex128
_0 := real /* ERROR "argument" */ () _ = real /* ERROR "argument" */ ()
_1 := real /* ERROR "argument" */ (1, 2) _ = real /* ERROR "argument" */ (1, 2)
_2 := real(10 /* ERROR "must be a complex number" */) _ = real(10 /* ERROR "must be a complex number" */)
_3 := real(2.7182818 /* ERROR "must be a complex number" */) _ = real(2.7182818 /* ERROR "must be a complex number" */)
_4 := real("foo" /* ERROR "must be a complex number" */) _ = real("foo" /* ERROR "must be a complex number" */)
const _5 = real(1 + 2i) const _5 = real(1 + 2i)
assert(_5 == 1) assert(_5 == 1)
f32 = _5 f32 = _5
...@@ -186,40 +191,40 @@ func _real() { ...@@ -186,40 +191,40 @@ func _real() {
} }
func _recover() { func _recover() {
_0 := recover() _ = recover()
_1 := recover /* ERROR "argument" */ (10) _ = recover /* ERROR "argument" */ (10)
recover() recover()
} }
func _Alignof() { func _Alignof() {
var x int var x int
_0 := unsafe /* ERROR "argument" */ .Alignof() _ = unsafe /* ERROR "argument" */ .Alignof()
_1 := unsafe /* ERROR "argument" */ .Alignof(1, 2) _ = unsafe /* ERROR "argument" */ .Alignof(1, 2)
_3 := unsafe.Alignof(int /* ERROR "not an expression" */) _ = unsafe.Alignof(int /* ERROR "not an expression" */)
_4 := unsafe.Alignof(42) _ = unsafe.Alignof(42)
_5 := unsafe.Alignof(new(struct{})) _ = unsafe.Alignof(new(struct{}))
unsafe /* ERROR "not used" */ .Alignof(x) unsafe /* ERROR "not used" */ .Alignof(x)
} }
func _Offsetof() { func _Offsetof() {
var x struct{ f int } var x struct{ f int }
_0 := unsafe /* ERROR "argument" */ .Offsetof() _ = unsafe /* ERROR "argument" */ .Offsetof()
_1 := unsafe /* ERROR "argument" */ .Offsetof(1, 2) _ = unsafe /* ERROR "argument" */ .Offsetof(1, 2)
_2 := unsafe.Offsetof(int /* ERROR "not an expression" */) _ = unsafe.Offsetof(int /* ERROR "not an expression" */)
_3 := unsafe.Offsetof(x /* ERROR "not a selector" */) _ = unsafe.Offsetof(x /* ERROR "not a selector" */)
_4 := unsafe.Offsetof(x.f) _ = unsafe.Offsetof(x.f)
_5 := unsafe.Offsetof((x.f)) _ = unsafe.Offsetof((x.f))
_6 := unsafe.Offsetof((((((((x))).f))))) _ = unsafe.Offsetof((((((((x))).f)))))
unsafe /* ERROR "not used" */ .Offsetof(x.f) unsafe /* ERROR "not used" */ .Offsetof(x.f)
} }
func _Sizeof() { func _Sizeof() {
var x int var x int
_0 := unsafe /* ERROR "argument" */ .Sizeof() _ = unsafe /* ERROR "argument" */ .Sizeof()
_1 := unsafe /* ERROR "argument" */ .Sizeof(1, 2) _ = unsafe /* ERROR "argument" */ .Sizeof(1, 2)
_2 := unsafe.Sizeof(int /* ERROR "not an expression" */) _ = unsafe.Sizeof(int /* ERROR "not an expression" */)
_3 := unsafe.Sizeof(42) _ = unsafe.Sizeof(42)
_4 := unsafe.Sizeof(new(complex128)) _ = unsafe.Sizeof(new(complex128))
unsafe /* ERROR "not used" */ .Sizeof(x) unsafe /* ERROR "not used" */ .Sizeof(x)
// basic types have size guarantees // basic types have size guarantees
...@@ -252,7 +257,7 @@ func _assert() { ...@@ -252,7 +257,7 @@ func _assert() {
// self-testing only // self-testing only
func _trace() { func _trace() {
// Uncomment the code below to test trace - will produce console output // Uncomment the code below to test trace - will produce console output
// _0 := trace /* ERROR "no value" */ () // _ = trace /* ERROR "no value" */ ()
// _1 := trace(1) // _ = trace(1)
// _2 := trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar") // _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
} }
...@@ -16,7 +16,7 @@ import ( ...@@ -16,7 +16,7 @@ import (
const pi = 3.1415 const pi = 3.1415
type ( type (
N undeclared /* ERROR "undeclared" */ /* ERROR "not a type" */ N undeclared /* ERROR "undeclared" */
B bool B bool
I int32 I int32
A [10]P A [10]P
...@@ -41,7 +41,7 @@ type ( ...@@ -41,7 +41,7 @@ type (
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 p2 unsafe.Pointer
) )
......
...@@ -26,7 +26,7 @@ var ( ...@@ -26,7 +26,7 @@ var (
array []byte array []byte
iface interface{} iface interface{}
blank _ /* ERROR "cannot use _" */ /* ERROR "not a type" */ blank _ /* ERROR "cannot use _" */
) )
// Global variables with initialization // Global variables with initialization
...@@ -63,8 +63,8 @@ var ( ...@@ -63,8 +63,8 @@ var (
t12 complex64 = -(u + *t11) / *&v t12 complex64 = -(u + *t11) / *&v
t13 int = a /* ERROR "shifted operand" */ << d t13 int = a /* ERROR "shifted operand" */ << d
t14 int = i << j /* ERROR "must be unsigned" */ t14 int = i << j /* ERROR "must be unsigned" */
t15 math /* ERROR "not in selector" */ /* ERROR "not a type" */ t15 math /* ERROR "not in selector" */
t16 math /* ERROR "not a type" */ .xxx /* ERROR "unexported" */ t16 math.xxx /* ERROR "unexported" */
t17 math /* ERROR "not a type" */ .Pi t17 math /* ERROR "not a type" */ .Pi
t18 float64 = math.Pi * 10.0 t18 float64 = math.Pi * 10.0
t19 int = t1 /* ERROR "cannot call" */ () t19 int = t1 /* ERROR "cannot call" */ ()
......
...@@ -28,9 +28,10 @@ type T2 struct { ...@@ -28,9 +28,10 @@ type T2 struct {
func (undeclared /* ERROR "undeclared" */) m() {} func (undeclared /* ERROR "undeclared" */) m() {}
func (x *undeclared /* ERROR "undeclared" */) m() {} func (x *undeclared /* ERROR "undeclared" */) m() {}
func (pi /* ERROR "not a type" */) m1() {} // TODO(gri) try to get rid of double error reporting here
func (x pi /* ERROR "not a type" */) m2() {} func (pi /* ERROR "not a type" */ /* ERROR "not a type" */) m1() {}
func (x *pi /* ERROR "not a type" */) m3() {} 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. // Blank types.
type _ struct { m int } type _ struct { m int }
......
...@@ -88,6 +88,11 @@ func indexes() { ...@@ -88,6 +88,11 @@ func indexes() {
_ = s[1 : 2] _ = s[1 : 2]
_ = s[2 /* ERROR "inverted slice range" */ : 1] _ = s[2 /* ERROR "inverted slice range" */ : 1]
_ = s[2 :] _ = 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 var t string
_ = t[- /* ERROR "index .* negative" */ 1] _ = 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