1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // This package implements typechecking of a Go AST.
6 // The result of the typecheck is an augmented AST
7 // with object and type information for each identifier.
20 // TODO(gri) don't report errors for objects/types that are marked as bad.
23 const debug
= true // set for debugging output
26 // An importer takes an import path and returns the data describing the
27 // respective package's exported interface. The data format is TBD.
29 type Importer
func(path
string) ([]byte, os
.Error
)
32 // CheckPackage typechecks a package and augments the AST by setting
33 // *ast.Object, *ast.Type, and *ast.Scope fields accordingly. If an
34 // importer is provided, it is used to handle imports, otherwise they
35 // are ignored (likely leading to typechecking errors).
37 // If errors are reported, the AST may be incompletely augmented (fields
38 // may be nil) or contain incomplete object, type, or scope information.
40 func CheckPackage(pkg
*ast
.Package
, importer Importer
) os
.Error
{
42 tc
.importer
= importer
44 return tc
.GetError(scanner
.Sorted
)
48 // CheckFile typechecks a single file, but otherwise behaves like
49 // CheckPackage. If the complete package consists of more than just
50 // one file, the file may not typecheck without errors.
52 func CheckFile(file
*ast
.File
, importer Importer
) os
.Error
{
53 // create a single-file dummy package
54 pkg
:= &ast
.Package
{file
.Name
.Name
, nil, map[string]*ast
.File
{file
.Name
.NamePos
.Filename
: file
}}
55 return CheckPackage(pkg
, importer
)
59 // ----------------------------------------------------------------------------
62 type typechecker
struct {
65 topScope
*ast
.Scope
// current top-most scope
66 cyclemap
map[*ast
.Object
]bool // for cycle detection
67 iota int // current value of iota
71 func (tc
*typechecker
) Errorf(pos token
.Position
, format
string, args
...interface{}) {
72 tc
.Error(pos
, fmt
.Sprintf(format
, args
...))
76 func assert(pred
bool) {
78 panic("internal error")
84 Typechecking is done in several phases:
86 phase 1: declare all global objects; also collect all function and method declarations
87 - all objects have kind, name, decl fields; the decl field permits
88 quick lookup of an object's declaration
89 - constant objects have an iota value
90 - type objects have unresolved types with empty scopes, all others have nil types
91 - report global double declarations
93 phase 2: bind methods to their receiver base types
94 - received base types must be declared in the package, thus for
95 each method a corresponding (unresolved) type must exist
96 - report method double declarations and errors with base types
98 phase 3: resolve all global objects
99 - sequentially iterate through all objects in the global scope
100 - resolve types for all unresolved types and assign types to
102 - assign types to all other objects, possibly by evaluating
103 constant and initializer expressions
104 - resolution may recurse; a cyclemap is used to detect cycles
105 - report global typing errors
107 phase 4: sequentially typecheck function and method bodies
108 - all global objects are declared and have types and values;
109 all methods have types
110 - sequentially process statements in each body; any object
111 referred to must be fully defined at this point
112 - report local typing errors
115 func (tc
*typechecker
) checkPackage(pkg
*ast
.Package
) {
116 // setup package scope
117 tc
.topScope
= Universe
119 defer tc
.closeScope()
121 // TODO(gri) there's no file scope at the moment since we ignore imports
123 // phase 1: declare all global objects; also collect all function and method declarations
124 var funcs
[]*ast
.FuncDecl
125 for _
, file
:= range pkg
.Files
{
126 for _
, decl
:= range file
.Decls
{
128 if f
, isFunc
:= decl
.(*ast
.FuncDecl
); isFunc
{
129 funcs
= append(funcs
, f
)
134 // phase 2: bind methods to their receiver base types
135 for _
, m
:= range funcs
{
141 // phase 3: resolve all global objects
142 // (note that objects with _ name are also in the scope)
143 tc
.cyclemap
= make(map[*ast
.Object
]bool)
144 for _
, obj
:= range tc
.topScope
.Objects
{
147 assert(len(tc
.cyclemap
) == 0)
149 // 4: sequentially typecheck function and method bodies
150 for _
, f
:= range funcs
{
151 tc
.checkBlock(f
.Body
.List
, f
.Name
.Obj
.Type
)
154 pkg
.Scope
= tc
.topScope
158 func (tc
*typechecker
) declGlobal(global ast
.Decl
) {
159 switch d
:= global
.(type) {
165 var prev
*ast
.ValueSpec
166 for _
, spec
:= range d
.Specs
{
167 switch s
:= spec
.(type) {
168 case *ast
.ImportSpec
:
169 // TODO(gri) imports go into file scope
174 // create a new spec with type and values from the previous one
176 s
= &ast
.ValueSpec
{s
.Doc
, s
.Names
, prev
.Type
, prev
.Values
, s
.Comment
}
178 // TODO(gri) this should probably go into the const decl code
179 tc
.Errorf(s
.Pos(), "missing initializer for const %s", s
.Names
[0].Name
)
182 for _
, name
:= range s
.Names
{
183 tc
.decl(ast
.Con
, name
, s
, iota)
186 for _
, name
:= range s
.Names
{
187 tc
.decl(ast
.Var
, name
, s
, 0)
195 obj
:= tc
.decl(ast
.Typ
, s
.Name
, s
, 0)
196 // give all type objects an unresolved type so
197 // that we can collect methods in the type scope
198 typ
:= ast
.NewType(ast
.Unresolved
)
208 tc
.decl(ast
.Fun
, d
.Name
, d
, 0)
217 // If x is of the form *T, deref returns T, otherwise it returns x.
218 func deref(x ast
.Expr
) ast
.Expr
{
219 if p
, isPtr
:= x
.(*ast
.StarExpr
); isPtr
{
226 func (tc
*typechecker
) bindMethod(method
*ast
.FuncDecl
) {
227 // a method is declared in the receiver base type's scope
229 base
:= deref(method
.Recv
.List
[0].Type
)
230 if name
, isIdent
:= base
.(*ast
.Ident
); isIdent
{
231 // if base is not an *ast.Ident, we had a syntax
232 // error and the parser reported an error already
233 obj
:= tc
.topScope
.Lookup(name
.Name
)
235 tc
.Errorf(name
.Pos(), "invalid receiver: %s is not declared in this package", name
.Name
)
236 } else if obj
.Kind
!= ast
.Typ
{
237 tc
.Errorf(name
.Pos(), "invalid receiver: %s is not a type", name
.Name
)
240 assert(typ
.Form
== ast
.Unresolved
)
245 // no receiver type found; use a dummy scope
246 // (we still want to type-check the method
247 // body, so make sure there is a name object
249 // TODO(gri) should we record the scope so
250 // that we don't lose the receiver for type-
251 // checking of the method body?
252 scope
= ast
.NewScope(nil)
254 tc
.declInScope(scope
, ast
.Fun
, method
.Name
, method
, 0)
258 func (tc
*typechecker
) resolve(obj
*ast
.Object
) {
259 // check for declaration cycles
260 if tc
.cyclemap
[obj
] {
261 tc
.Errorf(objPos(obj
), "illegal cycle in declaration of %s", obj
.Name
)
265 tc
.cyclemap
[obj
] = true
267 tc
.cyclemap
[obj
] = false, false
270 // resolve non-type objects
282 //obj.Type = tc.typeFor(nil, obj.Decl.(*ast.ValueSpec).Type, false)
285 obj
.Type
= ast
.NewType(ast
.Function
)
286 t
:= obj
.Decl
.(*ast
.FuncDecl
).Type
287 tc
.declSignature(obj
.Type
, nil, t
.Params
, t
.Results
)
290 // type objects have non-nil types when resolve is called
292 fmt
.Printf("kind = %s\n", obj
.Kind
)
299 // resolve type objects
300 if typ
.Form
== ast
.Unresolved
{
301 tc
.typeFor(typ
, typ
.Obj
.Decl
.(*ast
.TypeSpec
).Type
, false)
303 // provide types for all methods
304 for _
, obj
:= range typ
.Scope
.Objects
{
305 if obj
.Kind
== ast
.Fun
{
306 assert(obj
.Type
== nil)
307 obj
.Type
= ast
.NewType(ast
.Method
)
308 f
:= obj
.Decl
.(*ast
.FuncDecl
)
310 tc
.declSignature(obj
.Type
, f
.Recv
, t
.Params
, t
.Results
)
317 func (tc
*typechecker
) checkBlock(body
[]ast
.Stmt
, ftype
*ast
.Type
) {
319 defer tc
.closeScope()
321 // inject function/method parameters into block scope, if any
323 for _
, par
:= range ftype
.Params
.Objects
{
324 obj
:= tc
.topScope
.Insert(par
)
325 assert(obj
== par
) // ftype has no double declarations
329 for _
, stmt
:= range body
{
335 // ----------------------------------------------------------------------------
338 // unparen removes parentheses around x, if any.
339 func unparen(x ast
.Expr
) ast
.Expr
{
340 if ux
, hasParens
:= x
.(*ast
.ParenExpr
); hasParens
{
347 func (tc
*typechecker
) declFields(scope
*ast
.Scope
, fields
*ast
.FieldList
, ref
bool) (n
uint) {
349 for _
, f
:= range fields
.List
{
350 typ
:= tc
.typeFor(nil, f
.Type
, ref
)
351 for _
, name
:= range f
.Names
{
352 fld
:= tc
.declInScope(scope
, ast
.Var
, name
, f
, 0)
362 func (tc
*typechecker
) declSignature(typ
*ast
.Type
, recv
, params
, results
*ast
.FieldList
) {
363 assert((typ
.Form
== ast
.Method
) == (recv
!= nil))
364 typ
.Params
= ast
.NewScope(nil)
365 tc
.declFields(typ
.Params
, recv
, true)
366 tc
.declFields(typ
.Params
, params
, true)
367 typ
.N
= tc
.declFields(typ
.Params
, results
, true)
371 func (tc
*typechecker
) typeFor(def
*ast
.Type
, x ast
.Expr
, ref
bool) (typ
*ast
.Type
) {
375 if t
, isIdent
:= x
.(*ast
.Ident
); isIdent
{
378 if obj
.Kind
!= ast
.Typ
{
379 tc
.Errorf(t
.Pos(), "%s is not a type", t
.Name
)
381 typ
= ast
.NewType(ast
.BadType
)
384 typ
.Form
= ast
.BadType
391 tc
.resolve(obj
) // check for cycles even if type resolved
396 // new type declaration: copy type structure
399 def
.Key
, def
.Elt
= typ
.Key
, typ
.Elt
400 def
.Params
= typ
.Params
410 typ
= ast
.NewType(ast
.BadType
)
414 switch t
:= x
.(type) {
415 case *ast
.SelectorExpr
:
417 fmt
.Println("qualified identifier unimplemented")
419 typ
.Form
= ast
.BadType
422 typ
.Form
= ast
.Pointer
423 typ
.Elt
= tc
.typeFor(nil, t
.X
, true)
428 // TODO(gri) compute the real length
429 // (this may call resolve recursively)
434 typ
.Elt
= tc
.typeFor(nil, t
.Elt
, t
.Len
== nil)
436 case *ast
.StructType
:
437 typ
.Form
= ast
.Struct
438 tc
.declFields(typ
.Scope
, t
.Fields
, false)
441 typ
.Form
= ast
.Function
442 tc
.declSignature(typ
, nil, t
.Params
, t
.Results
)
444 case *ast
.InterfaceType
:
445 typ
.Form
= ast
.Interface
446 tc
.declFields(typ
.Scope
, t
.Methods
, true)
450 typ
.Key
= tc
.typeFor(nil, t
.Key
, true)
451 typ
.Elt
= tc
.typeFor(nil, t
.Value
, true)
454 typ
.Form
= ast
.Channel
456 typ
.Elt
= tc
.typeFor(nil, t
.Value
, true)
460 fmt
.Printf("x is %T\n", x
)
469 // ----------------------------------------------------------------------------
470 // TODO(gri) implement these place holders
472 func (tc
*typechecker
) declConst(*ast
.Object
) {
476 func (tc
*typechecker
) declVar(*ast
.Object
) {
480 func (tc
*typechecker
) checkStmt(ast
.Stmt
) {