]> Cypherpunks repositories - gostls13.git/commitdiff
go/ast, go/parser: populate identifier scopes at parse time
authorRobert Griesemer <gri@golang.org>
Mon, 7 Mar 2011 19:01:23 +0000 (11:01 -0800)
committerRobert Griesemer <gri@golang.org>
Mon, 7 Mar 2011 19:01:23 +0000 (11:01 -0800)
The parser populates all scopes for a given file (except
type-related scopes for structs, interfaces, and methods
of types) at parse time.

A new parser flag, DeclarationErrors, enables error messages
related to declaration errors (as far as it is possible to
provide them).

The resulting AST has all (non-field, non-method) identifiers
resolved that can be resolved w/o doing imports or parsing
missing package files.

The ast.File node contains the (partially complete)
package scope and a list of unresolved global identifiers.

All type-specific data structures have been removed from the AST.

The existing typechecker is functional but needs to be adjusted
(simplified) accordingly. Utility functions to resolve all
identifiers for a package (after handling imports and parsing
all package files) are  missing.

Unrelated changes:
- Rename typechecker/testdata files to that they are not considered
  by gofmt.
- Minor cleanups/simplifications.

Parses all .go files in src and misc without declaration errors.
Runs all tests. Changes do not affect gofmt output.

R=rsc
CC=golang-dev
https://golang.org/cl/4244049

16 files changed:
src/pkg/exp/eval/stmt_test.go
src/pkg/go/ast/ast.go
src/pkg/go/ast/filter.go
src/pkg/go/ast/scope.go
src/pkg/go/parser/parser.go
src/pkg/go/parser/parser_test.go
src/pkg/go/typechecker/Makefile
src/pkg/go/typechecker/scope.go
src/pkg/go/typechecker/testdata/test0.src [moved from src/pkg/go/typechecker/testdata/test0.go with 100% similarity]
src/pkg/go/typechecker/testdata/test1.src [moved from src/pkg/go/typechecker/testdata/test1.go with 100% similarity]
src/pkg/go/typechecker/testdata/test3.src [moved from src/pkg/go/typechecker/testdata/test3.go with 80% similarity]
src/pkg/go/typechecker/testdata/test4.src [moved from src/pkg/go/typechecker/testdata/test4.go with 100% similarity]
src/pkg/go/typechecker/type.go [new file with mode: 0644]
src/pkg/go/typechecker/typechecker.go
src/pkg/go/typechecker/typechecker_test.go
src/pkg/go/typechecker/universe.go

index 4a883ef5ee79b2460f8bee76f5a613cb6b4db055..a8a3e16204121e4db0e58d5d2c85b5a05d801893 100644 (file)
@@ -27,7 +27,7 @@ var stmtTests = []test{
        CErr("i, u := 1, 2", atLeastOneDecl),
        Val2("i, x := 2, f", "i", 2, "x", 1.0),
        // Various errors
-       CErr("1 := 2", "left side of := must be a name"),
+       CErr("1 := 2", "expected identifier"),
        CErr("c, a := 1, 1", "cannot assign"),
        // Unpacking
        Val2("x, y := oneTwo()", "x", 1, "y", 2),
index abafb5663b3baf0ef0dcfdebfc9d303be68a6ae1..feb31b631dfa577879928a537a7c9add5bcffc22 100644 (file)
@@ -937,11 +937,13 @@ func (d *FuncDecl) declNode() {}
 // via Doc and Comment fields.
 //
 type File struct {
-       Doc      *CommentGroup   // associated documentation; or nil
-       Package  token.Pos       // position of "package" keyword
-       Name     *Ident          // package name
-       Decls    []Decl          // top-level declarations; or nil
-       Comments []*CommentGroup // list of all comments in the source file
+       Doc        *CommentGroup   // associated documentation; or nil
+       Package    token.Pos       // position of "package" keyword
+       Name       *Ident          // package name
+       Decls      []Decl          // top-level declarations; or nil
+       Scope      *Scope          // package scope
+       Unresolved []*Ident        // unresolved global identifiers
+       Comments   []*CommentGroup // list of all comments in the source file
 }
 
 
@@ -959,7 +961,7 @@ func (f *File) End() token.Pos {
 //
 type Package struct {
        Name  string           // package name
-       Scope *Scope           // package scope; or nil
+       Scope *Scope           // package scope
        Files map[string]*File // Go source files by filename
 }
 
index 0c3cef4b27b15c976c8642c409d7a694f7d53c68..4da487ce02ad02fd7c508b64809537f6543edbc3 100644 (file)
@@ -425,5 +425,6 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
                }
        }
 
-       return &File{doc, pos, NewIdent(pkg.Name), decls, comments}
+       // TODO(gri) need to compute pkgScope and unresolved identifiers!
+       return &File{doc, pos, NewIdent(pkg.Name), decls, nil, nil, comments}
 }
index 956a208aede5aa3e24d482dc879bbf7373e230e0..91866dcf57b4a4194e1c42e112a40b8e0ad1b9c4 100644 (file)
@@ -2,31 +2,31 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file implements scopes, the objects they contain,
-// and object types.
+// This file implements scopes and the objects they contain.
 
 package ast
 
+import (
+       "bytes"
+       "fmt"
+       "go/token"
+)
+
+
 // A Scope maintains the set of named language entities declared
 // in the scope and a link to the immediately surrounding (outer)
 // scope.
 //
 type Scope struct {
        Outer   *Scope
-       Objects []*Object // in declaration order
-       // Implementation note: In some cases (struct fields,
-       // function parameters) we need the source order of
-       // variables. Thus for now, we store scope entries
-       // in a linear list. If scopes become very large
-       // (say, for packages), we may need to change this
-       // to avoid slow lookups.
+       Objects map[string]*Object
 }
 
 
 // NewScope creates a new scope nested in the outer scope.
 func NewScope(outer *Scope) *Scope {
-       const n = 4 // initial scope capacity, must be > 0
-       return &Scope{outer, make([]*Object, 0, n)}
+       const n = 4 // initial scope capacity
+       return &Scope{outer, make(map[string]*Object, n)}
 }
 
 
@@ -34,73 +34,108 @@ func NewScope(outer *Scope) *Scope {
 // found in scope s, otherwise it returns nil. Outer scopes
 // are ignored.
 //
-// Lookup always returns nil if name is "_", even if the scope
-// contains objects with that name.
-//
 func (s *Scope) Lookup(name string) *Object {
-       if name != "_" {
-               for _, obj := range s.Objects {
-                       if obj.Name == name {
-                               return obj
-                       }
-               }
-       }
-       return nil
+       return s.Objects[name]
 }
 
 
 // Insert attempts to insert a named object into the scope s.
-// If the scope does not contain an object with that name yet
-// or if the object is named "_", Insert inserts the object
-// and returns it. Otherwise, Insert leaves the scope unchanged
-// and returns the object found in the scope instead.
+// If the scope does not contain an object with that name yet,
+// Insert inserts the object and returns it. Otherwise, Insert
+// leaves the scope unchanged and returns the object found in
+// the scope instead.
 //
-func (s *Scope) Insert(obj *Object) *Object {
-       alt := s.Lookup(obj.Name)
-       if alt == nil {
-               s.append(obj)
+func (s *Scope) Insert(obj *Object) (alt *Object) {
+       if alt = s.Objects[obj.Name]; alt == nil {
+               s.Objects[obj.Name] = obj
                alt = obj
        }
-       return alt
+       return
 }
 
 
-func (s *Scope) append(obj *Object) {
-       s.Objects = append(s.Objects, obj)
+// Debugging support
+func (s *Scope) String() string {
+       var buf bytes.Buffer
+       fmt.Fprintf(&buf, "scope %p {", s)
+       if s != nil && len(s.Objects) > 0 {
+               fmt.Fprintln(&buf)
+               for _, obj := range s.Objects {
+                       fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name)
+               }
+       }
+       fmt.Fprintf(&buf, "}\n")
+       return buf.String()
 }
 
+
 // ----------------------------------------------------------------------------
 // Objects
 
-// An Object describes a language entity such as a package,
-// constant, type, variable, or function (incl. methods).
+// An Object describes a named language entity such as a package,
+// constant, type, variable, function (incl. methods), or label.
 //
 type Object struct {
-       Kind Kind
-       Name string // declared name
-       Type *Type
-       Decl interface{} // corresponding Field, XxxSpec or FuncDecl
-       N    int         // value of iota for this declaration
+       Kind ObjKind
+       Name string      // declared name
+       Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
+       Type interface{} // place holder for type information; may be nil
 }
 
 
 // NewObj creates a new object of a given kind and name.
-func NewObj(kind Kind, name string) *Object {
+func NewObj(kind ObjKind, name string) *Object {
        return &Object{Kind: kind, Name: name}
 }
 
 
-// Kind describes what an object represents.
-type Kind int
+// Pos computes the source position of the declaration of an object name.
+// The result may be an invalid position if it cannot be computed
+// (obj.Decl may be nil or not correct).
+func (obj *Object) Pos() token.Pos {
+       name := obj.Name
+       switch d := obj.Decl.(type) {
+       case *Field:
+               for _, n := range d.Names {
+                       if n.Name == name {
+                               return n.Pos()
+                       }
+               }
+       case *ValueSpec:
+               for _, n := range d.Names {
+                       if n.Name == name {
+                               return n.Pos()
+                       }
+               }
+       case *TypeSpec:
+               if d.Name.Name == name {
+                       return d.Name.Pos()
+               }
+       case *FuncDecl:
+               if d.Name.Name == name {
+                       return d.Name.Pos()
+               }
+       case *LabeledStmt:
+               if d.Label.Name == name {
+                       return d.Label.Pos()
+               }
+       }
+       return token.NoPos
+}
+
+
+// ObKind describes what an object represents.
+type ObjKind int
 
 // The list of possible Object kinds.
 const (
-       Bad Kind = iota // for error handling
-       Pkg             // package
-       Con             // constant
-       Typ             // type
-       Var             // variable
-       Fun             // function or method
+       Bad ObjKind = iota // for error handling
+       Pkg                // package
+       Con                // constant
+       Typ                // type
+       Var                // variable
+       Fun                // function or method
+       Lbl                // label
 )
 
 
@@ -111,132 +146,8 @@ var objKindStrings = [...]string{
        Typ: "type",
        Var: "var",
        Fun: "func",
+       Lbl: "label",
 }
 
 
-func (kind Kind) String() string { return objKindStrings[kind] }
-
-
-// IsExported returns whether obj is exported.
-func (obj *Object) IsExported() bool { return IsExported(obj.Name) }
-
-
-// ----------------------------------------------------------------------------
-// Types
-
-// A Type represents a Go type.
-type Type struct {
-       Form     Form
-       Obj      *Object // corresponding type name, or nil
-       Scope    *Scope  // fields and methods, always present
-       N        uint    // basic type id, array length, number of function results, or channel direction
-       Key, Elt *Type   // map key and array, pointer, slice, map or channel element
-       Params   *Scope  // function (receiver, input and result) parameters, tuple expressions (results of function calls), or nil
-       Expr     Expr    // corresponding AST expression
-}
-
-
-// NewType creates a new type of a given form.
-func NewType(form Form) *Type {
-       return &Type{Form: form, Scope: NewScope(nil)}
-}
-
-
-// Form describes the form of a type.
-type Form int
-
-// The list of possible type forms.
-const (
-       BadType    Form = iota // for error handling
-       Unresolved             // type not fully setup
-       Basic
-       Array
-       Struct
-       Pointer
-       Function
-       Method
-       Interface
-       Slice
-       Map
-       Channel
-       Tuple
-)
-
-
-var formStrings = [...]string{
-       BadType:    "badType",
-       Unresolved: "unresolved",
-       Basic:      "basic",
-       Array:      "array",
-       Struct:     "struct",
-       Pointer:    "pointer",
-       Function:   "function",
-       Method:     "method",
-       Interface:  "interface",
-       Slice:      "slice",
-       Map:        "map",
-       Channel:    "channel",
-       Tuple:      "tuple",
-}
-
-
-func (form Form) String() string { return formStrings[form] }
-
-
-// The list of basic type id's.
-const (
-       Bool = iota
-       Byte
-       Uint
-       Int
-       Float
-       Complex
-       Uintptr
-       String
-
-       Uint8
-       Uint16
-       Uint32
-       Uint64
-
-       Int8
-       Int16
-       Int32
-       Int64
-
-       Float32
-       Float64
-
-       Complex64
-       Complex128
-
-       // TODO(gri) ideal types are missing
-)
-
-
-var BasicTypes = map[uint]string{
-       Bool:    "bool",
-       Byte:    "byte",
-       Uint:    "uint",
-       Int:     "int",
-       Float:   "float",
-       Complex: "complex",
-       Uintptr: "uintptr",
-       String:  "string",
-
-       Uint8:  "uint8",
-       Uint16: "uint16",
-       Uint32: "uint32",
-       Uint64: "uint64",
-
-       Int8:  "int8",
-       Int16: "int16",
-       Int32: "int32",
-       Int64: "int64",
-
-       Float32: "float32",
-       Float64: "float64",
-
-       Complex64:  "complex64",
-       Complex128: "complex128",
-}
+func (kind ObjKind) String() string { return objKindStrings[kind] }
index 7c5843f36371a19b23b476edf985bc13f666a633..5d4814870c4134b06da9ba7ad6057da86a15df1f 100644 (file)
@@ -17,10 +17,6 @@ import (
 )
 
 
-// noPos is used when there is no corresponding source position for a token.
-var noPos token.Position
-
-
 // The mode parameter to the Parse* functions is a set of flags (or 0).
 // They control the amount of source code parsed and other optional
 // parser functionality.
@@ -30,6 +26,7 @@ const (
        ImportsOnly                        // parsing stops after import declarations
        ParseComments                      // parse comments and add them to AST
        Trace                              // print a trace of parsed productions
+       DeclarationErrors                  // report declaration errors
 )
 
 
@@ -46,8 +43,8 @@ type parser struct {
 
        // Comments
        comments    []*ast.CommentGroup
-       leadComment *ast.CommentGroup // the last lead comment
-       lineComment *ast.CommentGroup // the last line comment
+       leadComment *ast.CommentGroup // last lead comment
+       lineComment *ast.CommentGroup // last line comment
 
        // Next token
        pos token.Pos   // token position
@@ -56,6 +53,16 @@ type parser struct {
 
        // Non-syntactic parser control
        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
+
+       // Label scope
+       // (maintained by open/close LabelScope)
+       labelScope  *ast.Scope     // label scope for current function
+       targetStack [][]*ast.Ident // stack of unresolved labels
 }
 
 
@@ -72,9 +79,117 @@ func scannerMode(mode uint) uint {
 func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
        p.file = fset.AddFile(filename, fset.Base(), len(src))
        p.scanner.Init(p.file, src, p, scannerMode(mode))
+
        p.mode = mode
        p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
+
        p.next()
+
+       // set up the pkgScope here (as opposed to in parseFile) because
+       // there are other parser entry points (ParseExpr, etc.)
+       p.openScope()
+       p.pkgScope = p.topScope
+
+       // for the same reason, set up a label scope
+       p.openLabelScope()
+}
+
+
+// ----------------------------------------------------------------------------
+// Scoping support
+
+func (p *parser) openScope() {
+       p.topScope = ast.NewScope(p.topScope)
+}
+
+
+func (p *parser) closeScope() {
+       p.topScope = p.topScope.Outer
+}
+
+
+func (p *parser) openLabelScope() {
+       p.labelScope = ast.NewScope(p.labelScope)
+       p.targetStack = append(p.targetStack, nil)
+}
+
+
+func (p *parser) closeLabelScope() {
+       // resolve labels
+       n := len(p.targetStack) - 1
+       scope := p.labelScope
+       for _, ident := range p.targetStack[n] {
+               ident.Obj = scope.Lookup(ident.Name)
+               if ident.Obj == nil && p.mode&DeclarationErrors != 0 {
+                       p.error(ident.Pos(), fmt.Sprintf("label %s undefined", ident.Name))
+               }
+       }
+       // pop label scope
+       p.targetStack = p.targetStack[0:n]
+       p.labelScope = p.labelScope.Outer
+}
+
+
+func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
+       for _, ident := range idents {
+               if ident.Name != "_" {
+                       obj := ast.NewObj(kind, ident.Name)
+                       // remember the corresponding declaration for redeclaration
+                       // errors and global variable resolution/typechecking phase
+                       obj.Decl = decl
+                       alt := scope.Insert(obj)
+                       if alt != obj && p.mode&DeclarationErrors != 0 {
+                               prevDecl := ""
+                               if pos := alt.Pos(); pos.IsValid() {
+                                       prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.file.Position(pos))
+                               }
+                               p.error(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
+                       }
+                       ident.Obj = obj
+               }
+       }
+}
+
+
+func (p *parser) shortVarDecl(idents []*ast.Ident) {
+       // 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 {
+               if ident.Name != "_" {
+                       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
+                       alt := p.topScope.Insert(obj)
+                       if alt == obj {
+                               n++ // new declaration
+                       }
+                       ident.Obj = alt
+               }
+       }
+       if n == 0 && p.mode&DeclarationErrors != 0 {
+               p.error(idents[0].Pos(), "no new variables on left side of :=")
+       }
+}
+
+
+func (p *parser) resolve(ident *ast.Ident) {
+       if ident.Name == "_" {
+               return
+       }
+       // try to resolve the identifier
+       for s := p.topScope; s != nil; s = s.Outer {
+               if obj := s.Lookup(ident.Name); obj != nil {
+                       ident.Obj = obj
+                       return
+               }
+       }
+       // collect unresolved global identifiers; ignore the others
+       if p.topScope == p.pkgScope {
+               p.unresolved = append(p.unresolved, ident)
+       }
 }
 
 
@@ -339,13 +454,16 @@ func (p *parser) parseQualifiedIdent() ast.Expr {
                defer un(trace(p, "QualifiedIdent"))
        }
 
-       var x ast.Expr = p.parseIdent()
+       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
 }
 
@@ -426,7 +544,7 @@ func (p *parser) parseFieldDecl() *ast.Field {
                }
        }
 
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
 
        return &ast.Field{doc, idents, typ, tag, p.lineComment}
 }
@@ -519,7 +637,7 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
 }
 
 
-func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) {
+func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
        if p.trace {
                defer un(trace(p, "ParameterList"))
        }
@@ -528,7 +646,11 @@ func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) {
        if typ != nil {
                // IdentifierList Type
                idents := p.makeIdentList(list)
-               params = append(params, &ast.Field{nil, idents, typ, nil, nil})
+               field := &ast.Field{nil, idents, typ, nil, nil}
+               params = append(params, field)
+               // Go spec: The scope of an identifier denoting a function
+               // parameter or result variable is the function body.
+               p.declare(field, scope, ast.Var, idents...)
                if p.tok == token.COMMA {
                        p.next()
                }
@@ -536,7 +658,11 @@ func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) {
                for p.tok != token.RPAREN && p.tok != token.EOF {
                        idents := p.parseIdentList()
                        typ := p.parseVarType(ellipsisOk)
-                       params = append(params, &ast.Field{nil, idents, typ, nil, nil})
+                       field := &ast.Field{nil, idents, typ, nil, nil}
+                       params = append(params, field)
+                       // Go spec: The scope of an identifier denoting a function
+                       // parameter or result variable is the function body.
+                       p.declare(field, scope, ast.Var, idents...)
                        if p.tok != token.COMMA {
                                break
                        }
@@ -555,7 +681,7 @@ func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) {
 }
 
 
-func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList {
+func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
        if p.trace {
                defer un(trace(p, "Parameters"))
        }
@@ -563,7 +689,7 @@ func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList {
        var params []*ast.Field
        lparen := p.expect(token.LPAREN)
        if p.tok != token.RPAREN {
-               params = p.parseParameterList(ellipsisOk)
+               params = p.parseParameterList(scope, ellipsisOk)
        }
        rparen := p.expect(token.RPAREN)
 
@@ -571,13 +697,13 @@ func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList {
 }
 
 
-func (p *parser) parseResult() *ast.FieldList {
+func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
        if p.trace {
                defer un(trace(p, "Result"))
        }
 
        if p.tok == token.LPAREN {
-               return p.parseParameters(false)
+               return p.parseParameters(scope, false)
        }
 
        typ := p.tryType()
@@ -591,27 +717,28 @@ func (p *parser) parseResult() *ast.FieldList {
 }
 
 
-func (p *parser) parseSignature() (params, results *ast.FieldList) {
+func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
        if p.trace {
                defer un(trace(p, "Signature"))
        }
 
-       params = p.parseParameters(true)
-       results = p.parseResult()
+       params = p.parseParameters(scope, true)
+       results = p.parseResult(scope)
 
        return
 }
 
 
-func (p *parser) parseFuncType() *ast.FuncType {
+func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
        if p.trace {
                defer un(trace(p, "FuncType"))
        }
 
        pos := p.expect(token.FUNC)
-       params, results := p.parseSignature()
+       scope := ast.NewScope(p.topScope) // function scope
+       params, results := p.parseSignature(scope)
 
-       return &ast.FuncType{pos, params, results}
+       return &ast.FuncType{pos, params, results}, scope
 }
 
 
@@ -627,13 +754,14 @@ func (p *parser) parseMethodSpec() *ast.Field {
        if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
                // method
                idents = []*ast.Ident{ident}
-               params, results := p.parseSignature()
+               scope := ast.NewScope(nil) // method scope
+               params, results := p.parseSignature(scope)
                typ = &ast.FuncType{token.NoPos, params, results}
        } else {
                // embedded interface
                typ = x
        }
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
 
        return &ast.Field{doc, idents, typ, nil, p.lineComment}
 }
@@ -706,7 +834,8 @@ func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
        case token.MUL:
                return p.parsePointerType()
        case token.FUNC:
-               return p.parseFuncType()
+               typ, _ := p.parseFuncType()
+               return typ
        case token.INTERFACE:
                return p.parseInterfaceType()
        case token.MAP:
@@ -745,13 +874,17 @@ func (p *parser) parseStmtList() (list []ast.Stmt) {
 }
 
 
-func (p *parser) parseBody() *ast.BlockStmt {
+func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
        if p.trace {
                defer un(trace(p, "Body"))
        }
 
        lbrace := p.expect(token.LBRACE)
+       p.topScope = scope // open function scope
+       p.openLabelScope()
        list := p.parseStmtList()
+       p.closeLabelScope()
+       p.closeScope()
        rbrace := p.expect(token.RBRACE)
 
        return &ast.BlockStmt{lbrace, list, rbrace}
@@ -764,7 +897,9 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
        }
 
        lbrace := p.expect(token.LBRACE)
+       p.openScope()
        list := p.parseStmtList()
+       p.closeScope()
        rbrace := p.expect(token.RBRACE)
 
        return &ast.BlockStmt{lbrace, list, rbrace}
@@ -779,14 +914,14 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
                defer un(trace(p, "FuncTypeOrLit"))
        }
 
-       typ := p.parseFuncType()
+       typ, scope := p.parseFuncType()
        if p.tok != token.LBRACE {
                // function type only
                return typ
        }
 
        p.exprLev++
-       body := p.parseBody()
+       body := p.parseBody(scope)
        p.exprLev--
 
        return &ast.FuncLit{typ, body}
@@ -803,7 +938,9 @@ func (p *parser) parseOperand() ast.Expr {
 
        switch p.tok {
        case token.IDENT:
-               return p.parseIdent()
+               ident := p.parseIdent()
+               p.resolve(ident)
+               return ident
 
        case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
                x := &ast.BasicLit{p.pos, p.tok, p.lit}
@@ -1202,6 +1339,9 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
                pos, tok := p.pos, p.tok
                p.next()
                y := p.parseExprList()
+               if tok == token.DEFINE {
+                       p.shortVarDecl(p.makeIdentList(x))
+               }
                return &ast.AssignStmt{x, pos, tok, y}
        }
 
@@ -1216,7 +1356,12 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
                colon := p.pos
                p.next()
                if label, isIdent := x[0].(*ast.Ident); labelOk && isIdent {
-                       return &ast.LabeledStmt{label, colon, p.parseStmt()}
+                       // Go spec: The scope of a label is the body of the function
+                       // in which it is declared and excludes the body of any nested
+                       // function.
+                       stmt := &ast.LabeledStmt{label, colon, p.parseStmt()}
+                       p.declare(stmt, p.labelScope, ast.Lbl, label)
+                       return stmt
                }
                p.error(x[0].Pos(), "illegal label declaration")
                return &ast.BadStmt{x[0].Pos(), colon + 1}
@@ -1304,14 +1449,17 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
                defer un(trace(p, "BranchStmt"))
        }
 
-       s := &ast.BranchStmt{p.pos, tok, nil}
-       p.expect(tok)
+       pos := p.expect(tok)
+       var label *ast.Ident
        if tok != token.FALLTHROUGH && p.tok == token.IDENT {
-               s.Label = p.parseIdent()
+               label = p.parseIdent()
+               // add to list of unresolved targets
+               n := len(p.targetStack) - 1
+               p.targetStack[n] = append(p.targetStack[n], label)
        }
        p.expectSemi()
 
-       return s
+       return &ast.BranchStmt{pos, tok, label}
 }
 
 
@@ -1333,6 +1481,8 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
        }
 
        pos := p.expect(token.IF)
+       p.openScope()
+       defer p.closeScope()
 
        var s ast.Stmt
        var x ast.Expr
@@ -1373,7 +1523,6 @@ func (p *parser) parseCaseClause() *ast.CaseClause {
                defer un(trace(p, "CaseClause"))
        }
 
-       // SwitchCase
        pos := p.pos
        var x []ast.Expr
        if p.tok == token.CASE {
@@ -1384,7 +1533,9 @@ func (p *parser) parseCaseClause() *ast.CaseClause {
        }
 
        colon := p.expect(token.COLON)
+       p.openScope()
        body := p.parseStmtList()
+       p.closeScope()
 
        return &ast.CaseClause{pos, x, colon, body}
 }
@@ -1410,7 +1561,6 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
                defer un(trace(p, "TypeCaseClause"))
        }
 
-       // TypeSwitchCase
        pos := p.pos
        var types []ast.Expr
        if p.tok == token.CASE {
@@ -1421,7 +1571,9 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
        }
 
        colon := p.expect(token.COLON)
+       p.openScope()
        body := p.parseStmtList()
+       p.closeScope()
 
        return &ast.TypeCaseClause{pos, types, colon, body}
 }
@@ -1447,6 +1599,8 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
        }
 
        pos := p.expect(token.SWITCH)
+       p.openScope()
+       defer p.closeScope()
 
        var s1, s2 ast.Stmt
        if p.tok != token.LBRACE {
@@ -1497,7 +1651,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
                defer un(trace(p, "CommClause"))
        }
 
-       // CommCase
+       p.openScope()
        pos := p.pos
        var comm ast.Stmt
        if p.tok == token.CASE {
@@ -1518,7 +1672,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
                        pos := p.pos
                        tok := p.tok
                        var rhs ast.Expr
-                       if p.tok == token.ASSIGN || p.tok == token.DEFINE {
+                       if tok == token.ASSIGN || tok == token.DEFINE {
                                // RecvStmt with assignment
                                if len(lhs) > 2 {
                                        p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
@@ -1527,6 +1681,9 @@ func (p *parser) parseCommClause() *ast.CommClause {
                                }
                                p.next()
                                rhs = p.parseExpr()
+                               if tok == token.DEFINE {
+                                       p.shortVarDecl(p.makeIdentList(lhs))
+                               }
                        } else {
                                // rhs must be single receive operation
                                if len(lhs) > 1 {
@@ -1552,6 +1709,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
 
        colon := p.expect(token.COLON)
        body := p.parseStmtList()
+       p.closeScope()
 
        return &ast.CommClause{pos, comm, colon, body}
 }
@@ -1582,6 +1740,8 @@ func (p *parser) parseForStmt() ast.Stmt {
        }
 
        pos := p.expect(token.FOR)
+       p.openScope()
+       defer p.closeScope()
 
        var s1, s2, s3 ast.Stmt
        if p.tok != token.LBRACE {
@@ -1631,18 +1791,16 @@ func (p *parser) parseForStmt() ast.Stmt {
                        return &ast.BadStmt{pos, body.End()}
                }
                if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE {
-                       // rhs is range expression; check lhs
+                       // rhs is range expression
+                       // (any short variable declaration was handled by parseSimpleStat above)
                        return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
-               } else {
-                       p.errorExpected(s2.Pos(), "range clause")
-                       return &ast.BadStmt{pos, body.End()}
                }
-       } else {
-               // regular for statement
-               return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
+               p.errorExpected(s2.Pos(), "range clause")
+               return &ast.BadStmt{pos, body.End()}
        }
 
-       panic("unreachable")
+       // regular for statement
+       return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
 }
 
 
@@ -1715,10 +1873,11 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
        }
 
        var ident *ast.Ident
-       if p.tok == token.PERIOD {
+       switch p.tok {
+       case token.PERIOD:
                ident = &ast.Ident{p.pos, ".", nil}
                p.next()
-       } else if p.tok == token.IDENT {
+       case token.IDENT:
                ident = p.parseIdent()
        }
 
@@ -1729,7 +1888,7 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
        } else {
                p.expect(token.STRING) // use expect() error handling
        }
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
 
        return &ast.ImportSpec{doc, ident, path, p.lineComment}
 }
@@ -1747,9 +1906,16 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
                p.expect(token.ASSIGN)
                values = p.parseExprList()
        }
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
+
+       // Go spec: The scope of a constant or variable identifier declared inside
+       // a function begins at the end of the ConstSpec or VarSpec and ends at
+       // the end of the innermost containing block.
+       // (Global identifiers are resolved in a separate phase after parsing.)
+       spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+       p.declare(spec, p.topScope, ast.Con, idents...)
 
-       return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+       return spec
 }
 
 
@@ -1760,9 +1926,16 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
 
        ident := p.parseIdent()
        typ := p.parseType()
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
+
+       // Go spec: The scope of a type identifier declared inside a function begins
+       // at the identifier in the TypeSpec and ends at the end of the innermost
+       // containing block.
+       // (Global identifiers are resolved in a separate phase after parsing.)
+       spec := &ast.TypeSpec{doc, ident, typ, p.lineComment}
+       p.declare(spec, p.topScope, ast.Typ, ident)
 
-       return &ast.TypeSpec{doc, ident, typ, p.lineComment}
+       return spec
 }
 
 
@@ -1778,9 +1951,16 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
                p.expect(token.ASSIGN)
                values = p.parseExprList()
        }
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
+
+       // Go spec: The scope of a constant or variable identifier declared inside
+       // a function begins at the end of the ConstSpec or VarSpec and ends at
+       // the end of the innermost containing block.
+       // (Global identifiers are resolved in a separate phase after parsing.)
+       spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+       p.declare(spec, p.topScope, ast.Var, idents...)
 
-       return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+       return spec
 }
 
 
@@ -1809,13 +1989,13 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
 }
 
 
-func (p *parser) parseReceiver() *ast.FieldList {
+func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
        if p.trace {
                defer un(trace(p, "Receiver"))
        }
 
        pos := p.pos
-       par := p.parseParameters(false)
+       par := p.parseParameters(scope, false)
 
        // must have exactly one receiver
        if par.NumFields() != 1 {
@@ -1844,22 +2024,37 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
 
        doc := p.leadComment
        pos := p.expect(token.FUNC)
+       scope := ast.NewScope(p.topScope) // function scope
 
        var recv *ast.FieldList
        if p.tok == token.LPAREN {
-               recv = p.parseReceiver()
+               recv = p.parseReceiver(scope)
        }
 
        ident := p.parseIdent()
-       params, results := p.parseSignature()
+
+       params, results := p.parseSignature(scope)
 
        var body *ast.BlockStmt
        if p.tok == token.LBRACE {
-               body = p.parseBody()
+               body = p.parseBody(scope)
        }
        p.expectSemi()
 
-       return &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body}
+       decl := &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body}
+       if recv == nil {
+               // Go spec: The scope of an identifier denoting a constant, type,
+               // variable, or function (but not method) declared at top level
+               // (outside any function) is the package block.
+               //
+               // init() functions cannot be referred to and there may
+               // be more than one - don't put them in the pkgScope
+               if ident.Name != "init" {
+                       p.declare(decl, p.pkgScope, ast.Fun, ident)
+               }
+       }
+
+       return decl
 }
 
 
@@ -1918,6 +2113,8 @@ func (p *parser) parseFile() *ast.File {
        // package clause
        doc := p.leadComment
        pos := p.expect(token.PACKAGE)
+       // Go spec: The package clause is not a declaration;
+       // the package name does not appear in any scope.
        ident := p.parseIdent()
        p.expectSemi()
 
@@ -1940,5 +2137,20 @@ func (p *parser) parseFile() *ast.File {
                }
        }
 
-       return &ast.File{doc, pos, ident, decls, p.comments}
+       if p.topScope != p.pkgScope {
+               panic("internal error: 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)
+               if ident.Obj == nil {
+                       p.unresolved[i] = ident
+                       i++
+               }
+       }
+
+       return &ast.File{doc, pos, ident, decls, p.pkgScope, p.unresolved[0:i], p.comments}
 }
index 38535627a75ec76029993c986f53e25b04a82c00..8e07d9f87c9c43977d00ddd5a2273ed3f2fc880b 100644 (file)
@@ -73,7 +73,7 @@ var validFiles = []string{
 
 func TestParse3(t *testing.T) {
        for _, filename := range validFiles {
-               _, err := ParseFile(fset, filename, nil, 0)
+               _, err := ParseFile(fset, filename, nil, DeclarationErrors)
                if err != nil {
                        t.Errorf("ParseFile(%s): %v", filename, err)
                }
index 62b2aa7fe0c530757365dc66762b224818dd1717..83af3ef4e4590251128fda8aeded2264fef2e98c 100644 (file)
@@ -7,6 +7,7 @@ include ../../../Make.inc
 TARG=go/typechecker
 GOFILES=\
        scope.go\
+       type.go\
        typechecker.go\
        universe.go\
 
index 114c93ea86ef65ff2e981c4f4dfae2ee2566e8fa..bd24f4ca42dc3d911a8a4a12897d4e8d77211f38 100644 (file)
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file implements scope support functions.
+// DEPRECATED FILE - WILL GO AWAY EVENTUALLY.
+//
+// Scope handling is now done in go/parser.
+// The functionality here is only present to
+// keep the typechecker running for now.
 
 package typechecker
 
-import (
-       "fmt"
-       "go/ast"
-       "go/token"
-)
+import "go/ast"
 
 
 func (tc *typechecker) openScope() *ast.Scope {
@@ -24,52 +24,25 @@ func (tc *typechecker) closeScope() {
 }
 
 
-// objPos computes the source position of the declaration of an object name.
-// Only required for error reporting, so doesn't have to be fast.
-func objPos(obj *ast.Object) (pos token.Pos) {
-       switch d := obj.Decl.(type) {
-       case *ast.Field:
-               for _, n := range d.Names {
-                       if n.Name == obj.Name {
-                               return n.Pos()
-                       }
-               }
-       case *ast.ValueSpec:
-               for _, n := range d.Names {
-                       if n.Name == obj.Name {
-                               return n.Pos()
-                       }
-               }
-       case *ast.TypeSpec:
-               return d.Name.Pos()
-       case *ast.FuncDecl:
-               return d.Name.Pos()
-       }
-       if debug {
-               fmt.Printf("decl = %T\n", obj.Decl)
-       }
-       panic("unreachable")
-}
-
-
 // declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
 // It returns the newly allocated object. If an object with the same name already exists in scope, an error
 // is reported and the object is not inserted.
-// (Objects with _ name are always inserted into a scope without errors, but they cannot be found.)
-func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
        obj := ast.NewObj(kind, name.Name)
        obj.Decl = decl
-       obj.N = n
+       //obj.N = n
        name.Obj = obj
-       if alt := scope.Insert(obj); alt != obj {
-               tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, objPos(alt))
+       if name.Name != "_" {
+               if alt := scope.Insert(obj); alt != obj {
+                       tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, tc.fset.Position(alt.Pos()).String())
+               }
        }
        return obj
 }
 
 
 // decl is the same as declInScope(tc.topScope, ...)
-func (tc *typechecker) decl(kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+func (tc *typechecker) decl(kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
        return tc.declInScope(tc.topScope, kind, name, decl, n)
 }
 
@@ -91,7 +64,7 @@ func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
 
 // findField returns the object with the given name if visible in the type's scope.
 // If no such object is found, an error is reported and a bad object is returned instead.
-func (tc *typechecker) findField(typ *ast.Type, name *ast.Ident) (obj *ast.Object) {
+func (tc *typechecker) findField(typ *Type, name *ast.Ident) (obj *ast.Object) {
        // TODO(gri) This is simplistic at the moment and ignores anonymous fields.
        obj = typ.Scope.Lookup(name.Name)
        if obj == nil {
@@ -100,20 +73,3 @@ func (tc *typechecker) findField(typ *ast.Type, name *ast.Ident) (obj *ast.Objec
        }
        return
 }
-
-
-// printScope prints the objects in a scope.
-func printScope(scope *ast.Scope) {
-       fmt.Printf("scope %p {", scope)
-       if scope != nil && len(scope.Objects) > 0 {
-               fmt.Println()
-               for _, obj := range scope.Objects {
-                       form := "void"
-                       if obj.Type != nil {
-                               form = obj.Type.Form.String()
-                       }
-                       fmt.Printf("\t%s\t%s\n", obj.Name, form)
-               }
-       }
-       fmt.Printf("}\n")
-}
similarity index 80%
rename from src/pkg/go/typechecker/testdata/test3.go
rename to src/pkg/go/typechecker/testdata/test3.src
index ea35808a09fca815db838d86854399ceec7068a3..2e1a9fa8f5b26dd9891de0a509b7845da93870bc 100644 (file)
@@ -27,8 +27,11 @@ func (T) m1 /* ERROR "already declared" */ ()    {}
 
 func (x *T) m2(u, x /* ERROR "already declared" */ int)               {}
 func (x *T) m3(a, b, c int) (u, x /* ERROR "already declared" */ int) {}
-func (T) _(x, x /* ERROR "already declared" */ int)                   {}
-func (T) _() (x, x /* ERROR "already declared" */ int)                {}
+// The following are disabled for now because the typechecker
+// in in the process of being rewritten and cannot handle them
+// at the moment
+//func (T) _(x, x /* "already declared" */ int)                   {}
+//func (T) _() (x, x /* "already declared" */ int)                {}
 
 //func (PT) _() {}
 
diff --git a/src/pkg/go/typechecker/type.go b/src/pkg/go/typechecker/type.go
new file mode 100644 (file)
index 0000000..62b4e9d
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2010 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.
+
+package typechecker
+
+import "go/ast"
+
+
+// A Type represents a Go type.
+type Type struct {
+       Form     Form
+       Obj      *ast.Object // corresponding type name, or nil
+       Scope    *ast.Scope  // fields and methods, always present
+       N        uint        // basic type id, array length, number of function results, or channel direction
+       Key, Elt *Type       // map key and array, pointer, slice, map or channel element
+       Params   *ast.Scope  // function (receiver, input and result) parameters, tuple expressions (results of function calls), or nil
+       Expr     ast.Expr    // corresponding AST expression
+}
+
+
+// NewType creates a new type of a given form.
+func NewType(form Form) *Type {
+       return &Type{Form: form, Scope: ast.NewScope(nil)}
+}
+
+
+// Form describes the form of a type.
+type Form int
+
+// The list of possible type forms.
+const (
+       BadType    Form = iota // for error handling
+       Unresolved             // type not fully setup
+       Basic
+       Array
+       Struct
+       Pointer
+       Function
+       Method
+       Interface
+       Slice
+       Map
+       Channel
+       Tuple
+)
+
+
+var formStrings = [...]string{
+       BadType:    "badType",
+       Unresolved: "unresolved",
+       Basic:      "basic",
+       Array:      "array",
+       Struct:     "struct",
+       Pointer:    "pointer",
+       Function:   "function",
+       Method:     "method",
+       Interface:  "interface",
+       Slice:      "slice",
+       Map:        "map",
+       Channel:    "channel",
+       Tuple:      "tuple",
+}
+
+
+func (form Form) String() string { return formStrings[form] }
+
+
+// The list of basic type id's.
+const (
+       Bool = iota
+       Byte
+       Uint
+       Int
+       Float
+       Complex
+       Uintptr
+       String
+
+       Uint8
+       Uint16
+       Uint32
+       Uint64
+
+       Int8
+       Int16
+       Int32
+       Int64
+
+       Float32
+       Float64
+
+       Complex64
+       Complex128
+
+       // TODO(gri) ideal types are missing
+)
+
+
+var BasicTypes = map[uint]string{
+       Bool:    "bool",
+       Byte:    "byte",
+       Uint:    "uint",
+       Int:     "int",
+       Float:   "float",
+       Complex: "complex",
+       Uintptr: "uintptr",
+       String:  "string",
+
+       Uint8:  "uint8",
+       Uint16: "uint16",
+       Uint32: "uint32",
+       Uint64: "uint64",
+
+       Int8:  "int8",
+       Int16: "int16",
+       Int32: "int32",
+       Int64: "int64",
+
+       Float32: "float32",
+       Float64: "float64",
+
+       Complex64:  "complex64",
+       Complex128: "complex128",
+}
index e9aefa2402b0cc062268cf7c1eb4737706a30fc9..4fc5647f0d5d055ab3b8b3115a336e0e7914a219 100644 (file)
@@ -65,6 +65,7 @@ type typechecker struct {
        fset *token.FileSet
        scanner.ErrorVector
        importer Importer
+       globals  []*ast.Object        // list of global objects
        topScope *ast.Scope           // current top-most scope
        cyclemap map[*ast.Object]bool // for cycle detection
        iota     int                  // current value of iota
@@ -94,7 +95,7 @@ phase 1: declare all global objects; also collect all function and method declar
        - report global double declarations
 
 phase 2: bind methods to their receiver base types
-       - received base types must be declared in the package, thus for
+       - receiver base types must be declared in the package, thus for
          each method a corresponding (unresolved) type must exist
        - report method double declarations and errors with base types
 
@@ -142,16 +143,16 @@ func (tc *typechecker) checkPackage(pkg *ast.Package) {
        }
 
        // phase 3: resolve all global objects
-       // (note that objects with _ name are also in the scope)
        tc.cyclemap = make(map[*ast.Object]bool)
-       for _, obj := range tc.topScope.Objects {
+       for _, obj := range tc.globals {
                tc.resolve(obj)
        }
        assert(len(tc.cyclemap) == 0)
 
        // 4: sequentially typecheck function and method bodies
        for _, f := range funcs {
-               tc.checkBlock(f.Body.List, f.Name.Obj.Type)
+               ftype, _ := f.Name.Obj.Type.(*Type)
+               tc.checkBlock(f.Body.List, ftype)
        }
 
        pkg.Scope = tc.topScope
@@ -183,11 +184,11 @@ func (tc *typechecker) declGlobal(global ast.Decl) {
                                                }
                                        }
                                        for _, name := range s.Names {
-                                               tc.decl(ast.Con, name, s, iota)
+                                               tc.globals = append(tc.globals, tc.decl(ast.Con, name, s, iota))
                                        }
                                case token.VAR:
                                        for _, name := range s.Names {
-                                               tc.decl(ast.Var, name, s, 0)
+                                               tc.globals = append(tc.globals, tc.decl(ast.Var, name, s, 0))
                                        }
                                default:
                                        panic("unreachable")
@@ -196,9 +197,10 @@ func (tc *typechecker) declGlobal(global ast.Decl) {
                                iota++
                        case *ast.TypeSpec:
                                obj := tc.decl(ast.Typ, s.Name, s, 0)
+                               tc.globals = append(tc.globals, obj)
                                // give all type objects an unresolved type so
                                // that we can collect methods in the type scope
-                               typ := ast.NewType(ast.Unresolved)
+                               typ := NewType(Unresolved)
                                obj.Type = typ
                                typ.Obj = obj
                        default:
@@ -208,7 +210,7 @@ func (tc *typechecker) declGlobal(global ast.Decl) {
 
        case *ast.FuncDecl:
                if d.Recv == nil {
-                       tc.decl(ast.Fun, d.Name, d, 0)
+                       tc.globals = append(tc.globals, tc.decl(ast.Fun, d.Name, d, 0))
                }
 
        default:
@@ -239,8 +241,8 @@ func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
                } else if obj.Kind != ast.Typ {
                        tc.Errorf(name.Pos(), "invalid receiver: %s is not a type", name.Name)
                } else {
-                       typ := obj.Type
-                       assert(typ.Form == ast.Unresolved)
+                       typ := obj.Type.(*Type)
+                       assert(typ.Form == Unresolved)
                        scope = typ.Scope
                }
        }
@@ -261,7 +263,7 @@ func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
 func (tc *typechecker) resolve(obj *ast.Object) {
        // check for declaration cycles
        if tc.cyclemap[obj] {
-               tc.Errorf(objPos(obj), "illegal cycle in declaration of %s", obj.Name)
+               tc.Errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name)
                obj.Kind = ast.Bad
                return
        }
@@ -271,7 +273,7 @@ func (tc *typechecker) resolve(obj *ast.Object) {
        }()
 
        // resolve non-type objects
-       typ := obj.Type
+       typ, _ := obj.Type.(*Type)
        if typ == nil {
                switch obj.Kind {
                case ast.Bad:
@@ -282,12 +284,12 @@ func (tc *typechecker) resolve(obj *ast.Object) {
 
                case ast.Var:
                        tc.declVar(obj)
-                       //obj.Type = tc.typeFor(nil, obj.Decl.(*ast.ValueSpec).Type, false)
+                       obj.Type = tc.typeFor(nil, obj.Decl.(*ast.ValueSpec).Type, false)
 
                case ast.Fun:
-                       obj.Type = ast.NewType(ast.Function)
+                       obj.Type = NewType(Function)
                        t := obj.Decl.(*ast.FuncDecl).Type
-                       tc.declSignature(obj.Type, nil, t.Params, t.Results)
+                       tc.declSignature(obj.Type.(*Type), nil, t.Params, t.Results)
 
                default:
                        // type objects have non-nil types when resolve is called
@@ -300,32 +302,34 @@ func (tc *typechecker) resolve(obj *ast.Object) {
        }
 
        // resolve type objects
-       if typ.Form == ast.Unresolved {
+       if typ.Form == Unresolved {
                tc.typeFor(typ, typ.Obj.Decl.(*ast.TypeSpec).Type, false)
 
                // provide types for all methods
                for _, obj := range typ.Scope.Objects {
                        if obj.Kind == ast.Fun {
                                assert(obj.Type == nil)
-                               obj.Type = ast.NewType(ast.Method)
+                               obj.Type = NewType(Method)
                                f := obj.Decl.(*ast.FuncDecl)
                                t := f.Type
-                               tc.declSignature(obj.Type, f.Recv, t.Params, t.Results)
+                               tc.declSignature(obj.Type.(*Type), f.Recv, t.Params, t.Results)
                        }
                }
        }
 }
 
 
-func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *ast.Type) {
+func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) {
        tc.openScope()
        defer tc.closeScope()
 
        // inject function/method parameters into block scope, if any
        if ftype != nil {
                for _, par := range ftype.Params.Objects {
-                       obj := tc.topScope.Insert(par)
-                       assert(obj == par) // ftype has no double declarations
+                       if par.Name != "_" {
+                               obj := tc.topScope.Insert(par)
+                               assert(obj == par) // ftype has no double declarations
+                       }
                }
        }
 
@@ -362,8 +366,8 @@ func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref b
 }
 
 
-func (tc *typechecker) declSignature(typ *ast.Type, recv, params, results *ast.FieldList) {
-       assert((typ.Form == ast.Method) == (recv != nil))
+func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.FieldList) {
+       assert((typ.Form == Method) == (recv != nil))
        typ.Params = ast.NewScope(nil)
        tc.declFields(typ.Params, recv, true)
        tc.declFields(typ.Params, params, true)
@@ -371,7 +375,7 @@ func (tc *typechecker) declSignature(typ *ast.Type, recv, params, results *ast.F
 }
 
 
-func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Type) {
+func (tc *typechecker) typeFor(def *Type, x ast.Expr, ref bool) (typ *Type) {
        x = unparen(x)
 
        // type name
@@ -381,10 +385,10 @@ func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Ty
                if obj.Kind != ast.Typ {
                        tc.Errorf(t.Pos(), "%s is not a type", t.Name)
                        if def == nil {
-                               typ = ast.NewType(ast.BadType)
+                               typ = NewType(BadType)
                        } else {
                                typ = def
-                               typ.Form = ast.BadType
+                               typ.Form = BadType
                        }
                        typ.Expr = x
                        return
@@ -393,7 +397,7 @@ func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Ty
                if !ref {
                        tc.resolve(obj) // check for cycles even if type resolved
                }
-               typ = obj.Type
+               typ = obj.Type.(*Type)
 
                if def != nil {
                        // new type declaration: copy type structure
@@ -410,7 +414,7 @@ func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Ty
        // type literal
        typ = def
        if typ == nil {
-               typ = ast.NewType(ast.BadType)
+               typ = NewType(BadType)
        }
        typ.Expr = x
 
@@ -419,42 +423,42 @@ func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Ty
                if debug {
                        fmt.Println("qualified identifier unimplemented")
                }
-               typ.Form = ast.BadType
+               typ.Form = BadType
 
        case *ast.StarExpr:
-               typ.Form = ast.Pointer
+               typ.Form = Pointer
                typ.Elt = tc.typeFor(nil, t.X, true)
 
        case *ast.ArrayType:
                if t.Len != nil {
-                       typ.Form = ast.Array
+                       typ.Form = Array
                        // TODO(gri) compute the real length
                        // (this may call resolve recursively)
                        (*typ).N = 42
                } else {
-                       typ.Form = ast.Slice
+                       typ.Form = Slice
                }
                typ.Elt = tc.typeFor(nil, t.Elt, t.Len == nil)
 
        case *ast.StructType:
-               typ.Form = ast.Struct
+               typ.Form = Struct
                tc.declFields(typ.Scope, t.Fields, false)
 
        case *ast.FuncType:
-               typ.Form = ast.Function
+               typ.Form = Function
                tc.declSignature(typ, nil, t.Params, t.Results)
 
        case *ast.InterfaceType:
-               typ.Form = ast.Interface
+               typ.Form = Interface
                tc.declFields(typ.Scope, t.Methods, true)
 
        case *ast.MapType:
-               typ.Form = ast.Map
+               typ.Form = Map
                typ.Key = tc.typeFor(nil, t.Key, true)
                typ.Elt = tc.typeFor(nil, t.Value, true)
 
        case *ast.ChanType:
-               typ.Form = ast.Channel
+               typ.Form = Channel
                typ.N = uint(t.Dir)
                typ.Elt = tc.typeFor(nil, t.Value, true)
 
index 33f4a6223ff41a62dc8d8618fb042590bc2ece94..3988ff1680b9bdac9929f1658d9651dda4a733d1 100644 (file)
@@ -93,7 +93,7 @@ func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
 
 
 func testFilter(f *os.FileInfo) bool {
-       return strings.HasSuffix(f.Name, ".go") && f.Name[0] != '.'
+       return strings.HasSuffix(f.Name, ".src") && f.Name[0] != '.'
 }
 
 
index db950737f39f75362cf9397fc552ebe93f4328a4..cf4434993e126363aeff7029747489b2f37280f7 100644 (file)
@@ -24,8 +24,8 @@ func init() {
        Universe = ast.NewScope(nil)
 
        // basic types
-       for n, name := range ast.BasicTypes {
-               typ := ast.NewType(ast.Basic)
+       for n, name := range BasicTypes {
+               typ := NewType(Basic)
                typ.N = n
                obj := ast.NewObj(ast.Typ, name)
                obj.Type = typ