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(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 check.methods = make(map[*TypeName][]*Func)
502 for i := range methods {
503 m := &methods[i]
504
505 ptr, base := check.resolveBaseTypeName(m.ptr, m.recv)
506 if base != nil {
507 m.obj.hasPtrRecv_ = ptr
508 check.methods[base] = append(check.methods[base], m.obj)
509 }
510 }
511 }
512
513
514
515
516
517
518
519
520
521
522 func (check *Checker) unpackRecv(rtyp syntax.Expr, unpackParams bool) (ptr bool, base syntax.Expr, tparams []*syntax.Name) {
523
524 base = syntax.Unparen(rtyp)
525 if t, _ := base.(*syntax.Operation); t != nil && t.Op == syntax.Mul && t.Y == nil {
526 ptr = true
527 base = syntax.Unparen(t.X)
528 }
529
530
531 if ptyp, _ := base.(*syntax.IndexExpr); ptyp != nil {
532 base = ptyp.X
533 if unpackParams {
534 for _, arg := range syntax.UnpackListExpr(ptyp.Index) {
535 var par *syntax.Name
536 switch arg := arg.(type) {
537 case *syntax.Name:
538 par = arg
539 case *syntax.BadExpr:
540
541 case nil:
542 check.error(ptyp, InvalidSyntaxTree, "parameterized receiver contains nil parameters")
543 default:
544 check.errorf(arg, BadDecl, "receiver type parameter %s must be an identifier", arg)
545 }
546 if par == nil {
547 par = syntax.NewName(arg.Pos(), "_")
548 }
549 tparams = append(tparams, par)
550 }
551
552 }
553 }
554
555 return
556 }
557
558
559
560
561
562
563 func (check *Checker) resolveBaseTypeName(ptr bool, name *syntax.Name) (ptr_ bool, base *TypeName) {
564
565
566
567 var seen map[*TypeName]bool
568 for name != nil {
569
570
571 obj := check.pkg.scope.Lookup(name.Value)
572 if obj == nil {
573 break
574 }
575
576
577 tname, _ := obj.(*TypeName)
578 if tname == nil {
579 break
580 }
581
582
583 if seen[tname] {
584 break
585 }
586
587
588 tdecl := check.objMap[tname].tdecl
589 if !tdecl.Alias {
590 return ptr, tname
591 }
592
593
594
595 if tdecl.TParamList != nil {
596 break
597 }
598
599
600 if seen == nil {
601 seen = make(map[*TypeName]bool)
602 }
603 seen[tname] = true
604
605
606 typ := syntax.Unparen(tdecl.Type)
607
608
609 if pexpr, _ := typ.(*syntax.Operation); pexpr != nil && pexpr.Op == syntax.Mul && pexpr.Y == nil {
610
611 if ptr {
612 break
613 }
614 ptr = true
615 typ = syntax.Unparen(pexpr.X)
616 }
617
618
619
620
621
622 name, _ = typ.(*syntax.Name)
623 }
624
625
626 return false, nil
627 }
628
629
630 func (check *Checker) packageObjects() {
631
632 objList := make([]Object, len(check.objMap))
633 i := 0
634 for obj := range check.objMap {
635 objList[i] = obj
636 i++
637 }
638 slices.SortFunc(objList, func(a, b Object) int {
639 return cmp.Compare(a.order(), b.order())
640 })
641
642
643 for _, obj := range objList {
644 if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil {
645 check.collectMethods(obj)
646 }
647 }
648
649 if false && check.conf.EnableAlias {
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666 for _, obj := range objList {
667 check.objDecl(obj, nil)
668 }
669 } else {
670
671
672
673
674
675 var aliasList []*TypeName
676 var othersList []Object
677
678 for _, obj := range objList {
679 if tname, _ := obj.(*TypeName); tname != nil {
680 if check.objMap[tname].tdecl.Alias {
681 aliasList = append(aliasList, tname)
682 } else {
683 check.objDecl(obj, nil)
684 }
685 } else {
686 othersList = append(othersList, obj)
687 }
688 }
689
690 for _, obj := range aliasList {
691 check.objDecl(obj, nil)
692 }
693
694 for _, obj := range othersList {
695 check.objDecl(obj, nil)
696 }
697 }
698
699
700
701
702
703 check.methods = nil
704 }
705
706
707 func (check *Checker) unusedImports() {
708
709 if check.conf.IgnoreFuncBodies {
710 return
711 }
712
713
714
715
716
717 for _, obj := range check.imports {
718 if obj.name != "_" && !check.usedPkgNames[obj] {
719 check.errorUnusedPkg(obj)
720 }
721 }
722 }
723
724 func (check *Checker) errorUnusedPkg(obj *PkgName) {
725
726
727
728
729
730
731 path := obj.imported.path
732 elem := path
733 if i := strings.LastIndex(elem, "/"); i >= 0 {
734 elem = elem[i+1:]
735 }
736 if obj.name == "" || obj.name == "." || obj.name == elem {
737 check.softErrorf(obj, UnusedImport, "%q imported and not used", path)
738 } else {
739 check.softErrorf(obj, UnusedImport, "%q imported as %s and not used", path, obj.name)
740 }
741 }
742
743
744
745
746
747 func dir(path string) string {
748 if i := strings.LastIndexAny(path, `/\`); i > 0 {
749 return path[:i]
750 }
751
752 return "."
753 }
754
View as plain text