mirror of
https://github.com/golang/go
synced 2024-09-05 07:54:46 +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
|
@ -758,15 +758,10 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
|
|||
return n
|
||||
}
|
||||
|
||||
lhs := p.exprList(stmt.Lhs)
|
||||
rhs := p.exprList(stmt.Rhs)
|
||||
|
||||
n := p.nod(stmt, OAS, nil, nil) // assume common case
|
||||
|
||||
if stmt.Op == syntax.Def {
|
||||
n.SetColas(true)
|
||||
colasdefn(lhs, n) // modifies lhs, call before using lhs[0] in common case
|
||||
}
|
||||
rhs := p.exprList(stmt.Rhs)
|
||||
lhs := p.assignList(stmt.Lhs, n, stmt.Op == syntax.Def)
|
||||
|
||||
if len(lhs) == 1 && len(rhs) == 1 {
|
||||
// common case
|
||||
|
@ -845,6 +840,66 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
|
|||
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 {
|
||||
p.openScope(stmt.Pos())
|
||||
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))
|
||||
if r.Lhs != nil {
|
||||
lhs := p.exprList(r.Lhs)
|
||||
n.List.Set(lhs)
|
||||
if r.Def {
|
||||
n.SetColas(true)
|
||||
colasdefn(lhs, n)
|
||||
}
|
||||
n.List.Set(p.assignList(r.Lhs, n, r.Def))
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
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"
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ type T struct {
|
|||
|
||||
func f(a T) { // ERROR "live at entry to f: a"
|
||||
var e interface{}
|
||||
func() { // ERROR "live at entry to f.func1: &e a"
|
||||
e = a.s // ERROR "live at call to convT2Estring: &e a" "live at call to writebarrierptr: a"
|
||||
func() { // ERROR "live at entry to f.func1: a &e"
|
||||
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$"
|
||||
// Before the fix, both a and e were live at the previous line.
|
||||
_ = 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