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