From 1b2c3e664b08691df57d5999a3b478873dfb06a8 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 24 Mar 2011 11:45:52 -0700 Subject: [PATCH] go/parser: resolve identifiers properly Correctly distinguish between lhs and rhs identifiers and resolve/declare them accordingly. Collect field and method names in respective scopes (will be available after some minor AST API changes). Also collect imports since it's useful to have that list directly w/o having to re-traverse the AST (will also be available after some minor AST API changes). No external API changes in this CL. R=rsc, rog CC=golang-dev https://golang.org/cl/4271061 --- src/pkg/go/parser/interface.go | 2 +- src/pkg/go/parser/parser.go | 312 ++++++++++++++++++++++----------- 2 files changed, 213 insertions(+), 101 deletions(-) diff --git a/src/pkg/go/parser/interface.go b/src/pkg/go/parser/interface.go index 6f35b495efa..cca251b81fe 100644 --- a/src/pkg/go/parser/interface.go +++ b/src/pkg/go/parser/interface.go @@ -69,7 +69,7 @@ func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr, var p parser p.init(fset, filename, data, 0) - x := p.parseExpr() + x := p.parseRhs() if p.tok == token.SEMICOLON { p.next() // consume automatically inserted semicolon, if any } diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go index b0e8c8ad7a8..d2916d93a28 100644 --- a/src/pkg/go/parser/parser.go +++ b/src/pkg/go/parser/parser.go @@ -55,9 +55,10 @@ type parser struct { exprLev int // < 0: in control clause, >= 0: in expression // Ordinary identifer scopes - pkgScope *ast.Scope // pkgScope.Outer == nil - topScope *ast.Scope // top-most scope; may be pkgScope - unresolved []*ast.Ident // unresolved global identifiers + pkgScope *ast.Scope // pkgScope.Outer == nil + topScope *ast.Scope // top-most scope; may be pkgScope + unresolved []*ast.Ident // unresolved identifiers + imports []*ast.ImportSpec // list of imports // Label scope // (maintained by open/close LabelScope) @@ -141,6 +142,7 @@ func (p *parser) closeLabelScope() { func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) { for _, ident := range idents { + assert(ident.Obj == nil, "identifier already declared or resolved") if ident.Name != "_" { obj := ast.NewObj(kind, ident.Name) // remember the corresponding declaration for redeclaration @@ -166,6 +168,7 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) { // 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") if ident.Name != "_" { obj := ast.NewObj(ast.Var, ident.Name) // short var declarations cannot have redeclaration errors @@ -184,7 +187,19 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) { } -func (p *parser) resolve(ident *ast.Ident) { +// The unresolved object is a sentinel to mark identifiers that have been added +// to the list of unresolved identifiers. The sentinel is only used for verifying +// internal consistency. +var unresolved = new(ast.Object) + + +func (p *parser) resolve(x ast.Expr) { + // nothing to do if x is not an identifier or the blank identifier + ident, _ := x.(*ast.Ident) + if ident == nil { + return + } + assert(ident.Obj == nil, "identifier already declared or resolved") if ident.Name == "_" { return } @@ -195,10 +210,12 @@ func (p *parser) resolve(ident *ast.Ident) { return } } - // collect unresolved global identifiers; ignore the others - if p.topScope == p.pkgScope { - p.unresolved = append(p.unresolved, ident) - } + // all local scopes are known, so any unresolved identifier + // must be found either in the file scope, package scope + // (perhaps in another file), or universe scope --- collect + // them so that they can be resolved later + ident.Obj = unresolved + p.unresolved = append(p.unresolved, ident) } @@ -388,6 +405,13 @@ func (p *parser) expectSemi() { } +func assert(cond bool, msg string) { + if !cond { + panic("go/parser internal error: " + msg) + } +} + + // ---------------------------------------------------------------------------- // Identifiers @@ -422,21 +446,51 @@ func (p *parser) parseIdentList() (list []*ast.Ident) { // ---------------------------------------------------------------------------- // Common productions -func (p *parser) parseExprList() (list []ast.Expr) { +// If lhs is set, result list elements which are identifiers are not resolved. +func (p *parser) parseExprList(lhs bool) (list []ast.Expr) { if p.trace { defer un(trace(p, "ExpressionList")) } - list = append(list, p.parseExpr()) + list = append(list, p.parseExpr(lhs)) for p.tok == token.COMMA { p.next() - list = append(list, p.parseExpr()) + list = append(list, p.parseExpr(lhs)) } return } +func (p *parser) parseLhsList() []ast.Expr { + list := p.parseExprList(true) + switch p.tok { + case token.DEFINE: + // lhs of a short variable declaration + p.shortVarDecl(p.makeIdentList(list)) + case token.COLON: + // lhs of a label declaration or a communication clause of a select + // statement (parseLhsList is not called when parsing the case clause + // of a switch statement): + // - labels are declared by the caller of parseLhsList + // - for communication clauses, if there is a stand-alone identifier + // followed by a colon, we have a syntax error; there is no need + // to resolve the identifier in that case + default: + // identifiers must be declared elsewhere + for _, x := range list { + p.resolve(x) + } + } + return list +} + + +func (p *parser) parseRhsList() []ast.Expr { + return p.parseExprList(false) +} + + // ---------------------------------------------------------------------------- // Types @@ -458,31 +512,24 @@ func (p *parser) parseType() ast.Expr { } -func (p *parser) parseQualifiedIdent() ast.Expr { - if p.trace { - defer un(trace(p, "QualifiedIdent")) - } - - ident := p.parseIdent() - p.resolve(ident) - var x ast.Expr = ident - if p.tok == token.PERIOD { - // first identifier is a package identifier - p.next() - sel := p.parseIdent() - x = &ast.SelectorExpr{x, sel} - } - - return x -} - - +// If the result is an identifier, it is not resolved. func (p *parser) parseTypeName() ast.Expr { if p.trace { defer un(trace(p, "TypeName")) } - return p.parseQualifiedIdent() + ident := p.parseIdent() + // don't resolve ident yet - it may be a parameter or field name + + if p.tok == token.PERIOD { + // ident is a package name + p.next() + p.resolve(ident) + sel := p.parseIdent() + return &ast.SelectorExpr{ident, sel} + } + + return ident } @@ -497,7 +544,7 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr { len = &ast.Ellipsis{p.pos, nil} p.next() } else if p.tok != token.RBRACK { - len = p.parseExpr() + len = p.parseRhs() } p.expect(token.RBRACK) elt := p.parseType() @@ -521,7 +568,7 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident { } -func (p *parser) parseFieldDecl() *ast.Field { +func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field { if p.trace { defer un(trace(p, "FieldDecl")) } @@ -546,6 +593,7 @@ func (p *parser) parseFieldDecl() *ast.Field { } else { // ["*"] TypeName (AnonymousField) typ = list[0] // we always have at least one element + p.resolve(typ) if n := len(list); n > 1 || !isTypeName(deref(typ)) { pos := typ.Pos() p.errorExpected(pos, "anonymous field") @@ -555,7 +603,10 @@ func (p *parser) parseFieldDecl() *ast.Field { p.expectSemi() // call before accessing p.linecomment - return &ast.Field{doc, idents, typ, tag, p.lineComment} + field := &ast.Field{doc, idents, typ, tag, p.lineComment} + p.declare(field, scope, ast.Var, idents...) + + return field } @@ -566,15 +617,17 @@ func (p *parser) parseStructType() *ast.StructType { pos := p.expect(token.STRUCT) lbrace := p.expect(token.LBRACE) + scope := ast.NewScope(nil) // struct scope var list []*ast.Field for p.tok == token.IDENT || p.tok == token.MUL || p.tok == token.LPAREN { // a field declaration cannot start with a '(' but we accept // it here for more robust parsing and better error messages // (parseFieldDecl will check and complain if necessary) - list = append(list, p.parseFieldDecl()) + list = append(list, p.parseFieldDecl(scope)) } rbrace := p.expect(token.RBRACE) + // TODO(gri): store struct scope in AST return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false} } @@ -595,7 +648,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr { if isParam && p.tok == token.ELLIPSIS { pos := p.pos p.next() - typ := p.tryType() // don't use parseType so we can provide better error message + typ := p.tryIdentOrType(isParam) // don't use parseType so we can provide better error message if typ == nil { p.error(pos, "'...' parameter is missing type") typ = &ast.BadExpr{pos, p.pos} @@ -605,7 +658,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr { } return &ast.Ellipsis{pos, typ} } - return p.tryType() + return p.tryIdentOrType(false) } @@ -641,6 +694,9 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) { // if we had a list of identifiers, it must be followed by a type typ = p.tryVarType(isParam) + if typ != nil { + p.resolve(typ) + } return } @@ -682,6 +738,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [ // Type { "," Type } (anonymous parameters) params = make([]*ast.Field, len(list)) for i, x := range list { + p.resolve(x) params[i] = &ast.Field{Type: x} } } @@ -751,7 +808,7 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) { } -func (p *parser) parseMethodSpec() *ast.Field { +func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field { if p.trace { defer un(trace(p, "MethodSpec")) } @@ -759,7 +816,7 @@ func (p *parser) parseMethodSpec() *ast.Field { doc := p.leadComment var idents []*ast.Ident var typ ast.Expr - x := p.parseQualifiedIdent() + x := p.parseTypeName() if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN { // method idents = []*ast.Ident{ident} @@ -772,7 +829,10 @@ func (p *parser) parseMethodSpec() *ast.Field { } p.expectSemi() // call before accessing p.linecomment - return &ast.Field{doc, idents, typ, nil, p.lineComment} + spec := &ast.Field{doc, idents, typ, nil, p.lineComment} + p.declare(spec, scope, ast.Fun, idents...) + + return spec } @@ -783,12 +843,14 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType { pos := p.expect(token.INTERFACE) lbrace := p.expect(token.LBRACE) + scope := ast.NewScope(nil) // interface scope var list []*ast.Field for p.tok == token.IDENT { - list = append(list, p.parseMethodSpec()) + list = append(list, p.parseMethodSpec(scope)) } rbrace := p.expect(token.RBRACE) + // TODO(gri): store interface scope in AST return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false} } @@ -832,7 +894,8 @@ func (p *parser) parseChanType() *ast.ChanType { } -func (p *parser) tryRawType(ellipsisOk bool) ast.Expr { +// If the result is an identifier, it is not resolved. +func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr { switch p.tok { case token.IDENT: return p.parseTypeName() @@ -864,7 +927,13 @@ func (p *parser) tryRawType(ellipsisOk bool) ast.Expr { } -func (p *parser) tryType() ast.Expr { return p.tryRawType(false) } +func (p *parser) tryType() ast.Expr { + typ := p.tryIdentOrType(false) + if typ != nil { + p.resolve(typ) + } + return typ +} // ---------------------------------------------------------------------------- @@ -939,17 +1008,20 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr { // parseOperand may return an expression or a raw type (incl. array // types of the form [...]T. Callers must verify the result. +// If lhs is set and the result is an identifier, it is not resolved. // -func (p *parser) parseOperand() ast.Expr { +func (p *parser) parseOperand(lhs bool) ast.Expr { if p.trace { defer un(trace(p, "Operand")) } switch p.tok { case token.IDENT: - ident := p.parseIdent() - p.resolve(ident) - return ident + x := p.parseIdent() + if !lhs { + p.resolve(x) + } + return x case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING: x := &ast.BasicLit{p.pos, p.tok, p.lit()} @@ -960,7 +1032,7 @@ func (p *parser) parseOperand() ast.Expr { lparen := p.pos p.next() p.exprLev++ - x := p.parseExpr() + x := p.parseRhs() p.exprLev-- rparen := p.expect(token.RPAREN) return &ast.ParenExpr{lparen, x, rparen} @@ -969,9 +1041,11 @@ func (p *parser) parseOperand() ast.Expr { return p.parseFuncTypeOrLit() default: - t := p.tryRawType(true) // could be type for composite literal or conversion - if t != nil { - return t + if typ := p.tryIdentOrType(true); typ != nil { + // could be type for composite literal or conversion + _, isIdent := typ.(*ast.Ident) + assert(!isIdent, "type cannot be identifier") + return typ } } @@ -982,19 +1056,22 @@ func (p *parser) parseOperand() ast.Expr { } -func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr { +func (p *parser) parseSelector(x ast.Expr) ast.Expr { if p.trace { - defer un(trace(p, "SelectorOrTypeAssertion")) + defer un(trace(p, "Selector")) } - p.expect(token.PERIOD) - if p.tok == token.IDENT { - // selector - sel := p.parseIdent() - return &ast.SelectorExpr{x, sel} + sel := p.parseIdent() + + return &ast.SelectorExpr{x, sel} +} + + +func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr { + if p.trace { + defer un(trace(p, "TypeAssertion")) } - // type assertion p.expect(token.LPAREN) var typ ast.Expr if p.tok == token.TYPE { @@ -1019,13 +1096,13 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr { var low, high ast.Expr isSlice := false if p.tok != token.COLON { - low = p.parseExpr() + low = p.parseRhs() } if p.tok == token.COLON { isSlice = true p.next() if p.tok != token.RBRACK { - high = p.parseExpr() + high = p.parseRhs() } } p.exprLev-- @@ -1048,7 +1125,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { var list []ast.Expr var ellipsis token.Pos for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() { - list = append(list, p.parseExpr()) + list = append(list, p.parseRhs()) if p.tok == token.ELLIPSIS { ellipsis = p.pos p.next() @@ -1074,7 +1151,7 @@ func (p *parser) parseElement(keyOk bool) ast.Expr { return p.parseLiteralValue(nil) } - x := p.parseExpr() + x := p.parseRhs() if keyOk && p.tok == token.COLON { colon := p.pos p.next() @@ -1231,23 +1308,47 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr { } -func (p *parser) parsePrimaryExpr() ast.Expr { +// If lhs is set and the result is an identifier, it is not resolved. +func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr { if p.trace { defer un(trace(p, "PrimaryExpr")) } - x := p.parseOperand() + x := p.parseOperand(lhs) L: for { switch p.tok { case token.PERIOD: - x = p.parseSelectorOrTypeAssertion(p.checkExpr(x)) + p.next() + if lhs { + p.resolve(x) + } + switch p.tok { + case token.IDENT: + x = p.parseSelector(p.checkExpr(x)) + case token.LPAREN: + x = p.parseTypeAssertion(p.checkExpr(x)) + default: + pos := p.pos + p.next() // make progress + p.errorExpected(pos, "selector or type assertion") + x = &ast.BadExpr{pos, p.pos} + } case token.LBRACK: + if lhs { + p.resolve(x) + } x = p.parseIndexOrSlice(p.checkExpr(x)) case token.LPAREN: + if lhs { + p.resolve(x) + } x = p.parseCallOrConversion(p.checkExprOrType(x)) case token.LBRACE: if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) { + if lhs { + p.resolve(x) + } x = p.parseLiteralValue(x) } else { break L @@ -1255,13 +1356,15 @@ L: default: break L } + lhs = false // no need to try to resolve again } return x } -func (p *parser) parseUnaryExpr() ast.Expr { +// If lhs is set and the result is an identifier, it is not resolved. +func (p *parser) parseUnaryExpr(lhs bool) ast.Expr { if p.trace { defer un(trace(p, "UnaryExpr")) } @@ -1270,7 +1373,7 @@ func (p *parser) parseUnaryExpr() ast.Expr { case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.RANGE: pos, op := p.pos, p.tok p.next() - x := p.parseUnaryExpr() + x := p.parseUnaryExpr(false) return &ast.UnaryExpr{pos, op, p.checkExpr(x)} case token.ARROW: @@ -1283,32 +1386,37 @@ func (p *parser) parseUnaryExpr() ast.Expr { return &ast.ChanType{pos, ast.RECV, value} } - x := p.parseUnaryExpr() + x := p.parseUnaryExpr(false) return &ast.UnaryExpr{pos, token.ARROW, p.checkExpr(x)} case token.MUL: // pointer type or unary "*" expression pos := p.pos p.next() - x := p.parseUnaryExpr() + x := p.parseUnaryExpr(false) return &ast.StarExpr{pos, p.checkExprOrType(x)} } - return p.parsePrimaryExpr() + return p.parsePrimaryExpr(lhs) } -func (p *parser) parseBinaryExpr(prec1 int) ast.Expr { +// If lhs is set and the result is an identifier, it is not resolved. +func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr { if p.trace { defer un(trace(p, "BinaryExpr")) } - x := p.parseUnaryExpr() + x := p.parseUnaryExpr(lhs) for prec := p.tok.Precedence(); prec >= prec1; prec-- { for p.tok.Precedence() == prec { pos, op := p.pos, p.tok p.next() - y := p.parseBinaryExpr(prec + 1) + if lhs { + p.resolve(x) + lhs = false + } + y := p.parseBinaryExpr(false, prec+1) x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)} } } @@ -1317,14 +1425,20 @@ func (p *parser) parseBinaryExpr(prec1 int) ast.Expr { } +// If lhs is set and the result is an identifier, it is not resolved. // TODO(gri): parseExpr may return a type or even a raw type ([..]int) - // should reject when a type/raw type is obviously not allowed -func (p *parser) parseExpr() ast.Expr { +func (p *parser) parseExpr(lhs bool) ast.Expr { if p.trace { defer un(trace(p, "Expression")) } - return p.parseBinaryExpr(token.LowestPrec + 1) + return p.parseBinaryExpr(lhs, token.LowestPrec+1) +} + + +func (p *parser) parseRhs() ast.Expr { + return p.parseExpr(false) } @@ -1336,7 +1450,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { defer un(trace(p, "SimpleStmt")) } - x := p.parseExprList() + x := p.parseLhsList() switch p.tok { case @@ -1347,10 +1461,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { // assignment statement pos, tok := p.pos, p.tok p.next() - y := p.parseExprList() - if tok == token.DEFINE { - p.shortVarDecl(p.makeIdentList(x)) - } + y := p.parseRhsList() return &ast.AssignStmt{x, pos, tok, y} } @@ -1379,7 +1490,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { // send statement arrow := p.pos p.next() // consume "<-" - y := p.parseExpr() + y := p.parseRhs() return &ast.SendStmt{x[0], arrow, y} case token.INC, token.DEC: @@ -1395,7 +1506,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { func (p *parser) parseCallExpr() *ast.CallExpr { - x := p.parseExpr() + x := p.parseRhs() if call, isCall := x.(*ast.CallExpr); isCall { return call } @@ -1445,7 +1556,7 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt { p.expect(token.RETURN) var x []ast.Expr if p.tok != token.SEMICOLON && p.tok != token.RBRACE { - x = p.parseExprList() + x = p.parseRhsList() } p.expectSemi() @@ -1500,12 +1611,12 @@ func (p *parser) parseIfStmt() *ast.IfStmt { p.exprLev = -1 if p.tok == token.SEMICOLON { p.next() - x = p.parseExpr() + x = p.parseRhs() } else { s = p.parseSimpleStmt(false) if p.tok == token.SEMICOLON { p.next() - x = p.parseExpr() + x = p.parseRhs() } else { x = p.makeExpr(s) s = nil @@ -1552,7 +1663,7 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause { if p.tok == token.CASE { p.next() if exprSwitch { - list = p.parseExprList() + list = p.parseRhsList() } else { list = p.parseTypeList() } @@ -1639,7 +1750,7 @@ func (p *parser) parseCommClause() *ast.CommClause { var comm ast.Stmt if p.tok == token.CASE { p.next() - lhs := p.parseExprList() + lhs := p.parseLhsList() if p.tok == token.ARROW { // SendStmt if len(lhs) > 1 { @@ -1648,7 +1759,7 @@ func (p *parser) parseCommClause() *ast.CommClause { } arrow := p.pos p.next() - rhs := p.parseExpr() + rhs := p.parseRhs() comm = &ast.SendStmt{lhs[0], arrow, rhs} } else { // RecvStmt @@ -1663,10 +1774,7 @@ func (p *parser) parseCommClause() *ast.CommClause { lhs = lhs[0:2] } p.next() - rhs = p.parseExpr() - if tok == token.DEFINE { - p.shortVarDecl(p.makeIdentList(lhs)) - } + rhs = p.parseRhs() } else { // rhs must be single receive operation if len(lhs) > 1 { @@ -1873,7 +1981,11 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { } p.expectSemi() // call before accessing p.linecomment - return &ast.ImportSpec{doc, ident, path, p.lineComment} + // collect imports + spec := &ast.ImportSpec{doc, ident, path, p.lineComment} + p.imports = append(p.imports, spec) + + return spec } @@ -1887,7 +1999,7 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec { var values []ast.Expr if typ != nil || p.tok == token.ASSIGN || iota == 0 { p.expect(token.ASSIGN) - values = p.parseExprList() + values = p.parseRhsList() } p.expectSemi() // call before accessing p.linecomment @@ -1932,7 +2044,7 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { var values []ast.Expr if typ == nil || p.tok == token.ASSIGN { p.expect(token.ASSIGN) - values = p.parseExprList() + values = p.parseRhsList() } p.expectSemi() // call before accessing p.linecomment @@ -2120,20 +2232,20 @@ func (p *parser) parseFile() *ast.File { } } - if p.topScope != p.pkgScope { - panic("internal error: imbalanced scopes") - } + assert(p.topScope == p.pkgScope, "imbalanced scopes") // resolve global identifiers within the same file i := 0 for _, ident := range p.unresolved { // i <= index for current ident - ident.Obj = p.pkgScope.Lookup(ident.Name) + assert(ident.Obj == unresolved, "object already resolved") + ident.Obj = p.pkgScope.Lookup(ident.Name) // also removes unresolved sentinel if ident.Obj == nil { p.unresolved[i] = ident i++ } } + // TODO(gri): store p.imports in AST return &ast.File{doc, pos, ident, decls, p.pkgScope, p.unresolved[0:i], p.comments} }