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 )
16
17
18 var nopos syntax.Pos
19
20
21 const debug = false
22
23
24 const tracePos = true
25
26
27 type exprInfo struct {
28 isLhs bool
29 mode operandMode
30 typ *Basic
31 val constant.Value
32 }
33
34
35
36 type environment struct {
37 decl *declInfo
38 scope *Scope
39 version goVersion
40 iota constant.Value
41 errpos syntax.Pos
42 inTParamList bool
43 sig *Signature
44 isPanic map[*syntax.CallExpr]bool
45 hasLabel bool
46 hasCallOrRecv bool
47 }
48
49
50
51
52
53
54
55
56
57 func (env *environment) lookupScope(name string) (*Scope, Object) {
58 for s := env.scope; s != nil; s = s.parent {
59 if obj := s.Lookup(name); obj != nil {
60 return s, obj
61 }
62 }
63 return nil, nil
64 }
65
66
67 func (env *environment) lookup(name string) Object {
68 _, obj := env.lookupScope(name)
69 return obj
70 }
71
72
73
74
75
76
77
78 type importKey struct {
79 path, dir string
80 }
81
82
83 type dotImportKey struct {
84 scope *Scope
85 name string
86 }
87
88
89 type action struct {
90 version goVersion
91 f func()
92 desc *actionDesc
93 }
94
95
96
97 func (a *action) describef(pos poser, format string, args ...any) {
98 if debug {
99 a.desc = &actionDesc{pos, format, args}
100 }
101 }
102
103
104
105 type actionDesc struct {
106 pos poser
107 format string
108 args []any
109 }
110
111
112
113 type Checker struct {
114
115
116 conf *Config
117 ctxt *Context
118 pkg *Package
119 *Info
120 nextID uint64
121 objMap map[Object]*declInfo
122 objList []Object
123 impMap map[importKey]*Package
124
125
126
127
128
129
130
131
132
133
134 pkgPathMap map[string]map[string]bool
135 seenPkgMap map[*Package]bool
136
137
138
139
140 files []*syntax.File
141 versions map[*syntax.PosBase]string
142 imports []*PkgName
143 dotImportMap map[dotImportKey]*PkgName
144 brokenAliases map[*TypeName]bool
145 unionTypeSets map[*Union]*_TypeSet
146 usedVars map[*Var]bool
147 usedPkgNames map[*PkgName]bool
148 mono monoGraph
149
150 firstErr error
151 methods map[*TypeName][]*Func
152 untyped map[syntax.Expr]exprInfo
153 delayed []action
154 objPath []Object
155 objPathIdx map[Object]int
156 cleaners []cleaner
157
158
159
160 environment
161
162
163 posStack []syntax.Pos
164 indent int
165 }
166
167
168 func (check *Checker) addDeclDep(to Object) {
169 from := check.decl
170 if from == nil {
171 return
172 }
173 if _, found := check.objMap[to]; !found {
174 return
175 }
176 from.addDep(to)
177 }
178
179 func (check *Checker) rememberUntyped(e syntax.Expr, lhs bool, mode operandMode, typ *Basic, val constant.Value) {
180 m := check.untyped
181 if m == nil {
182 m = make(map[syntax.Expr]exprInfo)
183 check.untyped = m
184 }
185 m[e] = exprInfo{lhs, mode, typ, val}
186 }
187
188
189
190
191
192
193
194 func (check *Checker) later(f func()) *action {
195 i := len(check.delayed)
196 check.delayed = append(check.delayed, action{version: check.version, f: f})
197 return &check.delayed[i]
198 }
199
200
201 func (check *Checker) push(obj Object) {
202 if check.objPathIdx == nil {
203 check.objPathIdx = make(map[Object]int)
204 }
205 check.objPathIdx[obj] = len(check.objPath)
206 check.objPath = append(check.objPath, obj)
207 }
208
209
210 func (check *Checker) pop() {
211 i := len(check.objPath) - 1
212 obj := check.objPath[i]
213 check.objPath[i] = nil
214 check.objPath = check.objPath[:i]
215 delete(check.objPathIdx, obj)
216 }
217
218 type cleaner interface {
219 cleanup()
220 }
221
222
223
224 func (check *Checker) needsCleanup(c cleaner) {
225 check.cleaners = append(check.cleaners, c)
226 }
227
228
229
230 func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
231
232 if conf == nil {
233 conf = new(Config)
234 }
235
236
237 if info == nil {
238 info = new(Info)
239 }
240
241
242
243
244
245
246
247 return &Checker{
248 conf: conf,
249 ctxt: conf.Context,
250 pkg: pkg,
251 Info: info,
252 objMap: make(map[Object]*declInfo),
253 impMap: make(map[importKey]*Package),
254 usedVars: make(map[*Var]bool),
255 usedPkgNames: make(map[*PkgName]bool),
256 }
257 }
258
259
260
261 func (check *Checker) initFiles(files []*syntax.File) {
262
263
264
265 check.files = nil
266 check.imports = nil
267 check.dotImportMap = nil
268
269 check.firstErr = nil
270 check.methods = nil
271 check.untyped = nil
272 check.delayed = nil
273 check.objPath = nil
274 check.objPathIdx = nil
275 check.cleaners = nil
276
277
278
279
280
281 check.usedVars = make(map[*Var]bool)
282 check.usedPkgNames = make(map[*PkgName]bool)
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 package %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 pkgVersion := asGoVersion(check.conf.GoVersion)
313 if pkgVersion.isValid() && len(files) > 0 && pkgVersion.cmp(go_current) > 0 {
314 check.errorf(files[0], TooNew, "package requires newer Go version %v (application built with %v)",
315 pkgVersion, go_current)
316 }
317
318
319 for _, file := range check.files {
320
321
322
323 v := check.conf.GoVersion
324
325
326 if fileVersion := asGoVersion(file.GoVersion); fileVersion.isValid() {
327
328
329
330
331
332
333
334
335
336 v = string(versionMax(fileVersion, go1_21))
337
338
339
340
341 if fileVersion.cmp(go_current) > 0 {
342
343
344 check.errorf(file.PkgName, TooNew, "file requires newer Go version %v", fileVersion)
345 }
346 }
347 versions[file.Pos().FileBase()] = v
348 }
349 }
350
351 func versionMax(a, b goVersion) goVersion {
352 if a.cmp(b) > 0 {
353 return a
354 }
355 return b
356 }
357
358
359 func (check *Checker) pushPos(pos syntax.Pos) {
360 check.posStack = append(check.posStack, pos)
361 }
362
363
364 func (check *Checker) popPos() {
365 check.posStack = check.posStack[:len(check.posStack)-1]
366 }
367
368
369 type bailout struct{}
370
371 func (check *Checker) handleBailout(err *error) {
372 switch p := recover().(type) {
373 case nil, bailout:
374
375 *err = check.firstErr
376 default:
377 if len(check.posStack) > 0 {
378 doPrint := func(ps []syntax.Pos) {
379 for i := len(ps) - 1; i >= 0; i-- {
380 fmt.Fprintf(os.Stderr, "\t%v\n", ps[i])
381 }
382 }
383
384 fmt.Fprintln(os.Stderr, "The following panic happened checking types near:")
385 if len(check.posStack) <= 10 {
386 doPrint(check.posStack)
387 } else {
388
389 doPrint(check.posStack[len(check.posStack)-5:])
390 fmt.Fprintln(os.Stderr, "\t...")
391 doPrint(check.posStack[:5])
392 }
393 }
394
395
396 panic(p)
397 }
398 }
399
400
401 func (check *Checker) Files(files []*syntax.File) (err error) {
402 if check.pkg == Unsafe {
403
404
405
406 return nil
407 }
408
409
410
411
412
413 defer check.handleBailout(&err)
414 check.checkFiles(files)
415 return
416 }
417
418
419
420
421
422 func (check *Checker) checkFiles(files []*syntax.File) {
423 print := func(msg string) {
424 if check.conf.Trace {
425 fmt.Println()
426 fmt.Println(msg)
427 }
428 }
429
430 print("== initFiles ==")
431 check.initFiles(files)
432
433 print("== collectObjects ==")
434 check.collectObjects()
435
436 print("== sortObjects ==")
437 check.sortObjects()
438
439 print("== directCycles ==")
440 check.directCycles()
441
442 print("== packageObjects ==")
443 check.packageObjects()
444
445 print("== processDelayed ==")
446 check.processDelayed(0)
447
448 print("== cleanup ==")
449 check.cleanup()
450
451 print("== initOrder ==")
452 check.initOrder()
453
454 if !check.conf.DisableUnusedImportCheck {
455 print("== unusedImports ==")
456 check.unusedImports()
457 }
458
459 print("== recordUntyped ==")
460 check.recordUntyped()
461
462 if check.firstErr == nil {
463
464 check.monomorph()
465 }
466
467 check.pkg.goVersion = check.conf.GoVersion
468 check.pkg.complete = true
469
470
471 check.imports = nil
472 check.dotImportMap = nil
473 check.pkgPathMap = nil
474 check.seenPkgMap = nil
475 check.brokenAliases = nil
476 check.unionTypeSets = nil
477 check.usedVars = nil
478 check.usedPkgNames = nil
479 check.ctxt = nil
480
481
482
483 }
484
485
486 func (check *Checker) processDelayed(top int) {
487
488
489
490
491
492
493 savedVersion := check.version
494 for i := top; i < len(check.delayed); i++ {
495 a := &check.delayed[i]
496 if check.conf.Trace {
497 if a.desc != nil {
498 check.trace(a.desc.pos.Pos(), "-- "+a.desc.format, a.desc.args...)
499 } else {
500 check.trace(nopos, "-- delayed %p", a.f)
501 }
502 }
503 check.version = a.version
504 a.f()
505 if check.conf.Trace {
506 fmt.Println()
507 }
508 }
509 assert(top <= len(check.delayed))
510 check.delayed = check.delayed[:top]
511 check.version = savedVersion
512 }
513
514
515 func (check *Checker) cleanup() {
516
517 for i := 0; i < len(check.cleaners); i++ {
518 check.cleaners[i].cleanup()
519 }
520 check.cleaners = nil
521 }
522
523
524 func (check *Checker) recordTypeAndValueInSyntax(x syntax.Expr, mode operandMode, typ Type, val constant.Value) {
525 if check.StoreTypesInSyntax {
526 tv := TypeAndValue{mode, typ, val}
527 stv := syntax.TypeAndValue{Type: typ, Value: val}
528 if tv.IsVoid() {
529 stv.SetIsVoid()
530 }
531 if tv.IsType() {
532 stv.SetIsType()
533 }
534 if tv.IsBuiltin() {
535 stv.SetIsBuiltin()
536 }
537 if tv.IsValue() {
538 stv.SetIsValue()
539 }
540 if tv.IsNil() {
541 stv.SetIsNil()
542 }
543 if tv.Addressable() {
544 stv.SetAddressable()
545 }
546 if tv.Assignable() {
547 stv.SetAssignable()
548 }
549 if tv.HasOk() {
550 stv.SetHasOk()
551 }
552 x.SetTypeInfo(stv)
553 }
554 }
555
556
557 func (check *Checker) recordCommaOkTypesInSyntax(x syntax.Expr, t0, t1 Type) {
558 if check.StoreTypesInSyntax {
559
560
561 for {
562 tv := x.GetTypeInfo()
563 assert(tv.Type != nil)
564 pos := x.Pos()
565 tv.Type = NewTuple(
566 NewParam(pos, check.pkg, "", t0),
567 NewParam(pos, check.pkg, "", t1),
568 )
569 x.SetTypeInfo(tv)
570 p, _ := x.(*syntax.ParenExpr)
571 if p == nil {
572 break
573 }
574 x = p.X
575 }
576 }
577 }
578
579
580
581 func instantiatedIdent(expr syntax.Expr) *syntax.Name {
582 var selOrIdent syntax.Expr
583 switch e := expr.(type) {
584 case *syntax.IndexExpr:
585 selOrIdent = e.X
586 case *syntax.SelectorExpr, *syntax.Name:
587 selOrIdent = e
588 }
589 switch x := selOrIdent.(type) {
590 case *syntax.Name:
591 return x
592 case *syntax.SelectorExpr:
593 return x.Sel
594 }
595
596
597 panic(sprintf(nil, true, "instantiated ident not found; please report: %s", expr))
598 }
599
View as plain text