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 package %s", name, 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
331
332 for _, file := range check.files {
333
334
335
336 v := check.conf.GoVersion
337
338
339 if fileVersion := asGoVersion(file.GoVersion); fileVersion.isValid() {
340
341
342
343
344
345
346
347
348
349 v = string(versionMax(fileVersion, go1_21))
350
351
352
353
354 if fileVersion.cmp(go_current) > 0 {
355
356
357 check.errorf(file.PkgName, TooNew, "file requires newer Go version %v", fileVersion)
358 }
359 }
360 versions[file.Pos().FileBase()] = v
361 }
362 }
363
364 func versionMax(a, b goVersion) goVersion {
365 if a.cmp(b) > 0 {
366 return a
367 }
368 return b
369 }
370
371
372 type bailout struct{}
373
374 func (check *Checker) handleBailout(err *error) {
375 switch p := recover().(type) {
376 case nil, bailout:
377
378 *err = check.firstErr
379 default:
380
381 panic(p)
382 }
383 }
384
385
386 func (check *Checker) Files(files []*syntax.File) (err error) {
387 if check.pkg == Unsafe {
388
389
390
391 return nil
392 }
393
394
395
396
397
398 defer check.handleBailout(&err)
399 check.checkFiles(files)
400 return
401 }
402
403
404
405
406
407 func (check *Checker) checkFiles(files []*syntax.File) {
408
409
410 if check.conf.EnableAlias {
411 if atomic.AddInt32(&_aliasAny, 1) <= 0 {
412 panic("EnableAlias set while !EnableAlias type checking is ongoing")
413 }
414 defer atomic.AddInt32(&_aliasAny, -1)
415 } else {
416 if atomic.AddInt32(&_aliasAny, -1) >= 0 {
417 panic("!EnableAlias set while EnableAlias type checking is ongoing")
418 }
419 defer atomic.AddInt32(&_aliasAny, 1)
420 }
421
422 print := func(msg string) {
423 if check.conf.Trace {
424 fmt.Println()
425 fmt.Println(msg)
426 }
427 }
428
429 print("== initFiles ==")
430 check.initFiles(files)
431
432 print("== collectObjects ==")
433 check.collectObjects()
434
435 print("== packageObjects ==")
436 check.packageObjects()
437
438 print("== processDelayed ==")
439 check.processDelayed(0)
440
441 print("== cleanup ==")
442 check.cleanup()
443
444 print("== initOrder ==")
445 check.initOrder()
446
447 if !check.conf.DisableUnusedImportCheck {
448 print("== unusedImports ==")
449 check.unusedImports()
450 }
451
452 print("== recordUntyped ==")
453 check.recordUntyped()
454
455 if check.firstErr == nil {
456
457 check.monomorph()
458 }
459
460 check.pkg.goVersion = check.conf.GoVersion
461 check.pkg.complete = true
462
463
464 check.imports = nil
465 check.dotImportMap = nil
466 check.pkgPathMap = nil
467 check.seenPkgMap = nil
468 check.recvTParamMap = nil
469 check.brokenAliases = nil
470 check.unionTypeSets = nil
471 check.ctxt = nil
472
473
474 }
475
476
477 func (check *Checker) processDelayed(top int) {
478
479
480
481
482
483
484 for i := top; i < len(check.delayed); i++ {
485 a := &check.delayed[i]
486 if check.conf.Trace {
487 if a.desc != nil {
488 check.trace(a.desc.pos.Pos(), "-- "+a.desc.format, a.desc.args...)
489 } else {
490 check.trace(nopos, "-- delayed %p", a.f)
491 }
492 }
493 a.f()
494 if check.conf.Trace {
495 fmt.Println()
496 }
497 }
498 assert(top <= len(check.delayed))
499 check.delayed = check.delayed[:top]
500 }
501
502
503 func (check *Checker) cleanup() {
504
505 for i := 0; i < len(check.cleaners); i++ {
506 check.cleaners[i].cleanup()
507 }
508 check.cleaners = nil
509 }
510
511 func (check *Checker) record(x *operand) {
512
513
514 var typ Type
515 var val constant.Value
516 switch x.mode {
517 case invalid:
518 typ = Typ[Invalid]
519 case novalue:
520 typ = (*Tuple)(nil)
521 case constant_:
522 typ = x.typ
523 val = x.val
524 default:
525 typ = x.typ
526 }
527 assert(x.expr != nil && typ != nil)
528
529 if isUntyped(typ) {
530
531
532 check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
533 } else {
534 check.recordTypeAndValue(x.expr, x.mode, typ, val)
535 }
536 }
537
538 func (check *Checker) recordUntyped() {
539 if !debug && !check.recordTypes() {
540 return
541 }
542
543 for x, info := range check.untyped {
544 if debug && isTyped(info.typ) {
545 check.dump("%v: %s (type %s) is typed", atPos(x), x, info.typ)
546 panic("unreachable")
547 }
548 check.recordTypeAndValue(x, info.mode, info.typ, info.val)
549 }
550 }
551
552 func (check *Checker) recordTypeAndValue(x syntax.Expr, mode operandMode, typ Type, val constant.Value) {
553 assert(x != nil)
554 assert(typ != nil)
555 if mode == invalid {
556 return
557 }
558 if mode == constant_ {
559 assert(val != nil)
560
561
562 assert(!isValid(typ) || allBasic(typ, IsConstType))
563 }
564 if m := check.Types; m != nil {
565 m[x] = TypeAndValue{mode, typ, val}
566 }
567 if check.StoreTypesInSyntax {
568 tv := TypeAndValue{mode, typ, val}
569 stv := syntax.TypeAndValue{Type: typ, Value: val}
570 if tv.IsVoid() {
571 stv.SetIsVoid()
572 }
573 if tv.IsType() {
574 stv.SetIsType()
575 }
576 if tv.IsBuiltin() {
577 stv.SetIsBuiltin()
578 }
579 if tv.IsValue() {
580 stv.SetIsValue()
581 }
582 if tv.IsNil() {
583 stv.SetIsNil()
584 }
585 if tv.Addressable() {
586 stv.SetAddressable()
587 }
588 if tv.Assignable() {
589 stv.SetAssignable()
590 }
591 if tv.HasOk() {
592 stv.SetHasOk()
593 }
594 x.SetTypeInfo(stv)
595 }
596 }
597
598 func (check *Checker) recordBuiltinType(f syntax.Expr, sig *Signature) {
599
600
601
602
603 for {
604 check.recordTypeAndValue(f, builtin, sig, nil)
605 switch p := f.(type) {
606 case *syntax.Name, *syntax.SelectorExpr:
607 return
608 case *syntax.ParenExpr:
609 f = p.X
610 default:
611 panic("unreachable")
612 }
613 }
614 }
615
616
617
618 func (check *Checker) recordCommaOkTypes(x syntax.Expr, a []*operand) {
619 assert(x != nil)
620 assert(len(a) == 2)
621 if a[0].mode == invalid {
622 return
623 }
624 t0, t1 := a[0].typ, a[1].typ
625 assert(isTyped(t0) && isTyped(t1) && (allBoolean(t1) || t1 == universeError))
626 if m := check.Types; m != nil {
627 for {
628 tv := m[x]
629 assert(tv.Type != nil)
630 pos := x.Pos()
631 tv.Type = NewTuple(
632 NewVar(pos, check.pkg, "", t0),
633 NewVar(pos, check.pkg, "", t1),
634 )
635 m[x] = tv
636
637 p, _ := x.(*syntax.ParenExpr)
638 if p == nil {
639 break
640 }
641 x = p.X
642 }
643 }
644 if check.StoreTypesInSyntax {
645
646
647 for {
648 tv := x.GetTypeInfo()
649 assert(tv.Type != nil)
650 pos := x.Pos()
651 tv.Type = NewTuple(
652 NewVar(pos, check.pkg, "", t0),
653 NewVar(pos, check.pkg, "", t1),
654 )
655 x.SetTypeInfo(tv)
656 p, _ := x.(*syntax.ParenExpr)
657 if p == nil {
658 break
659 }
660 x = p.X
661 }
662 }
663 }
664
665
666
667
668
669
670
671 func (check *Checker) recordInstance(expr syntax.Expr, targs []Type, typ Type) {
672 ident := instantiatedIdent(expr)
673 assert(ident != nil)
674 assert(typ != nil)
675 if m := check.Instances; m != nil {
676 m[ident] = Instance{newTypeList(targs), typ}
677 }
678 }
679
680 func instantiatedIdent(expr syntax.Expr) *syntax.Name {
681 var selOrIdent syntax.Expr
682 switch e := expr.(type) {
683 case *syntax.IndexExpr:
684 selOrIdent = e.X
685 case *syntax.SelectorExpr, *syntax.Name:
686 selOrIdent = e
687 }
688 switch x := selOrIdent.(type) {
689 case *syntax.Name:
690 return x
691 case *syntax.SelectorExpr:
692 return x.Sel
693 }
694 panic("instantiated ident not found")
695 }
696
697 func (check *Checker) recordDef(id *syntax.Name, obj Object) {
698 assert(id != nil)
699 if m := check.Defs; m != nil {
700 m[id] = obj
701 }
702 }
703
704 func (check *Checker) recordUse(id *syntax.Name, obj Object) {
705 assert(id != nil)
706 assert(obj != nil)
707 if m := check.Uses; m != nil {
708 m[id] = obj
709 }
710 }
711
712 func (check *Checker) recordImplicit(node syntax.Node, obj Object) {
713 assert(node != nil)
714 assert(obj != nil)
715 if m := check.Implicits; m != nil {
716 m[node] = obj
717 }
718 }
719
720 func (check *Checker) recordSelection(x *syntax.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
721 assert(obj != nil && (recv == nil || len(index) > 0))
722 check.recordUse(x.Sel, obj)
723 if m := check.Selections; m != nil {
724 m[x] = &Selection{kind, recv, obj, index, indirect}
725 }
726 }
727
728 func (check *Checker) recordScope(node syntax.Node, scope *Scope) {
729 assert(node != nil)
730 assert(scope != nil)
731 if m := check.Scopes; m != nil {
732 m[node] = scope
733 }
734 }
735
View as plain text