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