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 compilerErrorMessages = false
25 )
26
27
28 type exprInfo struct {
29 isLhs bool
30 mode operandMode
31 typ *Basic
32 val constant.Value
33 }
34
35
36
37 type environment struct {
38 decl *declInfo
39 scope *Scope
40 pos token.Pos
41 iota constant.Value
42 errpos positioner
43 inTParamList bool
44 sig *Signature
45 isPanic map[*ast.CallExpr]bool
46 hasLabel bool
47 hasCallOrRecv bool
48 }
49
50
51 func (env *environment) lookup(name string) Object {
52 _, obj := env.scope.LookupParent(name, env.pos)
53 return obj
54 }
55
56
57
58
59
60
61
62 type importKey struct {
63 path, dir string
64 }
65
66
67 type dotImportKey struct {
68 scope *Scope
69 name string
70 }
71
72
73 type action struct {
74 f func()
75 desc *actionDesc
76 }
77
78
79
80 func (a *action) describef(pos positioner, format string, args ...any) {
81 if debug {
82 a.desc = &actionDesc{pos, format, args}
83 }
84 }
85
86
87
88 type actionDesc struct {
89 pos positioner
90 format string
91 args []any
92 }
93
94
95
96 type Checker struct {
97
98
99 conf *Config
100 ctxt *Context
101 fset *token.FileSet
102 pkg *Package
103 *Info
104 version version
105 nextID uint64
106 objMap map[Object]*declInfo
107 impMap map[importKey]*Package
108 valids instanceLookup
109
110
111
112
113
114
115
116
117 pkgPathMap map[string]map[string]bool
118 seenPkgMap map[*Package]bool
119
120
121
122
123 files []*ast.File
124 imports []*PkgName
125 dotImportMap map[dotImportKey]*PkgName
126 recvTParamMap map[*ast.Ident]*TypeParam
127 brokenAliases map[*TypeName]bool
128 unionTypeSets map[*Union]*_TypeSet
129 mono monoGraph
130
131 firstErr error
132 methods map[*TypeName][]*Func
133 untyped map[ast.Expr]exprInfo
134 delayed []action
135 objPath []Object
136 cleaners []cleaner
137
138
139
140 environment
141
142
143 indent int
144 }
145
146
147 func (check *Checker) addDeclDep(to Object) {
148 from := check.decl
149 if from == nil {
150 return
151 }
152 if _, found := check.objMap[to]; !found {
153 return
154 }
155 from.addDep(to)
156 }
157
158
159
160 func (check *Checker) brokenAlias(alias *TypeName) {
161 if check.brokenAliases == nil {
162 check.brokenAliases = make(map[*TypeName]bool)
163 }
164 check.brokenAliases[alias] = true
165 alias.typ = Typ[Invalid]
166 }
167
168
169 func (check *Checker) validAlias(alias *TypeName, typ Type) {
170 delete(check.brokenAliases, alias)
171 alias.typ = typ
172 }
173
174
175 func (check *Checker) isBrokenAlias(alias *TypeName) bool {
176 return alias.typ == Typ[Invalid] && check.brokenAliases[alias]
177 }
178
179 func (check *Checker) rememberUntyped(e ast.Expr, lhs bool, mode operandMode, typ *Basic, val constant.Value) {
180 m := check.untyped
181 if m == nil {
182 m = make(map[ast.Expr]exprInfo)
183 check.untyped = m
184 }
185 m[e] = exprInfo{lhs, mode, typ, val}
186 }
187
188
189
190
191
192
193
194 func (check *Checker) later(f func()) *action {
195 i := len(check.delayed)
196 check.delayed = append(check.delayed, action{f: f})
197 return &check.delayed[i]
198 }
199
200
201 func (check *Checker) push(obj Object) int {
202 check.objPath = append(check.objPath, obj)
203 return len(check.objPath) - 1
204 }
205
206
207 func (check *Checker) pop() Object {
208 i := len(check.objPath) - 1
209 obj := check.objPath[i]
210 check.objPath[i] = nil
211 check.objPath = check.objPath[:i]
212 return obj
213 }
214
215 type cleaner interface {
216 cleanup()
217 }
218
219
220
221 func (check *Checker) needsCleanup(c cleaner) {
222 check.cleaners = append(check.cleaners, c)
223 }
224
225
226
227 func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker {
228
229 if conf == nil {
230 conf = new(Config)
231 }
232
233
234 if info == nil {
235 info = new(Info)
236 }
237
238 version, err := parseGoVersion(conf.GoVersion)
239 if err != nil {
240 panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err))
241 }
242
243 return &Checker{
244 conf: conf,
245 ctxt: conf.Context,
246 fset: fset,
247 pkg: pkg,
248 Info: info,
249 version: version,
250 objMap: make(map[Object]*declInfo),
251 impMap: make(map[importKey]*Package),
252 }
253 }
254
255
256
257 func (check *Checker) initFiles(files []*ast.File) {
258
259 check.files = nil
260 check.imports = nil
261 check.dotImportMap = nil
262
263 check.firstErr = nil
264 check.methods = nil
265 check.untyped = nil
266 check.delayed = nil
267 check.objPath = nil
268 check.cleaners = nil
269
270
271 pkg := check.pkg
272 for _, file := range files {
273 switch name := file.Name.Name; pkg.name {
274 case "":
275 if name != "_" {
276 pkg.name = name
277 } else {
278 check.errorf(file.Name, _BlankPkgName, "invalid package name _")
279 }
280 fallthrough
281
282 case name:
283 check.files = append(check.files, file)
284
285 default:
286 check.errorf(atPos(file.Package), _MismatchedPkgName, "package %s; expected %s", name, pkg.name)
287
288 }
289 }
290 }
291
292
293 type bailout struct{}
294
295 func (check *Checker) handleBailout(err *error) {
296 switch p := recover().(type) {
297 case nil, bailout:
298
299 *err = check.firstErr
300 default:
301
302 panic(p)
303 }
304 }
305
306
307 func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(files) }
308
309 var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
310
311 func (check *Checker) checkFiles(files []*ast.File) (err error) {
312 if check.conf.FakeImportC && check.conf.go115UsesCgo {
313 return errBadCgo
314 }
315
316 defer check.handleBailout(&err)
317
318 print := func(msg string) {
319 if trace {
320 fmt.Println()
321 fmt.Println(msg)
322 }
323 }
324
325 print("== initFiles ==")
326 check.initFiles(files)
327
328 print("== collectObjects ==")
329 check.collectObjects()
330
331 print("== packageObjects ==")
332 check.packageObjects()
333
334 print("== processDelayed ==")
335 check.processDelayed(0)
336
337 print("== cleanup ==")
338 check.cleanup()
339
340 print("== initOrder ==")
341 check.initOrder()
342
343 if !check.conf.DisableUnusedImportCheck {
344 print("== unusedImports ==")
345 check.unusedImports()
346 }
347
348 print("== recordUntyped ==")
349 check.recordUntyped()
350
351 if check.firstErr == nil {
352
353 check.monomorph()
354 }
355
356 check.pkg.complete = true
357
358
359 check.imports = nil
360 check.dotImportMap = nil
361 check.pkgPathMap = nil
362 check.seenPkgMap = nil
363 check.recvTParamMap = nil
364 check.brokenAliases = nil
365 check.unionTypeSets = nil
366 check.ctxt = nil
367
368
369
370 return
371 }
372
373
374 func (check *Checker) processDelayed(top int) {
375
376
377
378
379
380
381 for i := top; i < len(check.delayed); i++ {
382 a := &check.delayed[i]
383 if trace {
384 if a.desc != nil {
385 check.trace(a.desc.pos.Pos(), "-- "+a.desc.format, a.desc.args...)
386 } else {
387 check.trace(token.NoPos, "-- delayed %p", a.f)
388 }
389 }
390 a.f()
391 if trace {
392 fmt.Println()
393 }
394 }
395 assert(top <= len(check.delayed))
396 check.delayed = check.delayed[:top]
397 }
398
399
400 func (check *Checker) cleanup() {
401
402 for i := 0; i < len(check.cleaners); i++ {
403 check.cleaners[i].cleanup()
404 }
405 check.cleaners = nil
406 }
407
408 func (check *Checker) record(x *operand) {
409
410
411 var typ Type
412 var val constant.Value
413 switch x.mode {
414 case invalid:
415 typ = Typ[Invalid]
416 case novalue:
417 typ = (*Tuple)(nil)
418 case constant_:
419 typ = x.typ
420 val = x.val
421 default:
422 typ = x.typ
423 }
424 assert(x.expr != nil && typ != nil)
425
426 if isUntyped(typ) {
427
428
429 check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
430 } else {
431 check.recordTypeAndValue(x.expr, x.mode, typ, val)
432 }
433 }
434
435 func (check *Checker) recordUntyped() {
436 if !debug && check.Types == nil {
437 return
438 }
439
440 for x, info := range check.untyped {
441 if debug && isTyped(info.typ) {
442 check.dump("%v: %s (type %s) is typed", x.Pos(), x, info.typ)
443 unreachable()
444 }
445 check.recordTypeAndValue(x, info.mode, info.typ, info.val)
446 }
447 }
448
449 func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type, val constant.Value) {
450 assert(x != nil)
451 assert(typ != nil)
452 if mode == invalid {
453 return
454 }
455 if mode == constant_ {
456 assert(val != nil)
457
458
459 assert(typ == Typ[Invalid] || allBasic(typ, IsConstType))
460 }
461 if m := check.Types; m != nil {
462 m[x] = TypeAndValue{mode, typ, val}
463 }
464 }
465
466 func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) {
467
468
469
470
471 for {
472 check.recordTypeAndValue(f, builtin, sig, nil)
473 switch p := f.(type) {
474 case *ast.Ident, *ast.SelectorExpr:
475 return
476 case *ast.ParenExpr:
477 f = p.X
478 default:
479 unreachable()
480 }
481 }
482 }
483
484 func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
485 assert(x != nil)
486 if a[0] == nil || a[1] == nil {
487 return
488 }
489 assert(isTyped(a[0]) && isTyped(a[1]) && (isBoolean(a[1]) || a[1] == universeError))
490 if m := check.Types; m != nil {
491 for {
492 tv := m[x]
493 assert(tv.Type != nil)
494 pos := x.Pos()
495 tv.Type = NewTuple(
496 NewVar(pos, check.pkg, "", a[0]),
497 NewVar(pos, check.pkg, "", a[1]),
498 )
499 m[x] = tv
500
501 p, _ := x.(*ast.ParenExpr)
502 if p == nil {
503 break
504 }
505 x = p.X
506 }
507 }
508 }
509
510
511
512
513
514
515
516 func (check *Checker) recordInstance(expr ast.Expr, targs []Type, typ Type) {
517 ident := instantiatedIdent(expr)
518 assert(ident != nil)
519 assert(typ != nil)
520 if m := check.Instances; m != nil {
521 m[ident] = Instance{newTypeList(targs), typ}
522 }
523 }
524
525 func instantiatedIdent(expr ast.Expr) *ast.Ident {
526 var selOrIdent ast.Expr
527 switch e := expr.(type) {
528 case *ast.IndexExpr:
529 selOrIdent = e.X
530 case *ast.IndexListExpr:
531 selOrIdent = e.X
532 case *ast.SelectorExpr, *ast.Ident:
533 selOrIdent = e
534 }
535 switch x := selOrIdent.(type) {
536 case *ast.Ident:
537 return x
538 case *ast.SelectorExpr:
539 return x.Sel
540 }
541 panic("instantiated ident not found")
542 }
543
544 func (check *Checker) recordDef(id *ast.Ident, obj Object) {
545 assert(id != nil)
546 if m := check.Defs; m != nil {
547 m[id] = obj
548 }
549 }
550
551 func (check *Checker) recordUse(id *ast.Ident, obj Object) {
552 assert(id != nil)
553 assert(obj != nil)
554 if m := check.Uses; m != nil {
555 m[id] = obj
556 }
557 }
558
559 func (check *Checker) recordImplicit(node ast.Node, obj Object) {
560 assert(node != nil)
561 assert(obj != nil)
562 if m := check.Implicits; m != nil {
563 m[node] = obj
564 }
565 }
566
567 func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
568 assert(obj != nil && (recv == nil || len(index) > 0))
569 check.recordUse(x.Sel, obj)
570 if m := check.Selections; m != nil {
571 m[x] = &Selection{kind, recv, obj, index, indirect}
572 }
573 }
574
575 func (check *Checker) recordScope(node ast.Node, scope *Scope) {
576 assert(node != nil)
577 assert(scope != nil)
578 if m := check.Scopes; m != nil {
579 m[node] = scope
580 }
581 }
582
View as plain text