type Object struct {
Kind ObjKind
Name string // declared name
- Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
+ Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, or AssignStmt; or nil
Data interface{} // object-specific data; or nil
Type interface{} // place holder for type information; may be nil
}
if d.Label.Name == name {
return d.Label.Pos()
}
+ case *AssignStmt:
+ for _, x := range d.Lhs {
+ if ident, isIdent := x.(*Ident); isIdent && ident.Name == name {
+ return ident.Pos()
+ }
+ }
}
return token.NoPos
}
}
}
-func (p *parser) shortVarDecl(idents []*ast.Ident) {
+func (p *parser) shortVarDecl(decl *ast.AssignStmt, list []ast.Expr) {
// Go spec: A short variable declaration may redeclare variables
// provided they were originally declared in the same block with
// the same type, and at least one of the non-blank variables is new.
n := 0 // number of new variables
- for _, ident := range idents {
- assert(ident.Obj == nil, "identifier already declared or resolved")
- obj := ast.NewObj(ast.Var, ident.Name)
- // short var declarations cannot have redeclaration errors
- // and are not global => no need to remember the respective
- // declaration
- ident.Obj = obj
- if ident.Name != "_" {
- if alt := p.topScope.Insert(obj); alt != nil {
- ident.Obj = alt // redeclaration
- } else {
- n++ // new declaration
+ for _, x := range list {
+ if ident, isIdent := x.(*ast.Ident); isIdent {
+ assert(ident.Obj == nil, "identifier already declared or resolved")
+ obj := ast.NewObj(ast.Var, ident.Name)
+ // remember corresponding assignment for other tools
+ obj.Decl = decl
+ ident.Obj = obj
+ if ident.Name != "_" {
+ if alt := p.topScope.Insert(obj); alt != nil {
+ ident.Obj = alt // redeclaration
+ } else {
+ n++ // new declaration
+ }
}
+ } else {
+ p.errorExpected(x.Pos(), "identifier")
}
}
if n == 0 && p.mode&DeclarationErrors != 0 {
- p.error(idents[0].Pos(), "no new variables on left side of :=")
+ p.error(list[0].Pos(), "no new variables on left side of :=")
}
}
for i, x := range list {
ident, isIdent := x.(*ast.Ident)
if !isIdent {
- pos := x.(ast.Expr).Pos()
+ pos := x.Pos()
p.errorExpected(pos, "identifier")
ident = &ast.Ident{pos, "_", nil}
}
} else {
y = p.parseRhsList()
}
+ as := &ast.AssignStmt{x, pos, tok, y}
if tok == token.DEFINE {
- p.shortVarDecl(p.makeIdentList(x))
+ p.shortVarDecl(as, x)
}
- return &ast.AssignStmt{x, pos, tok, y}, isRange
+ return as, isRange
}
if len(x) > 1 {
comm = &ast.SendStmt{lhs[0], arrow, rhs}
} else {
// RecvStmt
- pos := p.pos
- tok := p.tok
- var rhs ast.Expr
- if tok == token.ASSIGN || tok == token.DEFINE {
+ if tok := p.tok; tok == token.ASSIGN || tok == token.DEFINE {
// RecvStmt with assignment
if len(lhs) > 2 {
p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
// continue with first two expressions
lhs = lhs[0:2]
}
+ pos := p.pos
p.next()
- rhs = p.parseRhs()
- if tok == token.DEFINE && lhs != nil {
- p.shortVarDecl(p.makeIdentList(lhs))
+ rhs := p.parseRhs()
+ as := &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
+ if tok == token.DEFINE {
+ p.shortVarDecl(as, lhs)
}
+ comm = as
} else {
- // rhs must be single receive operation
+ // lhs must be single receive operation
if len(lhs) > 1 {
p.errorExpected(lhs[0].Pos(), "1 expression")
// continue with first expression
}
- rhs = lhs[0]
- lhs = nil // there is no lhs
- }
- if lhs != nil {
- comm = &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
- } else {
- comm = &ast.ExprStmt{rhs}
+ comm = &ast.ExprStmt{lhs[0]}
}
}
} else {