diff options
author | Rob Findley <rfindley@google.com> | 2020-09-11 14:23:34 -0400 |
---|---|---|
committer | Rob Findley <rfindley@google.com> | 2020-09-11 14:23:34 -0400 |
commit | f8b1c17aced24a1618c6984794be9770c5d260be (patch) | |
tree | 45af8d39b5c3d9f43d439ebec0a2ba42b49efe70 /src/go | |
parent | e5d91ab096a9ff9673311f1a7f3f860a7f9c2062 (diff) | |
parent | 07c1788357cfe6a4ee5f6f6a54d4fe9f579fa844 (diff) | |
download | go-git-dev.types.tar.gz |
[dev.types] all: merge master into dev.typesdev.types
Change-Id: Ia6964cb4e09153c15cc9c5b441373d1b3cb8f757
Diffstat (limited to 'src/go')
-rw-r--r-- | src/go/ast/ast.go | 6 | ||||
-rw-r--r-- | src/go/build/build.go | 6 | ||||
-rw-r--r-- | src/go/types/api_test.go | 9 | ||||
-rw-r--r-- | src/go/types/assignments.go | 17 | ||||
-rw-r--r-- | src/go/types/check_test.go | 32 | ||||
-rw-r--r-- | src/go/types/errors.go | 39 | ||||
-rw-r--r-- | src/go/types/expr.go | 153 | ||||
-rw-r--r-- | src/go/types/fixedbugs/issue23203a.src (renamed from src/go/types/testdata/issue23203a.src) | 0 | ||||
-rw-r--r-- | src/go/types/fixedbugs/issue23203b.src (renamed from src/go/types/testdata/issue23203b.src) | 0 | ||||
-rw-r--r-- | src/go/types/fixedbugs/issue26390.src (renamed from src/go/types/testdata/issue26390.src) | 2 | ||||
-rw-r--r-- | src/go/types/fixedbugs/issue28251.src (renamed from src/go/types/testdata/issue28251.src) | 0 | ||||
-rw-r--r-- | src/go/types/fixedbugs/issue6977.src (renamed from src/go/types/testdata/issue6977.src) | 0 | ||||
-rw-r--r-- | src/go/types/operand.go | 43 | ||||
-rw-r--r-- | src/go/types/self_test.go | 25 | ||||
-rw-r--r-- | src/go/types/stdlib_test.go | 51 | ||||
-rw-r--r-- | src/go/types/testdata/shifts.src | 23 |
16 files changed, 257 insertions, 149 deletions
diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go index 81c64589d0..1061f1d3ce 100644 --- a/src/go/ast/ast.go +++ b/src/go/ast/ast.go @@ -285,6 +285,12 @@ type ( } // A BasicLit node represents a literal of basic type. + // + // Note that for the CHAR and STRING kinds, the literal is stored + // with its quotes. For example, for a double-quoted STRING, the + // first and the last rune in the Value field will be ". The + // Unquote and UnquoteChar functions in the strconv package can be + // used to unquote STRING and CHAR values, respectively. BasicLit struct { ValuePos token.Pos // literal position Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING diff --git a/src/go/build/build.go b/src/go/build/build.go index 4a5da308a0..39bc3591a7 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -793,6 +793,12 @@ Found: if d.IsDir() { continue } + if (d.Mode() & os.ModeSymlink) != 0 { + if fi, err := os.Stat(filepath.Join(p.Dir, d.Name())); err == nil && fi.IsDir() { + // Symlinks to directories are not source files. + continue + } + } name := d.Name() ext := nameExt(name) diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 798c09bbff..75cebc9826 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -1243,6 +1243,9 @@ func TestConvertibleTo(t *testing.T) { {newDefined(new(Struct)), new(Struct), true}, {newDefined(Typ[Int]), new(Struct), false}, {Typ[UntypedInt], Typ[Int], true}, + // Untyped string values are not permitted by the spec, so the below + // behavior is undefined. + {Typ[UntypedString], Typ[String], true}, } { if got := ConvertibleTo(test.v, test.t); got != test.want { t.Errorf("ConvertibleTo(%v, %v) = %t, want %t", test.v, test.t, got, test.want) @@ -1260,6 +1263,12 @@ func TestAssignableTo(t *testing.T) { {newDefined(Typ[Int]), Typ[Int], false}, {newDefined(new(Struct)), new(Struct), true}, {Typ[UntypedBool], Typ[Bool], true}, + {Typ[UntypedString], Typ[Bool], false}, + // Neither untyped string nor untyped numeric assignments arise during + // normal type checking, so the below behavior is technically undefined by + // the spec. + {Typ[UntypedString], Typ[String], true}, + {Typ[UntypedInt], Typ[Int], true}, } { if got := AssignableTo(test.v, test.t); got != test.want { t.Errorf("AssignableTo(%v, %v) = %t, want %t", test.v, test.t, got, test.want) diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go index 34a9d7843d..4e8ec278fc 100644 --- a/src/go/types/assignments.go +++ b/src/go/types/assignments.go @@ -7,6 +7,7 @@ package types import ( + "errors" "go/ast" "go/token" ) @@ -33,8 +34,8 @@ func (check *Checker) assignment(x *operand, T Type, context string) { // spec: "If an untyped constant is assigned to a variable of interface // type or the blank identifier, the constant is first converted to type // bool, rune, int, float64, complex128 or string respectively, depending - // on whether the value is a boolean, rune, integer, floating-point, complex, - // or string constant." + // on whether the value is a boolean, rune, integer, floating-point, + // complex, or string constant." if T == nil || IsInterface(T) { if T == nil && x.typ == Typ[UntypedNil] { check.errorf(x.pos(), "use of untyped nil in %s", context) @@ -43,8 +44,16 @@ func (check *Checker) assignment(x *operand, T Type, context string) { } target = Default(x.typ) } - check.convertUntyped(x, target) - if x.mode == invalid { + if err := check.canConvertUntyped(x, target); err != nil { + var internalErr Error + var msg string + if errors.As(err, &internalErr) { + msg = internalErr.Msg + } else { + msg = err.Error() + } + check.errorf(x.pos(), "cannot use %s as %s value in %s: %v", x, target, context, msg) + x.mode = invalid return } } diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index 89122d75ff..e01c3de13b 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -34,6 +34,7 @@ import ( "go/token" "internal/testenv" "io/ioutil" + "path/filepath" "regexp" "strings" "testing" @@ -93,11 +94,6 @@ var tests = [][]string{ {"testdata/issues.src"}, {"testdata/blank.src"}, {"testdata/issue25008b.src", "testdata/issue25008a.src"}, // order (b before a) is crucial! - {"testdata/issue26390.src"}, // stand-alone test to ensure case is triggered - {"testdata/issue23203a.src"}, - {"testdata/issue23203b.src"}, - {"testdata/issue28251.src"}, - {"testdata/issue6977.src"}, } var fset = token.NewFileSet() @@ -259,7 +255,7 @@ func checkFiles(t *testing.T, testfiles []string) { // typecheck and collect typechecker errors var conf Config // special case for importC.src - if len(testfiles) == 1 && testfiles[0] == "testdata/importC.src" { + if len(testfiles) == 1 && strings.HasSuffix(testfiles[0], "importC.src") { conf.FakeImportC = true } conf.Importer = importer.Default() @@ -316,3 +312,27 @@ func TestCheck(t *testing.T) { checkFiles(t, files) } } + +func TestFixedBugs(t *testing.T) { testDir(t, "fixedbugs") } + +func testDir(t *testing.T, dir string) { + testenv.MustHaveGoBuild(t) + + fis, err := ioutil.ReadDir(dir) + if err != nil { + t.Fatal(err) + } + + for _, fi := range fis { + testname := filepath.Base(fi.Name()) + testname = strings.TrimSuffix(testname, filepath.Ext(testname)) + t.Run(testname, func(t *testing.T) { + filename := filepath.Join(dir, fi.Name()) + if fi.IsDir() { + t.Errorf("skipped directory %q", filename) + return + } + checkFiles(t, []string{filename}) + }) + } +} diff --git a/src/go/types/errors.go b/src/go/types/errors.go index 91b077163c..88e41c5713 100644 --- a/src/go/types/errors.go +++ b/src/go/types/errors.go @@ -7,6 +7,7 @@ package types import ( + "errors" "fmt" "go/ast" "go/token" @@ -72,22 +73,33 @@ func (check *Checker) dump(format string, args ...interface{}) { fmt.Println(check.sprintf(format, args...)) } -func (check *Checker) err(pos token.Pos, msg string, soft bool) { +func (check *Checker) err(err error) { + if err == nil { + return + } + var e Error + isInternal := errors.As(err, &e) // Cheap trick: Don't report errors with messages containing // "invalid operand" or "invalid type" as those tend to be // follow-on errors which don't add useful information. Only // exclude them if these strings are not at the beginning, // and only if we have at least one error already reported. - if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) { + isInvalidErr := isInternal && (strings.Index(e.Msg, "invalid operand") > 0 || strings.Index(e.Msg, "invalid type") > 0) + if check.firstErr != nil && isInvalidErr { return } - err := Error{check.fset, pos, msg, soft} if check.firstErr == nil { check.firstErr = err } if trace { + pos := e.Pos + msg := e.Msg + if !isInternal { + msg = err.Error() + pos = token.NoPos + } check.trace(pos, "ERROR: %s", msg) } @@ -99,15 +111,30 @@ func (check *Checker) err(pos token.Pos, msg string, soft bool) { } func (check *Checker) error(pos token.Pos, msg string) { - check.err(pos, msg, false) + check.err(Error{Fset: check.fset, Pos: pos, Msg: msg}) +} + +// newErrorf creates a new Error, but does not handle it. +func (check *Checker) newErrorf(pos token.Pos, format string, args ...interface{}) error { + return Error{ + Fset: check.fset, + Pos: pos, + Msg: check.sprintf(format, args...), + Soft: false, + } } func (check *Checker) errorf(pos token.Pos, format string, args ...interface{}) { - check.err(pos, check.sprintf(format, args...), false) + check.error(pos, check.sprintf(format, args...)) } func (check *Checker) softErrorf(pos token.Pos, format string, args ...interface{}) { - check.err(pos, check.sprintf(format, args...), true) + check.err(Error{ + Fset: check.fset, + Pos: pos, + Msg: check.sprintf(format, args...), + Soft: true, + }) } func (check *Checker) invalidAST(pos token.Pos, format string, args ...interface{}) { diff --git a/src/go/types/expr.go b/src/go/types/expr.go index d1e892a9b7..94d98f0fbb 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -329,8 +329,16 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c return false } -// representable checks that a constant operand is representable in the given basic type. +// representable checks that a constant operand is representable in the given +// basic type. func (check *Checker) representable(x *operand, typ *Basic) { + if err := check.isRepresentable(x, typ); err != nil { + x.mode = invalid + check.err(err) + } +} + +func (check *Checker) isRepresentable(x *operand, typ *Basic) error { assert(x.mode == constant_) if !representableConst(x.val, check, typ, &x.val) { var msg string @@ -350,9 +358,9 @@ func (check *Checker) representable(x *operand, typ *Basic) { } else { msg = "cannot convert %s to %s" } - check.errorf(x.pos(), msg, x, typ) - x.mode = invalid + return check.newErrorf(x.pos(), msg, x, typ) } + return nil } // updateExprType updates the type of x to typ and invokes itself @@ -488,12 +496,16 @@ func (check *Checker) updateExprVal(x ast.Expr, val constant.Value) { // convertUntyped attempts to set the type of an untyped value to the target type. func (check *Checker) convertUntyped(x *operand, target Type) { - if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] { - return + if err := check.canConvertUntyped(x, target); err != nil { + x.mode = invalid + check.err(err) } +} - // TODO(gri) Sloppy code - clean up. This function is central - // to assignment and expression checking. +func (check *Checker) canConvertUntyped(x *operand, target Type) error { + if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] { + return nil + } if isUntyped(target) { // both x and target are untyped @@ -505,82 +517,91 @@ func (check *Checker) convertUntyped(x *operand, target Type) { check.updateExprType(x.expr, target, false) } } else if xkind != tkind { - goto Error + return check.newErrorf(x.pos(), "cannot convert %s to %s", x, target) } - return + return nil + } + + if t, ok := target.Underlying().(*Basic); ok && x.mode == constant_ { + if err := check.isRepresentable(x, t); err != nil { + return err + } + // Expression value may have been rounded - update if needed. + check.updateExprVal(x.expr, x.val) + } else { + newTarget := check.implicitType(x, target) + if newTarget == nil { + return check.newErrorf(x.pos(), "cannot convert %s to %s", x, target) + } + target = newTarget } + x.typ = target + // Even though implicitType can return UntypedNil, this value is final: the + // predeclared identifier nil has no type. + check.updateExprType(x.expr, target, true) + return nil +} - // typed target +// implicitType returns the implicit type of x when used in a context where the +// target type is expected. If no such implicit conversion is possible, it +// returns nil. +func (check *Checker) implicitType(x *operand, target Type) Type { + assert(isUntyped(x.typ)) switch t := target.Underlying().(type) { case *Basic: - if x.mode == constant_ { - check.representable(x, t) - if x.mode == invalid { - return + assert(x.mode != constant_) + // Non-constant untyped values may appear as the + // result of comparisons (untyped bool), intermediate + // (delayed-checked) rhs operands of shifts, and as + // the value nil. + switch x.typ.(*Basic).kind { + case UntypedBool: + if !isBoolean(target) { + return nil } - // expression value may have been rounded - update if needed - check.updateExprVal(x.expr, x.val) - } else { - // Non-constant untyped values may appear as the - // result of comparisons (untyped bool), intermediate - // (delayed-checked) rhs operands of shifts, and as - // the value nil. - switch x.typ.(*Basic).kind { - case UntypedBool: - if !isBoolean(target) { - goto Error - } - case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex: - if !isNumeric(target) { - goto Error - } - case UntypedString: - // Non-constant untyped string values are not - // permitted by the spec and should not occur. - unreachable() - case UntypedNil: - // Unsafe.Pointer is a basic type that includes nil. - if !hasNil(target) { - goto Error - } - default: - goto Error + case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex: + if !isNumeric(target) { + return nil + } + case UntypedString: + // Non-constant untyped string values are not permitted by the spec and + // should not occur during normal typechecking passes, but this path is + // reachable via the AssignableTo API. + if !isString(target) { + return nil + } + case UntypedNil: + // Unsafe.Pointer is a basic type that includes nil. + if !hasNil(target) { + return nil } + default: + return nil } case *Interface: - // Update operand types to the default type rather then - // the target (interface) type: values must have concrete - // dynamic types. If the value is nil, keep it untyped - // (this is important for tools such as go vet which need - // the dynamic type for argument checking of say, print + // Values must have concrete dynamic types. If the value is nil, + // keep it untyped (this is important for tools such as go vet which + // need the dynamic type for argument checking of say, print // functions) if x.isNil() { - target = Typ[UntypedNil] - } else { - // cannot assign untyped values to non-empty interfaces - check.completeInterface(t) - if !t.Empty() { - goto Error - } - target = Default(x.typ) + return Typ[UntypedNil] + } + // cannot assign untyped values to non-empty interfaces + check.completeInterface(t) + if !t.Empty() { + return nil } + return Default(x.typ) case *Pointer, *Signature, *Slice, *Map, *Chan: if !x.isNil() { - goto Error + return nil } - // keep nil untyped - see comment for interfaces, above - target = Typ[UntypedNil] + // Keep nil untyped - see comment for interfaces, above. + return Typ[UntypedNil] default: - goto Error + return nil } - - x.typ = target - check.updateExprType(x.expr, target, true) // UntypedNils are final - return - -Error: - check.errorf(x.pos(), "cannot convert %s to %s", x, target) - x.mode = invalid + return target } func (check *Checker) comparison(x, y *operand, op token.Token) { diff --git a/src/go/types/testdata/issue23203a.src b/src/go/types/fixedbugs/issue23203a.src index 48cb5889cd..48cb5889cd 100644 --- a/src/go/types/testdata/issue23203a.src +++ b/src/go/types/fixedbugs/issue23203a.src diff --git a/src/go/types/testdata/issue23203b.src b/src/go/types/fixedbugs/issue23203b.src index 638ec6c5ce..638ec6c5ce 100644 --- a/src/go/types/testdata/issue23203b.src +++ b/src/go/types/fixedbugs/issue23203b.src diff --git a/src/go/types/testdata/issue26390.src b/src/go/types/fixedbugs/issue26390.src index b8e67e9bdd..9e0101f581 100644 --- a/src/go/types/testdata/issue26390.src +++ b/src/go/types/fixedbugs/issue26390.src @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// stand-alone test to ensure case is triggered + package issue26390 type A = T diff --git a/src/go/types/testdata/issue28251.src b/src/go/types/fixedbugs/issue28251.src index cd79e0e8b5..cd79e0e8b5 100644 --- a/src/go/types/testdata/issue28251.src +++ b/src/go/types/fixedbugs/issue28251.src diff --git a/src/go/types/testdata/issue6977.src b/src/go/types/fixedbugs/issue6977.src index 8f4e9ba2b2..8f4e9ba2b2 100644 --- a/src/go/types/testdata/issue6977.src +++ b/src/go/types/fixedbugs/issue6977.src diff --git a/src/go/types/operand.go b/src/go/types/operand.go index 80d11e2f21..6fbfe09627 100644 --- a/src/go/types/operand.go +++ b/src/go/types/operand.go @@ -205,15 +205,11 @@ func (x *operand) isNil() bool { return x.mode == value && x.typ == Typ[UntypedNil] } -// TODO(gri) The functions operand.assignableTo, checker.convertUntyped, -// checker.representable, and checker.assignment are -// overlapping in functionality. Need to simplify and clean up. - -// assignableTo reports whether x is assignable to a variable of type T. -// If the result is false and a non-nil reason is provided, it may be set -// to a more detailed explanation of the failure (result != ""). -// The check parameter may be nil if assignableTo is invoked through -// an exported API call, i.e., when all methods have been type-checked. +// assignableTo reports whether x is assignable to a variable of type T. If the +// result is false and a non-nil reason is provided, it may be set to a more +// detailed explanation of the failure (result != ""). The check parameter may +// be nil if assignableTo is invoked through an exported API call, i.e., when +// all methods have been type-checked. func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool { if x.mode == invalid || T == Typ[Invalid] { return true // avoid spurious errors @@ -229,34 +225,17 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool { Vu := V.Underlying() Tu := T.Underlying() - // x is an untyped value representable by a value of type T - // TODO(gri) This is borrowing from checker.convertUntyped and - // checker.representable. Need to clean up. + // x is an untyped value representable by a value of type T. if isUntyped(Vu) { - switch t := Tu.(type) { - case *Basic: - if x.isNil() && t.kind == UnsafePointer { - return true - } - if x.mode == constant_ { - return representableConst(x.val, check, t, nil) - } - // The result of a comparison is an untyped boolean, - // but may not be a constant. - if Vb, _ := Vu.(*Basic); Vb != nil { - return Vb.kind == UntypedBool && isBoolean(Tu) - } - case *Interface: - check.completeInterface(t) - return x.isNil() || t.Empty() - case *Pointer, *Signature, *Slice, *Map, *Chan: - return x.isNil() + if t, ok := Tu.(*Basic); ok && x.mode == constant_ { + return representableConst(x.val, check, t, nil) } + return check.implicitType(x, Tu) != nil } // Vu is typed - // x's type V and T have identical underlying types - // and at least one of V or T is not a named type + // x's type V and T have identical underlying types and at least one of V or + // T is not a named type. if check.identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) { return true } diff --git a/src/go/types/self_test.go b/src/go/types/self_test.go index 10ad06fbca..04c9cd3458 100644 --- a/src/go/types/self_test.go +++ b/src/go/types/self_test.go @@ -47,8 +47,13 @@ func TestBenchmark(t *testing.T) { // We're not using testing's benchmarking mechanism directly // because we want custom output. - for _, p := range []string{"types", "constant", filepath.Join("internal", "gcimporter")} { - path := filepath.Join("..", p) + for _, p := range []string{ + "net/http", + "go/parser", + "go/constant", + filepath.Join("go", "internal", "gcimporter"), + } { + path := filepath.Join("..", "..", p) runbench(t, path, false) runbench(t, path, true) fmt.Println() @@ -64,8 +69,13 @@ func runbench(t *testing.T, path string, ignoreFuncBodies bool) { b := testing.Benchmark(func(b *testing.B) { for i := 0; i < b.N; i++ { - conf := Config{IgnoreFuncBodies: ignoreFuncBodies} - conf.Check(path, fset, files, nil) + conf := Config{ + IgnoreFuncBodies: ignoreFuncBodies, + Importer: importer.Default(), + } + if _, err := conf.Check(path, fset, files, nil); err != nil { + t.Fatal(err) + } } }) @@ -77,10 +87,9 @@ func runbench(t *testing.T, path string, ignoreFuncBodies bool) { }) d := time.Duration(b.NsPerOp()) - fmt.Printf( - "%s: %s for %d lines (%d lines/s), ignoreFuncBodies = %v\n", - filepath.Base(path), d, lines, int64(float64(lines)/d.Seconds()), ignoreFuncBodies, - ) + fmt.Printf("%s (ignoreFuncBodies = %v):\n", filepath.Base(path), ignoreFuncBodies) + fmt.Printf("\t%s for %d lines (%.0f lines/s)\n", d, lines, float64(lines)/d.Seconds()) + fmt.Printf("\t%s\n", b.MemString()) } func pkgFiles(fset *token.FileSet, path string) ([]*ast.File, error) { diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go index 51ee0b1c36..f5a3273fa1 100644 --- a/src/go/types/stdlib_test.go +++ b/src/go/types/stdlib_test.go @@ -27,22 +27,21 @@ import ( . "go/types" ) -var ( - pkgCount int // number of packages processed - start time.Time - - // Use the same importer for all std lib tests to - // avoid repeated importing of the same packages. - stdLibImporter = importer.Default() -) +// Use the same importer for all std lib tests to +// avoid repeated importing of the same packages. +var stdLibImporter = importer.Default() func TestStdlib(t *testing.T) { testenv.MustHaveGoBuild(t) - start = time.Now() - walkDirs(t, filepath.Join(runtime.GOROOT(), "src")) + pkgCount := 0 + duration := walkPkgDirs(filepath.Join(runtime.GOROOT(), "src"), func(dir string, filenames []string) { + typecheck(t, dir, filenames) + pkgCount++ + }, t.Error) + if testing.Verbose() { - fmt.Println(pkgCount, "packages typechecked in", time.Since(start)) + fmt.Println(pkgCount, "packages typechecked in", duration) } } @@ -235,7 +234,6 @@ func typecheck(t *testing.T, path string, filenames []string) { } info := Info{Uses: make(map[*ast.Ident]Object)} conf.Check(path, fset, files, &info) - pkgCount++ // Perform checks of API invariants. @@ -278,39 +276,48 @@ func pkgFilenames(dir string) ([]string, error) { return filenames, nil } -// Note: Could use filepath.Walk instead of walkDirs but that wouldn't -// necessarily be shorter or clearer after adding the code to -// terminate early for -short tests. +func walkPkgDirs(dir string, pkgh func(dir string, filenames []string), errh func(args ...interface{})) time.Duration { + w := walker{time.Now(), 10 * time.Millisecond, pkgh, errh} + w.walk(dir) + return time.Since(w.start) +} -func walkDirs(t *testing.T, dir string) { +type walker struct { + start time.Time + dmax time.Duration + pkgh func(dir string, filenames []string) + errh func(args ...interface{}) +} + +func (w *walker) walk(dir string) { // limit run time for short tests - if testing.Short() && time.Since(start) >= 10*time.Millisecond { + if testing.Short() && time.Since(w.start) >= w.dmax { return } fis, err := ioutil.ReadDir(dir) if err != nil { - t.Error(err) + w.errh(err) return } - // typecheck package in directory + // apply pkgh to the files in directory dir // but ignore files directly under $GOROOT/src (might be temporary test files). if dir != filepath.Join(runtime.GOROOT(), "src") { files, err := pkgFilenames(dir) if err != nil { - t.Error(err) + w.errh(err) return } if files != nil { - typecheck(t, dir, files) + w.pkgh(dir, files) } } // traverse subdirectories, but don't walk into testdata for _, fi := range fis { if fi.IsDir() && fi.Name() != "testdata" { - walkDirs(t, filepath.Join(dir, fi.Name())) + w.walk(filepath.Join(dir, fi.Name())) } } } diff --git a/src/go/types/testdata/shifts.src b/src/go/types/testdata/shifts.src index ebc95ba4d7..c9a38ae169 100644 --- a/src/go/types/testdata/shifts.src +++ b/src/go/types/testdata/shifts.src @@ -193,14 +193,27 @@ func shifts6() { _ = float32(1.0 /* ERROR "must be integer" */ <<s) _ = float32(1.1 /* ERROR "must be integer" */ <<s) + _ = int32(0x80000000 /* ERROR "overflows int32" */ << s) + // TODO(rfindley) Eliminate the redundant error here. + _ = int32(( /* ERROR "truncated to int32" */ 0x80000000 /* ERROR "truncated to int32" */ + 0i) << s) + + _ = int(1+0i<<0) + _ = int((1+0i)<<s) + _ = int(1.0<<s) + _ = int(complex(1, 0)<<s) + _ = int(float32/* ERROR "must be integer" */(1.0) <<s) + _ = int(1.1 /* ERROR must be integer */ <<s) + _ = int(( /* ERROR "must be integer" */ 1+1i) <<s) + + _ = complex(1 /* ERROR "must be integer" */ <<s, 0) + var b []int _ = append(b, 1<<s) _ = append(b, 1.0<<s) + _ = append(b, (1+0i)<<s) _ = append(b, 1.1 /* ERROR "must be integer" */ <<s) - - _ = append(b, 1<<s) - _ = append(b, 1.0<<s) // should fail - see TODO in append code - _ = append(b, 1.1 /* ERROR "must be integer" */ <<s) + _ = append(b, (1 + 0i) <<s) + _ = append(b, ( /* ERROR "must be integer" */ 1 + 1i) <<s) _ = complex(1.0 /* ERROR "must be integer" */ <<s, 0) _ = complex(1.1 /* ERROR "must be integer" */ <<s, 0) @@ -379,4 +392,4 @@ func issue22969() { var _ int8 = 0xff /* ERROR "overflows int8" */ << s var _ int16 = 0xffff /* ERROR "overflows int16" */ << s var _ int32 = 0x80000000 /* ERROR "overflows int32" */ << s -}
\ No newline at end of file +} |