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