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 imp = NewPackage("C", "C")
138 imp.fake = true
139 imp.cgo = check.conf.go115UsesCgo
140 } else {
141
142 var err error
143 if importer := check.conf.Importer; importer == nil {
144 err = fmt.Errorf("Config.Importer not installed")
145 } else if importerFrom, ok := importer.(ImporterFrom); ok {
146 imp, err = importerFrom.ImportFrom(path, dir, 0)
147 if imp == nil && err == nil {
148 err = fmt.Errorf("Config.Importer.ImportFrom(%s, %s, 0) returned nil but no error", path, dir)
149 }
150 } else {
151 imp, err = importer.Import(path)
152 if imp == nil && err == nil {
153 err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path)
154 }
155 }
156
157
158 if err == nil && imp != nil && (imp.name == "_" || imp.name == "") {
159 err = fmt.Errorf("invalid package name: %q", imp.name)
160 imp = nil
161 }
162 if err != nil {
163 check.errorf(pos, BrokenImport, "could not import %s (%s)", path, err)
164 if imp == nil {
165
166
167 name := path
168 if i := len(name); i > 0 && name[i-1] == '/' {
169 name = name[:i-1]
170 }
171 if i := strings.LastIndex(name, "/"); i >= 0 {
172 name = name[i+1:]
173 }
174 imp = NewPackage(path, name)
175 }
176
177 imp.fake = true
178 }
179 }
180
181
182 if imp.complete || imp.fake {
183 check.impMap[key] = imp
184
185
186
187 if check.pkgPathMap != nil {
188 check.markImports(imp)
189 }
190 return imp
191 }
192
193
194 return nil
195 }
196
197
198
199
200 func (check *Checker) collectObjects() {
201 pkg := check.pkg
202
203
204
205
206
207
208
209 var pkgImports = make(map[*Package]bool)
210 for _, imp := range pkg.imports {
211 pkgImports[imp] = true
212 }
213
214 type methodInfo struct {
215 obj *Func
216 ptr bool
217 recv *syntax.Name
218 }
219 var methods []methodInfo
220 var fileScopes []*Scope
221 for fileNo, file := range check.files {
222
223
224 check.recordDef(file.PkgName, nil)
225
226 fileScope := NewScope(pkg.scope, syntax.StartPos(file), syntax.EndPos(file), check.filename(fileNo))
227 fileScopes = append(fileScopes, fileScope)
228 check.recordScope(file, fileScope)
229
230
231
232
233 fileDir := dir(file.PkgName.Pos().RelFilename())
234
235 first := -1
236 var last *syntax.ConstDecl
237 for index, decl := range file.DeclList {
238 if _, ok := decl.(*syntax.ConstDecl); !ok {
239 first = -1
240 }
241
242 switch s := decl.(type) {
243 case *syntax.ImportDecl:
244
245 if s.Path == nil || s.Path.Bad {
246 continue
247 }
248 path, err := validatedImportPath(s.Path.Value)
249 if err != nil {
250 check.errorf(s.Path, BadImportPath, "invalid import path (%s)", err)
251 continue
252 }
253
254 imp := check.importPackage(s.Path.Pos(), path, fileDir)
255 if imp == nil {
256 continue
257 }
258
259
260 name := imp.name
261 if s.LocalPkgName != nil {
262 name = s.LocalPkgName.Value
263 if path == "C" {
264
265 check.error(s.LocalPkgName, ImportCRenamed, `cannot rename import "C"`)
266 continue
267 }
268 }
269
270 if name == "init" {
271 check.error(s, InvalidInitDecl, "cannot import package as init - init must be a func")
272 continue
273 }
274
275
276
277
278 if !pkgImports[imp] {
279 pkgImports[imp] = true
280 pkg.imports = append(pkg.imports, imp)
281 }
282
283 pkgName := NewPkgName(s.Pos(), pkg, name, imp)
284 if s.LocalPkgName != nil {
285
286 check.recordDef(s.LocalPkgName, pkgName)
287 } else {
288 check.recordImplicit(s, pkgName)
289 }
290
291 if imp.fake {
292
293 pkgName.used = true
294 }
295
296
297 check.imports = append(check.imports, pkgName)
298 if name == "." {
299
300 if check.dotImportMap == nil {
301 check.dotImportMap = make(map[dotImportKey]*PkgName)
302 }
303
304 for name, obj := range imp.scope.elems {
305
306
307
308
309
310 if isExported(name) {
311
312
313
314
315
316 if alt := fileScope.Lookup(name); alt != nil {
317 var err error_
318 err.code = DuplicateDecl
319 err.errorf(s.LocalPkgName, "%s redeclared in this block", alt.Name())
320 err.recordAltDecl(alt)
321 check.report(&err)
322 } else {
323 fileScope.insert(name, obj)
324 check.dotImportMap[dotImportKey{fileScope, name}] = pkgName
325 }
326 }
327 }
328 } else {
329
330
331 check.declare(fileScope, nil, pkgName, nopos)
332 }
333
334 case *syntax.ConstDecl:
335
336 if first < 0 || s.Group == nil || file.DeclList[index-1].(*syntax.ConstDecl).Group != s.Group {
337 first = index
338 last = nil
339 }
340 iota := constant.MakeInt64(int64(index - first))
341
342
343 inherited := true
344 switch {
345 case s.Type != nil || s.Values != nil:
346 last = s
347 inherited = false
348 case last == nil:
349 last = new(syntax.ConstDecl)
350 inherited = false
351 }
352
353
354 values := syntax.UnpackListExpr(last.Values)
355 for i, name := range s.NameList {
356 obj := NewConst(name.Pos(), pkg, name.Value, nil, iota)
357
358 var init syntax.Expr
359 if i < len(values) {
360 init = values[i]
361 }
362
363 d := &declInfo{file: fileScope, vtyp: last.Type, init: init, inherited: inherited}
364 check.declarePkgObj(name, obj, d)
365 }
366
367
368 check.arity(s.Pos(), s.NameList, values, true, inherited)
369
370 case *syntax.VarDecl:
371 lhs := make([]*Var, len(s.NameList))
372
373
374
375
376 var d1 *declInfo
377 if _, ok := s.Values.(*syntax.ListExpr); !ok {
378
379
380
381 d1 = &declInfo{file: fileScope, lhs: lhs, vtyp: s.Type, init: s.Values}
382 }
383
384
385 values := syntax.UnpackListExpr(s.Values)
386 for i, name := range s.NameList {
387 obj := NewVar(name.Pos(), pkg, name.Value, nil)
388 lhs[i] = obj
389
390 d := d1
391 if d == nil {
392
393 var init syntax.Expr
394 if i < len(values) {
395 init = values[i]
396 }
397 d = &declInfo{file: fileScope, vtyp: s.Type, init: init}
398 }
399
400 check.declarePkgObj(name, obj, d)
401 }
402
403
404 if s.Type == nil || values != nil {
405 check.arity(s.Pos(), s.NameList, values, false, false)
406 }
407
408 case *syntax.TypeDecl:
409 _ = len(s.TParamList) != 0 && check.verifyVersionf(s.TParamList[0], go1_18, "type parameter")
410 obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
411 check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
412
413 case *syntax.FuncDecl:
414 name := s.Name.Value
415 obj := NewFunc(s.Name.Pos(), pkg, name, nil)
416 hasTParamError := false
417 if s.Recv == nil {
418
419 if name == "init" || name == "main" && pkg.name == "main" {
420 code := InvalidInitDecl
421 if name == "main" {
422 code = InvalidMainDecl
423 }
424 if len(s.TParamList) != 0 {
425 check.softErrorf(s.TParamList[0], code, "func %s must have no type parameters", name)
426 hasTParamError = true
427 }
428 if t := s.Type; len(t.ParamList) != 0 || len(t.ResultList) != 0 {
429 check.softErrorf(s.Name, code, "func %s must have no arguments and no return values", name)
430 }
431 }
432
433 if name == "init" {
434 obj.parent = pkg.scope
435 check.recordDef(s.Name, obj)
436
437 if s.Body == nil {
438
439 check.softErrorf(obj.pos, MissingInitBody, "missing function body")
440 }
441 } else {
442 check.declare(pkg.scope, s.Name, obj, nopos)
443 }
444 } else {
445
446
447 ptr, recv, _ := check.unpackRecv(s.Recv.Type, false)
448
449
450
451 if recv != nil && name != "_" {
452 methods = append(methods, methodInfo{obj, ptr, recv})
453 }
454 check.recordDef(s.Name, obj)
455 }
456 _ = len(s.TParamList) != 0 && !hasTParamError && check.verifyVersionf(s.TParamList[0], go1_18, "type parameter")
457 info := &declInfo{file: fileScope, fdecl: s}
458
459
460
461
462 check.objMap[obj] = info
463 obj.setOrder(uint32(len(check.objMap)))
464
465 default:
466 check.errorf(s, InvalidSyntaxTree, "unknown syntax.Decl node %T", s)
467 }
468 }
469 }
470
471
472 for _, scope := range fileScopes {
473 for name, obj := range scope.elems {
474 if alt := pkg.scope.Lookup(name); alt != nil {
475 obj = resolve(name, obj)
476 var err error_
477 err.code = DuplicateDecl
478 if pkg, ok := obj.(*PkgName); ok {
479 err.errorf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported())
480 err.recordAltDecl(pkg)
481 } else {
482 err.errorf(alt, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
483
484 err.recordAltDecl(obj)
485 }
486 check.report(&err)
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 check.enableAlias {
681
682 for _, obj := range objList {
683 check.objDecl(obj, nil)
684 }
685 } else {
686
687
688
689
690
691 var aliasList []*TypeName
692 var othersList []Object
693
694 for _, obj := range objList {
695 if tname, _ := obj.(*TypeName); tname != nil {
696 if check.objMap[tname].tdecl.Alias {
697 aliasList = append(aliasList, tname)
698 } else {
699 check.objDecl(obj, nil)
700 }
701 } else {
702 othersList = append(othersList, obj)
703 }
704 }
705
706 for _, obj := range aliasList {
707 check.objDecl(obj, nil)
708 }
709
710 for _, obj := range othersList {
711 check.objDecl(obj, nil)
712 }
713 }
714
715
716
717
718
719 check.methods = nil
720 }
721
722
723 type inSourceOrder []Object
724
725 func (a inSourceOrder) Len() int { return len(a) }
726 func (a inSourceOrder) Less(i, j int) bool { return a[i].order() < a[j].order() }
727 func (a inSourceOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
728
729
730 func (check *Checker) unusedImports() {
731
732 if check.conf.IgnoreFuncBodies {
733 return
734 }
735
736
737
738
739
740 for _, obj := range check.imports {
741 if !obj.used && obj.name != "_" {
742 check.errorUnusedPkg(obj)
743 }
744 }
745 }
746
747 func (check *Checker) errorUnusedPkg(obj *PkgName) {
748
749
750
751
752
753
754 path := obj.imported.path
755 elem := path
756 if i := strings.LastIndex(elem, "/"); i >= 0 {
757 elem = elem[i+1:]
758 }
759 if obj.name == "" || obj.name == "." || obj.name == elem {
760 check.softErrorf(obj, UnusedImport, "%q imported and not used", path)
761 } else {
762 check.softErrorf(obj, UnusedImport, "%q imported as %s and not used", path, obj.name)
763 }
764 }
765
766
767
768
769
770 func dir(path string) string {
771 if i := strings.LastIndexAny(path, `/\`); i > 0 {
772 return path[:i]
773 }
774
775 return "."
776 }
777
View as plain text