check.assignment(x, lhs.typ, context)
if x.mode == invalid {
+ lhs.used = true // avoid follow-on "declared but not used" errors
return nil
}
func (check *Checker) assignVar(lhs syntax.Expr, x *operand) Type {
if x.mode == invalid || x.typ == Typ[Invalid] {
- check.useLHS(lhs)
+ check.use(lhs)
return nil
}
return
}
+ ok := true
for i, lhs := range lhs {
- check.initVar(lhs, rhs[i], context)
+ if check.initVar(lhs, rhs[i], context) == nil {
+ ok = false
+ }
+ }
+
+ // avoid follow-on "declared but not used" errors if any initialization failed
+ if !ok {
+ for _, lhs := range lhs {
+ lhs.used = true
+ }
}
}
rhs, commaOk := check.exprList(orig_rhs, len(lhs) == 2)
if len(lhs) != len(rhs) {
- check.useLHS(lhs...)
+ check.use(lhs...)
// don't report an error if we already reported one
for _, x := range rhs {
if x.mode == invalid {
return
}
+ ok := true
for i, lhs := range lhs {
- check.assignVar(lhs, rhs[i])
+ if check.assignVar(lhs, rhs[i]) == nil {
+ ok = false
+ }
+ }
+
+ // avoid follow-on "declared but not used" errors if any assignment failed
+ if !ok {
+ // don't call check.use to avoid re-evaluation of the lhs expressions
+ for _, lhs := range lhs {
+ if name, _ := unparen(lhs).(*syntax.Name); name != nil {
+ if obj := check.lookup(name.Value); obj != nil {
+ // see comment in assignVar
+ if v, _ := obj.(*Var); v != nil && v.pkg == check.pkg {
+ v.used = true
+ }
+ }
+ }
+ }
}
}
for i, lhs := range lhs {
ident, _ := lhs.(*syntax.Name)
if ident == nil {
- check.useLHS(lhs)
+ check.use(lhs)
check.errorf(lhs, "non-name %s on left side of :=", lhs)
hasErr = true
continue
func (check *Checker) use(arg ...syntax.Expr) {
var x operand
for _, e := range arg {
- // Certain AST fields may legally be nil (e.g., the ast.SliceExpr.High field).
- if e == nil {
+ switch n := e.(type) {
+ case nil:
+ // some AST fields may be nil (e.g., elements of syntax.SliceExpr.Index)
+ // TODO(gri) can those fields really make it here?
continue
- }
- if l, _ := e.(*syntax.ListExpr); l != nil {
- check.use(l.ElemList...)
- continue
- }
- check.rawExpr(&x, e, nil, false)
- }
-}
-
-// useLHS is like use, but doesn't "use" top-level identifiers.
-// It should be called instead of use if the arguments are
-// expressions on the lhs of an assignment.
-// The arguments must not be nil.
-func (check *Checker) useLHS(arg ...syntax.Expr) {
- var x operand
- for _, e := range arg {
- // If the lhs is an identifier denoting a variable v, this assignment
- // is not a 'use' of v. Remember current value of v.used and restore
- // after evaluating the lhs via check.rawExpr.
- var v *Var
- var v_used bool
- if ident, _ := unparen(e).(*syntax.Name); ident != nil {
- // never type-check the blank name on the lhs
- if ident.Value == "_" {
+ case *syntax.Name:
+ // don't report an error evaluating blank
+ if n.Value == "_" {
continue
}
- if _, obj := check.scope.LookupParent(ident.Value, nopos); obj != nil {
- // It's ok to mark non-local variables, but ignore variables
- // from other packages to avoid potential race conditions with
- // dot-imported variables.
- if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
- v = w
- v_used = v.used
- }
- }
+ case *syntax.ListExpr:
+ check.use(n.ElemList...)
+ continue
}
check.rawExpr(&x, e, nil, false)
- if v != nil {
- v.used = v_used // restore v.used
- }
}
}
// declaration, but the post statement must not."
if s, _ := s.Post.(*syntax.AssignStmt); s != nil && s.Op == syntax.Def {
// The parser already reported an error.
- // Don't call useLHS here because we want to use the lhs in
- // this erroneous statement so that we don't get errors about
- // these lhs variables being declared but not used.
check.use(s.Lhs) // avoid follow-up errors
}
check.stmt(inner, s.Body)
package main
func main() {
- var s string = nil; // ERROR "illegal|invalid|incompatible|cannot"
- _ = s
+ var s string = nil // ERROR "illegal|invalid|incompatible|cannot"
}
package main
func main() {
- const a uint64 = 10;
- var b int64 = a; // ERROR "convert|cannot|incompatible"
- _ = b
+ const a uint64 = 10
+ var b int64 = a // ERROR "convert|cannot|incompatible"
}
func f() (int, bool) { return 0, true }
func main() {
- x, y := f(), 2; // ERROR "multi|2-valued"
- _, _ = x, y
+ x, y := f(), 2 // ERROR "multi|2-valued"
}
package main
func f1() {
- a, b := f() // ERROR "assignment mismatch|does not match|cannot initialize"
- _ = a
- _ = b
+ a, b := f() // ERROR "assignment mismatch|does not match|cannot initialize"
}
func f2() {
var a, b int
- a, b = f() // ERROR "assignment mismatch|does not match|cannot assign"
- _ = a
- _ = b
+ a, b = f() // ERROR "assignment mismatch|does not match|cannot assign"
}
func f() int {
- return 1;
+ return 1
}
func main() {
var x int
- _ = x
- x = make(map[int]int) // ERROR "cannot use make\(map\[int\]int\)|incompatible"
- x = make(map[int]int, 0) // ERROR "cannot use make\(map\[int\]int, 0\)|incompatible"
+ x = make(map[int]int) // ERROR "cannot use make\(map\[int\]int\)|incompatible"
+ x = make(map[int]int, 0) // ERROR "cannot use make\(map\[int\]int, 0\)|incompatible"
x = make(map[int]int, zero) // ERROR "cannot use make\(map\[int\]int, zero\)|incompatible"
- x = make(chan int) // ERROR "cannot use make\(chan int\)|incompatible"
- x = make(chan int, 0) // ERROR "cannot use make\(chan int, 0\)|incompatible"
- x = make(chan int, zero) // ERROR "cannot use make\(chan int, zero\)|incompatible"
- _ = x
+ x = make(chan int) // ERROR "cannot use make\(chan int\)|incompatible"
+ x = make(chan int, 0) // ERROR "cannot use make\(chan int, 0\)|incompatible"
+ x = make(chan int, zero) // ERROR "cannot use make\(chan int, zero\)|incompatible"
}
func (start *Start) Next() *Inst { return nil }
-
func AddInst(Inst) *Inst {
print("ok in addinst\n")
return nil
func main() {
print("call addinst\n")
var x Inst = AddInst(new(Start)) // ERROR "pointer to interface|incompatible type"
- _ = x
print("return from addinst\n")
- var y *Inst = new(Start) // ERROR "pointer to interface|incompatible type"
- _ = y
+ var y *Inst = new(Start) // ERROR "pointer to interface|incompatible type"
}