1
0
mirror of https://github.com/golang/go synced 2024-10-01 05:28:33 -06:00

go.tools/go/types: test against test/fixedbugs

Fixed several bugs:
- lhs blank identifier may be parenthesized: (_) = 0 is ok
- constant shift counts in non-constant shifts must be >= 0
- init functions must have a body

Classified currently failing tests:
- 10 classes of errors not checked at the moment

R=adonovan, r
CC=golang-dev
https://golang.org/cl/11952046
This commit is contained in:
Robert Griesemer 2013-07-31 20:08:18 -07:00
parent 976d735966
commit caf3fc90ed
7 changed files with 69 additions and 37 deletions

View File

@ -110,12 +110,13 @@ func (check *checker) assignVar(lhs ast.Expr, x *operand) Type {
return nil
}
// Don't evaluate lhs if it is the blank identifier.
if ident, _ := lhs.(*ast.Ident); ident != nil && ident.Name == "_" {
// Don't evaluate lhs if it is the (possibly parenthesized) blank identifier.
if ident, _ := unparen(lhs).(*ast.Ident); ident != nil && ident.Name == "_" {
check.recordObject(ident, nil)
// If the lhs is untyped, determine the default type.
// The spec is unclear about this, but gc appears to
// do this.
// TODO(gri) This is still not correct (try: _ = nil; _ = 1<<1e3)
typ := x.typ
if isUntyped(typ) {
// convert untyped types to default types

View File

@ -542,7 +542,7 @@ func (check *checker) shift(x, y *operand, op token.Token) {
const stupidShift = 1023 - 1 + 52 // so we can express smallestFloat64
s, ok := exact.Uint64Val(y.val)
if !ok || s > stupidShift {
check.invalidOp(y.pos(), "%s: stupid shift", y)
check.invalidOp(y.pos(), "stupid shift count %s", y)
x.mode = invalid
return
}
@ -577,6 +577,11 @@ func (check *checker) shift(x, y *operand, op token.Token) {
}
}
// constant rhs must be >= 0
if y.mode == constant && exact.Sign(y.val) < 0 {
check.invalidOp(y.pos(), "shift count %s must not be negative", y)
}
// non-constant shift - lhs must be an integer
if !isInteger(x.typ) {
check.invalidOp(x.pos(), "shifted operand %s must be integer", x)

View File

@ -288,6 +288,11 @@ func (check *checker) resolveFiles(files []*ast.File) {
// don't declare init functions in the package scope - they are invisible
obj.parent = pkg.scope
check.recordObject(d.Name, obj)
// init functions must have a body
if d.Body == nil {
check.errorf(obj.pos, "missing function body")
// ok to continue
}
} else {
check.declareObj(pkg.scope, d.Name, obj)
}

View File

@ -37,34 +37,21 @@ func TestStdlib(t *testing.T) {
}
}
func TestStdtest(t *testing.T) {
path := filepath.Join(runtime.GOROOT(), "test")
func testTestDir(t *testing.T, path string, ignore ...string) {
files, err := ioutil.ReadDir(path)
if err != nil {
t.Fatal(err)
}
excluded := make(map[string]bool)
for _, filename := range ignore {
excluded[filename] = true
}
fset := token.NewFileSet()
for _, f := range files {
// filter directory contents
if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") {
continue
}
// explicitly exclude files that the type-checker still has problems with
switch f.Name() {
case "cmplxdivide.go":
// This test also needs file cmplxdivide1.go; ignore.
continue
case "goto.go", "label1.go":
// TODO(gri) implement missing label checks
continue
case "sizeof.go", "switch.go":
// TODO(gri) tone down duplicate checking in expression switches
continue
case "typeswitch2.go":
// TODO(gri) implement duplicate checking in type switches
if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] {
continue
}
@ -76,13 +63,13 @@ func TestStdtest(t *testing.T) {
file, err := parser.ParseFile(fset, filename, nil, parser.ParseComments|parser.AllErrors)
// check per-file instructions
// For now we only check two cases.
// For now we only check some cases.
expectErrors := false
if len(file.Comments) > 0 {
if group := file.Comments[0]; len(group.List) > 0 {
cmd := strings.TrimSpace(group.List[0].Text[2:]) // 2: ignore // or /* of comment
switch cmd {
case "skip":
case "skip", "compiledir":
continue
case "errorcheck":
expectErrors = true
@ -107,6 +94,33 @@ func TestStdtest(t *testing.T) {
}
}
func TestStdtest(t *testing.T) {
testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
"cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
"goto.go", "label1.go", // TODO(gri) implement missing label checks
"sizeof.go", "switch.go", // TODO(gri) tone down duplicate checking in expr switches
"typeswitch2.go", // TODO(gri) implement duplicate checking in type switches
)
}
func TestStdfixed(t *testing.T) {
testTestDir(t, filepath.Join(runtime.GOROOT(), "test/fixedbugs"),
"bug050.go", "bug088.go", "bug106.go", // TODO(gri) parser loses comments when bailing out early
"bug222.go", "bug282.go", "bug306.go", // TODO(gri) parser loses comments when bailing out early
"bug136.go", "bug179.go", "bug344.go", // TODO(gri) implement missing label checks
"bug165.go", // TODO(gri) isComparable not working for incomplete struct type
"bug176.go", // TODO(gri) composite literal array index must be non-negative constant
"bug200.go", // TODO(gri) complete duplicate checking in expr switches
"bug223.go", "bug413.go", "bug459.go", // TODO(gri) complete initialization checks
"bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
"bug250.go", // TODO(gri) fix recursive interfaces
"bug326.go", // TODO(gri) assignment doesn't guard against len(rhs) == 0
"bug373.go", // TODO(gri) implement use checks
"bug376.go", // TODO(gri) built-ins must be called (no built-in function expressions)
"issue3924.go", // TODO(gri) && and || produce bool result (not untyped bool)
)
}
// Package paths of excluded packages.
var excluded = map[string]bool{
"builtin": true,

View File

@ -57,6 +57,7 @@ type init /* ERROR "cannot declare init" */ struct{}
var _, init /* ERROR "cannot declare init" */ int
func init() {}
func init /* ERROR "missing function body" */ ()
func _() { const init = 0 }
func _() { type init int }

View File

@ -11,6 +11,7 @@ func shifts0() {
_ = 0<<0
_ = 1<<s
_ = 1<<- /* ERROR "stupid shift" */ 1
_ = 1<<1075 /* ERROR "stupid shift" */
_ = 2.0<<1
_ int = 2<<s
@ -30,20 +31,20 @@ func shifts0() {
func shifts1() {
// basic non-constant shifts
var (
i0 int
u0 uint
i int
u uint
v0 = 1<<0
v1 = 1<<i0 /* ERROR "must be unsigned" */
v2 = 1<<u0
v3 = 1<<"foo" /* ERROR "cannot convert" */
v4 = 1<<- /* ERROR "stupid shift" */ 1
v5 = 1<<1075 /* ERROR "stupid shift" */
v6 = 1 /* ERROR "overflows" */ <<100
_ = 1<<0
_ = 1<<i /* ERROR "must be unsigned" */
_ = 1<<u
_ = 1<<"foo" /* ERROR "cannot convert" */
_ = i<<0
_ = i<<- /* ERROR "must not be negative" */ 1
_ = 1 /* ERROR "overflows" */ <<100
v10 uint = 1 << 0
v11 uint = 1 << u0
v12 float32 = 1 /* ERROR "must be integer" */ << u0
_ uint = 1 << 0
_ uint = 1 << u
_ float32 = 1 /* ERROR "must be integer" */ << u
)
}

View File

@ -55,6 +55,11 @@ func assignments() {
g := func(int, bool){}
var m map[int]int
g/* ERROR "too few arguments" */ (m[0])
// assignments to _
_ = nil /* ERROR "use of untyped nil" */
_ = 1<<1000 // TODO(gri) this should fail
(_) = 0
}
func shortVarDecls() {