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