Source file
src/go/types/check.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "errors"
11 "fmt"
12 "go/ast"
13 "go/constant"
14 "go/token"
15 )
16
17
18 const (
19 debug = false
20 trace = false
21 )
22
23
24
25
26
27
28
29
30
31
32
33
34 const forceStrict = false
35
36
37 type exprInfo struct {
38 isLhs bool
39 mode operandMode
40 typ *Basic
41 val constant.Value
42 }
43
44
45 type context struct {
46 decl *declInfo
47 scope *Scope
48 pos token.Pos
49 iota constant.Value
50 errpos positioner
51 sig *Signature
52 isPanic map[*ast.CallExpr]bool
53 hasLabel bool
54 hasCallOrRecv bool
55 }
56
57
58 func (ctxt *context) lookup(name string) Object {
59 _, obj := ctxt.scope.LookupParent(name, ctxt.pos)
60 return obj
61 }
62
63
64
65
66
67
68
69 type importKey struct {
70 path, dir string
71 }
72
73
74 type dotImportKey struct {
75 scope *Scope
76 obj Object
77 }
78
79
80
81 type Checker struct {
82
83
84 conf *Config
85 fset *token.FileSet
86 pkg *Package
87 *Info
88 version version
89 objMap map[Object]*declInfo
90 impMap map[importKey]*Package
91 posMap map[*Interface][]token.Pos
92 typMap map[string]*Named
93
94
95
96
97
98
99
100
101 pkgPathMap map[string]map[string]bool
102 seenPkgMap map[*Package]bool
103
104
105
106
107 files []*ast.File
108 imports []*PkgName
109 dotImportMap map[dotImportKey]*PkgName
110
111 firstErr error
112 methods map[*TypeName][]*Func
113 untyped map[ast.Expr]exprInfo
114 delayed []func()
115 objPath []Object
116
117
118
119 context
120
121
122 indent int
123 }
124
125
126 func (check *Checker) addDeclDep(to Object) {
127 from := check.decl
128 if from == nil {
129 return
130 }
131 if _, found := check.objMap[to]; !found {
132 return
133 }
134 from.addDep(to)
135 }
136
137 func (check *Checker) rememberUntyped(e ast.Expr, lhs bool, mode operandMode, typ *Basic, val constant.Value) {
138 m := check.untyped
139 if m == nil {
140 m = make(map[ast.Expr]exprInfo)
141 check.untyped = m
142 }
143 m[e] = exprInfo{lhs, mode, typ, val}
144 }
145
146
147
148
149
150 func (check *Checker) later(f func()) {
151 check.delayed = append(check.delayed, f)
152 }
153
154
155 func (check *Checker) push(obj Object) int {
156 check.objPath = append(check.objPath, obj)
157 return len(check.objPath) - 1
158 }
159
160
161 func (check *Checker) pop() Object {
162 i := len(check.objPath) - 1
163 obj := check.objPath[i]
164 check.objPath[i] = nil
165 check.objPath = check.objPath[:i]
166 return obj
167 }
168
169
170
171 func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker {
172
173 if conf == nil {
174 conf = new(Config)
175 }
176
177
178 if info == nil {
179 info = new(Info)
180 }
181
182 version, err := parseGoVersion(conf.goVersion)
183 if err != nil {
184 panic(fmt.Sprintf("invalid Go version %q (%v)", conf.goVersion, err))
185 }
186
187 return &Checker{
188 conf: conf,
189 fset: fset,
190 pkg: pkg,
191 Info: info,
192 version: version,
193 objMap: make(map[Object]*declInfo),
194 impMap: make(map[importKey]*Package),
195 posMap: make(map[*Interface][]token.Pos),
196 typMap: make(map[string]*Named),
197 }
198 }
199
200
201
202 func (check *Checker) initFiles(files []*ast.File) {
203
204 check.files = nil
205 check.imports = nil
206 check.dotImportMap = nil
207
208 check.firstErr = nil
209 check.methods = nil
210 check.untyped = nil
211 check.delayed = nil
212
213
214 pkg := check.pkg
215 for _, file := range files {
216 switch name := file.Name.Name; pkg.name {
217 case "":
218 if name != "_" {
219 pkg.name = name
220 } else {
221 check.errorf(file.Name, _BlankPkgName, "invalid package name _")
222 }
223 fallthrough
224
225 case name:
226 check.files = append(check.files, file)
227
228 default:
229 check.errorf(atPos(file.Package), _MismatchedPkgName, "package %s; expected %s", name, pkg.name)
230
231 }
232 }
233 }
234
235
236 type bailout struct{}
237
238 func (check *Checker) handleBailout(err *error) {
239 switch p := recover().(type) {
240 case nil, bailout:
241
242 *err = check.firstErr
243 default:
244
245 panic(p)
246 }
247 }
248
249
250 func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(files) }
251
252 var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
253
254 func (check *Checker) checkFiles(files []*ast.File) (err error) {
255 if check.conf.FakeImportC && check.conf.go115UsesCgo {
256 return errBadCgo
257 }
258
259 defer check.handleBailout(&err)
260
261 check.initFiles(files)
262
263 check.collectObjects()
264
265 check.packageObjects()
266
267 check.processDelayed(0)
268
269 check.initOrder()
270
271 if !check.conf.DisableUnusedImportCheck {
272 check.unusedImports()
273 }
274
275 check.recordUntyped()
276
277 if check.Info != nil {
278 sanitizeInfo(check.Info)
279 }
280
281 check.pkg.complete = true
282
283
284 check.imports = nil
285 check.dotImportMap = nil
286 check.pkgPathMap = nil
287 check.seenPkgMap = nil
288
289
290
291 return
292 }
293
294
295 func (check *Checker) processDelayed(top int) {
296
297
298
299
300
301
302 for i := top; i < len(check.delayed); i++ {
303 check.delayed[i]()
304 }
305 assert(top <= len(check.delayed))
306 check.delayed = check.delayed[:top]
307 }
308
309 func (check *Checker) record(x *operand) {
310
311
312 var typ Type
313 var val constant.Value
314 switch x.mode {
315 case invalid:
316 typ = Typ[Invalid]
317 case novalue:
318 typ = (*Tuple)(nil)
319 case constant_:
320 typ = x.typ
321 val = x.val
322 default:
323 typ = x.typ
324 }
325 assert(x.expr != nil && typ != nil)
326
327 if isUntyped(typ) {
328
329
330 check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
331 } else {
332 check.recordTypeAndValue(x.expr, x.mode, typ, val)
333 }
334 }
335
336 func (check *Checker) recordUntyped() {
337 if !debug && check.Types == nil {
338 return
339 }
340
341 for x, info := range check.untyped {
342 if debug && isTyped(info.typ) {
343 check.dump("%v: %s (type %s) is typed", x.Pos(), x, info.typ)
344 unreachable()
345 }
346 check.recordTypeAndValue(x, info.mode, info.typ, info.val)
347 }
348 }
349
350 func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type, val constant.Value) {
351 assert(x != nil)
352 assert(typ != nil)
353 if mode == invalid {
354 return
355 }
356 if mode == constant_ {
357 assert(val != nil)
358
359
360 assert(typ == Typ[Invalid] || is(typ, IsConstType))
361 }
362 if m := check.Types; m != nil {
363 m[x] = TypeAndValue{mode, typ, val}
364 }
365 }
366
367 func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) {
368
369
370
371
372 for {
373 check.recordTypeAndValue(f, builtin, sig, nil)
374 switch p := f.(type) {
375 case *ast.Ident, *ast.SelectorExpr:
376 return
377 case *ast.ParenExpr:
378 f = p.X
379 default:
380 unreachable()
381 }
382 }
383 }
384
385 func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
386 assert(x != nil)
387 if a[0] == nil || a[1] == nil {
388 return
389 }
390 assert(isTyped(a[0]) && isTyped(a[1]) && (isBoolean(a[1]) || a[1] == universeError))
391 if m := check.Types; m != nil {
392 for {
393 tv := m[x]
394 assert(tv.Type != nil)
395 pos := x.Pos()
396 tv.Type = NewTuple(
397 NewVar(pos, check.pkg, "", a[0]),
398 NewVar(pos, check.pkg, "", a[1]),
399 )
400 m[x] = tv
401
402 p, _ := x.(*ast.ParenExpr)
403 if p == nil {
404 break
405 }
406 x = p.X
407 }
408 }
409 }
410
411 func (check *Checker) recordInferred(call ast.Expr, targs []Type, sig *Signature) {
412 assert(call != nil)
413 assert(sig != nil)
414 if m := getInferred(check.Info); m != nil {
415 m[call] = _Inferred{targs, sig}
416 }
417 }
418
419 func (check *Checker) recordDef(id *ast.Ident, obj Object) {
420 assert(id != nil)
421 if m := check.Defs; m != nil {
422 m[id] = obj
423 }
424 }
425
426 func (check *Checker) recordUse(id *ast.Ident, obj Object) {
427 assert(id != nil)
428 assert(obj != nil)
429 if m := check.Uses; m != nil {
430 m[id] = obj
431 }
432 }
433
434 func (check *Checker) recordImplicit(node ast.Node, obj Object) {
435 assert(node != nil)
436 assert(obj != nil)
437 if m := check.Implicits; m != nil {
438 m[node] = obj
439 }
440 }
441
442 func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
443 assert(obj != nil && (recv == nil || len(index) > 0))
444 check.recordUse(x.Sel, obj)
445 if m := check.Selections; m != nil {
446 m[x] = &Selection{kind, recv, obj, index, indirect}
447 }
448 }
449
450 func (check *Checker) recordScope(node ast.Node, scope *Scope) {
451 assert(node != nil)
452 assert(scope != nil)
453 if m := check.Scopes; m != nil {
454 m[node] = scope
455 }
456 }
457
View as plain text