1
2
3
4
5 package types2
6
7 import (
8 "cmd/compile/internal/syntax"
9 "cmp"
10 "fmt"
11 "go/constant"
12 . "internal/types/errors"
13 "slices"
14 "strconv"
15 "strings"
16 "unicode"
17 )
18
19
20 type declInfo struct {
21 file *Scope
22 version goVersion
23 lhs []*Var
24 vtyp syntax.Expr
25 init syntax.Expr
26 inherited bool
27 tdecl *syntax.TypeDecl
28 fdecl *syntax.FuncDecl
29
30
31 deps map[Object]bool
32 }
33
34
35
36 func (d *declInfo) hasInitializer() bool {
37 return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
38 }
39
40
41 func (d *declInfo) addDep(obj Object) {
42 m := d.deps
43 if m == nil {
44 m = make(map[Object]bool)
45 d.deps = m
46 }
47 m[obj] = true
48 }
49
50
51
52
53
54 func (check *Checker) arity(pos syntax.Pos, names []*syntax.Name, inits []syntax.Expr, constDecl, inherited bool) {
55 l := len(names)
56 r := len(inits)
57
58 const code = WrongAssignCount
59 switch {
60 case l < r:
61 n := inits[l]
62 if inherited {
63 check.errorf(pos, code, "extra init expr at %s", n.Pos())
64 } else {
65 check.errorf(n, code, "extra init expr %s", n)
66 }
67 case l > r && (constDecl || r != 1):
68 n := names[r]
69 check.errorf(n, code, "missing init expr for %s", n.Value)
70 }
71 }
72
73 func validatedImportPath(path string) (string, error) {
74 s, err := strconv.Unquote(path)
75 if err != nil {
76 return "", err
77 }
78 if s == "" {
79 return "", fmt.Errorf("empty string")
80 }
81 const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
82 for _, r := range s {
83 if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
84 return s, fmt.Errorf("invalid character %#U", r)
85 }
86 }
87 return s, nil
88 }
89
90
91
92 func (check *Checker) declarePkgObj(ident *syntax.Name, obj Object, d *declInfo) {
93 assert(ident.Value == obj.Name())
94
95
96
97 if ident.Value == "init" {
98 check.error(ident, InvalidInitDecl, "cannot declare init - must be func")
99 return
100 }
101
102
103
104 if ident.Value == "main" && check.pkg.name == "main" {
105 check.error(ident, InvalidMainDecl, "cannot declare main - must be func")
106 return
107 }
108
109 check.declare(check.pkg.scope, ident, obj, nopos)
110 check.objMap[obj] = d
111 obj.setOrder(uint32(len(check.objMap)))
112 }
113
114
115 func (check *Checker) filename(fileNo int) string {
116 file := check.files[fileNo]
117 if pos := file.Pos(); pos.IsKnown() {
118
119
120 return pos.RelFilename()
121 }
122 return fmt.Sprintf("file[%d]", fileNo)
123 }
124
125 func (check *Checker) importPackage(pos syntax.Pos, path, dir string) *Package {
126
127
128
129
130
131 key := importKey{path, dir}
132 imp := check.impMap[key]
133 if imp != nil {
134 return imp
135 }
136
137
138 if path == "C" && (check.conf.FakeImportC || check.conf.go115UsesCgo) {
139 if check.conf.FakeImportC && check.conf.go115UsesCgo {
140 check.error(pos, BadImportPath, "cannot use FakeImportC and go115UsesCgo together")
141 }
142 imp = NewPackage("C", "C")
143 imp.fake = true
144 imp.cgo = check.conf.go115UsesCgo
145 } else {
146
147 var err error
148 if importer := check.conf.Importer; importer == nil {
149 err = fmt.Errorf("Config.Importer not installed")
150 } else if importerFrom, ok := importer.(ImporterFrom); ok {
151 imp, err = importerFrom.ImportFrom(path, dir, 0)
152 if imp == nil && err == nil {
153 err = fmt.Errorf("Config.Importer.ImportFrom(%s, %s, 0) returned nil but no error", path, dir)
154 }
155 } else {
156 imp, err = importer.Import(path)
157 if imp == nil && err == nil {
158 err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path)
159 }
160 }
161
162
163 if err == nil && imp != nil && (imp.name == "_" || imp.name == "") {
164 err = fmt.Errorf("invalid package name: %q", imp.name)
165 imp = nil
166 }
167 if err != nil {
168 check.errorf(pos, BrokenImport, "could not import %s (%s)", path, err)
169 if imp == nil {
170
171
172 name := strings.TrimSuffix(path, "/")
173 if i := strings.LastIndex(name, "/"); i >= 0 {
174 name = name[i+1:]
175 }
176 imp = NewPackage(path, name)
177 }
178
179 imp.fake = true
180 }
181 }
182
183
184 if imp.complete || imp.fake {
185 check.impMap[key] = imp
186
187
188
189 if check.pkgPathMap != nil {
190 check.markImports(imp)
191 }
192 return imp
193 }
194
195
196 return nil
197 }
198
199
200
201
202 func (check *Checker) collectObjects() {
203 pkg := check.pkg
204
205
206
207
208
209
210
211 var pkgImports = make(map[*Package]bool)
212 for _, imp := range pkg.imports {
213 pkgImports[imp] = true
214 }
215
216 type methodInfo struct {
217 obj *Func
218 ptr bool
219 recv *syntax.Name
220 }
221 var methods []methodInfo
222
223 fileScopes := make([]*Scope, len(check.files))
224 for fileNo, file := range check.files {
225 check.version = asGoVersion(check.versions[file.Pos().FileBase()])
226
227
228
229 check.recordDef(file.PkgName, nil)
230
231 fileScope := NewScope(pkg.scope, syntax.StartPos(file), syntax.EndPos(file), check.filename(fileNo))
232 fileScopes[fileNo] = fileScope
233 check.recordScope(file, fileScope)
234
235
236
237
238 fileDir := dir(file.PkgName.Pos().RelFilename())
239
240 first := -1
241 var last *syntax.ConstDecl
242 for index, decl := range file.DeclList {
243 if _, ok := decl.(*syntax.ConstDecl); !ok {
244 first = -1
245 }
246
247 switch s := decl.(type) {
248 case *syntax.ImportDecl:
249
250 if s.Path == nil || s.Path.Bad {
251 continue
252 }
253 path, err := validatedImportPath(s.Path.Value)
254 if err != nil {
255 check.errorf(s.Path, BadImportPath, "invalid import path (%s)", err)
256 continue
257 }
258
259 imp := check.importPackage(s.Path.Pos(), path, fileDir)
260 if imp == nil {
261 continue
262 }
263
264
265 name := imp.name
266 if s.LocalPkgName != nil {
267 name = s.LocalPkgName.Value
268 if path == "C" {
269
270 check.error(s.LocalPkgName, ImportCRenamed, `cannot rename import "C"`)
271 continue
272 }
273 }
274
275 if name == "init" {
276 check.error(s, InvalidInitDecl, "cannot import package as init - init must be a func")
277 continue
278 }
279
280
281
282
283 if !pkgImports[imp] {
284 pkgImports[imp] = true
285 pkg.imports = append(pkg.imports, imp)
286 }
287
288 pkgName := NewPkgName(s.Pos(), pkg, name, imp)
289 if s.LocalPkgName != nil {
290
291 check.recordDef(s.LocalPkgName, pkgName)
292 } else {
293 check.recordImplicit(s, pkgName)
294 }
295
296 if imp.fake {
297
298 check.usedPkgNames[pkgName] = true
299 }
300
301
302 check.imports = append(check.imports, pkgName)
303 if name == "." {
304
305 if check.dotImportMap == nil {
306 check.dotImportMap = make(map[dotImportKey]*PkgName)
307 }
308
309 for name, obj := range imp.scope.elems {
310
311
312
313
314
315 if isExported(name) {
316
317
318
319
320
321 if alt := fileScope.Lookup(name); alt != nil {
322 err := check.newError(DuplicateDecl)
323 err.addf(s.LocalPkgName, "%s redeclared in this block", alt.Name())
324 err.addAltDecl(alt)
325 err.report()
326 } else {
327 fileScope.insert(name, obj)
328 check.dotImportMap[dotImportKey{fileScope, name}] = pkgName
329 }
330 }
331 }
332 } else {
333
334
335 check.declare(fileScope, nil, pkgName, nopos)
336 }
337
338 case *syntax.ConstDecl:
339
340 if first < 0 || s.Group == nil || file.DeclList[index-1].(*syntax.ConstDecl).Group != s.Group {
341 first = index
342 last = nil
343 }
344 iota := constant.MakeInt64(int64(index - first))
345
346
347 inherited := true
348 switch {
349 case s.Type != nil || s.Values != nil:
350 last = s
351 inherited = false
352 case last == nil:
353 last = new(syntax.ConstDecl)
354 inherited = false
355 }
356
357
358 values := syntax.UnpackListExpr(last.Values)
359 for i, name := range s.NameList {
360 obj := NewConst(name.Pos(), pkg, name.Value, nil, iota)
361
362 var init syntax.Expr
363 if i < len(values) {
364 init = values[i]
365 }
366
367 d := &declInfo{file: fileScope, version: check.version, vtyp: last.Type, init: init, inherited: inherited}
368 check.declarePkgObj(name, obj, d)
369 }
370
371
372 check.arity(s.Pos(), s.NameList, values, true, inherited)
373
374 case *syntax.VarDecl:
375 lhs := make([]*Var, len(s.NameList))
376
377
378
379
380 var d1 *declInfo
381 if _, ok := s.Values.(*syntax.ListExpr); !ok {
382
383
384
385 d1 = &declInfo{file: fileScope, version: check.version, lhs: lhs, vtyp: s.Type, init: s.Values}
386 }
387
388
389 values := syntax.UnpackListExpr(s.Values)
390 for i, name := range s.NameList {
391 obj := newVar(PackageVar, name.Pos(), pkg, name.Value, nil)
392 lhs[i] = obj
393
394 d := d1
395 if d == nil {
396
397 var init syntax.Expr
398 if i < len(values) {
399 init = values[i]
400 }
401 d = &declInfo{file: fileScope, version: check.version, vtyp: s.Type, init: init}
402 }
403
404 check.declarePkgObj(name, obj, d)
405 }
406
407
408 if s.Type == nil || values != nil {
409 check.arity(s.Pos(), s.NameList, values, false, false)
410 }
411
412 case *syntax.TypeDecl:
413 obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
414 check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, version: check.version, tdecl: s})
415
416 case *syntax.FuncDecl:
417 name := s.Name.Value
418 obj := NewFunc(s.Name.Pos(), pkg, name, nil)
419 hasTParamError := false
420 if s.Recv == nil {
421
422 if name == "init" || name == "main" && pkg.name == "main" {
423 code := InvalidInitDecl
424 if name == "main" {
425 code = InvalidMainDecl
426 }
427 if len(s.TParamList) != 0 {
428 check.softErrorf(s.TParamList[0], code, "func %s must have no type parameters", name)
429 hasTParamError = true
430 }
431 if t := s.Type; len(t.ParamList) != 0 || len(t.ResultList) != 0 {
432 check.softErrorf(s.Name, code, "func %s must have no arguments and no return values", name)
433 }
434 }
435
436 if name == "init" {
437 obj.parent = pkg.scope
438 check.recordDef(s.Name, obj)
439 if s.Body == nil {
440 check.softErrorf(obj.pos, MissingInitBody, "func init must have a body")
441 }
442 } else {
443 check.declare(pkg.scope, s.Name, obj, nopos)
444 }
445 } else {
446
447
448 ptr, base, _ := check.unpackRecv(s.Recv.Type, false)
449
450
451
452 if recv, _ := base.(*syntax.Name); recv != nil && name != "_" {
453 methods = append(methods, methodInfo{obj, ptr, recv})
454 }
455 check.recordDef(s.Name, obj)
456 }
457 _ = len(s.TParamList) != 0 && !hasTParamError && check.verifyVersionf(s.TParamList[0], go1_18, "type parameter")
458 info := &declInfo{file: fileScope, version: check.version, fdecl: s}
459
460
461
462
463 check.objMap[obj] = info
464 obj.setOrder(uint32(len(check.objMap)))
465
466 default:
467 check.errorf(s, InvalidSyntaxTree, "unknown syntax.Decl node %T", s)
468 }
469 }
470 }
471
472
473 for _, scope := range fileScopes {
474 for name, obj := range scope.elems {
475 if alt := pkg.scope.Lookup(name); alt != nil {
476 obj = resolve(name, obj)
477 err := check.newError(DuplicateDecl)
478 if pkg, ok := obj.(*PkgName); ok {
479 err.addf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported())
480 err.addAltDecl(pkg)
481 } else {
482 err.addf(alt, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
483
484 err.addAltDecl(obj)
485 }
486 err.report()
487 }
488 }
489 }
490
491
492
493
494
495 if methods == nil {
496 return
497 }
498
499 check.methods = make(map[*TypeName][]*Func)
500 for i := range methods {
501 m := &methods[i]
502
503 ptr, base := check.resolveBaseTypeName(m.ptr, m.recv)
504 if base != nil {
505 m.obj.hasPtrRecv_ = ptr
506 check.methods[base] = append(check.methods[base], m.obj)
507 }
508 }
509 }
510
511
512
513
514
515
516
517
518
519
520 func (check *Checker) unpackRecv(rtyp syntax.Expr, unpackParams bool) (ptr bool, base syntax.Expr, tparams []*syntax.Name) {
521
522 base = syntax.Unparen(rtyp)
523 if t, _ := base.(*syntax.Operation); t != nil && t.Op == syntax.Mul && t.Y == nil {
524 ptr = true
525 base = syntax.Unparen(t.X)
526 }
527
528
529 if ptyp, _ := base.(*syntax.IndexExpr); ptyp != nil {
530 base = ptyp.X
531 if unpackParams {
532 for _, arg := range syntax.UnpackListExpr(ptyp.Index) {
533 var par *syntax.Name
534 switch arg := arg.(type) {
535 case *syntax.Name:
536 par = arg
537 case *syntax.BadExpr:
538
539 case nil:
540 check.error(ptyp, InvalidSyntaxTree, "parameterized receiver contains nil parameters")
541 default:
542 check.errorf(arg, BadDecl, "receiver type parameter %s must be an identifier", arg)
543 }
544 if par == nil {
545 par = syntax.NewName(arg.Pos(), "_")
546 }
547 tparams = append(tparams, par)
548 }
549
550 }
551 }
552
553 return
554 }
555
556
557
558
559
560
561 func (check *Checker) resolveBaseTypeName(ptr bool, name *syntax.Name) (ptr_ bool, base *TypeName) {
562
563
564
565 var seen map[*TypeName]bool
566 for name != nil {
567
568
569 obj := check.pkg.scope.Lookup(name.Value)
570 if obj == nil {
571 break
572 }
573
574
575 tname, _ := obj.(*TypeName)
576 if tname == nil {
577 break
578 }
579
580
581 if seen[tname] {
582 break
583 }
584
585
586 tdecl := check.objMap[tname].tdecl
587 if !tdecl.Alias {
588 return ptr, tname
589 }
590
591
592
593 if tdecl.TParamList != nil {
594 break
595 }
596
597
598 if seen == nil {
599 seen = make(map[*TypeName]bool)
600 }
601 seen[tname] = true
602
603
604 typ := syntax.Unparen(tdecl.Type)
605
606
607 if pexpr, _ := typ.(*syntax.Operation); pexpr != nil && pexpr.Op == syntax.Mul && pexpr.Y == nil {
608
609 if ptr {
610 break
611 }
612 ptr = true
613 typ = syntax.Unparen(pexpr.X)
614 }
615
616
617
618
619
620 name, _ = typ.(*syntax.Name)
621 }
622
623
624 return false, nil
625 }
626
627
628 func (check *Checker) packageObjects() {
629
630 objList := make([]Object, len(check.objMap))
631 i := 0
632 for obj := range check.objMap {
633 objList[i] = obj
634 i++
635 }
636 slices.SortFunc(objList, func(a, b Object) int {
637 return cmp.Compare(a.order(), b.order())
638 })
639
640
641 for _, obj := range objList {
642 if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil {
643 check.collectMethods(obj)
644 }
645 }
646
647 if false && check.conf.EnableAlias {
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664 for _, obj := range objList {
665 check.objDecl(obj, nil)
666 }
667 } else {
668
669
670
671
672
673 var aliasList []*TypeName
674 var othersList []Object
675
676 for _, obj := range objList {
677 if tname, _ := obj.(*TypeName); tname != nil {
678 if check.objMap[tname].tdecl.Alias {
679 aliasList = append(aliasList, tname)
680 } else {
681 check.objDecl(obj, nil)
682 }
683 } else {
684 othersList = append(othersList, obj)
685 }
686 }
687
688 for _, obj := range aliasList {
689 check.objDecl(obj, nil)
690 }
691
692 for _, obj := range othersList {
693 check.objDecl(obj, nil)
694 }
695 }
696
697
698
699
700
701 check.methods = nil
702 }
703
704
705 func (check *Checker) unusedImports() {
706
707 if check.conf.IgnoreFuncBodies {
708 return
709 }
710
711
712
713
714
715 for _, obj := range check.imports {
716 if obj.name != "_" && !check.usedPkgNames[obj] {
717 check.errorUnusedPkg(obj)
718 }
719 }
720 }
721
722 func (check *Checker) errorUnusedPkg(obj *PkgName) {
723
724
725
726
727
728
729 path := obj.imported.path
730 elem := path
731 if i := strings.LastIndex(elem, "/"); i >= 0 {
732 elem = elem[i+1:]
733 }
734 if obj.name == "" || obj.name == "." || obj.name == elem {
735 check.softErrorf(obj, UnusedImport, "%q imported and not used", path)
736 } else {
737 check.softErrorf(obj, UnusedImport, "%q imported as %s and not used", path, obj.name)
738 }
739 }
740
741
742
743
744
745 func dir(path string) string {
746 if i := strings.LastIndexAny(path, `/\`); i > 0 {
747 return path[:i]
748 }
749
750 return "."
751 }
752
View as plain text