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