"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
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)
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
}
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
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
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
}
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
// 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)
}
}
// 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)
}
}
{"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"}},
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]+): *(.*)`)
// 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 {
}
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:
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
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
}
delete(errmap, pos)
}
} else {
- t.Errorf("%s: no error expected: %q", pos, msg)
+ t.Errorf("%s: no error expected: %q", pos, gotMsg)
}
-
}
}
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)
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.
// 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;
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
// - clients need access to builtins type information
// - 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) {
if list == nil {
return
if !isRepresentableConst(x.val, check.ctxt, typ.Kind) {
var msg string
if isNumeric(x.typ) && isNumeric(typ) {
- msg = "%s overflows %s"
+ msg = "%s overflows (or cannot be accurately represented as) %s"
} else {
msg = "cannot convert %s to %s"
}
}
}
-// updateExprType updates the type of all untyped nodes in the
-// expression tree of x to typ. If shiftOp is set, x is the lhs
-// of a shift expression. In that case, and if x is in the set
-// of shift operands with delayed type checking, and typ is not
-// an untyped type, updateExprType will check if typ is an
-// integer type.
-// If Context.Expr != nil, it is called for all nodes that are
-// now assigned their final (not untyped) type.
-func (check *checker) updateExprType(x ast.Expr, typ Type, shiftOp bool) {
+// updateExprType updates the type of x to typ and invokes itself
+// recursively for the operands of x, depending on expression kind.
+// If typ is still an untyped and not the final type, updateExprType
+// only updates the recorded untyped type for x and possibly its
+// operands. Otherwise (i.e., typ is not an untyped type anymore,
+// or it is the final type for x), Context.Expr is invoked, if present.
+// Also, if x is a constant, it must be representable as a value of typ,
+// and if x is the (formerly untyped) lhs operand of a non-constant
+// 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) {
case *ast.BadExpr,
*ast.FuncLit,
*ast.CompositeLit,
- *ast.SelectorExpr,
*ast.IndexExpr,
*ast.SliceExpr,
*ast.TypeAssertExpr,
- *ast.CallExpr,
*ast.StarExpr,
*ast.KeyValueExpr,
*ast.ArrayType,
*ast.InterfaceType,
*ast.MapType,
*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
- case *ast.Ident, *ast.BasicLit:
- // update type
+ case *ast.CallExpr:
+ // 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:
- check.updateExprType(x.X, typ, false)
+ check.updateExprType(x.X, typ, final)
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:
+ if old.isConst {
+ break // see comment for unary expressions
+ }
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) {
- // result type depends only on lhs operand
- check.updateExprType(x.X, typ, true)
+ // The result type depends only on lhs operand.
+ // The rhs type was updated when checking the shift.
+ check.updateExprType(x.X, typ, final)
} else {
- // operand types match result type
- check.updateExprType(x.X, typ, false)
- check.updateExprType(x.Y, typ, false)
+ // The operand types match the result type.
+ check.updateExprType(x.X, typ, final)
+ check.updateExprType(x.Y, typ, final)
}
- case *ast.Ellipsis:
- unreachable()
default:
unreachable()
}
- // TODO(gri) t should always exist, shouldn't it?
- if t := check.untyped[x]; t != nil {
- if isUntyped(typ) {
- check.untyped[x] = typ.(*Basic)
- } else {
- // notify clients of final type for x
- if f := check.ctxt.Expr; f != nil {
- f(x, typ, check.constants[x])
- }
- delete(check.untyped, x)
- delete(check.constants, x)
- // check delayed shift
- // Note: Using shiftOp is an optimization: it prevents
- // map lookups when we know x is not a shiftOp in the
- // first place.
- if shiftOp && check.shiftOps[x] {
- if !isInteger(typ) {
- check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ)
- }
- delete(check.shiftOps, x)
- }
+ // If the new type is not final and still untyped, just
+ // update the recorded type.
+ if !final && isUntyped(typ) {
+ old.typ = underlying(typ).(*Basic)
+ check.untyped[x] = old
+ return
+ }
+
+ // Otherwise we have the final (typed or untyped type).
+ // Remove it from the map.
+ delete(check.untyped, x)
+
+ // If x is the lhs of a shift, its final type must be integer.
+ // We already know from the shift check that it is representable
+ // as an integer if it is a constant.
+ if old.isLhs && !isInteger(typ) {
+ check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ)
+ return
+ }
+
+ // 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)
}
}
}
x.typ = target
- check.updateExprType(x.expr, target, false)
+ check.updateExprType(x.expr, target, true) // UntypedNils are final
return
Error:
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]
}
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
// integer type or be an untyped constant that can be converted to
// unsigned integer type."
switch {
case isInteger(y.typ) && isUnsigned(y.typ):
// nothing to do
- case y.mode == constant && isUntyped(y.typ):
- check.convertUntyped(x, Typ[UntypedInt])
+ case isUntyped(y.typ):
+ check.convertUntyped(y, Typ[UntypedInt])
+ if y.mode == invalid {
+ x.mode = invalid
+ return
+ }
default:
check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
x.mode = invalid
if x.mode == constant {
if y.mode == constant {
- // constant shift - lhs must be (representable as) an integer
- if isUntyped(x.typ) {
- if !isRepresentableConst(x.val, check.ctxt, UntypedInt) {
- check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+ if untypedx {
+ x.typ = Typ[UntypedInt]
+ }
+ if x.val != nil && y.val != nil {
+ // rhs must be within reasonable bounds
+ const stupidShift = 1024
+ s, ok := y.val.(int64)
+ if !ok || s < 0 || s >= stupidShift {
+ check.invalidOp(y.pos(), "%s: stupid shift", y)
x.mode = invalid
return
}
- x.typ = Typ[UntypedInt]
- }
- assert(x.isInteger(check.ctxt))
-
- // rhs must be within reasonable bounds
- const stupidShift = 1024
- s, ok := y.val.(int64)
- if !ok || s < 0 || s >= stupidShift {
- check.invalidOp(y.pos(), "%s: stupid shift", y)
- x.mode = invalid
- return
+ // everything's ok
+ x.val = shiftConst(x.val, uint(s), op)
+ } else {
+ x.val = nil
}
-
- // everything's ok
- x.val = shiftConst(x.val, uint(s), op)
return
}
// non-constant shift with constant lhs
- if isUntyped(x.typ) {
+ if untypedx {
// 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
// if the shift expression were replaced by its left operand alone;
// instance, if the shift expression is an operand in a comparison
// against an untyped constant)".
- // delay operand checking until we know the type
- check.shiftOps[x.expr] = true
+ // Delay operand checking until we know the final type:
+ // 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
return
}
// x.typ is unchanged
}
-// index checks an index expression for validity. If length >= 0, it is the upper
-// bound for the index. The result is a valid index >= 0, or a negative value.
-//
-func (check *checker) index(index ast.Expr, length int64, iota int) int64 {
+// index checks an index/size expression arg for validity.
+// If length >= 0, it is the upper bound for arg.
+// TODO(gri): Do we need iota?
+func (check *checker) index(arg ast.Expr, length int64, iota int) (i int64, ok bool) {
var x operand
+ check.expr(&x, arg, nil, iota)
- check.expr(&x, index, nil, iota)
- if !x.isInteger(check.ctxt) {
- check.errorf(x.pos(), "index %s must be integer", &x)
- return -1
- }
- 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)
- if !ok {
- check.errorf(x.pos(), "stupid index %s", &x)
- return -1
+ // an untyped constant must be representable as Int
+ check.convertUntyped(&x, Typ[Int])
+ if x.mode == invalid {
+ return
}
- if i < 0 {
- check.errorf(x.pos(), "index %s must not be negative", &x)
- return -1
+
+ // the index/size must be of integer type
+ if !isInteger(x.typ) {
+ check.invalidArg(x.pos(), "%s must be integer", &x)
+ return
}
- if length >= 0 && i >= length {
- check.errorf(x.pos(), "index %s is out of bounds (>= %d)", &x, length)
- return -1
+
+ // a constant index/size i must be 0 <= i < length
+ if x.mode == constant && x.val != nil {
+ i = x.val.(int64)
+ if i < 0 {
+ check.invalidArg(x.pos(), "%s must not be negative", &x)
+ return
+ }
+ if length >= 0 && i >= length {
+ check.errorf(x.pos(), "index %s is out of bounds (>= %d)", &x, length)
+ return
+ }
+ // 0 <= i [ && i < length ]
+ return i, true
}
- return i
+ return -1, true
}
// compositeLitKey resolves unresolved composite literal keys.
eval := e
if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
check.compositeLitKey(kv.Key)
- if i := check.index(kv.Key, length, iota); i >= 0 {
- index = i
+ if i, ok := check.index(kv.Key, length, iota); ok {
+ if i >= 0 {
+ index = i
+ }
validIndex = true
}
eval = kv.Value
var emptyResult Result
func (check *checker) callExpr(x *operand) {
+ // convert x into a user-friendly set of values
var typ Type
var val interface{}
switch x.mode {
// until it becomes typed or until the end of
// type checking
if isUntyped(typ) {
- check.untyped[x.expr] = typ.(*Basic)
- if val != nil {
- check.constants[x.expr] = val
- }
+ check.untyped[x.expr] = exprInfo{x.mode == constant, false, typ.(*Basic), val}
return
}
defer check.untrace("=> %s", x)
}
+ // record final type of x if untyped, notify clients of type otherwise
defer check.callExpr(x)
switch e := e.(type) {
}
continue
}
- if x.mode == constant {
+ if x.mode == constant && x.val != nil {
if visited[x.val] {
check.errorf(x.pos(), "duplicate key %s in map literal", x.val)
continue
case *Basic:
if isString(typ) {
valid = true
- if x.mode == constant {
+ if x.mode == constant && x.val != nil {
length = int64(len(x.val.(string)))
}
// an indexed string always yields a byte value
case *Basic:
if isString(typ) {
valid = true
- if x.mode == constant {
+ if x.mode == constant && x.val != nil {
length = int64(len(x.val.(string))) + 1 // +1 for slice
}
// a sliced string always yields a string value
lo := int64(0)
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)
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 {
hi = length
}
}
// 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.
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
}
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)
_ = 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() {
}
func _make() {
- n := 0
+ var n int
+ var m float32
+ var s uint
_ = make /* ERROR "argument" */ ()
_ = make(1 /* ERROR "not a type" */)
_ = 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)
}
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)))))
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() {
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
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
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// various expressions
-
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() {
_ = 1 /* ERROR "cannot index" */ [0]
_ = indexes /* ERROR "cannot index" */ [0]
_ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2]
var a [10]int
- _ = a[true /* ERROR "must be integer" */ ]
- _ = a["foo" /* ERROR "must be integer" */ ]
- _ = a[1.1 /* ERROR "must be integer" */ ]
+ _ = a[true /* ERROR "cannot convert" */ ]
+ _ = a["foo" /* ERROR "cannot convert" */ ]
+ _ = a[1.1 /* ERROR "overflows" */ ]
_ = a[1.0]
- _ = a[- /* ERROR "index .* negative" */ 1]
- _ = a[- /* ERROR "index .* negative" */ 1 :]
- _ = a[: - /* ERROR "index .* negative" */ 1]
+ _ = a[- /* ERROR "negative" */ 1]
+ _ = a[- /* ERROR "negative" */ 1 :]
+ _ = a[: - /* ERROR "negative" */ 1]
var a0 int
a0 = a[0]
var a1 int32
a1 = a /* ERROR "cannot assign" */ [1]
_ = a[9]
_ = a[10 /* ERROR "index .* out of bounds" */ ]
- _ = a[1 /* ERROR "stupid index" */ <<100]
+ _ = a[1 /* ERROR "overflows" */ <<100]
_ = a[10:]
_ = a[:10]
_ = a[10:10]
_ = 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[9]
_ = pa[10 /* ERROR "index .* out of bounds" */ ]
- _ = pa[1 /* ERROR "stupid index" */ <<100]
+ _ = pa[1 /* ERROR "overflows" */ <<100]
_ = pa[10:]
_ = pa[:10]
_ = pa[10:10]
_ = 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
_ = b[0 /* ERROR "index .* out of bounds" */ ]
_ = b[0:0]
var s []int
- _ = s[- /* ERROR "index .* negative" */ 1]
- _ = s[- /* ERROR "index .* negative" */ 1 :]
- _ = s[: - /* ERROR "index .* negative" */ 1]
+ _ = s[- /* ERROR "negative" */ 1]
+ _ = s[- /* ERROR "negative" */ 1 :]
+ _ = s[: - /* ERROR "negative" */ 1]
_ = s[0]
_ = s[1 : 2]
_ = s[2 /* ERROR "inverted slice range" */ : 1]
_ = s[2 :]
- _ = s[: 1 /* ERROR "stupid index" */ <<100]
- _ = s[1 /* ERROR "stupid index" */ <<100 :]
- _ = s[1 /* ERROR "stupid index" */ <<100 : 1 /* ERROR "stupid index" */ <<100]
+ _ = s[: 1 /* ERROR "overflows" */ <<100]
+ _ = s[1 /* ERROR "overflows" */ <<100 :]
+ _ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
var t string
- _ = t[- /* ERROR "index .* negative" */ 1]
- _ = t[- /* ERROR "index .* negative" */ 1 :]
- _ = t[: - /* ERROR "index .* negative" */ 1]
+ _ = t[- /* ERROR "negative" */ 1]
+ _ = t[- /* ERROR "negative" */ 1 :]
+ _ = t[: - /* ERROR "negative" */ 1]
var t0 byte
t0 = t[0]
var t1 rune
_ = ("foo" + "bar")[6 /* ERROR "index .* out of bounds" */ ]
const c = "foo"
- _ = c[- /* ERROR "index .* negative" */ 1]
- _ = c[- /* ERROR "index .* negative" */ 1 :]
- _ = c[: - /* ERROR "index .* negative" */ 1]
+ _ = c[- /* ERROR "negative" */ 1]
+ _ = c[- /* ERROR "negative" */ 1 :]
+ _ = c[: - /* ERROR "negative" */ 1]
var c0 byte
c0 = c[0]
var c2 float32
_ = T /* ERROR "has no method" */ .x
_ = 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() {
_ = T1{aa /* ERROR "unknown field" */ : 0}
_ = T1{1 /* ERROR "invalid field name" */ : 0}
_ = 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{T0: { /* ERROR "missing type" */ }}
_ = T1{T0: T0{}}
_ = T0{1, b /* ERROR "mixture" */ : 2, 3}
_ = T0{1, 2} /* ERROR "too few 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() {
_ = 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, 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, 10 /* ERROR "index .* out of bounds" */ }
_ = 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, 5 /* ERROR "duplicate index" */ }
_ = 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, 4: 4, 1 /* ERROR "stupid index" */ <<100: 4}
+ _ = 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 "overflows" */ <<100: 4}
_ = A1{2.0}
- _ = A1{2.1 /* ERROR "cannot use" */ }
- _ = A1{"foo" /* ERROR "cannot use" */ }
+ _ = A1{2.1 /* ERROR "overflows" */ }
+ _ = A1{"foo" /* ERROR "cannot convert" */ }
a0 := [...]int{}
assert(len(a0) == 0)
a13 = a1
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}
assert(len(a3) == 5) // somewhat arbitrary
_ = 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, 10}
- _ = S0{- /* ERROR "index .* negative" */ 1: 0}
+ _ = S0{- /* ERROR "negative" */ 1: 0}
_ = S0{8: 8, 9}
_ = S0{8: 8, 9, 10}
_ = 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, 5 /* ERROR "duplicate index" */ }
_ = 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, 4: 4, 1 /* ERROR "stupid index" */ <<100: 4}
+ _ = 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 "overflows" */ <<100: 4}
_ = S0{2.0}
- _ = S0{2.1 /* ERROR "cannot use" */ }
- _ = S0{"foo" /* ERROR "cannot use" */ }
+ _ = S0{2.1 /* ERROR "overflows" */ }
+ _ = S0{"foo" /* ERROR "cannot convert" */ }
// indices must be resolved correctly
// (for details, see comment in go/parser/parser.go, method parseElement)
_ = M0{}
_ = M0{1 /* ERROR "missing key" */ }
- _ = M0{1 /* ERROR "cannot use .* as string key" */ : 2}
- _ = M0{"foo": "bar" /* ERROR "cannot use .* as int value" */ }
+ _ = M0{1 /* ERROR "cannot convert" */ : 2}
+ _ = M0{"foo": "bar" /* ERROR "cannot convert" */ }
_ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
// map keys must be resolved correctly
f1(10.0)
f1 /* ERROR "too few arguments" */ ()
f1(x, y /* ERROR "too many arguments" */ )
- f1(s /* ERROR "cannot assign" */ )
+ f1(s /* ERROR "cannot pass" */ )
f1(x ... /* ERROR "cannot use ..." */ )
f1(g0 /* ERROR "used as value" */ ())
f1(g1())
f2 /* ERROR "too few arguments" */ ()
f2 /* ERROR "too few arguments" */ (3.14)
f2(3.14, "foo")
- f2(x /* ERROR "cannot assign" */ , "foo")
+ f2(x /* ERROR "cannot pass" */ , "foo")
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())
fs /* ERROR "too few arguments" */ ()
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(gs())
fv()
fv(1, 2.0, x)
- fv(s /* ERROR "cannot assign" */ )
+ fv(s /* ERROR "cannot pass" */ )
fv(s...)
fv(1, s /* ERROR "can only use ... with matching parameter" */ ...)
- fv(gs /* ERROR "cannot assign" */ ())
- fv(gs /* ERROR "cannot assign" */ ()...)
+ fv(gs /* ERROR "cannot pass" */ ())
+ fv(gs /* ERROR "cannot pass" */ ()...)
fi()
fi(1, 2.0, x, 3.14, "foo")
--- /dev/null
+// 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 {}
+ }
+}
}
switch x {
- case 1 /* ERROR "overflows int" */ << 100:
+ case 1 /* ERROR "overflows" */ << 100:
}
switch x {
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