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 ...interface{}) {
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 []interface{}
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 cleaners []cleaner
180
181
182
183 environment
184
185
186 posStack []syntax.Pos
187 indent int
188 }
189
190
191 func (check *Checker) addDeclDep(to Object) {
192 from := check.decl
193 if from == nil {
194 return
195 }
196 if _, found := check.objMap[to]; !found {
197 return
198 }
199 from.addDep(to)
200 }
201
202
203
204
205
206
207
208 func (check *Checker) brokenAlias(alias *TypeName) {
209 assert(!check.conf.EnableAlias)
210 if check.brokenAliases == nil {
211 check.brokenAliases = make(map[*TypeName]bool)
212 }
213 check.brokenAliases[alias] = true
214 alias.typ = Typ[Invalid]
215 }
216
217
218 func (check *Checker) validAlias(alias *TypeName, typ Type) {
219 assert(!check.conf.EnableAlias)
220 delete(check.brokenAliases, alias)
221 alias.typ = typ
222 }
223
224
225 func (check *Checker) isBrokenAlias(alias *TypeName) bool {
226 assert(!check.conf.EnableAlias)
227 return check.brokenAliases[alias]
228 }
229
230 func (check *Checker) rememberUntyped(e syntax.Expr, lhs bool, mode operandMode, typ *Basic, val constant.Value) {
231 m := check.untyped
232 if m == nil {
233 m = make(map[syntax.Expr]exprInfo)
234 check.untyped = m
235 }
236 m[e] = exprInfo{lhs, mode, typ, val}
237 }
238
239
240
241
242
243
244
245 func (check *Checker) later(f func()) *action {
246 i := len(check.delayed)
247 check.delayed = append(check.delayed, action{version: check.version, f: f})
248 return &check.delayed[i]
249 }
250
251
252 func (check *Checker) push(obj Object) int {
253 check.objPath = append(check.objPath, obj)
254 return len(check.objPath) - 1
255 }
256
257
258 func (check *Checker) pop() Object {
259 i := len(check.objPath) - 1
260 obj := check.objPath[i]
261 check.objPath[i] = nil
262 check.objPath = check.objPath[:i]
263 return obj
264 }
265
266 type cleaner interface {
267 cleanup()
268 }
269
270
271
272 func (check *Checker) needsCleanup(c cleaner) {
273 check.cleaners = append(check.cleaners, c)
274 }
275
276
277
278 func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
279
280 if conf == nil {
281 conf = new(Config)
282 }
283
284
285 if info == nil {
286 info = new(Info)
287 }
288
289
290
291
292
293
294
295 return &Checker{
296 conf: conf,
297 ctxt: conf.Context,
298 pkg: pkg,
299 Info: info,
300 objMap: make(map[Object]*declInfo),
301 impMap: make(map[importKey]*Package),
302 usedVars: make(map[*Var]bool),
303 usedPkgNames: make(map[*PkgName]bool),
304 }
305 }
306
307
308
309 func (check *Checker) initFiles(files []*syntax.File) {
310
311
312
313 check.files = nil
314 check.imports = nil
315 check.dotImportMap = nil
316
317 check.firstErr = nil
318 check.methods = nil
319 check.untyped = nil
320 check.delayed = nil
321 check.objPath = nil
322 check.cleaners = nil
323
324
325
326
327
328 check.usedVars = make(map[*Var]bool)
329 check.usedPkgNames = make(map[*PkgName]bool)
330
331
332 pkg := check.pkg
333 for _, file := range files {
334 switch name := file.PkgName.Value; pkg.name {
335 case "":
336 if name != "_" {
337 pkg.name = name
338 } else {
339 check.error(file.PkgName, BlankPkgName, "invalid package name _")
340 }
341 fallthrough
342
343 case name:
344 check.files = append(check.files, file)
345
346 default:
347 check.errorf(file, MismatchedPkgName, "package %s; expected package %s", name, pkg.name)
348
349 }
350 }
351
352
353 versions := check.Info.FileVersions
354 if versions == nil {
355 versions = make(map[*syntax.PosBase]string)
356 }
357 check.versions = versions
358
359 pkgVersion := asGoVersion(check.conf.GoVersion)
360 if pkgVersion.isValid() && len(files) > 0 && pkgVersion.cmp(go_current) > 0 {
361 check.errorf(files[0], TooNew, "package requires newer Go version %v (application built with %v)",
362 pkgVersion, go_current)
363 }
364
365
366 for _, file := range check.files {
367
368
369
370 v := check.conf.GoVersion
371
372
373 if fileVersion := asGoVersion(file.GoVersion); fileVersion.isValid() {
374
375
376
377
378
379
380
381
382
383 v = string(versionMax(fileVersion, go1_21))
384
385
386
387
388 if fileVersion.cmp(go_current) > 0 {
389
390
391 check.errorf(file.PkgName, TooNew, "file requires newer Go version %v", fileVersion)
392 }
393 }
394 versions[file.Pos().FileBase()] = v
395 }
396 }
397
398 func versionMax(a, b goVersion) goVersion {
399 if a.cmp(b) > 0 {
400 return a
401 }
402 return b
403 }
404
405
406 func (check *Checker) pushPos(pos syntax.Pos) {
407 check.posStack = append(check.posStack, pos)
408 }
409
410
411 func (check *Checker) popPos() {
412 check.posStack = check.posStack[:len(check.posStack)-1]
413 }
414
415
416 type bailout struct{}
417
418 func (check *Checker) handleBailout(err *error) {
419 switch p := recover().(type) {
420 case nil, bailout:
421
422 *err = check.firstErr
423 default:
424 if len(check.posStack) > 0 {
425 doPrint := func(ps []syntax.Pos) {
426 for i := len(ps) - 1; i >= 0; i-- {
427 fmt.Fprintf(os.Stderr, "\t%v\n", ps[i])
428 }
429 }
430
431 fmt.Fprintln(os.Stderr, "The following panic happened checking types near:")
432 if len(check.posStack) <= 10 {
433 doPrint(check.posStack)
434 } else {
435
436 doPrint(check.posStack[len(check.posStack)-5:])
437 fmt.Fprintln(os.Stderr, "\t...")
438 doPrint(check.posStack[:5])
439 }
440 }
441
442
443 panic(p)
444 }
445 }
446
447
448 func (check *Checker) Files(files []*syntax.File) (err error) {
449 if check.pkg == Unsafe {
450
451
452
453 return nil
454 }
455
456
457
458
459
460 defer check.handleBailout(&err)
461 check.checkFiles(files)
462 return
463 }
464
465
466
467
468
469 func (check *Checker) checkFiles(files []*syntax.File) {
470
471
472 if check.conf.EnableAlias {
473 if atomic.AddInt32(&_aliasAny, 1) <= 0 {
474 panic("EnableAlias set while !EnableAlias type checking is ongoing")
475 }
476 defer atomic.AddInt32(&_aliasAny, -1)
477 } else {
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 }
483
484 print := func(msg string) {
485 if check.conf.Trace {
486 fmt.Println()
487 fmt.Println(msg)
488 }
489 }
490
491 print("== initFiles ==")
492 check.initFiles(files)
493
494 print("== collectObjects ==")
495 check.collectObjects()
496
497 print("== sortObjects ==")
498 check.sortObjects()
499
500 print("== packageObjects ==")
501 check.packageObjects()
502
503 print("== processDelayed ==")
504 check.processDelayed(0)
505
506 print("== cleanup ==")
507 check.cleanup()
508
509 print("== initOrder ==")
510 check.initOrder()
511
512 if !check.conf.DisableUnusedImportCheck {
513 print("== unusedImports ==")
514 check.unusedImports()
515 }
516
517 print("== recordUntyped ==")
518 check.recordUntyped()
519
520 if check.firstErr == nil {
521
522 check.monomorph()
523 }
524
525 check.pkg.goVersion = check.conf.GoVersion
526 check.pkg.complete = true
527
528
529 check.imports = nil
530 check.dotImportMap = nil
531 check.pkgPathMap = nil
532 check.seenPkgMap = nil
533 check.brokenAliases = nil
534 check.unionTypeSets = nil
535 check.usedVars = nil
536 check.usedPkgNames = nil
537 check.ctxt = nil
538
539
540
541 }
542
543
544 func (check *Checker) processDelayed(top int) {
545
546
547
548
549
550
551 savedVersion := check.version
552 for i := top; i < len(check.delayed); i++ {
553 a := &check.delayed[i]
554 if check.conf.Trace {
555 if a.desc != nil {
556 check.trace(a.desc.pos.Pos(), "-- "+a.desc.format, a.desc.args...)
557 } else {
558 check.trace(nopos, "-- delayed %p", a.f)
559 }
560 }
561 check.version = a.version
562 a.f()
563 if check.conf.Trace {
564 fmt.Println()
565 }
566 }
567 assert(top <= len(check.delayed))
568 check.delayed = check.delayed[:top]
569 check.version = savedVersion
570 }
571
572
573 func (check *Checker) cleanup() {
574
575 for i := 0; i < len(check.cleaners); i++ {
576 check.cleaners[i].cleanup()
577 }
578 check.cleaners = nil
579 }
580
581
582 func (check *Checker) recordTypeAndValueInSyntax(x syntax.Expr, mode operandMode, typ Type, val constant.Value) {
583 if check.StoreTypesInSyntax {
584 tv := TypeAndValue{mode, typ, val}
585 stv := syntax.TypeAndValue{Type: typ, Value: val}
586 if tv.IsVoid() {
587 stv.SetIsVoid()
588 }
589 if tv.IsType() {
590 stv.SetIsType()
591 }
592 if tv.IsBuiltin() {
593 stv.SetIsBuiltin()
594 }
595 if tv.IsValue() {
596 stv.SetIsValue()
597 }
598 if tv.IsNil() {
599 stv.SetIsNil()
600 }
601 if tv.Addressable() {
602 stv.SetAddressable()
603 }
604 if tv.Assignable() {
605 stv.SetAssignable()
606 }
607 if tv.HasOk() {
608 stv.SetHasOk()
609 }
610 x.SetTypeInfo(stv)
611 }
612 }
613
614
615 func (check *Checker) recordCommaOkTypesInSyntax(x syntax.Expr, t0, t1 Type) {
616 if check.StoreTypesInSyntax {
617
618
619 for {
620 tv := x.GetTypeInfo()
621 assert(tv.Type != nil)
622 pos := x.Pos()
623 tv.Type = NewTuple(
624 NewParam(pos, check.pkg, "", t0),
625 NewParam(pos, check.pkg, "", t1),
626 )
627 x.SetTypeInfo(tv)
628 p, _ := x.(*syntax.ParenExpr)
629 if p == nil {
630 break
631 }
632 x = p.X
633 }
634 }
635 }
636
637
638
639 func instantiatedIdent(expr syntax.Expr) *syntax.Name {
640 var selOrIdent syntax.Expr
641 switch e := expr.(type) {
642 case *syntax.IndexExpr:
643 selOrIdent = e.X
644 case *syntax.SelectorExpr, *syntax.Name:
645 selOrIdent = e
646 }
647 switch x := selOrIdent.(type) {
648 case *syntax.Name:
649 return x
650 case *syntax.SelectorExpr:
651 return x.Sel
652 }
653
654
655 panic(sprintf(nil, true, "instantiated ident not found; please report: %s", expr))
656 }
657
View as plain text