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