Source file
src/go/types/check.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "go/ast"
11 "go/constant"
12 "go/token"
13 )
14
15
16 const (
17 debug = false
18 trace = false
19 )
20
21
22
23
24
25
26
27
28
29
30
31
32 const strict = false
33
34
35 type exprInfo struct {
36 isLhs bool
37 mode operandMode
38 typ *Basic
39 val constant.Value
40 }
41
42
43 type funcInfo struct {
44 name string
45 decl *declInfo
46 sig *Signature
47 body *ast.BlockStmt
48 }
49
50
51 type context struct {
52 decl *declInfo
53 scope *Scope
54 iota constant.Value
55 sig *Signature
56 hasLabel bool
57 hasCallOrRecv bool
58 }
59
60
61
62
63
64
65
66 type importKey struct {
67 path, dir string
68 }
69
70
71
72 type Checker struct {
73
74
75 conf *Config
76 fset *token.FileSet
77 pkg *Package
78 *Info
79 objMap map[Object]*declInfo
80 impMap map[importKey]*Package
81
82
83
84
85 files []*ast.File
86 unusedDotImports map[*Scope]map[*Package]token.Pos
87
88 firstErr error
89 methods map[string][]*Func
90 untyped map[ast.Expr]exprInfo
91 funcs []funcInfo
92 delayed []func()
93
94
95
96 context
97 pos token.Pos
98
99
100 indent int
101 }
102
103
104
105 func (check *Checker) addUnusedDotImport(scope *Scope, pkg *Package, pos token.Pos) {
106 mm := check.unusedDotImports
107 if mm == nil {
108 mm = make(map[*Scope]map[*Package]token.Pos)
109 check.unusedDotImports = mm
110 }
111 m := mm[scope]
112 if m == nil {
113 m = make(map[*Package]token.Pos)
114 mm[scope] = m
115 }
116 m[pkg] = pos
117 }
118
119
120 func (check *Checker) addDeclDep(to Object) {
121 from := check.decl
122 if from == nil {
123 return
124 }
125 if _, found := check.objMap[to]; !found {
126 return
127 }
128 from.addDep(to)
129 }
130
131 func (check *Checker) assocMethod(tname string, meth *Func) {
132 m := check.methods
133 if m == nil {
134 m = make(map[string][]*Func)
135 check.methods = m
136 }
137 m[tname] = append(m[tname], meth)
138 }
139
140 func (check *Checker) rememberUntyped(e ast.Expr, lhs bool, mode operandMode, typ *Basic, val constant.Value) {
141 m := check.untyped
142 if m == nil {
143 m = make(map[ast.Expr]exprInfo)
144 check.untyped = m
145 }
146 m[e] = exprInfo{lhs, mode, typ, val}
147 }
148
149 func (check *Checker) later(name string, decl *declInfo, sig *Signature, body *ast.BlockStmt) {
150 check.funcs = append(check.funcs, funcInfo{name, decl, sig, body})
151 }
152
153 func (check *Checker) delay(f func()) {
154 check.delayed = append(check.delayed, f)
155 }
156
157
158
159 func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker {
160
161 if conf == nil {
162 conf = new(Config)
163 }
164
165
166 if info == nil {
167 info = new(Info)
168 }
169
170 return &Checker{
171 conf: conf,
172 fset: fset,
173 pkg: pkg,
174 Info: info,
175 objMap: make(map[Object]*declInfo),
176 impMap: make(map[importKey]*Package),
177 }
178 }
179
180
181
182 func (check *Checker) initFiles(files []*ast.File) {
183
184 check.files = nil
185 check.unusedDotImports = nil
186
187 check.firstErr = nil
188 check.methods = nil
189 check.untyped = nil
190 check.funcs = nil
191 check.delayed = nil
192
193
194 pkg := check.pkg
195 for _, file := range files {
196 switch name := file.Name.Name; pkg.name {
197 case "":
198 if name != "_" {
199 pkg.name = name
200 } else {
201 check.errorf(file.Name.Pos(), "invalid package name _")
202 }
203 fallthrough
204
205 case name:
206 check.files = append(check.files, file)
207
208 default:
209 check.errorf(file.Package, "package %s; expected %s", name, pkg.name)
210
211 }
212 }
213 }
214
215
216 type bailout struct{}
217
218 func (check *Checker) handleBailout(err *error) {
219 switch p := recover().(type) {
220 case nil, bailout:
221
222 *err = check.firstErr
223 default:
224
225 panic(p)
226 }
227 }
228
229
230 func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(files) }
231
232 func (check *Checker) checkFiles(files []*ast.File) (err error) {
233 defer check.handleBailout(&err)
234
235 check.initFiles(files)
236
237 check.collectObjects()
238
239 check.packageObjects(check.resolveOrder())
240
241 check.functionBodies()
242
243 check.initOrder()
244
245 if !check.conf.DisableUnusedImportCheck {
246 check.unusedImports()
247 }
248
249
250 for _, f := range check.delayed {
251 f()
252 }
253
254 check.recordUntyped()
255
256 check.pkg.complete = true
257 return
258 }
259
260 func (check *Checker) recordUntyped() {
261 if !debug && check.Types == nil {
262 return
263 }
264
265 for x, info := range check.untyped {
266 if debug && isTyped(info.typ) {
267 check.dump("%s: %s (type %s) is typed", x.Pos(), x, info.typ)
268 unreachable()
269 }
270 check.recordTypeAndValue(x, info.mode, info.typ, info.val)
271 }
272 }
273
274 func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type, val constant.Value) {
275 assert(x != nil)
276 assert(typ != nil)
277 if mode == invalid {
278 return
279 }
280 assert(typ != nil)
281 if mode == constant_ {
282 assert(val != nil)
283 assert(typ == Typ[Invalid] || isConstType(typ))
284 }
285 if m := check.Types; m != nil {
286 m[x] = TypeAndValue{mode, typ, val}
287 }
288 }
289
290 func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) {
291
292
293
294
295 for {
296 check.recordTypeAndValue(f, builtin, sig, nil)
297 switch p := f.(type) {
298 case *ast.Ident:
299 return
300 case *ast.ParenExpr:
301 f = p.X
302 default:
303 unreachable()
304 }
305 }
306 }
307
308 func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
309 assert(x != nil)
310 if a[0] == nil || a[1] == nil {
311 return
312 }
313 assert(isTyped(a[0]) && isTyped(a[1]) && isBoolean(a[1]))
314 if m := check.Types; m != nil {
315 for {
316 tv := m[x]
317 assert(tv.Type != nil)
318 pos := x.Pos()
319 tv.Type = NewTuple(
320 NewVar(pos, check.pkg, "", a[0]),
321 NewVar(pos, check.pkg, "", a[1]),
322 )
323 m[x] = tv
324
325 p, _ := x.(*ast.ParenExpr)
326 if p == nil {
327 break
328 }
329 x = p.X
330 }
331 }
332 }
333
334 func (check *Checker) recordDef(id *ast.Ident, obj Object) {
335 assert(id != nil)
336 if m := check.Defs; m != nil {
337 m[id] = obj
338 }
339 }
340
341 func (check *Checker) recordUse(id *ast.Ident, obj Object) {
342 assert(id != nil)
343 assert(obj != nil)
344 if m := check.Uses; m != nil {
345 m[id] = obj
346 }
347 }
348
349 func (check *Checker) recordImplicit(node ast.Node, obj Object) {
350 assert(node != nil)
351 assert(obj != nil)
352 if m := check.Implicits; m != nil {
353 m[node] = obj
354 }
355 }
356
357 func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
358 assert(obj != nil && (recv == nil || len(index) > 0))
359 check.recordUse(x.Sel, obj)
360 if m := check.Selections; m != nil {
361 m[x] = &Selection{kind, recv, obj, index, indirect}
362 }
363 }
364
365 func (check *Checker) recordScope(node ast.Node, scope *Scope) {
366 assert(node != nil)
367 assert(scope != nil)
368 if m := check.Scopes; m != nil {
369 m[node] = scope
370 }
371 }
372
View as plain text