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