Commit 021b040a authored by Robert Griesemer's avatar Robert Griesemer

go/ast, go/parser: populate identifier scopes at parse time

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
parent 4b4a1ea8
...@@ -27,7 +27,7 @@ var stmtTests = []test{ ...@@ -27,7 +27,7 @@ var stmtTests = []test{
CErr("i, u := 1, 2", atLeastOneDecl), CErr("i, u := 1, 2", atLeastOneDecl),
Val2("i, x := 2, f", "i", 2, "x", 1.0), Val2("i, x := 2, f", "i", 2, "x", 1.0),
// Various errors // Various errors
CErr("1 := 2", "left side of := must be a name"), CErr("1 := 2", "expected identifier"),
CErr("c, a := 1, 1", "cannot assign"), CErr("c, a := 1, 1", "cannot assign"),
// Unpacking // Unpacking
Val2("x, y := oneTwo()", "x", 1, "y", 2), Val2("x, y := oneTwo()", "x", 1, "y", 2),
......
...@@ -937,11 +937,13 @@ func (d *FuncDecl) declNode() {} ...@@ -937,11 +937,13 @@ func (d *FuncDecl) declNode() {}
// via Doc and Comment fields. // via Doc and Comment fields.
// //
type File struct { type File struct {
Doc *CommentGroup // associated documentation; or nil Doc *CommentGroup // associated documentation; or nil
Package token.Pos // position of "package" keyword Package token.Pos // position of "package" keyword
Name *Ident // package name Name *Ident // package name
Decls []Decl // top-level declarations; or nil Decls []Decl // top-level declarations; or nil
Comments []*CommentGroup // list of all comments in the source file 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 { ...@@ -959,7 +961,7 @@ func (f *File) End() token.Pos {
// //
type Package struct { type Package struct {
Name string // package name Name string // package name
Scope *Scope // package scope; or nil Scope *Scope // package scope
Files map[string]*File // Go source files by filename Files map[string]*File // Go source files by filename
} }
......
...@@ -425,5 +425,6 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *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}
} }
...@@ -2,31 +2,31 @@ ...@@ -2,31 +2,31 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// This file implements scopes, the objects they contain, // This file implements scopes and the objects they contain.
// and object types.
package ast package ast
import (
"bytes"
"fmt"
"go/token"
)
// A Scope maintains the set of named language entities declared // A Scope maintains the set of named language entities declared
// in the scope and a link to the immediately surrounding (outer) // in the scope and a link to the immediately surrounding (outer)
// scope. // scope.
// //
type Scope struct { type Scope struct {
Outer *Scope Outer *Scope
Objects []*Object // in declaration order Objects map[string]*Object
// 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.
} }
// NewScope creates a new scope nested in the outer scope. // NewScope creates a new scope nested in the outer scope.
func NewScope(outer *Scope) *Scope { func NewScope(outer *Scope) *Scope {
const n = 4 // initial scope capacity, must be > 0 const n = 4 // initial scope capacity
return &Scope{outer, make([]*Object, 0, n)} return &Scope{outer, make(map[string]*Object, n)}
} }
...@@ -34,73 +34,108 @@ func NewScope(outer *Scope) *Scope { ...@@ -34,73 +34,108 @@ func NewScope(outer *Scope) *Scope {
// found in scope s, otherwise it returns nil. Outer scopes // found in scope s, otherwise it returns nil. Outer scopes
// are ignored. // 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 { func (s *Scope) Lookup(name string) *Object {
if name != "_" { return s.Objects[name]
for _, obj := range s.Objects {
if obj.Name == name {
return obj
}
}
}
return nil
} }
// Insert attempts to insert a named object into the scope s. // Insert attempts to insert a named object into the scope s.
// If the scope does not contain an object with that name yet // If the scope does not contain an object with that name yet,
// or if the object is named "_", Insert inserts the object // Insert inserts the object and returns it. Otherwise, Insert
// and returns it. Otherwise, Insert leaves the scope unchanged // leaves the scope unchanged and returns the object found in
// and returns the object found in the scope instead. // the scope instead.
// //
func (s *Scope) Insert(obj *Object) *Object { func (s *Scope) Insert(obj *Object) (alt *Object) {
alt := s.Lookup(obj.Name) if alt = s.Objects[obj.Name]; alt == nil {
if alt == nil { s.Objects[obj.Name] = obj
s.append(obj)
alt = obj alt = obj
} }
return alt return
} }
func (s *Scope) append(obj *Object) { // Debugging support
s.Objects = append(s.Objects, obj) 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 // Objects
// An Object describes a language entity such as a package, // An Object describes a named language entity such as a package,
// constant, type, variable, or function (incl. methods). // constant, type, variable, function (incl. methods), or label.
// //
type Object struct { type Object struct {
Kind Kind Kind ObjKind
Name string // declared name Name string // declared name
Type *Type Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
Decl interface{} // corresponding Field, XxxSpec or FuncDecl Type interface{} // place holder for type information; may be nil
N int // value of iota for this declaration
} }
// NewObj creates a new object of a given kind and name. // 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} return &Object{Kind: kind, Name: name}
} }
// Kind describes what an object represents. // Pos computes the source position of the declaration of an object name.
type Kind int // 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. // The list of possible Object kinds.
const ( const (
Bad Kind = iota // for error handling Bad ObjKind = iota // for error handling
Pkg // package Pkg // package
Con // constant Con // constant
Typ // type Typ // type
Var // variable Var // variable
Fun // function or method Fun // function or method
Lbl // label
) )
...@@ -111,132 +146,8 @@ var objKindStrings = [...]string{ ...@@ -111,132 +146,8 @@ var objKindStrings = [...]string{
Typ: "type", Typ: "type",
Var: "var", Var: "var",
Fun: "func", Fun: "func",
Lbl: "label",
} }
func (kind Kind) String() string { return objKindStrings[kind] } func (kind ObjKind) 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",
}
This diff is collapsed.
...@@ -73,7 +73,7 @@ var validFiles = []string{ ...@@ -73,7 +73,7 @@ var validFiles = []string{
func TestParse3(t *testing.T) { func TestParse3(t *testing.T) {
for _, filename := range validFiles { for _, filename := range validFiles {
_, err := ParseFile(fset, filename, nil, 0) _, err := ParseFile(fset, filename, nil, DeclarationErrors)
if err != nil { if err != nil {
t.Errorf("ParseFile(%s): %v", filename, err) t.Errorf("ParseFile(%s): %v", filename, err)
} }
......
...@@ -7,6 +7,7 @@ include ../../../Make.inc ...@@ -7,6 +7,7 @@ include ../../../Make.inc
TARG=go/typechecker TARG=go/typechecker
GOFILES=\ GOFILES=\
scope.go\ scope.go\
type.go\
typechecker.go\ typechecker.go\
universe.go\ universe.go\
......
...@@ -2,15 +2,15 @@ ...@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // 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 package typechecker
import ( import "go/ast"
"fmt"
"go/ast"
"go/token"
)
func (tc *typechecker) openScope() *ast.Scope { func (tc *typechecker) openScope() *ast.Scope {
...@@ -24,52 +24,25 @@ func (tc *typechecker) closeScope() { ...@@ -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. // 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 // 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. // 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.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
obj := ast.NewObj(kind, name.Name) obj := ast.NewObj(kind, name.Name)
obj.Decl = decl obj.Decl = decl
obj.N = n //obj.N = n
name.Obj = obj name.Obj = obj
if alt := scope.Insert(obj); alt != obj { if name.Name != "_" {
tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, objPos(alt)) 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 return obj
} }
// decl is the same as declInScope(tc.topScope, ...) // 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) return tc.declInScope(tc.topScope, kind, name, decl, n)
} }
...@@ -91,7 +64,7 @@ func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) { ...@@ -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. // 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. // 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. // TODO(gri) This is simplistic at the moment and ignores anonymous fields.
obj = typ.Scope.Lookup(name.Name) obj = typ.Scope.Lookup(name.Name)
if obj == nil { if obj == nil {
...@@ -100,20 +73,3 @@ func (tc *typechecker) findField(typ *ast.Type, name *ast.Ident) (obj *ast.Objec ...@@ -100,20 +73,3 @@ func (tc *typechecker) findField(typ *ast.Type, name *ast.Ident) (obj *ast.Objec
} }
return 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")
}
...@@ -27,8 +27,11 @@ func (T) m1 /* ERROR "already declared" */ () {} ...@@ -27,8 +27,11 @@ func (T) m1 /* ERROR "already declared" */ () {}
func (x *T) m2(u, x /* ERROR "already declared" */ int) {} 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 (x *T) m3(a, b, c int) (u, x /* ERROR "already declared" */ int) {}
func (T) _(x, x /* ERROR "already declared" */ int) {} // The following are disabled for now because the typechecker
func (T) _() (x, x /* ERROR "already declared" */ int) {} // 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) _() {} //func (PT) _() {}
......
// 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",
}
...@@ -65,6 +65,7 @@ type typechecker struct { ...@@ -65,6 +65,7 @@ type typechecker struct {
fset *token.FileSet fset *token.FileSet
scanner.ErrorVector scanner.ErrorVector
importer Importer importer Importer
globals []*ast.Object // list of global objects
topScope *ast.Scope // current top-most scope topScope *ast.Scope // current top-most scope
cyclemap map[*ast.Object]bool // for cycle detection cyclemap map[*ast.Object]bool // for cycle detection
iota int // current value of iota iota int // current value of iota
...@@ -94,7 +95,7 @@ phase 1: declare all global objects; also collect all function and method declar ...@@ -94,7 +95,7 @@ phase 1: declare all global objects; also collect all function and method declar
- report global double declarations - report global double declarations
phase 2: bind methods to their receiver base types 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 each method a corresponding (unresolved) type must exist
- report method double declarations and errors with base types - report method double declarations and errors with base types
...@@ -142,16 +143,16 @@ func (tc *typechecker) checkPackage(pkg *ast.Package) { ...@@ -142,16 +143,16 @@ func (tc *typechecker) checkPackage(pkg *ast.Package) {
} }
// phase 3: resolve all global objects // phase 3: resolve all global objects
// (note that objects with _ name are also in the scope)
tc.cyclemap = make(map[*ast.Object]bool) tc.cyclemap = make(map[*ast.Object]bool)
for _, obj := range tc.topScope.Objects { for _, obj := range tc.globals {
tc.resolve(obj) tc.resolve(obj)
} }
assert(len(tc.cyclemap) == 0) assert(len(tc.cyclemap) == 0)
// 4: sequentially typecheck function and method bodies // 4: sequentially typecheck function and method bodies
for _, f := range funcs { 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 pkg.Scope = tc.topScope
...@@ -183,11 +184,11 @@ func (tc *typechecker) declGlobal(global ast.Decl) { ...@@ -183,11 +184,11 @@ func (tc *typechecker) declGlobal(global ast.Decl) {
} }
} }
for _, name := range s.Names { 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: case token.VAR:
for _, name := range s.Names { 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: default:
panic("unreachable") panic("unreachable")
...@@ -196,9 +197,10 @@ func (tc *typechecker) declGlobal(global ast.Decl) { ...@@ -196,9 +197,10 @@ func (tc *typechecker) declGlobal(global ast.Decl) {
iota++ iota++
case *ast.TypeSpec: case *ast.TypeSpec:
obj := tc.decl(ast.Typ, s.Name, s, 0) obj := tc.decl(ast.Typ, s.Name, s, 0)
tc.globals = append(tc.globals, obj)
// give all type objects an unresolved type so // give all type objects an unresolved type so
// that we can collect methods in the type scope // that we can collect methods in the type scope
typ := ast.NewType(ast.Unresolved) typ := NewType(Unresolved)
obj.Type = typ obj.Type = typ
typ.Obj = obj typ.Obj = obj
default: default:
...@@ -208,7 +210,7 @@ func (tc *typechecker) declGlobal(global ast.Decl) { ...@@ -208,7 +210,7 @@ func (tc *typechecker) declGlobal(global ast.Decl) {
case *ast.FuncDecl: case *ast.FuncDecl:
if d.Recv == nil { 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: default:
...@@ -239,8 +241,8 @@ func (tc *typechecker) bindMethod(method *ast.FuncDecl) { ...@@ -239,8 +241,8 @@ func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
} else if obj.Kind != ast.Typ { } else if obj.Kind != ast.Typ {
tc.Errorf(name.Pos(), "invalid receiver: %s is not a type", name.Name) tc.Errorf(name.Pos(), "invalid receiver: %s is not a type", name.Name)
} else { } else {
typ := obj.Type typ := obj.Type.(*Type)
assert(typ.Form == ast.Unresolved) assert(typ.Form == Unresolved)
scope = typ.Scope scope = typ.Scope
} }
} }
...@@ -261,7 +263,7 @@ func (tc *typechecker) bindMethod(method *ast.FuncDecl) { ...@@ -261,7 +263,7 @@ func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
func (tc *typechecker) resolve(obj *ast.Object) { func (tc *typechecker) resolve(obj *ast.Object) {
// check for declaration cycles // check for declaration cycles
if tc.cyclemap[obj] { 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 obj.Kind = ast.Bad
return return
} }
...@@ -271,7 +273,7 @@ func (tc *typechecker) resolve(obj *ast.Object) { ...@@ -271,7 +273,7 @@ func (tc *typechecker) resolve(obj *ast.Object) {
}() }()
// resolve non-type objects // resolve non-type objects
typ := obj.Type typ, _ := obj.Type.(*Type)
if typ == nil { if typ == nil {
switch obj.Kind { switch obj.Kind {
case ast.Bad: case ast.Bad:
...@@ -282,12 +284,12 @@ func (tc *typechecker) resolve(obj *ast.Object) { ...@@ -282,12 +284,12 @@ func (tc *typechecker) resolve(obj *ast.Object) {
case ast.Var: case ast.Var:
tc.declVar(obj) 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: case ast.Fun:
obj.Type = ast.NewType(ast.Function) obj.Type = NewType(Function)
t := obj.Decl.(*ast.FuncDecl).Type 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: default:
// type objects have non-nil types when resolve is called // type objects have non-nil types when resolve is called
...@@ -300,32 +302,34 @@ func (tc *typechecker) resolve(obj *ast.Object) { ...@@ -300,32 +302,34 @@ func (tc *typechecker) resolve(obj *ast.Object) {
} }
// resolve type objects // resolve type objects
if typ.Form == ast.Unresolved { if typ.Form == Unresolved {
tc.typeFor(typ, typ.Obj.Decl.(*ast.TypeSpec).Type, false) tc.typeFor(typ, typ.Obj.Decl.(*ast.TypeSpec).Type, false)
// provide types for all methods // provide types for all methods
for _, obj := range typ.Scope.Objects { for _, obj := range typ.Scope.Objects {
if obj.Kind == ast.Fun { if obj.Kind == ast.Fun {
assert(obj.Type == nil) assert(obj.Type == nil)
obj.Type = ast.NewType(ast.Method) obj.Type = NewType(Method)
f := obj.Decl.(*ast.FuncDecl) f := obj.Decl.(*ast.FuncDecl)
t := f.Type 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() tc.openScope()
defer tc.closeScope() defer tc.closeScope()
// inject function/method parameters into block scope, if any // inject function/method parameters into block scope, if any
if ftype != nil { if ftype != nil {
for _, par := range ftype.Params.Objects { for _, par := range ftype.Params.Objects {
obj := tc.topScope.Insert(par) if par.Name != "_" {
assert(obj == par) // ftype has no double declarations 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 ...@@ -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) { func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.FieldList) {
assert((typ.Form == ast.Method) == (recv != nil)) assert((typ.Form == Method) == (recv != nil))
typ.Params = ast.NewScope(nil) typ.Params = ast.NewScope(nil)
tc.declFields(typ.Params, recv, true) tc.declFields(typ.Params, recv, true)
tc.declFields(typ.Params, params, true) tc.declFields(typ.Params, params, true)
...@@ -371,7 +375,7 @@ func (tc *typechecker) declSignature(typ *ast.Type, recv, params, results *ast.F ...@@ -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) x = unparen(x)
// type name // type name
...@@ -381,10 +385,10 @@ func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Ty ...@@ -381,10 +385,10 @@ func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Ty
if obj.Kind != ast.Typ { if obj.Kind != ast.Typ {
tc.Errorf(t.Pos(), "%s is not a type", t.Name) tc.Errorf(t.Pos(), "%s is not a type", t.Name)
if def == nil { if def == nil {
typ = ast.NewType(ast.BadType) typ = NewType(BadType)
} else { } else {
typ = def typ = def
typ.Form = ast.BadType typ.Form = BadType
} }
typ.Expr = x typ.Expr = x
return return
...@@ -393,7 +397,7 @@ func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Ty ...@@ -393,7 +397,7 @@ func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Ty
if !ref { if !ref {
tc.resolve(obj) // check for cycles even if type resolved tc.resolve(obj) // check for cycles even if type resolved
} }
typ = obj.Type typ = obj.Type.(*Type)
if def != nil { if def != nil {
// new type declaration: copy type structure // 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 ...@@ -410,7 +414,7 @@ func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Ty
// type literal // type literal
typ = def typ = def
if typ == nil { if typ == nil {
typ = ast.NewType(ast.BadType) typ = NewType(BadType)
} }
typ.Expr = x typ.Expr = x
...@@ -419,42 +423,42 @@ func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Ty ...@@ -419,42 +423,42 @@ func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Ty
if debug { if debug {
fmt.Println("qualified identifier unimplemented") fmt.Println("qualified identifier unimplemented")
} }
typ.Form = ast.BadType typ.Form = BadType
case *ast.StarExpr: case *ast.StarExpr:
typ.Form = ast.Pointer typ.Form = Pointer
typ.Elt = tc.typeFor(nil, t.X, true) typ.Elt = tc.typeFor(nil, t.X, true)
case *ast.ArrayType: case *ast.ArrayType:
if t.Len != nil { if t.Len != nil {
typ.Form = ast.Array typ.Form = Array
// TODO(gri) compute the real length // TODO(gri) compute the real length
// (this may call resolve recursively) // (this may call resolve recursively)
(*typ).N = 42 (*typ).N = 42
} else { } else {
typ.Form = ast.Slice typ.Form = Slice
} }
typ.Elt = tc.typeFor(nil, t.Elt, t.Len == nil) typ.Elt = tc.typeFor(nil, t.Elt, t.Len == nil)
case *ast.StructType: case *ast.StructType:
typ.Form = ast.Struct typ.Form = Struct
tc.declFields(typ.Scope, t.Fields, false) tc.declFields(typ.Scope, t.Fields, false)
case *ast.FuncType: case *ast.FuncType:
typ.Form = ast.Function typ.Form = Function
tc.declSignature(typ, nil, t.Params, t.Results) tc.declSignature(typ, nil, t.Params, t.Results)
case *ast.InterfaceType: case *ast.InterfaceType:
typ.Form = ast.Interface typ.Form = Interface
tc.declFields(typ.Scope, t.Methods, true) tc.declFields(typ.Scope, t.Methods, true)
case *ast.MapType: case *ast.MapType:
typ.Form = ast.Map typ.Form = Map
typ.Key = tc.typeFor(nil, t.Key, true) typ.Key = tc.typeFor(nil, t.Key, true)
typ.Elt = tc.typeFor(nil, t.Value, true) typ.Elt = tc.typeFor(nil, t.Value, true)
case *ast.ChanType: case *ast.ChanType:
typ.Form = ast.Channel typ.Form = Channel
typ.N = uint(t.Dir) typ.N = uint(t.Dir)
typ.Elt = tc.typeFor(nil, t.Value, true) typ.Elt = tc.typeFor(nil, t.Value, true)
......
...@@ -93,7 +93,7 @@ func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) { ...@@ -93,7 +93,7 @@ func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
func testFilter(f *os.FileInfo) bool { func testFilter(f *os.FileInfo) bool {
return strings.HasSuffix(f.Name, ".go") && f.Name[0] != '.' return strings.HasSuffix(f.Name, ".src") && f.Name[0] != '.'
} }
......
...@@ -24,8 +24,8 @@ func init() { ...@@ -24,8 +24,8 @@ func init() {
Universe = ast.NewScope(nil) Universe = ast.NewScope(nil)
// basic types // basic types
for n, name := range ast.BasicTypes { for n, name := range BasicTypes {
typ := ast.NewType(ast.Basic) typ := NewType(Basic)
typ.N = n typ.N = n
obj := ast.NewObj(ast.Typ, name) obj := ast.NewObj(ast.Typ, name)
obj.Type = typ obj.Type = typ
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment