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