]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1] go/parser: resolve all parameter types
authorRobert Griesemer <gri@golang.org>
Wed, 13 Jun 2012 20:24:12 +0000 (16:24 -0400)
committerRobert Griesemer <gri@golang.org>
Wed, 13 Jun 2012 20:24:12 +0000 (16:24 -0400)
««« backport 0a76445053e5
go/parser: resolve all parameter types

Fixes #3655.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/6213065

»»»

src/pkg/go/parser/parser.go
src/pkg/go/parser/parser_test.go

index fc676de56571eac90b8957971deb5deddb6388b0..20e505d97a89aa8babd2ee99b72ae2f6e9592bdf 100644 (file)
@@ -627,10 +627,10 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 
        doc := p.leadComment
 
-       // fields
+       // FieldDecl
        list, typ := p.parseVarList(false)
 
-       // optional tag
+       // Tag
        var tag *ast.BasicLit
        if p.tok == token.STRING {
                tag = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
@@ -645,7 +645,6 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *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")
@@ -657,6 +656,7 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 
        field := &ast.Field{Doc: doc, Names: idents, Type: typ, Tag: tag, Comment: p.lineComment}
        p.declare(field, nil, scope, ast.Var, idents...)
+       p.resolve(typ)
 
        return field
 }
@@ -699,12 +699,15 @@ func (p *parser) parsePointerType() *ast.StarExpr {
        return &ast.StarExpr{Star: star, X: base}
 }
 
+// If the result is an identifier, it is not resolved.
 func (p *parser) tryVarType(isParam bool) ast.Expr {
        if isParam && p.tok == token.ELLIPSIS {
                pos := p.pos
                p.next()
                typ := p.tryIdentOrType(isParam) // don't use parseType so we can provide better error message
-               if typ == nil {
+               if typ != nil {
+                       p.resolve(typ)
+               } else {
                        p.error(pos, "'...' parameter is missing type")
                        typ = &ast.BadExpr{From: pos, To: p.pos}
                }
@@ -713,6 +716,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
        return p.tryIdentOrType(false)
 }
 
+// If the result is an identifier, it is not resolved.
 func (p *parser) parseVarType(isParam bool) ast.Expr {
        typ := p.tryVarType(isParam)
        if typ == nil {
@@ -724,6 +728,7 @@ func (p *parser) parseVarType(isParam bool) ast.Expr {
        return typ
 }
 
+// If any of the results are identifiers, they are not resolved.
 func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
        if p.trace {
                defer un(trace(p, "VarList"))
@@ -744,9 +749,7 @@ 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
-       if typ = p.tryVarType(isParam); typ != nil {
-               p.resolve(typ)
-       }
+       typ = p.tryVarType(isParam)
 
        return
 }
@@ -756,7 +759,10 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
                defer un(trace(p, "ParameterList"))
        }
 
+       // ParameterDecl
        list, typ := p.parseVarList(ellipsisOk)
+
+       // analyze case
        if typ != nil {
                // IdentifierList Type
                idents := p.makeIdentList(list)
@@ -765,10 +771,10 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
                // Go spec: The scope of an identifier denoting a function
                // parameter or result variable is the function body.
                p.declare(field, nil, scope, ast.Var, idents...)
+               p.resolve(typ)
                if p.tok == token.COMMA {
                        p.next()
                }
-
                for p.tok != token.RPAREN && p.tok != token.EOF {
                        idents := p.parseIdentList()
                        typ := p.parseVarType(ellipsisOk)
@@ -777,18 +783,18 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
                        // Go spec: The scope of an identifier denoting a function
                        // parameter or result variable is the function body.
                        p.declare(field, nil, scope, ast.Var, idents...)
+                       p.resolve(typ)
                        if !p.atComma("parameter list") {
                                break
                        }
                        p.next()
                }
-
        } else {
                // Type { "," Type } (anonymous parameters)
                params = make([]*ast.Field, len(list))
-               for i, x := range list {
-                       p.resolve(x)
-                       params[i] = &ast.Field{Type: x}
+               for i, typ := range list {
+                       p.resolve(typ)
+                       params[i] = &ast.Field{Type: typ}
                }
        }
 
index 7e0ae882187489f1095b5b24d6516c20ab885e1c..1b7a41b1bf15007e1ae92551f1f1703429a6287f 100644 (file)
@@ -135,6 +135,67 @@ func TestVarScope(t *testing.T) {
        }
 }
 
+func TestUnresolved(t *testing.T) {
+       f, err := ParseFile(fset, "", `
+package p
+//
+func f1a(int)
+func f2a(byte, int, float)
+func f3a(a, b int, c float)
+func f4a(...complex)
+func f5a(a s1a, b ...complex)
+//
+func f1b(*int)
+func f2b([]byte, (int), *float)
+func f3b(a, b *int, c []float)
+func f4b(...*complex)
+func f5b(a s1a, b ...[]complex)
+//
+type s1a struct { int }
+type s2a struct { byte; int; s1a }
+type s3a struct { a, b int; c float }
+//
+type s1b struct { *int }
+type s2b struct { byte; int; *float }
+type s3b struct { a, b *s3b; c []float }
+`, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       want := "int " + // f1a
+               "byte int float " + // f2a
+               "int float " + // f3a
+               "complex " + // f4a
+               "complex " + // f5a
+               //
+               "int " + // f1b
+               "byte int float " + // f2b
+               "int float " + // f3b
+               "complex " + // f4b
+               "complex " + // f5b
+               //
+               "int " + // s1a
+               "byte int " + // s2a
+               "int float " + // s3a
+               //
+               "int " + // s1a
+               "byte int float " + // s2a
+               "float " // s3a
+
+       // collect unresolved identifiers
+       var buf bytes.Buffer
+       for _, u := range f.Unresolved {
+               buf.WriteString(u.Name)
+               buf.WriteByte(' ')
+       }
+       got := buf.String()
+
+       if got != want {
+               t.Errorf("\ngot:  %s\nwant: %s", got, want)
+       }
+}
+
 var imports = map[string]bool{
        `"a"`:        true,
        "`a`":        true,