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 pkgName.used = 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(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
440 if s.Body == nil {
441
442 check.softErrorf(obj.pos, MissingInitBody, "missing function body")
443 }
444 } else {
445 check.declare(pkg.scope, s.Name, obj, nopos)
446 }
447 } else {
448
449
450 ptr, base, _ := check.unpackRecv(s.Recv.Type, false)
451
452
453
454 if recv, _ := base.(*syntax.Name); recv != nil && name != "_" {
455 methods = append(methods, methodInfo{obj, ptr, recv})
456 }
457 check.recordDef(s.Name, obj)
458 }
459 _ = len(s.TParamList) != 0 && !hasTParamError && check.verifyVersionf(s.TParamList[0], go1_18, "type parameter")
460 info := &declInfo{file: fileScope, version: check.version, fdecl: s}
461
462
463
464
465 check.objMap[obj] = info
466 obj.setOrder(uint32(len(check.objMap)))
467
468 default:
469 check.errorf(s, InvalidSyntaxTree, "unknown syntax.Decl node %T", s)
470 }
471 }
472 }
473
474
475 for _, scope := range fileScopes {
476 for name, obj := range scope.elems {
477 if alt := pkg.scope.Lookup(name); alt != nil {
478 obj = resolve(name, obj)
479 err := check.newError(DuplicateDecl)
480 if pkg, ok := obj.(*PkgName); ok {
481 err.addf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported())
482 err.addAltDecl(pkg)
483 } else {
484 err.addf(alt, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
485
486 err.addAltDecl(obj)
487 }
488 err.report()
489 }
490 }
491 }
492
493
494
495
496
497 if methods == nil {
498 return
499 }
500
501
502
503
504
505
506 lookupScope := func(name *syntax.Name) *Scope {
507 for i, file := range check.files {
508 found := false
509 syntax.Inspect(file, func(n syntax.Node) bool {
510 if found {
511 return false
512 }
513 switch n := n.(type) {
514 case *syntax.Name:
515 if n == name {
516 found = true
517 return false
518 }
519 case *syntax.BlockStmt:
520 return false
521 }
522 return true
523 })
524 if found {
525 return fileScopes[i]
526 }
527 }
528 return nil
529 }
530
531 check.methods = make(map[*TypeName][]*Func)
532 for i := range methods {
533 m := &methods[i]
534
535 ptr, base := check.resolveBaseTypeName(m.ptr, m.recv, lookupScope)
536 if base != nil {
537 m.obj.hasPtrRecv_ = ptr
538 check.methods[base] = append(check.methods[base], m.obj)
539 }
540 }
541 }
542
543
544
545
546
547
548
549
550
551
552 func (check *Checker) unpackRecv(rtyp syntax.Expr, unpackParams bool) (ptr bool, base syntax.Expr, tparams []*syntax.Name) {
553
554 base = syntax.Unparen(rtyp)
555 if t, _ := base.(*syntax.Operation); t != nil && t.Op == syntax.Mul && t.Y == nil {
556 ptr = true
557 base = syntax.Unparen(t.X)
558 }
559
560
561 if ptyp, _ := base.(*syntax.IndexExpr); ptyp != nil {
562 base = ptyp.X
563 if unpackParams {
564 for _, arg := range syntax.UnpackListExpr(ptyp.Index) {
565 var par *syntax.Name
566 switch arg := arg.(type) {
567 case *syntax.Name:
568 par = arg
569 case *syntax.BadExpr:
570
571 case nil:
572 check.error(ptyp, InvalidSyntaxTree, "parameterized receiver contains nil parameters")
573 default:
574 check.errorf(arg, BadDecl, "receiver type parameter %s must be an identifier", arg)
575 }
576 if par == nil {
577 par = syntax.NewName(arg.Pos(), "_")
578 }
579 tparams = append(tparams, par)
580 }
581
582 }
583 }
584
585 return
586 }
587
588
589
590
591
592 func (check *Checker) resolveBaseTypeName(seenPtr bool, typ syntax.Expr, lookupScope func(*syntax.Name) *Scope) (ptr bool, base *TypeName) {
593
594
595
596
597
598 ptr = seenPtr
599 var seen map[*TypeName]bool
600 for {
601
602
603 if pexpr, _ := typ.(*syntax.Operation); pexpr != nil && pexpr.Op == syntax.Mul && pexpr.Y == nil {
604
605 if ptr {
606 return false, nil
607 }
608 ptr = true
609 typ = syntax.Unparen(pexpr.X)
610 }
611
612
613 var name string
614 switch typ := typ.(type) {
615 case *syntax.Name:
616 name = typ.Value
617 case *syntax.SelectorExpr:
618
619
620
621
622
623
624 if ident, _ := typ.X.(*syntax.Name); ident != nil && ident.Value == "C" {
625
626
627 obj := lookupScope(ident).Lookup(ident.Value)
628
629
630 if pname, _ := obj.(*PkgName); pname != nil {
631 if pname.imported.cgo {
632 name = "_Ctype_" + typ.Sel.Value
633 }
634 }
635 }
636 if name == "" {
637 return false, nil
638 }
639 default:
640 return false, nil
641 }
642
643
644
645 obj := check.pkg.scope.Lookup(name)
646 if obj == nil {
647 return false, nil
648 }
649
650
651 tname, _ := obj.(*TypeName)
652 if tname == nil {
653 return false, nil
654 }
655
656
657 if seen[tname] {
658 return false, nil
659 }
660
661
662
663 tdecl := check.objMap[tname].tdecl
664 if !tdecl.Alias {
665 return ptr, tname
666 }
667
668
669 typ = tdecl.Type
670 if seen == nil {
671 seen = make(map[*TypeName]bool)
672 }
673 seen[tname] = true
674 }
675 }
676
677
678 func (check *Checker) packageObjects() {
679
680 objList := make([]Object, len(check.objMap))
681 i := 0
682 for obj := range check.objMap {
683 objList[i] = obj
684 i++
685 }
686 slices.SortFunc(objList, func(a, b Object) int {
687 return cmp.Compare(a.order(), b.order())
688 })
689
690
691 for _, obj := range objList {
692 if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil {
693 check.collectMethods(obj)
694 }
695 }
696
697 if false && check.conf.EnableAlias {
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714 for _, obj := range objList {
715 check.objDecl(obj, nil)
716 }
717 } else {
718
719
720
721
722
723 var aliasList []*TypeName
724 var othersList []Object
725
726 for _, obj := range objList {
727 if tname, _ := obj.(*TypeName); tname != nil {
728 if check.objMap[tname].tdecl.Alias {
729 aliasList = append(aliasList, tname)
730 } else {
731 check.objDecl(obj, nil)
732 }
733 } else {
734 othersList = append(othersList, obj)
735 }
736 }
737
738 for _, obj := range aliasList {
739 check.objDecl(obj, nil)
740 }
741
742 for _, obj := range othersList {
743 check.objDecl(obj, nil)
744 }
745 }
746
747
748
749
750
751 check.methods = nil
752 }
753
754
755 func (check *Checker) unusedImports() {
756
757 if check.conf.IgnoreFuncBodies {
758 return
759 }
760
761
762
763
764
765 for _, obj := range check.imports {
766 if !obj.used && obj.name != "_" {
767 check.errorUnusedPkg(obj)
768 }
769 }
770 }
771
772 func (check *Checker) errorUnusedPkg(obj *PkgName) {
773
774
775
776
777
778
779 path := obj.imported.path
780 elem := path
781 if i := strings.LastIndex(elem, "/"); i >= 0 {
782 elem = elem[i+1:]
783 }
784 if obj.name == "" || obj.name == "." || obj.name == elem {
785 check.softErrorf(obj, UnusedImport, "%q imported and not used", path)
786 } else {
787 check.softErrorf(obj, UnusedImport, "%q imported as %s and not used", path, obj.name)
788 }
789 }
790
791
792
793
794
795 func dir(path string) string {
796 if i := strings.LastIndexAny(path, `/\`); i > 0 {
797 return path[:i]
798 }
799
800 return "."
801 }
802
View as plain text