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 infoMap map[*Named]typeInfo
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 infoMap: make(map[*Named]typeInfo),
253 }
254 }
255
256
257
258 func (check *Checker) initFiles(files []*ast.File) {
259
260 check.files = nil
261 check.imports = nil
262 check.dotImportMap = nil
263
264 check.firstErr = nil
265 check.methods = nil
266 check.untyped = nil
267 check.delayed = nil
268 check.objPath = nil
269 check.cleaners = nil
270
271
272 pkg := check.pkg
273 for _, file := range files {
274 switch name := file.Name.Name; pkg.name {
275 case "":
276 if name != "_" {
277 pkg.name = name
278 } else {
279 check.errorf(file.Name, _BlankPkgName, "invalid package name _")
280 }
281 fallthrough
282
283 case name:
284 check.files = append(check.files, file)
285
286 default:
287 check.errorf(atPos(file.Package), _MismatchedPkgName, "package %s; expected %s", name, pkg.name)
288
289 }
290 }
291 }
292
293
294 type bailout struct{}
295
296 func (check *Checker) handleBailout(err *error) {
297 switch p := recover().(type) {
298 case nil, bailout:
299
300 *err = check.firstErr
301 default:
302
303 panic(p)
304 }
305 }
306
307
308 func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(files) }
309
310 var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
311
312 func (check *Checker) checkFiles(files []*ast.File) (err error) {
313 if check.conf.FakeImportC && check.conf.go115UsesCgo {
314 return errBadCgo
315 }
316
317 defer check.handleBailout(&err)
318
319 print := func(msg string) {
320 if trace {
321 fmt.Println()
322 fmt.Println(msg)
323 }
324 }
325
326 print("== initFiles ==")
327 check.initFiles(files)
328
329 print("== collectObjects ==")
330 check.collectObjects()
331
332 print("== packageObjects ==")
333 check.packageObjects()
334
335 print("== processDelayed ==")
336 check.processDelayed(0)
337
338 print("== cleanup ==")
339 check.cleanup()
340
341 print("== initOrder ==")
342 check.initOrder()
343
344 if !check.conf.DisableUnusedImportCheck {
345 print("== unusedImports ==")
346 check.unusedImports()
347 }
348
349 print("== recordUntyped ==")
350 check.recordUntyped()
351
352 if check.firstErr == nil {
353
354 check.monomorph()
355 }
356
357 check.pkg.complete = true
358
359
360 check.imports = nil
361 check.dotImportMap = nil
362 check.pkgPathMap = nil
363 check.seenPkgMap = nil
364 check.recvTParamMap = nil
365 check.brokenAliases = nil
366 check.unionTypeSets = nil
367 check.ctxt = nil
368
369
370
371 return
372 }
373
374
375 func (check *Checker) processDelayed(top int) {
376
377
378
379
380
381
382 for i := top; i < len(check.delayed); i++ {
383 a := &check.delayed[i]
384 if trace && a.desc != nil {
385 fmt.Println()
386 check.trace(a.desc.pos.Pos(), "-- "+a.desc.format, a.desc.args...)
387 }
388 a.f()
389 }
390 assert(top <= len(check.delayed))
391 check.delayed = check.delayed[:top]
392 }
393
394
395 func (check *Checker) cleanup() {
396
397 for i := 0; i < len(check.cleaners); i++ {
398 check.cleaners[i].cleanup()
399 }
400 check.cleaners = nil
401 }
402
403 func (check *Checker) record(x *operand) {
404
405
406 var typ Type
407 var val constant.Value
408 switch x.mode {
409 case invalid:
410 typ = Typ[Invalid]
411 case novalue:
412 typ = (*Tuple)(nil)
413 case constant_:
414 typ = x.typ
415 val = x.val
416 default:
417 typ = x.typ
418 }
419 assert(x.expr != nil && typ != nil)
420
421 if isUntyped(typ) {
422
423
424 check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
425 } else {
426 check.recordTypeAndValue(x.expr, x.mode, typ, val)
427 }
428 }
429
430 func (check *Checker) recordUntyped() {
431 if !debug && check.Types == nil {
432 return
433 }
434
435 for x, info := range check.untyped {
436 if debug && isTyped(info.typ) {
437 check.dump("%v: %s (type %s) is typed", x.Pos(), x, info.typ)
438 unreachable()
439 }
440 check.recordTypeAndValue(x, info.mode, info.typ, info.val)
441 }
442 }
443
444 func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type, val constant.Value) {
445 assert(x != nil)
446 assert(typ != nil)
447 if mode == invalid {
448 return
449 }
450 if mode == constant_ {
451 assert(val != nil)
452
453
454 assert(typ == Typ[Invalid] || allBasic(typ, IsConstType))
455 }
456 if m := check.Types; m != nil {
457 m[x] = TypeAndValue{mode, typ, val}
458 }
459 }
460
461 func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) {
462
463
464
465
466 for {
467 check.recordTypeAndValue(f, builtin, sig, nil)
468 switch p := f.(type) {
469 case *ast.Ident, *ast.SelectorExpr:
470 return
471 case *ast.ParenExpr:
472 f = p.X
473 default:
474 unreachable()
475 }
476 }
477 }
478
479 func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
480 assert(x != nil)
481 if a[0] == nil || a[1] == nil {
482 return
483 }
484 assert(isTyped(a[0]) && isTyped(a[1]) && (isBoolean(a[1]) || a[1] == universeError))
485 if m := check.Types; m != nil {
486 for {
487 tv := m[x]
488 assert(tv.Type != nil)
489 pos := x.Pos()
490 tv.Type = NewTuple(
491 NewVar(pos, check.pkg, "", a[0]),
492 NewVar(pos, check.pkg, "", a[1]),
493 )
494 m[x] = tv
495
496 p, _ := x.(*ast.ParenExpr)
497 if p == nil {
498 break
499 }
500 x = p.X
501 }
502 }
503 }
504
505
506
507
508
509
510
511 func (check *Checker) recordInstance(expr ast.Expr, targs []Type, typ Type) {
512 ident := instantiatedIdent(expr)
513 assert(ident != nil)
514 assert(typ != nil)
515 if m := check.Instances; m != nil {
516 m[ident] = Instance{newTypeList(targs), typ}
517 }
518 }
519
520 func instantiatedIdent(expr ast.Expr) *ast.Ident {
521 var selOrIdent ast.Expr
522 switch e := expr.(type) {
523 case *ast.IndexExpr:
524 selOrIdent = e.X
525 case *ast.IndexListExpr:
526 selOrIdent = e.X
527 case *ast.SelectorExpr, *ast.Ident:
528 selOrIdent = e
529 }
530 switch x := selOrIdent.(type) {
531 case *ast.Ident:
532 return x
533 case *ast.SelectorExpr:
534 return x.Sel
535 }
536 panic("instantiated ident not found")
537 }
538
539 func (check *Checker) recordDef(id *ast.Ident, obj Object) {
540 assert(id != nil)
541 if m := check.Defs; m != nil {
542 m[id] = obj
543 }
544 }
545
546 func (check *Checker) recordUse(id *ast.Ident, obj Object) {
547 assert(id != nil)
548 assert(obj != nil)
549 if m := check.Uses; m != nil {
550 m[id] = obj
551 }
552 }
553
554 func (check *Checker) recordImplicit(node ast.Node, obj Object) {
555 assert(node != nil)
556 assert(obj != nil)
557 if m := check.Implicits; m != nil {
558 m[node] = obj
559 }
560 }
561
562 func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
563 assert(obj != nil && (recv == nil || len(index) > 0))
564 check.recordUse(x.Sel, obj)
565 if m := check.Selections; m != nil {
566 m[x] = &Selection{kind, recv, obj, index, indirect}
567 }
568 }
569
570 func (check *Checker) recordScope(node ast.Node, scope *Scope) {
571 assert(node != nil)
572 assert(scope != nil)
573 if m := check.Scopes; m != nil {
574 m[node] = scope
575 }
576 }
577
View as plain text