mirror of
https://github.com/golang/go
synced 2024-11-02 11:50:30 +00:00
cmd/compile: allow := to shadow dot-imported names
Historically, gc optimistically parsed the left-hand side of assignments as expressions. Later, if it discovered a ":=" assignment, it rewrote the parsed expressions as declarations. This failed in the presence of dot imports though, because we lost information about whether an imported object was named via a bare identifier "Foo" or a normal qualified "pkg.Foo". This CL fixes the issue by specially noding the left-hand side of ":=" assignments. Fixes #22076. Change-Id: I18190ecdb863112e7d009e1687e6112eec559921 Reviewed-on: https://go-review.googlesource.com/66810 Run-TryBot: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Daniel Martí <mvdan@mvdan.cc> Reviewed-by: Robert Griesemer <gri@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
3b8a031569
commit
f22ef70254
4 changed files with 91 additions and 16 deletions
|
@ -758,15 +758,10 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
lhs := p.exprList(stmt.Lhs)
|
|
||||||
rhs := p.exprList(stmt.Rhs)
|
|
||||||
|
|
||||||
n := p.nod(stmt, OAS, nil, nil) // assume common case
|
n := p.nod(stmt, OAS, nil, nil) // assume common case
|
||||||
|
|
||||||
if stmt.Op == syntax.Def {
|
rhs := p.exprList(stmt.Rhs)
|
||||||
n.SetColas(true)
|
lhs := p.assignList(stmt.Lhs, n, stmt.Op == syntax.Def)
|
||||||
colasdefn(lhs, n) // modifies lhs, call before using lhs[0] in common case
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(lhs) == 1 && len(rhs) == 1 {
|
if len(lhs) == 1 && len(rhs) == 1 {
|
||||||
// common case
|
// common case
|
||||||
|
@ -845,6 +840,66 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
|
||||||
panic("unhandled Stmt")
|
panic("unhandled Stmt")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *noder) assignList(expr syntax.Expr, defn *Node, colas bool) []*Node {
|
||||||
|
if !colas {
|
||||||
|
return p.exprList(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
defn.SetColas(true)
|
||||||
|
|
||||||
|
var exprs []syntax.Expr
|
||||||
|
if list, ok := expr.(*syntax.ListExpr); ok {
|
||||||
|
exprs = list.ElemList
|
||||||
|
} else {
|
||||||
|
exprs = []syntax.Expr{expr}
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]*Node, len(exprs))
|
||||||
|
seen := make(map[*types.Sym]bool, len(exprs))
|
||||||
|
|
||||||
|
newOrErr := false
|
||||||
|
for i, expr := range exprs {
|
||||||
|
p.lineno(expr)
|
||||||
|
res[i] = nblank
|
||||||
|
|
||||||
|
name, ok := expr.(*syntax.Name)
|
||||||
|
if !ok {
|
||||||
|
yyerrorpos(expr.Pos(), "non-name %v on left side of :=", p.expr(expr))
|
||||||
|
newOrErr = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
sym := p.name(name)
|
||||||
|
if sym.IsBlank() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if seen[sym] {
|
||||||
|
yyerrorpos(expr.Pos(), "%v repeated on left side of :=", sym)
|
||||||
|
newOrErr = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[sym] = true
|
||||||
|
|
||||||
|
if sym.Block == types.Block {
|
||||||
|
res[i] = oldname(sym)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newOrErr = true
|
||||||
|
n := newname(sym)
|
||||||
|
declare(n, dclcontext)
|
||||||
|
n.Name.Defn = defn
|
||||||
|
defn.Ninit.Append(nod(ODCL, n, nil))
|
||||||
|
res[i] = n
|
||||||
|
}
|
||||||
|
|
||||||
|
if !newOrErr {
|
||||||
|
yyerrorl(defn.Pos, "no new variables on left side of :=")
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*Node {
|
func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*Node {
|
||||||
p.openScope(stmt.Pos())
|
p.openScope(stmt.Pos())
|
||||||
nodes := p.stmts(stmt.List)
|
nodes := p.stmts(stmt.List)
|
||||||
|
@ -884,12 +939,7 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
|
||||||
|
|
||||||
n = p.nod(r, ORANGE, nil, p.expr(r.X))
|
n = p.nod(r, ORANGE, nil, p.expr(r.X))
|
||||||
if r.Lhs != nil {
|
if r.Lhs != nil {
|
||||||
lhs := p.exprList(r.Lhs)
|
n.List.Set(p.assignList(r.Lhs, n, r.Def))
|
||||||
n.List.Set(lhs)
|
|
||||||
if r.Def {
|
|
||||||
n.SetColas(true)
|
|
||||||
colasdefn(lhs, n)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
n = p.nod(stmt, OFOR, nil, nil)
|
n = p.nod(stmt, OFOR, nil, nil)
|
||||||
|
|
|
@ -14,7 +14,7 @@ func foo(runtime.UintType, i int) { // ERROR "cannot declare name runtime.UintT
|
||||||
}
|
}
|
||||||
|
|
||||||
func bar(i int) {
|
func bar(i int) {
|
||||||
runtime.UintType := i // ERROR "cannot declare name runtime.UintType|non-name on left side|undefined identifier"
|
runtime.UintType := i // ERROR "non-name runtime.UintType|non-name on left side|undefined identifier"
|
||||||
println(runtime.UintType) // GCCGO_ERROR "invalid use of type|undefined identifier"
|
println(runtime.UintType) // GCCGO_ERROR "invalid use of type|undefined identifier"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ type T struct {
|
||||||
|
|
||||||
func f(a T) { // ERROR "live at entry to f: a"
|
func f(a T) { // ERROR "live at entry to f: a"
|
||||||
var e interface{}
|
var e interface{}
|
||||||
func() { // ERROR "live at entry to f.func1: &e a"
|
func() { // ERROR "live at entry to f.func1: a &e"
|
||||||
e = a.s // ERROR "live at call to convT2Estring: &e a" "live at call to writebarrierptr: a"
|
e = a.s // ERROR "live at call to convT2Estring: a &e" "live at call to writebarrierptr: a"
|
||||||
}() // ERROR "live at call to f.func1: e$"
|
}() // ERROR "live at call to f.func1: e$"
|
||||||
// Before the fix, both a and e were live at the previous line.
|
// Before the fix, both a and e were live at the previous line.
|
||||||
_ = e
|
_ = e
|
||||||
|
|
25
test/fixedbugs/issue22076.go
Normal file
25
test/fixedbugs/issue22076.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// compile
|
||||||
|
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// Issue 22076: Couldn't use ":=" to declare names that refer to
|
||||||
|
// dot-imported symbols.
|
||||||
|
|
||||||
|
package p
|
||||||
|
|
||||||
|
import . "bytes"
|
||||||
|
|
||||||
|
var _ Reader // use "bytes" import
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
Buffer := 0
|
||||||
|
_ = Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
for Buffer := range []int{} {
|
||||||
|
_ = Buffer
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue