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 ( ...@@ -11,6 +11,9 @@ import (
"go/token" "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 // 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 // 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 // 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 ...@@ -170,6 +173,10 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
goto Error goto Error
} }
// arguments have final type
check.updateExprType(args[0], typ, true)
check.updateExprType(args[1], typ, true)
case _Copy: case _Copy:
var y operand var y operand
check.expr(&y, args[1], nil, iota) check.expr(&y, args[1], nil, iota)
...@@ -269,24 +276,13 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, 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) 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 var sizes []int64 // constant integer arguments, if any
for _, arg := range args[1:] { for _, arg := range args[1:] {
check.expr(x, arg, nil, iota) if s, ok := check.index(arg, -1, iota); ok && s >= 0 {
if x.isInteger(check.ctxt) { sizes = append(sizes, s)
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) { if len(sizes) == 2 && sizes[0] > sizes[1] {
check.invalidArg(args[1].Pos(), "length and capacity swapped") check.invalidArg(args[1].Pos(), "length and capacity swapped")
// safe to continue // safe to continue
} }
......
...@@ -18,6 +18,15 @@ const ( ...@@ -18,6 +18,15 @@ const (
trace = false // turn on for detailed type resolution traces 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 { type checker struct {
ctxt *Context ctxt *Context
fset *token.FileSet fset *token.FileSet
...@@ -31,14 +40,7 @@ type checker struct { ...@@ -31,14 +40,7 @@ type checker struct {
initspecs map[*ast.ValueSpec]*ast.ValueSpec // "inherited" type and initialization expressions for constant declarations initspecs map[*ast.ValueSpec]*ast.ValueSpec // "inherited" type and initialization expressions for constant declarations
methods map[*TypeName]*Scope // maps type names to associated methods methods map[*TypeName]*Scope // maps type names to associated methods
conversions map[*ast.CallExpr]bool // set of type-checked conversions (to distinguish from calls) conversions map[*ast.CallExpr]bool // set of type-checked conversions (to distinguish from calls)
untyped map[ast.Expr]exprInfo // map of expressions without final type
// 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
// functions // functions
funclist []function // list of functions/methods with correct signatures and non-empty bodies 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) { ...@@ -234,18 +236,14 @@ func (check *checker) object(obj Object, cycleOk bool) {
obj.Type = Typ[Invalid] obj.Type = Typ[Invalid]
return return
} }
obj.visited = true
switch d := obj.decl.(type) { switch d := obj.decl.(type) {
case *ast.Field: case *ast.Field:
unreachable() // function parameters are always typed when collected unreachable() // function parameters are always typed when collected
case *ast.ValueSpec: case *ast.ValueSpec:
obj.visited = true
check.valueSpec(d.Pos(), obj, d.Names, d, 0) check.valueSpec(d.Pos(), obj, d.Names, d, 0)
case *ast.AssignStmt: case *ast.AssignStmt:
// If we reach here, we have a short variable declaration unreachable() // assign1to1 sets the type for failing short var decls
// where the rhs didn't typecheck and thus the lhs has no
// types.
obj.visited = true
obj.Type = Typ[Invalid]
default: default:
unreachable() // see also function newObj unreachable() // see also function newObj
} }
...@@ -428,9 +426,7 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package, ...@@ -428,9 +426,7 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package,
initspecs: make(map[*ast.ValueSpec]*ast.ValueSpec), initspecs: make(map[*ast.ValueSpec]*ast.ValueSpec),
methods: make(map[*TypeName]*Scope), methods: make(map[*TypeName]*Scope),
conversions: make(map[*ast.CallExpr]bool), conversions: make(map[*ast.CallExpr]bool),
untyped: make(map[ast.Expr]*Basic), untyped: make(map[ast.Expr]exprInfo),
constants: make(map[ast.Expr]interface{}),
shiftOps: make(map[ast.Expr]bool),
} }
// set results and handle panics // set results and handle panics
...@@ -490,9 +486,9 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package, ...@@ -490,9 +486,9 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package,
// remaining untyped expressions must indeed be untyped // remaining untyped expressions must indeed be untyped
if debug { if debug {
for x, typ := range check.untyped { for x, info := range check.untyped {
if !isUntyped(typ) { if !isUntyped(info.typ) {
check.dump("%s: %s (type %s) is not untyped", x.Pos(), x, typ) check.dump("%s: %s (type %s) is not untyped", x.Pos(), x, info.typ)
panic(0) panic(0)
} }
} }
...@@ -503,8 +499,12 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package, ...@@ -503,8 +499,12 @@ func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package,
// after function body checking for smaller // after function body checking for smaller
// map size and more immediate feedback. // map size and more immediate feedback.
if ctxt.Expr != nil { if ctxt.Expr != nil {
for x, typ := range check.untyped { for x, info := range check.untyped {
ctxt.Expr(x, typ, check.constants[x]) var val interface{}
if info.isConst {
val = info.val
}
ctxt.Expr(x, info.typ, val)
} }
} }
......
...@@ -54,6 +54,7 @@ var tests = []struct { ...@@ -54,6 +54,7 @@ var tests = []struct {
{"expr1", []string{"testdata/expr1.src"}}, {"expr1", []string{"testdata/expr1.src"}},
{"expr2", []string{"testdata/expr2.src"}}, {"expr2", []string{"testdata/expr2.src"}},
{"expr3", []string{"testdata/expr3.src"}}, {"expr3", []string{"testdata/expr3.src"}},
{"shifts", []string{"testdata/shifts.src"}},
{"builtins", []string{"testdata/builtins.src"}}, {"builtins", []string{"testdata/builtins.src"}},
{"conversions", []string{"testdata/conversions.src"}}, {"conversions", []string{"testdata/conversions.src"}},
{"stmt0", []string{"testdata/stmt0.src"}}, {"stmt0", []string{"testdata/stmt0.src"}},
...@@ -62,17 +63,6 @@ var tests = []struct { ...@@ -62,17 +63,6 @@ var tests = []struct {
var fset = token.NewFileSet() 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 . // Positioned errors are of the form filename:line:column: message .
var posMsgRx = regexp.MustCompile(`^(.*:[0-9]+:[0-9]+): *(.*)`) var posMsgRx = regexp.MustCompile(`^(.*:[0-9]+:[0-9]+): *(.*)`)
...@@ -120,6 +110,7 @@ var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`) ...@@ -120,6 +110,7 @@ var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
// in files and returns them as a map of error positions to error messages. // 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 { 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) errmap := make(map[string][]string)
for _, file := range files { for _, file := range files {
...@@ -130,10 +121,7 @@ func errMap(t *testing.T, testname string, files []*ast.File) map[string][]strin ...@@ -130,10 +121,7 @@ func errMap(t *testing.T, testname string, files []*ast.File) map[string][]strin
} }
var s scanner.Scanner var s scanner.Scanner
// file was parsed already - do not add it again to the file s.Init(fset.AddFile(filename, fset.Base(), len(src)), src, nil, scanner.ScanComments)
// 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)
var prev string // position string of last non-comment, non-semicolon token var prev string // position string of last non-comment, non-semicolon token
scanFile: scanFile:
...@@ -143,9 +131,8 @@ func errMap(t *testing.T, testname string, files []*ast.File) map[string][]strin ...@@ -143,9 +131,8 @@ func errMap(t *testing.T, testname string, files []*ast.File) map[string][]strin
case token.EOF: case token.EOF:
break scanFile break scanFile
case token.COMMENT: case token.COMMENT:
s := errRx.FindStringSubmatch(lit) if s := errRx.FindStringSubmatch(lit); len(s) == 2 {
if len(s) == 2 { errmap[prev] = append(errmap[prev], s[1])
errmap[prev] = append(errmap[prev], string(s[1]))
} }
case token.SEMICOLON: case token.SEMICOLON:
// ignore automatically inserted semicolon // ignore automatically inserted semicolon
...@@ -164,17 +151,17 @@ func errMap(t *testing.T, testname string, files []*ast.File) map[string][]strin ...@@ -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) { func eliminate(t *testing.T, errmap map[string][]string, errlist []error) {
for _, err := range errlist { for _, err := range errlist {
pos, msg := splitError(err) pos, gotMsg := splitError(err)
list := errmap[pos] list := errmap[pos]
index := -1 // list index of matching message, if any index := -1 // list index of matching message, if any
// we expect one of the messages in list to match the error at pos // we expect one of the messages in list to match the error at pos
for i, msg := range list { for i, wantRx := range list {
rx, err := regexp.Compile(msg) rx, err := regexp.Compile(wantRx)
if err != nil { if err != nil {
t.Errorf("%s: %v", pos, err) t.Errorf("%s: %v", pos, err)
continue continue
} }
if rx.MatchString(msg) { if rx.MatchString(gotMsg) {
index = i index = i
break break
} }
...@@ -190,9 +177,8 @@ func eliminate(t *testing.T, errmap map[string][]string, errlist []error) { ...@@ -190,9 +177,8 @@ func eliminate(t *testing.T, errmap map[string][]string, errlist []error) {
delete(errmap, pos) delete(errmap, pos)
} }
} else { } 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) { ...@@ -213,10 +199,8 @@ func checkFiles(t *testing.T, testname string, testfiles []string) {
return return
} }
// match and eliminate errors // match and eliminate errors;
// we are expecting the following 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) errmap := errMap(t, testname, files)
eliminate(t, errmap, errlist) eliminate(t, errmap, errlist)
......
...@@ -182,24 +182,6 @@ func isZeroConst(x interface{}) bool { ...@@ -182,24 +182,6 @@ func isZeroConst(x interface{}) bool {
return ok && i == 0 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 // isRepresentableConst reports whether the value of constant x can
// be represented as a value of the basic type Typ[as] without loss // be represented as a value of the basic type Typ[as] without loss
// of precision. // of precision.
......
...@@ -36,7 +36,7 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota ...@@ -36,7 +36,7 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota
// common issue. // common issue.
if typ.Kind == String { if typ.Kind == String {
switch { switch {
case x.isInteger(check.ctxt): case x.isInteger():
codepoint, ok := x.val.(int64) codepoint, ok := x.val.(int64)
if !ok { if !ok {
// absolute value too large (or unknown) for conversion; // absolute value too large (or unknown) for conversion;
...@@ -60,6 +60,9 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota ...@@ -60,6 +60,9 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota
x.mode = value x.mode = value
} }
// the conversion argument types are final
check.updateExprType(x.expr, x.typ, true)
check.conversions[conv] = true // for cap/len checking check.conversions[conv] = true // for cap/len checking
x.expr = conv x.expr = conv
x.typ = typ x.typ = typ
......
...@@ -24,6 +24,51 @@ import ( ...@@ -24,6 +24,51 @@ import (
// - clients need access to builtins type information // - clients need access to builtins type information
// - API tests are missing (e.g., identifiers should be handled as expressions in callbacks) // - API tests are missing (e.g., identifiers should be handled as expressions in callbacks)
/*
Basic algorithm:
Expressions are checked recursively, top down. Expression checker functions
are generally of the form:
func f(x *operand, e *ast.Expr, ...)
where e is the expression to be checked, and x is the result of the check.
The check performed by f may fail in which case x.mode == invalid, and
related error messages will have been issued by f.
If a hint argument is present, it is the composite literal element type
of an outer composite literal; it is used to type-check composite literal
elements that have no explicit type specification in the source
(e.g.: []T{{...}, {...}}, the hint is the type T in this case).
If an iota argument >= 0 is present, it is the value of iota for the
specific expression.
All expressions are checked via rawExpr, which dispatches according
to expression kind. Upon returning, rawExpr is recording the types and
constant values for all expressions that have an untyped type (those types
may change on the way up in the expression tree). Usually these are constants,
but the results of comparisons or non-constant shifts of untyped constants
may also be untyped, but not constant.
Untyped expressions may eventually become fully typed (i.e., not untyped),
typically when the value is assigned to a variable, or is used otherwise.
The updateExprType method is used to record this final type and update
the recorded types: the type-checked expression tree is again traversed down,
and the new type is propagated as needed. Untyped constant expression values
that become fully typed must now be representable by the full type (constant
sub-expression trees are left alone except for their roots). This mechanism
ensures that a client sees the actual (run-time) type an untyped value would
have. It also permits type-checking of lhs shift operands "as if the shift
were not present": when updateExprType visits an untyped lhs shift operand
and assigns it it's final type, that type must be an integer type, and a
constant lhs must be representable as an integer.
When an expression gets its final type, either on the way out from rawExpr,
on the way down in updateExprType, or at the end of the type checker run,
if present the Context.Expr method is invoked to notify a go/types client.
*/
func (check *checker) collectParams(list *ast.FieldList, variadicOk bool) (params []*Var, isVariadic bool) { func (check *checker) collectParams(list *ast.FieldList, variadicOk bool) (params []*Var, isVariadic bool) {
if list == nil { if list == nil {
return return
...@@ -260,7 +305,7 @@ func (check *checker) isRepresentable(x *operand, typ *Basic) { ...@@ -260,7 +305,7 @@ func (check *checker) isRepresentable(x *operand, typ *Basic) {
if !isRepresentableConst(x.val, check.ctxt, typ.Kind) { if !isRepresentableConst(x.val, check.ctxt, typ.Kind) {
var msg string var msg string
if isNumeric(x.typ) && isNumeric(typ) { if isNumeric(x.typ) && isNumeric(typ) {
msg = "%s overflows %s" msg = "%s overflows (or cannot be accurately represented as) %s"
} else { } else {
msg = "cannot convert %s to %s" msg = "cannot convert %s to %s"
} }
...@@ -269,24 +314,30 @@ func (check *checker) isRepresentable(x *operand, typ *Basic) { ...@@ -269,24 +314,30 @@ func (check *checker) isRepresentable(x *operand, typ *Basic) {
} }
} }
// updateExprType updates the type of all untyped nodes in the // updateExprType updates the type of x to typ and invokes itself
// expression tree of x to typ. If shiftOp is set, x is the lhs // recursively for the operands of x, depending on expression kind.
// of a shift expression. In that case, and if x is in the set // If typ is still an untyped and not the final type, updateExprType
// of shift operands with delayed type checking, and typ is not // only updates the recorded untyped type for x and possibly its
// an untyped type, updateExprType will check if typ is an // operands. Otherwise (i.e., typ is not an untyped type anymore,
// integer type. // or it is the final type for x), Context.Expr is invoked, if present.
// If Context.Expr != nil, it is called for all nodes that are // Also, if x is a constant, it must be representable as a value of typ,
// now assigned their final (not untyped) type. // and if x is the (formerly untyped) lhs operand of a non-constant
func (check *checker) updateExprType(x ast.Expr, typ Type, shiftOp bool) { // shift, it must be an integer value.
//
func (check *checker) updateExprType(x ast.Expr, typ Type, final bool) {
old, found := check.untyped[x]
if !found {
return // nothing to do
}
// update operands of x if necessary
switch x := x.(type) { switch x := x.(type) {
case *ast.BadExpr, case *ast.BadExpr,
*ast.FuncLit, *ast.FuncLit,
*ast.CompositeLit, *ast.CompositeLit,
*ast.SelectorExpr,
*ast.IndexExpr, *ast.IndexExpr,
*ast.SliceExpr, *ast.SliceExpr,
*ast.TypeAssertExpr, *ast.TypeAssertExpr,
*ast.CallExpr,
*ast.StarExpr, *ast.StarExpr,
*ast.KeyValueExpr, *ast.KeyValueExpr,
*ast.ArrayType, *ast.ArrayType,
...@@ -295,58 +346,86 @@ func (check *checker) updateExprType(x ast.Expr, typ Type, shiftOp bool) { ...@@ -295,58 +346,86 @@ func (check *checker) updateExprType(x ast.Expr, typ Type, shiftOp bool) {
*ast.InterfaceType, *ast.InterfaceType,
*ast.MapType, *ast.MapType,
*ast.ChanType: *ast.ChanType:
// these expression are never untyped - nothing to do // These expression are never untyped - nothing to do.
// The respective sub-expressions got their final types
// upon assignment or use.
if debug {
check.dump("%s: found old type(%s): %s (new: %s)", x.Pos(), x, old.typ, typ)
unreachable()
}
return return
case *ast.Ident, *ast.BasicLit: case *ast.CallExpr:
// update type // Resulting in an untyped constant (e.g., built-in complex).
// The respective calls take care of calling updateExprType
// for the arguments if necessary.
case *ast.Ident, *ast.BasicLit, *ast.SelectorExpr:
// An identifier denoting a constant, a constant literal,
// or a qualified identifier (imported untyped constant).
// No operands to take care of.
case *ast.ParenExpr: case *ast.ParenExpr:
check.updateExprType(x.X, typ, false) check.updateExprType(x.X, typ, final)
case *ast.UnaryExpr: case *ast.UnaryExpr:
check.updateExprType(x.X, typ, false) // If x is a constant, the operands were constants.
// They don't need to be updated since they never
// get "materialized" into a typed value; and they
// will be processed at the end of the type check.
if old.isConst {
break
}
check.updateExprType(x.X, typ, final)
case *ast.BinaryExpr: case *ast.BinaryExpr:
if old.isConst {
break // see comment for unary expressions
}
if isComparison(x.Op) { if isComparison(x.Op) {
// result type is independent of operand types // The result type is independent of operand types
// and the operand types must have final types.
} else if isShift(x.Op) { } else if isShift(x.Op) {
// result type depends only on lhs operand // The result type depends only on lhs operand.
check.updateExprType(x.X, typ, true) // The rhs type was updated when checking the shift.
check.updateExprType(x.X, typ, final)
} else { } else {
// operand types match result type // The operand types match the result type.
check.updateExprType(x.X, typ, false) check.updateExprType(x.X, typ, final)
check.updateExprType(x.Y, typ, false) check.updateExprType(x.Y, typ, final)
} }
case *ast.Ellipsis:
unreachable()
default: default:
unreachable() unreachable()
} }
// TODO(gri) t should always exist, shouldn't it? // If the new type is not final and still untyped, just
if t := check.untyped[x]; t != nil { // update the recorded type.
if isUntyped(typ) { if !final && isUntyped(typ) {
check.untyped[x] = typ.(*Basic) old.typ = underlying(typ).(*Basic)
} else { check.untyped[x] = old
// notify clients of final type for x return
if f := check.ctxt.Expr; f != nil {
f(x, typ, check.constants[x])
} }
// Otherwise we have the final (typed or untyped type).
// Remove it from the map.
delete(check.untyped, x) delete(check.untyped, x)
delete(check.constants, x)
// check delayed shift // If x is the lhs of a shift, its final type must be integer.
// Note: Using shiftOp is an optimization: it prevents // We already know from the shift check that it is representable
// map lookups when we know x is not a shiftOp in the // as an integer if it is a constant.
// first place. if old.isLhs && !isInteger(typ) {
if shiftOp && check.shiftOps[x] {
if !isInteger(typ) {
check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ) check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ)
return
} }
delete(check.shiftOps, x)
} // Everything's fine, notify client of final type for x.
if f := check.ctxt.Expr; f != nil {
var val interface{}
if old.isConst {
val = old.val
} }
f(x, typ, val)
} }
} }
...@@ -419,7 +498,7 @@ func (check *checker) convertUntyped(x *operand, target Type) { ...@@ -419,7 +498,7 @@ func (check *checker) convertUntyped(x *operand, target Type) {
} }
x.typ = target x.typ = target
check.updateExprType(x.expr, target, false) check.updateExprType(x.expr, target, true) // UntypedNils are final
return return
Error: Error:
...@@ -456,18 +535,39 @@ func (check *checker) comparison(x, y *operand, op token.Token) { ...@@ -456,18 +535,39 @@ func (check *checker) comparison(x, y *operand, op token.Token) {
x.mode = value x.mode = value
} }
// The result type of a comparison is always boolean and
// independent of the argument types. They have now their
// final types (untyped or typed): update the respective
// expression trees.
check.updateExprType(x.expr, x.typ, true)
check.updateExprType(y.expr, y.typ, true)
x.typ = Typ[UntypedBool] x.typ = Typ[UntypedBool]
} }
func (check *checker) shift(x, y *operand, op token.Token) { func (check *checker) shift(x, y *operand, op token.Token) {
untypedx := isUntyped(x.typ)
// The lhs must be of integer type or be representable
// as an integer; otherwise the shift has no chance.
if !isInteger(x.typ) && (!untypedx || !isRepresentableConst(x.val, nil, UntypedInt)) {
check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
x.mode = invalid
return
}
// spec: "The right operand in a shift expression must have unsigned // spec: "The right operand in a shift expression must have unsigned
// integer type or be an untyped constant that can be converted to // integer type or be an untyped constant that can be converted to
// unsigned integer type." // unsigned integer type."
switch { switch {
case isInteger(y.typ) && isUnsigned(y.typ): case isInteger(y.typ) && isUnsigned(y.typ):
// nothing to do // nothing to do
case y.mode == constant && isUntyped(y.typ): case isUntyped(y.typ):
check.convertUntyped(x, Typ[UntypedInt]) check.convertUntyped(y, Typ[UntypedInt])
if y.mode == invalid {
x.mode = invalid
return
}
default: default:
check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y) check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
x.mode = invalid x.mode = invalid
...@@ -476,17 +576,10 @@ func (check *checker) shift(x, y *operand, op token.Token) { ...@@ -476,17 +576,10 @@ func (check *checker) shift(x, y *operand, op token.Token) {
if x.mode == constant { if x.mode == constant {
if y.mode == constant { if y.mode == constant {
// constant shift - lhs must be (representable as) an integer if untypedx {
if isUntyped(x.typ) {
if !isRepresentableConst(x.val, check.ctxt, UntypedInt) {
check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
x.mode = invalid
return
}
x.typ = Typ[UntypedInt] x.typ = Typ[UntypedInt]
} }
assert(x.isInteger(check.ctxt)) if x.val != nil && y.val != nil {
// rhs must be within reasonable bounds // rhs must be within reasonable bounds
const stupidShift = 1024 const stupidShift = 1024
s, ok := y.val.(int64) s, ok := y.val.(int64)
...@@ -495,14 +588,16 @@ func (check *checker) shift(x, y *operand, op token.Token) { ...@@ -495,14 +588,16 @@ func (check *checker) shift(x, y *operand, op token.Token) {
x.mode = invalid x.mode = invalid
return return
} }
// everything's ok // everything's ok
x.val = shiftConst(x.val, uint(s), op) x.val = shiftConst(x.val, uint(s), op)
} else {
x.val = nil
}
return return
} }
// non-constant shift with constant lhs // non-constant shift with constant lhs
if isUntyped(x.typ) { if untypedx {
// spec: "If the left operand of a non-constant shift expression is // spec: "If the left operand of a non-constant shift expression is
// an untyped constant, the type of the constant is what it would be // an untyped constant, the type of the constant is what it would be
// if the shift expression were replaced by its left operand alone; // if the shift expression were replaced by its left operand alone;
...@@ -510,8 +605,16 @@ func (check *checker) shift(x, y *operand, op token.Token) { ...@@ -510,8 +605,16 @@ func (check *checker) shift(x, y *operand, op token.Token) {
// instance, if the shift expression is an operand in a comparison // instance, if the shift expression is an operand in a comparison
// against an untyped constant)". // against an untyped constant)".
// delay operand checking until we know the type // Delay operand checking until we know the final type:
check.shiftOps[x.expr] = true // The lhs expression must be in the untyped map, mark
// the entry as lhs shift operand.
if info, ok := check.untyped[x.expr]; ok {
info.isLhs = true
check.untyped[x.expr] = info
} else {
unreachable()
}
// keep x's type
x.mode = value x.mode = value
return return
} }
...@@ -613,36 +716,41 @@ func (check *checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token, iota ...@@ -613,36 +716,41 @@ func (check *checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token, iota
// x.typ is unchanged // x.typ is unchanged
} }
// index checks an index expression for validity. If length >= 0, it is the upper // index checks an index/size expression arg for validity.
// bound for the index. The result is a valid index >= 0, or a negative value. // If length >= 0, it is the upper bound for arg.
// // TODO(gri): Do we need iota?
func (check *checker) index(index ast.Expr, length int64, iota int) int64 { func (check *checker) index(arg ast.Expr, length int64, iota int) (i int64, ok bool) {
var x operand var x operand
check.expr(&x, arg, nil, iota)
check.expr(&x, index, nil, iota) // an untyped constant must be representable as Int
if !x.isInteger(check.ctxt) { check.convertUntyped(&x, Typ[Int])
check.errorf(x.pos(), "index %s must be integer", &x) if x.mode == invalid {
return -1 return
}
if x.mode != constant {
return -1 // we cannot check more
} }
// The spec doesn't require int64 indices, but perhaps it should.
i, ok := x.val.(int64) // the index/size must be of integer type
if !ok { if !isInteger(x.typ) {
check.errorf(x.pos(), "stupid index %s", &x) check.invalidArg(x.pos(), "%s must be integer", &x)
return -1 return
} }
// a constant index/size i must be 0 <= i < length
if x.mode == constant && x.val != nil {
i = x.val.(int64)
if i < 0 { if i < 0 {
check.errorf(x.pos(), "index %s must not be negative", &x) check.invalidArg(x.pos(), "%s must not be negative", &x)
return -1 return
} }
if length >= 0 && i >= length { 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
}
// 0 <= i [ && i < length ]
return i, true
} }
return i return -1, true
} }
// compositeLitKey resolves unresolved composite literal keys. // compositeLitKey resolves unresolved composite literal keys.
...@@ -673,8 +781,10 @@ func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64, iota ...@@ -673,8 +781,10 @@ func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64, iota
eval := e eval := e
if kv, _ := e.(*ast.KeyValueExpr); kv != nil { if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
check.compositeLitKey(kv.Key) check.compositeLitKey(kv.Key)
if i := check.index(kv.Key, length, iota); i >= 0 { if i, ok := check.index(kv.Key, length, iota); ok {
if i >= 0 {
index = i index = i
}
validIndex = true validIndex = true
} }
eval = kv.Value eval = kv.Value
...@@ -756,6 +866,7 @@ func (check *checker) argument(sig *Signature, i int, arg ast.Expr, x *operand, ...@@ -756,6 +866,7 @@ func (check *checker) argument(sig *Signature, i int, arg ast.Expr, x *operand,
var emptyResult Result var emptyResult Result
func (check *checker) callExpr(x *operand) { func (check *checker) callExpr(x *operand) {
// convert x into a user-friendly set of values
var typ Type var typ Type
var val interface{} var val interface{}
switch x.mode { switch x.mode {
...@@ -774,10 +885,7 @@ func (check *checker) callExpr(x *operand) { ...@@ -774,10 +885,7 @@ func (check *checker) callExpr(x *operand) {
// until it becomes typed or until the end of // until it becomes typed or until the end of
// type checking // type checking
if isUntyped(typ) { if isUntyped(typ) {
check.untyped[x.expr] = typ.(*Basic) check.untyped[x.expr] = exprInfo{x.mode == constant, false, typ.(*Basic), val}
if val != nil {
check.constants[x.expr] = val
}
return return
} }
...@@ -806,6 +914,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle ...@@ -806,6 +914,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
defer check.untrace("=> %s", x) defer check.untrace("=> %s", x)
} }
// record final type of x if untyped, notify clients of type otherwise
defer check.callExpr(x) defer check.callExpr(x)
switch e := e.(type) { switch e := e.(type) {
...@@ -998,7 +1107,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle ...@@ -998,7 +1107,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
} }
continue continue
} }
if x.mode == constant { if x.mode == constant && x.val != nil {
if visited[x.val] { if visited[x.val] {
check.errorf(x.pos(), "duplicate key %s in map literal", x.val) check.errorf(x.pos(), "duplicate key %s in map literal", x.val)
continue continue
...@@ -1112,7 +1221,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle ...@@ -1112,7 +1221,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
case *Basic: case *Basic:
if isString(typ) { if isString(typ) {
valid = true valid = true
if x.mode == constant { if x.mode == constant && x.val != nil {
length = int64(len(x.val.(string))) length = int64(len(x.val.(string)))
} }
// an indexed string always yields a byte value // an indexed string always yields a byte value
...@@ -1183,7 +1292,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle ...@@ -1183,7 +1292,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
case *Basic: case *Basic:
if isString(typ) { if isString(typ) {
valid = true valid = true
if x.mode == constant { if x.mode == constant && x.val != nil {
length = int64(len(x.val.(string))) + 1 // +1 for slice length = int64(len(x.val.(string))) + 1 // +1 for slice
} }
// a sliced string always yields a string value // a sliced string always yields a string value
...@@ -1228,12 +1337,16 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle ...@@ -1228,12 +1337,16 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
lo := int64(0) lo := int64(0)
if e.Low != nil { if e.Low != nil {
lo = check.index(e.Low, length, iota) if i, ok := check.index(e.Low, length, iota); ok && i >= 0 {
lo = i
}
} }
hi := int64(-1) hi := int64(-1)
if e.High != nil { if e.High != nil {
hi = check.index(e.High, length, iota) if i, ok := check.index(e.High, length, iota); ok && i >= 0 {
hi = i
}
} else if length >= 0 { } else if length >= 0 {
hi = length hi = length
} }
......
...@@ -205,11 +205,10 @@ func (x *operand) isAssignable(ctxt *Context, T Type) bool { ...@@ -205,11 +205,10 @@ func (x *operand) isAssignable(ctxt *Context, T Type) bool {
} }
// isInteger reports whether x is a (typed or untyped) integer value. // 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() bool {
func (x *operand) isInteger(ctxt *Context) bool {
return x.mode == invalid || return x.mode == invalid ||
isInteger(x.typ) || 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. // 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 ...@@ -59,6 +59,8 @@ func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota
if !decl { if !decl {
// anything can be assigned to the blank identifier // anything can be assigned to the blank identifier
if ident != nil && ident.Name == "_" { if ident != nil && ident.Name == "_" {
// the rhs has its final type
check.updateExprType(rhs, x.typ, true)
return return
} }
......
...@@ -54,6 +54,7 @@ func _complex() { ...@@ -54,6 +54,7 @@ func _complex() {
var f32 float32 var f32 float32
var f64 float64 var f64 float64
var c64 complex64 var c64 complex64
var c128 complex128
_ = complex /* ERROR "argument" */ () _ = complex /* ERROR "argument" */ ()
_ = complex /* ERROR "argument" */ (1) _ = complex /* ERROR "argument" */ (1)
_ = complex(true /* ERROR "invalid argument" */ , 0) _ = complex(true /* ERROR "invalid argument" */ , 0)
...@@ -78,6 +79,21 @@ func _complex() { ...@@ -78,6 +79,21 @@ func _complex() {
_ = complex(1, 1.1) _ = complex(1, 1.1)
_ = complex(1, 'a') _ = complex(1, 'a')
complex /* ERROR "not used" */ (1, 2) 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() { func _copy() {
...@@ -161,7 +177,9 @@ func _len() { ...@@ -161,7 +177,9 @@ func _len() {
} }
func _make() { func _make() {
n := 0 var n int
var m float32
var s uint
_ = make /* ERROR "argument" */ () _ = make /* ERROR "argument" */ ()
_ = make(1 /* ERROR "not a type" */) _ = make(1 /* ERROR "not a type" */)
...@@ -172,32 +190,40 @@ func _make() { ...@@ -172,32 +190,40 @@ func _make() {
_ = make/* ERROR "arguments" */ ([]int, 2, 3, 4) _ = make/* ERROR "arguments" */ ([]int, 2, 3, 4)
_ = make([]int, int /* ERROR "not an expression" */) _ = make([]int, int /* ERROR "not an expression" */)
_ = make([]int, 10, float32 /* ERROR "not an expression" */) _ = make([]int, 10, float32 /* ERROR "not an expression" */)
_ = make([]int, "foo" /* ERROR "must be an integer" */) _ = make([]int, "foo" /* ERROR "cannot convert" */)
_ = make([]int, 10, 2.3 /* ERROR "must be an integer" */) _ = make([]int, 10, 2.3 /* ERROR "overflows" */)
_ = make([]int, 5, 10.0) _ = make([]int, 5, 10.0)
_ = make([]int, 0i) _ = 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, - /* ERROR "must not be negative" */ 1, 10)
_ = make([]int, 0, - /* ERROR "must not be negative" */ 1) _ = 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, - /* 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 "overflows" */ <<100, 1 /* ERROR "overflows" */ <<100)
_ = make([]int, 1 /* ERROR "length and capacity swapped" */ <<100 + 1, 1<<100) _ = make([]int, 10 /* ERROR "length and capacity swapped" */ , 9)
_ = make([]int, 1 /* ERROR "length and capacity swapped" */ <<100, 12345) _ = make([]int, 1 /* ERROR "overflows" */ <<100, 12345)
_ = make([]int, m /* ERROR "must be integer" */ )
// maps // maps
_ = make /* ERROR "arguments" */ (map[int]string, 10, 20) _ = make /* ERROR "arguments" */ (map[int]string, 10, 20)
_ = make(map[int]float32, int /* ERROR "not an expression" */) _ = 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, 10)
_ = make(map[int]float32, n) _ = make(map[int]float32, n)
_ = make(map[int]float32, int64(n)) _ = make(map[int]float32, int64(n))
_ = make(map[string]bool, 10.0)
_ = make(map[string]bool, 10.0<<s)
// channels // channels
_ = make /* ERROR "arguments" */ (chan int, 10, 20) _ = make /* ERROR "arguments" */ (chan int, 10, 20)
_ = make(chan int, int /* ERROR "not an expression" */) _ = 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 float64, 10)
_ = make(chan chan int, n) _ = make(chan chan int, n)
_ = make(chan string, int64(n)) _ = make(chan string, int64(n))
_ = make(chan bool, 10.0)
_ = make(chan bool, 10.0<<s)
make /* ERROR "not used" */ ([]int, 10) make /* ERROR "not used" */ ([]int, 10)
} }
...@@ -309,8 +335,8 @@ func _Offsetof() { ...@@ -309,8 +335,8 @@ func _Offsetof() {
var x struct{ f int } var x struct{ f int }
_ = unsafe /* ERROR "argument" */ .Offsetof() _ = unsafe /* ERROR "argument" */ .Offsetof()
_ = unsafe /* ERROR "argument" */ .Offsetof(1, 2) _ = unsafe /* ERROR "argument" */ .Offsetof(1, 2)
_ = unsafe.Offsetof(int /* ERROR "not an expression" */) _ = unsafe.Offsetof(int /* ERROR "not a selector expression" */)
_ = unsafe.Offsetof(x /* ERROR "not a selector" */) _ = unsafe.Offsetof(x /* ERROR "not a selector expression" */)
_ = unsafe.Offsetof(x.f) _ = unsafe.Offsetof(x.f)
_ = unsafe.Offsetof((x.f)) _ = unsafe.Offsetof((x.f))
_ = unsafe.Offsetof((((((((x))).f))))) _ = unsafe.Offsetof((((((((x))).f)))))
...@@ -338,7 +364,7 @@ func _Offsetof() { ...@@ -338,7 +364,7 @@ func _Offsetof() {
var y2 S2 var y2 S2
assert(unsafe.Offsetof(y2.S1) == 0) 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() { func _Sizeof() {
......
...@@ -37,7 +37,7 @@ var ( ...@@ -37,7 +37,7 @@ var (
s4 = s + t s4 = s + t
s5 = s /* ERROR "invalid operation" */ / t s5 = s /* ERROR "invalid operation" */ / t
s6 = array[t1] s6 = array[t1]
s7 = array[x /* ERROR "index" */] s7 = array[x /* ERROR "integer" */]
s8 = &a s8 = &a
s10 = &42 /* ERROR "cannot take address" */ s10 = &42 /* ERROR "cannot take address" */
s11 = &v s11 = &v
...@@ -48,16 +48,16 @@ var ( ...@@ -48,16 +48,16 @@ var (
s19 = s1 /* ERROR "cannot call" */ () s19 = s1 /* ERROR "cannot call" */ ()
s20 = f0 /* ERROR "no value" */ () s20 = f0 /* ERROR "no value" */ ()
s21 = f6(1, s1, i) 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 t1 int = i + j
t2 int = i /* ERROR "mismatched types" */ + x 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 t4 string = s + t
t5 string = s /* ERROR "invalid operation" */ / t t5 string = s /* ERROR "invalid operation" */ / t
t6 byte = array[t1] t6 byte = array[t1]
t7 byte = array[x /* ERROR "index" */] t7 byte = array[x /* ERROR "must be integer" */]
t8 *int = & /* ERROR "cannot assign" */ a t8 *int = & /* ERROR "cannot initialize" */ a
t10 *int = &42 /* ERROR "cannot take address" */ t10 *int = &42 /* ERROR "cannot take address" */
t11 *complex64 = &v t11 *complex64 = &v
t12 complex64 = -(u + *t11) / *&v t12 complex64 = -(u + *t11) / *&v
......
...@@ -2,171 +2,45 @@ ...@@ -2,171 +2,45 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// various expressions
package expr3 package expr3
func shifts1() {
var (
i0 int
u0 uint
)
var (
v0 = 1<<0
v1 = 1<<i0 /* ERROR "must be unsigned" */
v2 = 1<<u0
v3 = 1<<"foo" /* ERROR "must be unsigned" */
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
n = 1.0<<s != 0 // 1.0 has type int; n == false if ints are 32bits in size
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) {
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)
// TODO(gri) add more tests (systematically)
}
func shifts4() {
// 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 {}
}
}
// TODO(gri) The error messages below depend on adjusting the spec
// to reflect what gc is doing at the moment (the spec
// asks for run-time errors at the moment - see issue 4231).
// TODO(gri) This has been fixed in the spec. Fix this.
//
func indexes() { func indexes() {
_ = 1 /* ERROR "cannot index" */ [0] _ = 1 /* ERROR "cannot index" */ [0]
_ = indexes /* ERROR "cannot index" */ [0] _ = indexes /* ERROR "cannot index" */ [0]
_ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2] _ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2]
var a [10]int var a [10]int
_ = a[true /* ERROR "must be integer" */ ] _ = a[true /* ERROR "cannot convert" */ ]
_ = a["foo" /* ERROR "must be integer" */ ] _ = a["foo" /* ERROR "cannot convert" */ ]
_ = a[1.1 /* ERROR "must be integer" */ ] _ = a[1.1 /* ERROR "overflows" */ ]
_ = a[1.0] _ = a[1.0]
_ = a[- /* ERROR "index .* negative" */ 1] _ = a[- /* ERROR "negative" */ 1]
_ = a[- /* ERROR "index .* negative" */ 1 :] _ = a[- /* ERROR "negative" */ 1 :]
_ = a[: - /* ERROR "index .* negative" */ 1] _ = a[: - /* ERROR "negative" */ 1]
var a0 int var a0 int
a0 = a[0] a0 = a[0]
var a1 int32 var a1 int32
a1 = a /* ERROR "cannot assign" */ [1] a1 = a /* ERROR "cannot assign" */ [1]
_ = a[9] _ = a[9]
_ = a[10 /* ERROR "index .* out of bounds" */ ] _ = a[10 /* ERROR "index .* out of bounds" */ ]
_ = a[1 /* ERROR "stupid index" */ <<100] _ = a[1 /* ERROR "overflows" */ <<100]
_ = a[10:] _ = a[10:]
_ = a[:10] _ = a[:10]
_ = a[10:10] _ = a[10:10]
_ = a[11 /* ERROR "index .* out of bounds" */ :] _ = a[11 /* ERROR "index .* out of bounds" */ :]
_ = a[: 11 /* ERROR "index .* out of bounds" */ ] _ = a[: 11 /* ERROR "index .* out of bounds" */ ]
_ = a[: 1 /* ERROR "stupid index" */ <<100] _ = a[: 1 /* ERROR "overflows" */ <<100]
pa := &a pa := &a
_ = pa[9] _ = pa[9]
_ = pa[10 /* ERROR "index .* out of bounds" */ ] _ = pa[10 /* ERROR "index .* out of bounds" */ ]
_ = pa[1 /* ERROR "stupid index" */ <<100] _ = pa[1 /* ERROR "overflows" */ <<100]
_ = pa[10:] _ = pa[10:]
_ = pa[:10] _ = pa[:10]
_ = pa[10:10] _ = pa[10:10]
_ = pa[11 /* ERROR "index .* out of bounds" */ :] _ = pa[11 /* ERROR "index .* out of bounds" */ :]
_ = pa[: 11 /* ERROR "index .* out of bounds" */ ] _ = pa[: 11 /* ERROR "index .* out of bounds" */ ]
_ = pa[: 1 /* ERROR "stupid index" */ <<100] _ = pa[: 1 /* ERROR "overflows" */ <<100]
var b [0]int var b [0]int
_ = b[0 /* ERROR "index .* out of bounds" */ ] _ = b[0 /* ERROR "index .* out of bounds" */ ]
...@@ -176,21 +50,21 @@ func indexes() { ...@@ -176,21 +50,21 @@ func indexes() {
_ = b[0:0] _ = b[0:0]
var s []int var s []int
_ = s[- /* ERROR "index .* negative" */ 1] _ = s[- /* ERROR "negative" */ 1]
_ = s[- /* ERROR "index .* negative" */ 1 :] _ = s[- /* ERROR "negative" */ 1 :]
_ = s[: - /* ERROR "index .* negative" */ 1] _ = s[: - /* ERROR "negative" */ 1]
_ = s[0] _ = s[0]
_ = 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 /* ERROR "stupid index" */ <<100] _ = s[: 1 /* ERROR "overflows" */ <<100]
_ = s[1 /* ERROR "stupid index" */ <<100 :] _ = s[1 /* ERROR "overflows" */ <<100 :]
_ = s[1 /* ERROR "stupid index" */ <<100 : 1 /* ERROR "stupid index" */ <<100] _ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
var t string var t string
_ = t[- /* ERROR "index .* negative" */ 1] _ = t[- /* ERROR "negative" */ 1]
_ = t[- /* ERROR "index .* negative" */ 1 :] _ = t[- /* ERROR "negative" */ 1 :]
_ = t[: - /* ERROR "index .* negative" */ 1] _ = t[: - /* ERROR "negative" */ 1]
var t0 byte var t0 byte
t0 = t[0] t0 = t[0]
var t1 rune var t1 rune
...@@ -199,9 +73,9 @@ func indexes() { ...@@ -199,9 +73,9 @@ func indexes() {
_ = ("foo" + "bar")[6 /* ERROR "index .* out of bounds" */ ] _ = ("foo" + "bar")[6 /* ERROR "index .* out of bounds" */ ]
const c = "foo" const c = "foo"
_ = c[- /* ERROR "index .* negative" */ 1] _ = c[- /* ERROR "negative" */ 1]
_ = c[- /* ERROR "index .* negative" */ 1 :] _ = c[- /* ERROR "negative" */ 1 :]
_ = c[: - /* ERROR "index .* negative" */ 1] _ = c[: - /* ERROR "negative" */ 1]
var c0 byte var c0 byte
c0 = c[0] c0 = c[0]
var c2 float32 var c2 float32
...@@ -233,7 +107,7 @@ func method_expressions() { ...@@ -233,7 +107,7 @@ func method_expressions() {
_ = T /* ERROR "has no method" */ .x _ = T /* ERROR "has no method" */ .x
_ = T.m _ = T.m
var f func(*T) = (*T).m var f func(*T) = (*T).m
var g func(*T) = ( /* ERROR "cannot assign" */ T).m var g func(*T) = ( /* ERROR "cannot initialize" */ T).m
} }
func struct_literals() { func struct_literals() {
...@@ -254,7 +128,7 @@ func struct_literals() { ...@@ -254,7 +128,7 @@ func struct_literals() {
_ = T1{aa /* ERROR "unknown field" */ : 0} _ = T1{aa /* ERROR "unknown field" */ : 0}
_ = T1{1 /* ERROR "invalid field name" */ : 0} _ = T1{1 /* ERROR "invalid field name" */ : 0}
_ = T1{a: 0, s: "foo", u: 0, a /* ERROR "duplicate field" */: 10} _ = T1{a: 0, s: "foo", u: 0, a /* ERROR "duplicate field" */: 10}
_ = T1{a: "foo" /* ERROR "cannot use" */ } _ = T1{a: "foo" /* ERROR "cannot convert" */ }
_ = T1{c /* ERROR "unknown field" */ : 0} _ = T1{c /* ERROR "unknown field" */ : 0}
_ = T1{T0: { /* ERROR "missing type" */ }} _ = T1{T0: { /* ERROR "missing type" */ }}
_ = T1{T0: T0{}} _ = T1{T0: T0{}}
...@@ -265,7 +139,7 @@ func struct_literals() { ...@@ -265,7 +139,7 @@ func struct_literals() {
_ = T0{1, b /* ERROR "mixture" */ : 2, 3} _ = T0{1, b /* ERROR "mixture" */ : 2, 3}
_ = T0{1, 2} /* ERROR "too few values" */ _ = T0{1, 2} /* ERROR "too few values" */
_ = T0{1, 2, 3, 4 /* ERROR "too many values" */ } _ = T0{1, 2, 3, 4 /* ERROR "too many values" */ }
_ = T0{1, "foo" /* ERROR "cannot use" */, 3.4 /* ERROR "cannot use" */} _ = T0{1, "foo" /* ERROR "cannot convert" */, 3.4 /* ERROR "overflows" */}
} }
func array_literals() { func array_literals() {
...@@ -279,18 +153,18 @@ func array_literals() { ...@@ -279,18 +153,18 @@ func array_literals() {
_ = A1{0, 1, 2} _ = A1{0, 1, 2}
_ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
_ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /* ERROR "index .* out of bounds" */ } _ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /* ERROR "index .* out of bounds" */ }
_ = A1{- /* ERROR "index .* negative" */ 1: 0} _ = A1{- /* ERROR "negative" */ 1: 0}
_ = A1{8: 8, 9} _ = A1{8: 8, 9}
_ = A1{8: 8, 9, 10 /* ERROR "index .* out of bounds" */ } _ = A1{8: 8, 9, 10 /* ERROR "index .* out of bounds" */ }
_ = A1{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4} _ = A1{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
_ = A1{5: 5, 6, 7, 3: 3, 4} _ = A1{5: 5, 6, 7, 3: 3, 4}
_ = A1{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ } _ = A1{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
_ = A1{10 /* ERROR "index .* out of bounds" */ : 10, 10 /* ERROR "index .* out of bounds" */ : 10} _ = A1{10 /* ERROR "index .* out of bounds" */ : 10, 10 /* ERROR "index .* out of bounds" */ : 10}
_ = A1{5: 5, 6, 7, 3: 3, 1 /* ERROR "stupid index" */ <<100: 4, 5 /* ERROR "duplicate index" */ } _ = A1{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
_ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "stupid index" */ <<100: 4} _ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
_ = A1{2.0} _ = A1{2.0}
_ = A1{2.1 /* ERROR "cannot use" */ } _ = A1{2.1 /* ERROR "overflows" */ }
_ = A1{"foo" /* ERROR "cannot use" */ } _ = A1{"foo" /* ERROR "cannot convert" */ }
a0 := [...]int{} a0 := [...]int{}
assert(len(a0) == 0) assert(len(a0) == 0)
...@@ -302,7 +176,7 @@ func array_literals() { ...@@ -302,7 +176,7 @@ func array_literals() {
a13 = a1 a13 = a1
a14 = a1 /* ERROR "cannot assign" */ a14 = a1 /* ERROR "cannot assign" */
a2 := [...]int{- /* ERROR "index .* negative" */ 1: 0} a2 := [...]int{- /* ERROR "negative" */ 1: 0}
a3 := [...]int{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4} a3 := [...]int{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
assert(len(a3) == 5) // somewhat arbitrary assert(len(a3) == 5) // somewhat arbitrary
...@@ -326,18 +200,18 @@ func slice_literals() { ...@@ -326,18 +200,18 @@ func slice_literals() {
_ = S0{0, 1, 2} _ = S0{0, 1, 2}
_ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
_ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} _ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
_ = S0{- /* ERROR "index .* negative" */ 1: 0} _ = S0{- /* ERROR "negative" */ 1: 0}
_ = S0{8: 8, 9} _ = S0{8: 8, 9}
_ = S0{8: 8, 9, 10} _ = S0{8: 8, 9, 10}
_ = S0{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4} _ = S0{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
_ = S0{5: 5, 6, 7, 3: 3, 4} _ = S0{5: 5, 6, 7, 3: 3, 4}
_ = S0{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ } _ = S0{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
_ = S0{10: 10, 10 /* ERROR "duplicate index" */ : 10} _ = S0{10: 10, 10 /* ERROR "duplicate index" */ : 10}
_ = S0{5: 5, 6, 7, 3: 3, 1 /* ERROR "stupid index" */ <<100: 4, 5 /* ERROR "duplicate index" */ } _ = S0{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
_ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "stupid index" */ <<100: 4} _ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
_ = S0{2.0} _ = S0{2.0}
_ = S0{2.1 /* ERROR "cannot use" */ } _ = S0{2.1 /* ERROR "overflows" */ }
_ = S0{"foo" /* ERROR "cannot use" */ } _ = S0{"foo" /* ERROR "cannot convert" */ }
// indices must be resolved correctly // indices must be resolved correctly
// (for details, see comment in go/parser/parser.go, method parseElement) // (for details, see comment in go/parser/parser.go, method parseElement)
...@@ -356,8 +230,8 @@ func map_literals() { ...@@ -356,8 +230,8 @@ func map_literals() {
_ = M0{} _ = M0{}
_ = M0{1 /* ERROR "missing key" */ } _ = M0{1 /* ERROR "missing key" */ }
_ = M0{1 /* ERROR "cannot use .* as string key" */ : 2} _ = M0{1 /* ERROR "cannot convert" */ : 2}
_ = M0{"foo": "bar" /* ERROR "cannot use .* as int value" */ } _ = M0{"foo": "bar" /* ERROR "cannot convert" */ }
_ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 } _ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
// map keys must be resolved correctly // map keys must be resolved correctly
...@@ -428,7 +302,7 @@ func _calls() { ...@@ -428,7 +302,7 @@ func _calls() {
f1(10.0) f1(10.0)
f1 /* ERROR "too few arguments" */ () f1 /* ERROR "too few arguments" */ ()
f1(x, y /* ERROR "too many arguments" */ ) f1(x, y /* ERROR "too many arguments" */ )
f1(s /* ERROR "cannot assign" */ ) f1(s /* ERROR "cannot pass" */ )
f1(x ... /* ERROR "cannot use ..." */ ) f1(x ... /* ERROR "cannot use ..." */ )
f1(g0 /* ERROR "used as value" */ ()) f1(g0 /* ERROR "used as value" */ ())
f1(g1()) f1(g1())
...@@ -437,24 +311,24 @@ func _calls() { ...@@ -437,24 +311,24 @@ func _calls() {
f2 /* ERROR "too few arguments" */ () f2 /* ERROR "too few arguments" */ ()
f2 /* ERROR "too few arguments" */ (3.14) f2 /* ERROR "too few arguments" */ (3.14)
f2(3.14, "foo") f2(3.14, "foo")
f2(x /* ERROR "cannot assign" */ , "foo") f2(x /* ERROR "cannot pass" */ , "foo")
f2(g0 /* ERROR "used as value" */ ()) f2(g0 /* ERROR "used as value" */ ())
f2 /* ERROR "too few arguments" */ (g1 /* ERROR "cannot assign" */ ()) f2 /* ERROR "too few arguments" */ (g1 /* ERROR "cannot pass" */ ())
f2(g2()) f2(g2())
fs /* ERROR "too few arguments" */ () fs /* ERROR "too few arguments" */ ()
fs(g0 /* ERROR "used as value" */ ()) fs(g0 /* ERROR "used as value" */ ())
fs(g1 /* ERROR "cannot assign" */ ()) fs(g1 /* ERROR "cannot pass" */ ())
// fs(g2()) // TODO(gri) missing position in error message // fs(g2()) // TODO(gri) missing position in error message
fs(gs()) fs(gs())
fv() fv()
fv(1, 2.0, x) fv(1, 2.0, x)
fv(s /* ERROR "cannot assign" */ ) fv(s /* ERROR "cannot pass" */ )
fv(s...) fv(s...)
fv(1, s /* ERROR "can only use ... with matching parameter" */ ...) fv(1, s /* ERROR "can only use ... with matching parameter" */ ...)
fv(gs /* ERROR "cannot assign" */ ()) fv(gs /* ERROR "cannot pass" */ ())
fv(gs /* ERROR "cannot assign" */ ()...) fv(gs /* ERROR "cannot pass" */ ()...)
fi() fi()
fi(1, 2.0, x, 3.14, "foo") fi(1, 2.0, x, 3.14, "foo")
......
// 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() { ...@@ -116,7 +116,7 @@ func switches() {
} }
switch x { switch x {
case 1 /* ERROR "overflows int" */ << 100: case 1 /* ERROR "overflows" */ << 100:
} }
switch x { switch x {
...@@ -171,13 +171,13 @@ func typeswitches() { ...@@ -171,13 +171,13 @@ func typeswitches() {
switch t := x.(type) { switch t := x.(type) {
case nil: case nil:
var v bool = t /* ERROR "cannot assign" */ var v bool = t /* ERROR "cannot initialize" */
case int: case int:
var v int = t var v int = t
case float32, complex64: case float32, complex64:
var v float32 = t /* ERROR "cannot assign" */ var v float32 = t /* ERROR "cannot initialize" */
default: default:
var v float32 = t /* ERROR "cannot assign" */ var v float32 = t /* ERROR "cannot initialize" */
} }
var t I 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