From 379e0e7704234cadd7c2ae1237374e615cbf4ebc Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Mon, 21 Apr 2014 14:05:25 -0400 Subject: [PATCH] go.tools/go/types: x,y:=0,0 is a Use (not Def) of x if it is already defined. + test. Fixes golang/go#7827 LGTM=gri R=gri CC=golang-codereviews https://golang.org/cl/89600045 --- go/types/assignments.go | 3 +-- go/types/issues_test.go | 59 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/go/types/assignments.go b/go/types/assignments.go index 0af71d56..d79e418b 100644 --- a/go/types/assignments.go +++ b/go/types/assignments.go @@ -289,14 +289,13 @@ func (check *checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) { } else { check.errorf(lhs.Pos(), "cannot assign to %s", lhs) } + check.recordUse(ident, alt) } else { // declare new variable, possibly a blank (_) variable obj = NewVar(ident.Pos(), check.pkg, name, nil) if name != "_" { newVars = append(newVars, obj) } - } - if obj != nil { check.recordDef(ident, obj) } } else { diff --git a/go/types/issues_test.go b/go/types/issues_test.go index cd86ea0a..95c6f675 100644 --- a/go/types/issues_test.go +++ b/go/types/issues_test.go @@ -7,8 +7,10 @@ package types_test import ( + "fmt" "go/ast" "go/parser" + "sort" "strings" "testing" @@ -144,3 +146,60 @@ type T struct{} // receiver type after method declaration t.Errorf("got %s (%p) != %s (%p)", res1, res2, res1, res2) } } + +// This tests that uses of existing vars on the LHS of an assignment +// are Uses, not Defs; and also that the (illegal) use of a non-var on +// the LHS of an assignment is a Use nonetheless. +func TestIssue7827(t *testing.T) { + const src = ` +package p +func _() { + const w = 1 // defs w + x, y := 2, 3 // defs x, y + w, x, z := 4, 5, 6 // uses w, x, defs z; error: cannot assign to w + _, _, _ = x, y, z // uses x, y, z +} +` + const want = `L3 defs func p._() +L4 defs const w untyped int +L5 defs var x int +L5 defs var y int +L6 defs var z int +L6 uses const w untyped int +L6 uses var x int +L7 uses var x int +L7 uses var y int +L7 uses var z int` + + f, err := parser.ParseFile(fset, "", src, 0) + if err != nil { + t.Fatal(err) + } + + // don't abort at the first error + conf := Config{Error: func(err error) { t.Log(err) }} + defs := make(map[*ast.Ident]Object) + uses := make(map[*ast.Ident]Object) + _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs, Uses: uses}) + if s := fmt.Sprint(err); !strings.HasSuffix(s, "cannot assign to w") { + t.Errorf("Check: unexpected error: %s", s) + } + + var facts []string + for id, obj := range defs { + if obj != nil { + fact := fmt.Sprintf("L%d defs %s", fset.Position(id.Pos()).Line, obj) + facts = append(facts, fact) + } + } + for id, obj := range uses { + fact := fmt.Sprintf("L%d uses %s", fset.Position(id.Pos()).Line, obj) + facts = append(facts, fact) + } + sort.Strings(facts) + + got := strings.Join(facts, "\n") + if got != want { + t.Errorf("Unexpected defs/uses\ngot:\n%s\nwant:\n%s", got, want) + } +}