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