Commit 5183bfda authored by Robert Griesemer's avatar Robert Griesemer

go/types: update operand types early

For expressions where the result type is independent
of the argument types (comparisons, conversions, rhs
of shifts), set the final expression types for those
subtrees early.

This fixes several bugs where incorrect lhs shift
operands where used (say in a comparison), but were
not reported.

Together with the changes listed below this CL fixes
many type-checker bugs.

Also:
- better documented updateExprType
- added larger comment to expr.go explaining
  the basic expression checking algorithm
- use latest definition for indices and make
  arguments; use the same code to check both
- use the same mechanism for cycle detection
  in constant expressions as for variables
  (new field Constant.visited)
- more tests for complex and make builtins
- many more and systematic tests for shifts;
  moved them into separate testfile
- in the testing code, don't compare the
  expected error pattern against itself
  (the actual message was always ignored...)
- fix affected error patterns in the test files
- various cleanups along the way

R=adonovan
CC=golang-dev
https://golang.org/cl/7432051
parent ed10fa7e
......@@ -11,6 +11,9 @@ import (
"go/token"
)
// TODO(gri): Several built-ins are missing assignment checks. As a result,
// non-constant shift arguments may not be properly type-checked.
// builtin typechecks a built-in call. The built-in type is bin, and iota is the current
// value of iota or -1 if iota doesn't have a value in the current context. The result
// of the call is returned via x. If the call has type errors, the returned x is marked
......@@ -170,6 +173,10 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
goto Error
}
// arguments have final type
check.updateExprType(args[0], typ, true)
check.updateExprType(args[1], typ, true)
case _Copy:
var y operand
check.expr(&y, args[1], nil, iota)
......@@ -269,24 +276,13 @@ 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
var sizes []int64 // constant integer arguments, if any
for _, arg := range args[1:] {
check.expr(x, arg, nil, iota)
if x.isInteger(check.ctxt) {
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 s, ok := check.index(arg, -1, iota); ok && s >= 0 {
sizes = append(sizes, s)
}
}
if len(sizes) == 2 && compareConst(sizes[0], sizes[1], token.GTR) {
if len(sizes) == 2 && sizes[0] > sizes[1] {
check.invalidArg(args[1].Pos(), "length and capacity swapped")
// safe to continue
}
......
......@@ -18,6 +18,15 @@ const (
trace = false // turn on for detailed type resolution traces
)
// exprInfo stores type and constant value for an untyped expression.
type exprInfo struct {
isConst bool // expression has a, possibly unknown, constant value
isLhs bool // expression is lhs operand of a shift with delayed type check
typ *Basic
val interface{} // constant value (may be nil if unknown); valid if isConst
}
// A checker is an instance of the type checker.
type checker struct {
ctxt *Context
fset *token.FileSet
......@@ -31,14 +40,7 @@ type checker struct {
initspecs map[*ast.ValueSpec]*ast.ValueSpec // "inherited" type and initialization expressions for constant declarations
methods map[*TypeName]*Scope // maps type names to associated methods
conversions map[*ast.CallExpr]bool // set of type-checked conversions (to distinguish from calls)
// untyped expressions
// TODO(gri): Consider merging the untyped and constants map. Should measure
// the ratio between untyped non-constant and untyped constant expressions
// to make an informed decision.
untyped map[ast.Expr]*Basic // map of expressions of untyped type
constants map[ast.Expr]interface{} // map of untyped constant expressions; each key also appears in untyped
shiftOps map[ast.Expr]bool // map of lhs shift operands with delayed type-checking
untyped map[ast.Expr]exprInfo // map of expressions without final type
// functions
funclist []function // list of functions/methods with correct signatures and non-empty bodies
......@@ -234,18 +236,14 @@ func (check *checker) object(obj Object, cycleOk bool) {
obj.Type = Typ[Invalid]
return
}
obj.visited = true
switch d := obj.decl.(type) {
case *ast.Field:
unreachable() // function parameters are always typed when collected
case *ast.ValueSpec:
obj.visited = true
check.valueSpec(d.Pos(), obj, d.Names, d, 0)
case *ast.AssignStmt:
// If we reach here, we have a short variable declaration
// where the rhs didn't typecheck and thus the lhs has no
// types.
obj.visited = true
obj.Type = Typ[Invalid]
unreachable() // assign1to1 sets the type for failing short var decls
default:
unreachable() // see also function newObj
}
......@@ -428,9 +426,7 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package,
initspecs: make(map[*ast.ValueSpec]*ast.ValueSpec),
methods: make(map[*TypeName]*Scope),
conversions: make(map[*ast.CallExpr]bool),
untyped: make(map[ast.Expr]*Basic),
constants: make(map[ast.Expr]interface{}),
shiftOps: make(map[ast.Expr]bool),
untyped: make(map[ast.Expr]exprInfo),
}
// set results and handle panics
......@@ -490,9 +486,9 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package,
// remaining untyped expressions must indeed be untyped
if debug {
for x, typ := range check.untyped {
if !isUntyped(typ) {
check.dump("%s: %s (type %s) is not untyped", x.Pos(), x, typ)
for x, info := range check.untyped {
if !isUntyped(info.typ) {
check.dump("%s: %s (type %s) is not untyped", x.Pos(), x, info.typ)
panic(0)
}
}
......@@ -503,8 +499,12 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package,
// after function body checking for smaller
// map size and more immediate feedback.
if ctxt.Expr != nil {
for x, typ := range check.untyped {
ctxt.Expr(x, typ, check.constants[x])
for x, info := range check.untyped {
var val interface{}
if info.isConst {
val = info.val
}
ctxt.Expr(x, info.typ, val)
}
}
......
......@@ -54,6 +54,7 @@ var tests = []struct {
{"expr1", []string{"testdata/expr1.src"}},
{"expr2", []string{"testdata/expr2.src"}},
{"expr3", []string{"testdata/expr3.src"}},
{"shifts", []string{"testdata/shifts.src"}},
{"builtins", []string{"testdata/builtins.src"}},
{"conversions", []string{"testdata/conversions.src"}},
{"stmt0", []string{"testdata/stmt0.src"}},
......@@ -62,17 +63,6 @@ var tests = []struct {
var fset = token.NewFileSet()
func getFile(filename string) (file *token.File) {
fset.Iterate(func(f *token.File) bool {
if f.Name() == filename {
file = f
return false // end iteration
}
return true
})
return file
}
// Positioned errors are of the form filename:line:column: message .
var posMsgRx = regexp.MustCompile(`^(.*:[0-9]+:[0-9]+): *(.*)`)
......@@ -120,6 +110,7 @@ var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
// in files and returns them as a map of error positions to error messages.
//
func errMap(t *testing.T, testname string, files []*ast.File) map[string][]string {
// map of position strings to lists of error message patterns
errmap := make(map[string][]string)
for _, file := range files {
......@@ -130,10 +121,7 @@ func errMap(t *testing.T, testname string, files []*ast.File) map[string][]strin
}
var s scanner.Scanner
// file was parsed already - do not add it again to the file
// set otherwise the position information returned here will
// not match the position information collected by the parser
s.Init(getFile(filename), src, nil, scanner.ScanComments)
s.Init(fset.AddFile(filename, fset.Base(), len(src)), src, nil, scanner.ScanComments)
var prev string // position string of last non-comment, non-semicolon token
scanFile:
......@@ -143,9 +131,8 @@ func errMap(t *testing.T, testname string, files []*ast.File) map[string][]strin
case token.EOF:
break scanFile
case token.COMMENT:
s := errRx.FindStringSubmatch(lit)
if len(s) == 2 {
errmap[prev] = append(errmap[prev], string(s[1]))
if s := errRx.FindStringSubmatch(lit); len(s) == 2 {
errmap[prev] = append(errmap[prev], s[1])
}
case token.SEMICOLON:
// ignore automatically inserted semicolon
......@@ -164,17 +151,17 @@ func errMap(t *testing.T, testname string, files []*ast.File) map[string][]strin
func eliminate(t *testing.T, errmap map[string][]string, errlist []error) {
for _, err := range errlist {
pos, msg := splitError(err)
pos, gotMsg := splitError(err)
list := errmap[pos]
index := -1 // list index of matching message, if any
// we expect one of the messages in list to match the error at pos
for i, msg := range list {
rx, err := regexp.Compile(msg)
for i, wantRx := range list {
rx, err := regexp.Compile(wantRx)
if err != nil {
t.Errorf("%s: %v", pos, err)
continue
}
if rx.MatchString(msg) {
if rx.MatchString(gotMsg) {
index = i
break
}
......@@ -190,9 +177,8 @@ func eliminate(t *testing.T, errmap map[string][]string, errlist []error) {
delete(errmap, pos)
}
} else {
t.Errorf("%s: no error expected: %q", pos, msg)
t.Errorf("%s: no error expected: %q", pos, gotMsg)
}
}
}
......@@ -213,10 +199,8 @@ func checkFiles(t *testing.T, testname string, testfiles []string) {
return
}
// match and eliminate errors
// match and eliminate errors;
// we are expecting the following errors
// (collect these after parsing the files so that
// they are found in the file set)
errmap := errMap(t, testname, files)
eliminate(t, errmap, errlist)
......
......@@ -182,24 +182,6 @@ func isZeroConst(x interface{}) bool {
return ok && i == 0
}
// isNegConst reports whether the value of constant x is < 0.
// x must be a non-complex numeric value.
//
func isNegConst(x interface{}) bool {
switch x := x.(type) {
case nil:
return false
case int64:
return x < 0
case *big.Int:
return x.Sign() < 0
case *big.Rat:
return x.Sign() < 0
}
unreachable()
return false
}
// isRepresentableConst reports whether the value of constant x can
// be represented as a value of the basic type Typ[as] without loss
// of precision.
......
......@@ -36,7 +36,7 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota
// common issue.
if typ.Kind == String {
switch {
case x.isInteger(check.ctxt):
case x.isInteger():
codepoint, ok := x.val.(int64)
if !ok {
// absolute value too large (or unknown) for conversion;
......@@ -60,6 +60,9 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota
x.mode = value
}
// the conversion argument types are final
check.updateExprType(x.expr, x.typ, true)
check.conversions[conv] = true // for cap/len checking
x.expr = conv
x.typ = typ
......
This diff is collapsed.
......@@ -205,11 +205,10 @@ func (x *operand) isAssignable(ctxt *Context, T Type) bool {
}
// isInteger reports whether x is a (typed or untyped) integer value.
// TODO(gri) remove ctxt argument - it is not required for UntypedInt.
func (x *operand) isInteger(ctxt *Context) bool {
func (x *operand) isInteger() bool {
return x.mode == invalid ||
isInteger(x.typ) ||
x.mode == constant && isRepresentableConst(x.val, ctxt, UntypedInt)
x.mode == constant && isRepresentableConst(x.val, nil, UntypedInt) // no context required for UntypedInt
}
// lookupResult represents the result of a struct field/method lookup.
......
......@@ -59,6 +59,8 @@ func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota
if !decl {
// anything can be assigned to the blank identifier
if ident != nil && ident.Name == "_" {
// the rhs has its final type
check.updateExprType(rhs, x.typ, true)
return
}
......
......@@ -54,6 +54,7 @@ func _complex() {
var f32 float32
var f64 float64
var c64 complex64
var c128 complex128
_ = complex /* ERROR "argument" */ ()
_ = complex /* ERROR "argument" */ (1)
_ = complex(true /* ERROR "invalid argument" */ , 0)
......@@ -78,6 +79,21 @@ func _complex() {
_ = complex(1, 1.1)
_ = complex(1, 'a')
complex /* ERROR "not used" */ (1, 2)
var _ complex64 = complex(f32, f32)
var _ complex64 = complex /* ERROR "cannot initialize" */ (f64, f64)
var _ complex128 = complex /* ERROR "cannot initialize" */ (f32, f32)
var _ complex128 = complex(f64, f64)
// untyped constants
const _ int = complex(1, 0)
const _ float32 = complex(1, 0)
const _ complex64 = complex(1, 0)
const _ complex128 = complex(1, 0)
const _ int = complex /* ERROR "int" */ (1.1, 0)
const _ float32 = complex /* ERROR "float32" */ (1, 2)
}
func _copy() {
......@@ -161,7 +177,9 @@ func _len() {
}
func _make() {
n := 0
var n int
var m float32
var s uint
_ = make /* ERROR "argument" */ ()
_ = make(1 /* ERROR "not a type" */)
......@@ -172,32 +190,40 @@ func _make() {
_ = 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, "foo" /* ERROR "cannot convert" */)
_ = make([]int, 10, 2.3 /* ERROR "overflows" */)
_ = make([]int, 5, 10.0)
_ = make([]int, 0i)
_ = make([]int, 1.0)
_ = make([]int, 1.0<<s)
_ = make([]int, 1.1 /* ERROR "int" */ <<s)
_ = 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)
_ = make([]int, 1 /* ERROR "overflows" */ <<100, 1 /* ERROR "overflows" */ <<100)
_ = make([]int, 10 /* ERROR "length and capacity swapped" */ , 9)
_ = make([]int, 1 /* ERROR "overflows" */ <<100, 12345)
_ = make([]int, m /* ERROR "must be integer" */ )
// maps
_ = 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, "foo" /* ERROR "cannot convert" */)
_ = make(map[int]float32, 10)
_ = make(map[int]float32, n)
_ = make(map[int]float32, int64(n))
_ = make(map[string]bool, 10.0)
_ = make(map[string]bool, 10.0<<s)
// channels
_ = 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<- int, "foo" /* ERROR "cannot convert" */)
_ = make(<-chan float64, 10)
_ = make(chan chan int, n)
_ = make(chan string, int64(n))
_ = make(chan bool, 10.0)
_ = make(chan bool, 10.0<<s)
make /* ERROR "not used" */ ([]int, 10)
}
......@@ -309,8 +335,8 @@ func _Offsetof() {
var x struct{ f int }
_ = 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(int /* ERROR "not a selector expression" */)
_ = unsafe.Offsetof(x /* ERROR "not a selector expression" */)
_ = unsafe.Offsetof(x.f)
_ = unsafe.Offsetof((x.f))
_ = unsafe.Offsetof((((((((x))).f)))))
......@@ -338,7 +364,7 @@ func _Offsetof() {
var y2 S2
assert(unsafe.Offsetof(y2.S1) == 0)
_ = unsafe.Offsetof(y2 /* ERROR "embedded via pointer" */ .x)
_ = unsafe.Offsetof(y2 /* ERROR "embedded via a pointer" */ .x)
}
func _Sizeof() {
......
......@@ -37,7 +37,7 @@ var (
s4 = s + t
s5 = s /* ERROR "invalid operation" */ / t
s6 = array[t1]
s7 = array[x /* ERROR "index" */]
s7 = array[x /* ERROR "integer" */]
s8 = &a
s10 = &42 /* ERROR "cannot take address" */
s11 = &v
......@@ -48,16 +48,16 @@ var (
s19 = s1 /* ERROR "cannot call" */ ()
s20 = f0 /* ERROR "no value" */ ()
s21 = f6(1, s1, i)
s22 = f6(1, s1, uu /* ERROR "cannot assign" */ )
s22 = f6(1, s1, uu /* ERROR "cannot pass argument" */ )
t1 int = i + j
t2 int = i /* ERROR "mismatched types" */ + x
t3 int = c /* ERROR "cannot assign" */ + d
t3 int = c /* ERROR "cannot initialize" */ + d
t4 string = s + t
t5 string = s /* ERROR "invalid operation" */ / t
t6 byte = array[t1]
t7 byte = array[x /* ERROR "index" */]
t8 *int = & /* ERROR "cannot assign" */ a
t7 byte = array[x /* ERROR "must be integer" */]
t8 *int = & /* ERROR "cannot initialize" */ a
t10 *int = &42 /* ERROR "cannot take address" */
t11 *complex64 = &v
t12 complex64 = -(u + *t11) / *&v
......
This diff is collapsed.
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package shifts
func shifts1() {
// basics
var (
i0 int
u0 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<<1025 /* ERROR "stupid shift" */
v6 = 1 /* ERROR "overflows" */ <<100
v10 uint = 1 << 0
v11 uint = 1 << u0
v12 float32 = 1 /* ERROR "must be integer" */ << u0
)
}
func shifts2() {
// from the spec
var (
s uint = 33
i = 1<<s // 1 has type int
j int32 = 1<<s // 1 has type int32; j == 0
k = uint64(1<<s) // 1 has type uint64; k == 1<<33
m int = 1.0<<s // 1.0 has type int
// Disabled test below. gc and gccgo disagree: gc permits it per spec special case,
// gccgo does not (issue 4881). The spec special case seems not justified (issue 4883),
// and go/types agrees with gccgo.
// n = 1.0<<s != 0 // 1.0 has type int; n == false if ints are 32bits in size
n = 1.0 /* ERROR "must be integer" */ <<s != 0
o = 1<<s == 2<<s // 1 and 2 have type int; o == true if ints are 32bits in size
p = 1<<s == 1<<33 // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
u = 1.0 /* ERROR "must be integer" */ <<s // illegal: 1.0 has type float64, cannot shift
v float32 = 1 /* ERROR "must be integer" */ <<s // illegal: 1 has type float32, cannot shift
w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression
)
}
func shifts3(a int16, b float32) {
// random tests
var (
s uint = 11
u = 1 /* ERROR "must be integer" */ <<s + 1.0
v complex128 = 1 /* ERROR "must be integer" */ << s + 1.0 /* ERROR "must be integer" */ << s + 1
)
x := 1.0 /* ERROR "must be integer" */ <<s + 1
shifts3(1.0 << s, 1 /* ERROR "must be integer" */ >> s)
}
func shifts4() {
// shifts in comparisons w/ untyped operands
var s uint
_ = 1<<s == 1
_ = 1 /* ERROR "integer" */ <<s == 1.
_ = 1. /* ERROR "integer" */ <<s == 1
_ = 1. /* ERROR "integer" */ <<s == 1.
_ = 1<<s + 1 == 1
_ = 1 /* ERROR "integer" */ <<s + 1 == 1.
_ = 1 /* ERROR "integer" */ <<s + 1. == 1
_ = 1 /* ERROR "integer" */ <<s + 1. == 1.
_ = 1. /* ERROR "integer" */ <<s + 1 == 1
_ = 1. /* ERROR "integer" */ <<s + 1 == 1.
_ = 1. /* ERROR "integer" */ <<s + 1. == 1
_ = 1. /* ERROR "integer" */ <<s + 1. == 1.
_ = 1<<s == 1<<s
_ = 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
_ = 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s
_ = 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
_ = 1<<s + 1<<s == 1
_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1
_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
_ = 1<<s + 1<<s == 1<<s + 1<<s
_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
}
func shifts5() {
// shifts in comparisons w/ typed operands
var s uint
var x int
_ = 1<<s == x
_ = 1.<<s == x
_ = 1.1 /* ERROR "int" */ <<s == x
_ = 1<<s + x == 1
_ = 1<<s + x == 1.
_ = 1<<s + x == 1.1 /* ERROR "int" */
_ = 1.<<s + x == 1
_ = 1.<<s + x == 1.
_ = 1.<<s + x == 1.1 /* ERROR "int" */
_ = 1.1 /* ERROR "int" */ <<s + x == 1
_ = 1.1 /* ERROR "int" */ <<s + x == 1.
_ = 1.1 /* ERROR "int" */ <<s + x == 1.1
_ = 1<<s == x<<s
_ = 1.<<s == x<<s
_ = 1.1 /* ERROR "int" */ <<s == x<<s
}
func shifts6() {
// shifts as operands in non-arithmetic operations and as arguments
var a [10]int
var s uint
_ = a[1<<s]
_ = a[1.0]
_ = a[1.0<<s]
_ = make([]int, 1.0)
_ = make([]int, 1.0<<s)
_ = make([]int, 1.1 /* ERROR "integer" */ <<s)
_ = float32(1)
_ = float32(1<<s)
_ = float32(1.0)
_ = float32(1.0 /* ERROR "int" */ <<s)
_ = float32(1.1 /* ERROR "int" */ <<s)
var b []int
_ = append(b, 1<<s)
_ = append(b, 1.0<<s)
_ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
var c []float32
_ = 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)
_ = complex(1.0 /* ERROR "must be integer" */ <<s, 0)
_ = complex(1.1 /* ERROR "must be integer" */ <<s, 0)
_ = complex(0, 1.0 /* ERROR "must be integer" */ <<s)
_ = complex(0, 1.1 /* ERROR "must be integer" */ <<s)
// TODO(gri) The delete below is not type-checked correctly yet.
// var m1 map[int]string
// delete(m1, 1<<s)
}
func shifts7() {
// shifts of shifts
var s uint
var x int
_ = 1<<(1<<s)
_ = 1<<(1.<<s)
_ = 1. /* ERROR "integer" */ <<(1<<s)
_ = 1. /* ERROR "integer" */ <<(1.<<s)
x = 1<<(1<<s)
x = 1<<(1.<<s)
x = 1.<<(1<<s)
x = 1.<<(1.<<s)
_ = (1<<s)<<(1<<s)
_ = (1<<s)<<(1.<<s)
_ = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
_ = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
x = (1<<s)<<(1<<s)
x = (1<<s)<<(1.<<s)
x = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
x = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
}
func shifts8() {
// various originally failing snippets of code from the std library
// from src/pkg/compress/lzw/reader.go:90
{
var d struct {
bits uint32
width uint
}
_ = uint16(d.bits & (1<<d.width - 1))
}
// from src/pkg/debug/dwarf/buf.go:116
{
var ux uint64
var bits uint
x := int64(ux)
if x&(1<<(bits-1)) != 0 {}
}
// from src/pkg/encoding/asn1/asn1.go:160
{
var bytes []byte
if bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {}
}
// from src/pkg/math/big/rat.go:140
{
var exp int
var mantissa uint64
shift := uint64(-1022 - (exp - 1)) // [1..53)
_ = mantissa & (1<<shift - 1)
}
// from src/pkg/net/interface.go:51
{
type Flags uint
var f Flags
var i int
if f&(1<<uint(i)) != 0 {}
}
// from src/pkg/runtime/softfloat64.go:234
{
var gm uint64
var shift uint
_ = gm & (1<<shift - 1)
}
// from src/pkg/strconv/atof.go:326
{
var mant uint64
var mantbits uint
if mant == 2<<mantbits {}
}
// from src/pkg/syscall/route_bsd.go:82
{
var Addrs int32
const rtaRtMask = 1
var i uint
if Addrs&rtaRtMask&(1<<i) == 0 {}
}
// from src/pkg/text/scanner/scanner.go:540
{
var s struct { Whitespace uint64 }
var ch rune
for s.Whitespace&(1<<uint(ch)) != 0 {}
}
}
......@@ -116,7 +116,7 @@ func switches() {
}
switch x {
case 1 /* ERROR "overflows int" */ << 100:
case 1 /* ERROR "overflows" */ << 100:
}
switch x {
......@@ -171,13 +171,13 @@ func typeswitches() {
switch t := x.(type) {
case nil:
var v bool = t /* ERROR "cannot assign" */
var v bool = t /* ERROR "cannot initialize" */
case int:
var v int = t
case float32, complex64:
var v float32 = t /* ERROR "cannot assign" */
var v float32 = t /* ERROR "cannot initialize" */
default:
var v float32 = t /* ERROR "cannot assign" */
var v float32 = t /* ERROR "cannot initialize" */
}
var t I
......
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