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