github.com/bir3/gocompiler@v0.9.2202/src/go/types/resolver.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package types 6 7 import ( 8 "fmt" 9 "github.com/bir3/gocompiler/src/go/ast" 10 "github.com/bir3/gocompiler/src/go/constant" 11 "github.com/bir3/gocompiler/src/go/internal/typeparams" 12 "github.com/bir3/gocompiler/src/go/token" 13 . "github.com/bir3/gocompiler/src/internal/types/errors" 14 "sort" 15 "strconv" 16 "strings" 17 "unicode" 18 ) 19 20 // A declInfo describes a package-level const, type, var, or func declaration. 21 type declInfo struct { 22 file *Scope // scope of file containing this declaration 23 lhs []*Var // lhs of n:1 variable declarations, or nil 24 vtyp ast.Expr // type, or nil (for const and var declarations only) 25 init ast.Expr // init/orig expression, or nil (for const and var declarations only) 26 inherited bool // if set, the init expression is inherited from a previous constant declaration 27 tdecl *ast.TypeSpec // type declaration, or nil 28 fdecl *ast.FuncDecl // func declaration, or nil 29 30 // The deps field tracks initialization expression dependencies. 31 deps map[Object]bool // lazily initialized 32 } 33 34 // hasInitializer reports whether the declared object has an initialization 35 // expression or function body. 36 func (d *declInfo) hasInitializer() bool { 37 return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil 38 } 39 40 // addDep adds obj to the set of objects d's init expression depends on. 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 // arityMatch checks that the lhs and rhs of a const or var decl 51 // have the appropriate number of names and init exprs. For const 52 // decls, init is the value spec providing the init exprs; for 53 // var decls, init is nil (the init exprs are in s in this case). 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 // var decl w/o init expr 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 // init exprs from s 71 n := s.Values[l] 72 check.errorf(n, code, "extra init expr %s", n) 73 // TODO(gri) avoid declared and not used error here 74 } else { 75 // init exprs "inherited" 76 check.errorf(s, code, "extra init expr at %s", check.fset.Position(init.Pos())) 77 // TODO(gri) avoid declared and not used error here 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 // declarePkgObj declares obj in the package scope, records its ident -> obj mapping, 103 // and updates check.objMap. The object must not be a function or method. 104 func (check *Checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) { 105 assert(ident.Name == obj.Name()) 106 107 // spec: "A package-scope or file-scope identifier with name init 108 // may only be declared to be a function with this (func()) signature." 109 if ident.Name == "init" { 110 check.error(ident, InvalidInitDecl, "cannot declare init - must be func") 111 return 112 } 113 114 // spec: "The main package must have package name main and declare 115 // a function main that takes no arguments and returns no value." 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 // filename returns a filename suitable for debugging output. 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 // If we already have a package for the given (path, dir) 137 // pair, use it instead of doing a full import. 138 // Checker.impMap only caches packages that are marked Complete 139 // or fake (dummy packages for failed imports). Incomplete but 140 // non-fake packages do require an import to complete them. 141 key := importKey{path, dir} 142 imp := check.impMap[key] 143 if imp != nil { 144 return imp 145 } 146 147 // no package yet => import it 148 if path == "C" && (check.conf.FakeImportC || check.conf.go115UsesCgo) { 149 imp = NewPackage("C", "C") 150 imp.fake = true // package scope is not populated 151 imp.cgo = check.conf.go115UsesCgo 152 } else { 153 // ordinary import 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 // make sure we have a valid package name 169 // (errors here can only happen through manipulation of packages after creation) 170 if err == nil && imp != nil && (imp.name == "_" || imp.name == "") { 171 err = fmt.Errorf("invalid package name: %q", imp.name) 172 imp = nil // create fake package below 173 } 174 if err != nil { 175 check.errorf(at, BrokenImport, "could not import %s (%s)", path, err) 176 if imp == nil { 177 // create a new fake package 178 // come up with a sensible package name (heuristic) 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 // continue to use the package as best as we can 189 imp.fake = true // avoid follow-up lookup failures 190 } 191 } 192 193 // package should be complete or marked fake, but be cautious 194 if imp.complete || imp.fake { 195 check.impMap[key] = imp 196 // Once we've formatted an error message, keep the pkgPathMap 197 // up-to-date on subsequent imports. It is used for package 198 // qualification in error messages. 199 if check.pkgPathMap != nil { 200 check.markImports(imp) 201 } 202 return imp 203 } 204 205 // something went wrong (importer may have returned incomplete package without error) 206 return nil 207 } 208 209 // collectObjects collects all file and package objects and inserts them 210 // into their respective scopes. It also performs imports and associates 211 // methods with receiver base type names. 212 func (check *Checker) collectObjects() { 213 pkg := check.pkg 214 215 // pkgImports is the set of packages already imported by any package file seen 216 // so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate 217 // it (pkg.imports may not be empty if we are checking test files incrementally). 218 // Note that pkgImports is keyed by package (and thus package path), not by an 219 // importKey value. Two different importKey values may map to the same package 220 // which is why we cannot use the check.impMap here. 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 // method 228 ptr bool // true if pointer receiver 229 recv *ast.Ident // receiver type name 230 } 231 var methods []methodInfo // collected methods with valid receivers and non-blank _ names 232 var fileScopes []*Scope 233 for fileNo, file := range check.files { 234 // The package identifier denotes the current package, 235 // but there is no corresponding package object. 236 check.recordDef(file.Name, nil) 237 238 // Use the actual source file extent rather than *ast.File extent since the 239 // latter doesn't include comments which appear at the start or end of the file. 240 // Be conservative and use the *ast.File extent if we don't have a *token.File. 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 // determine file directory, necessary to resolve imports 250 // FileName may be "" (typically for tests) in which case 251 // we get "." as the directory which is what we would want. 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 // import package 258 if d.spec.Path.Value == "" { 259 return // error reported by parser 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 // local name overrides imported package name 273 name := imp.name 274 if d.spec.Name != nil { 275 name = d.spec.Name.Name 276 if path == "C" { 277 // match 1.17 cmd/compile (not prescribed by spec) 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 // add package to list of explicit imports 289 // (this functionality is provided as a convenience 290 // for clients; it is not needed for type-checking) 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 // in a dot-import, the dot represents the package 299 check.recordDef(d.spec.Name, pkgName) 300 } else { 301 check.recordImplicit(d.spec, pkgName) 302 } 303 304 if imp.fake { 305 // match 1.17 cmd/compile (not prescribed by spec) 306 pkgName.used = true 307 } 308 309 // add import to file scope 310 check.imports = append(check.imports, pkgName) 311 if name == "." { 312 // dot-import 313 if check.dotImportMap == nil { 314 check.dotImportMap = make(map[dotImportKey]*PkgName) 315 } 316 // merge imported scope with file scope 317 for name, obj := range imp.scope.elems { 318 // Note: Avoid eager resolve(name, obj) here, so we only 319 // resolve dot-imported objects as needed. 320 321 // A package scope may contain non-exported objects, 322 // do not import them! 323 if token.IsExported(name) { 324 // declare dot-imported object 325 // (Do not use check.declare because it modifies the object 326 // via Object.setScopePos, which leads to a race condition; 327 // the object may be imported into more than one file scope 328 // concurrently. See go.dev/issue/32154.) 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 // declare imported package object in file scope 340 // (no need to provide s.Name since we called check.recordDef earlier) 341 check.declare(fileScope, nil, pkgName, nopos) 342 } 343 case constDecl: 344 // declare all constants 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 // If there's exactly one rhs initializer, use 360 // the same declInfo d1 for all lhs variables 361 // so that each lhs variable depends on the same 362 // rhs initializer (n:1 var declaration). 363 var d1 *declInfo 364 if len(d.spec.Values) == 1 { 365 // The lhs elements are only set up after the for loop below, 366 // but that's ok because declareVar only collects the declInfo 367 // for a later phase. 368 d1 = &declInfo{file: fileScope, lhs: lhs, vtyp: d.spec.Type, init: d.spec.Values[0]} 369 } 370 371 // declare all variables 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 // individual assignments 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 // avoid duplicate type parameter errors 396 if d.decl.Recv.NumFields() == 0 { 397 // regular function 398 if d.decl.Recv != nil { 399 check.error(d.decl.Recv, BadRecv, "method has no receiver") 400 // treat as function 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 // TODO(rFindley) Should this be a hard error? 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 // don't declare init functions in the package scope - they are invisible 418 obj.parent = pkg.scope 419 check.recordDef(d.decl.Name, obj) 420 // init functions must have a body 421 if d.decl.Body == nil { 422 // TODO(gri) make this error message consistent with the others above 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 // method 430 431 // TODO(rFindley) earlier versions of this code checked that methods 432 // have no type parameters, but this is checked later 433 // when type checking the function type. Confirm that 434 // we don't need to check tparams here. 435 436 ptr, recv, _ := check.unpackRecv(d.decl.Recv.List[0].Type, false) 437 // (Methods with invalid receiver cannot be associated to a type, and 438 // methods with blank _ names are never found; no need to collect any 439 // of them. They will still be type-checked with all the other functions.) 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 // Methods are not package-level objects but we still track them in the 448 // object map so that we can handle them like regular functions (if the 449 // receiver is invalid); also we need their fdecl info when associating 450 // them with their receiver base type, below. 451 check.objMap[obj] = info 452 obj.setOrder(uint32(len(check.objMap))) 453 } 454 }) 455 } 456 457 // verify that objects in package and file scopes have different names 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 // TODO(gri) dot-imported objects don't have a position; reportAltDecl won't print anything 468 check.reportAltDecl(obj) 469 } 470 } 471 } 472 } 473 474 // Now that we have all package scope objects and all methods, 475 // associate methods with receiver base type name where possible. 476 // Ignore methods that have an invalid receiver. They will be 477 // type-checked later, with regular functions. 478 if methods == nil { 479 return // nothing to do 480 } 481 check.methods = make(map[*TypeName][]*Func) 482 for i := range methods { 483 m := &methods[i] 484 // Determine the receiver base type and associate m with it. 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 // unpackRecv unpacks a receiver type and returns its components: ptr indicates whether 494 // rtyp is a pointer receiver, rname is the receiver type name, and tparams are its 495 // type parameters, if any. The type parameters are only unpacked if unpackParams is 496 // set. If rname is nil, the receiver is unusable (i.e., the source has a bug which we 497 // cannot easily work around). 498 func (check *Checker) unpackRecv(rtyp ast.Expr, unpackParams bool) (ptr bool, rname *ast.Ident, tparams []*ast.Ident) { 499 L: // unpack receiver type 500 // This accepts invalid receivers such as ***T and does not 501 // work for other invalid receivers, but we don't care. The 502 // validity of receiver expressions is checked elsewhere. 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 // unpack type parameters, if any 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 // ignore - error already reported by parser 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 // unpack receiver name 542 if name, _ := rtyp.(*ast.Ident); name != nil { 543 rname = name 544 } 545 546 return 547 } 548 549 // resolveBaseTypeName returns the non-alias base type name for typ, and whether 550 // there was a pointer indirection to get to it. The base type name must be declared 551 // in package scope, and there can be at most one pointer indirection. If no such type 552 // name exists, the returned base is nil. 553 func (check *Checker) resolveBaseTypeName(seenPtr bool, typ ast.Expr, fileScopes []*Scope) (ptr bool, base *TypeName) { 554 // Algorithm: Starting from a type expression, which may be a name, 555 // we follow that type through alias declarations until we reach a 556 // non-alias type name. If we encounter anything but pointer types or 557 // parentheses we're done. If we encounter more than one pointer type 558 // we're done. 559 ptr = seenPtr 560 var seen map[*TypeName]bool 561 for { 562 // Note: this differs from types2, but is necessary. The syntax parser 563 // strips unnecessary parens. 564 typ = unparen(typ) 565 566 // check if we have a pointer type 567 if pexpr, _ := typ.(*ast.StarExpr); pexpr != nil { 568 // if we've already seen a pointer, we're done 569 if ptr { 570 return false, nil 571 } 572 ptr = true 573 typ = unparen(pexpr.X) // continue with pointer base type 574 } 575 576 // typ must be a name, or a C.name cgo selector. 577 var name string 578 switch typ := typ.(type) { 579 case *ast.Ident: 580 name = typ.Name 581 case *ast.SelectorExpr: 582 // C.struct_foo is a valid type name for packages using cgo. 583 // 584 // Detect this case, and adjust name so that the correct TypeName is 585 // resolved below. 586 if ident, _ := typ.X.(*ast.Ident); ident != nil && ident.Name == "C" { 587 // Check whether "C" actually resolves to an import of "C", by looking 588 // in the appropriate file scope. 589 var obj Object 590 for _, scope := range fileScopes { 591 if scope.Contains(ident.Pos()) { 592 obj = scope.Lookup(ident.Name) 593 } 594 } 595 // If Config.go115UsesCgo is set, the typechecker will resolve Cgo 596 // selectors to their cgo name. We must do the same here. 597 if pname, _ := obj.(*PkgName); pname != nil { 598 if pname.imported.cgo { // only set if Config.go115UsesCgo is set 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 // name must denote an object found in the current package scope 611 // (note that dot-imported objects are not in the package scope!) 612 obj := check.pkg.scope.Lookup(name) 613 if obj == nil { 614 return false, nil 615 } 616 617 // the object must be a type name... 618 tname, _ := obj.(*TypeName) 619 if tname == nil { 620 return false, nil 621 } 622 623 // ... which we have not seen before 624 if seen[tname] { 625 return false, nil 626 } 627 628 // we're done if tdecl defined tname as a new type 629 // (rather than an alias) 630 tdecl := check.objMap[tname].tdecl // must exist for objects in package scope 631 if !tdecl.Assign.IsValid() { 632 return ptr, tname 633 } 634 635 // otherwise, continue resolving 636 typ = tdecl.Type 637 if seen == nil { 638 seen = make(map[*TypeName]bool) 639 } 640 seen[tname] = true 641 } 642 } 643 644 // packageObjects typechecks all package objects, but not function bodies. 645 func (check *Checker) packageObjects() { 646 // process package objects in source order for reproducible results 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 // add new methods to already type-checked types (from a prior Checker.Files call) 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 // With Alias nodes we can process declarations in any order. 664 for _, obj := range objList { 665 check.objDecl(obj, nil) 666 } 667 } else { 668 // Without Alias nodes, we process non-alias type declarations first, followed by 669 // alias declarations, and then everything else. This appears to avoid most situations 670 // where the type of an alias is needed before it is available. 671 // There may still be cases where this is not good enough (see also go.dev/issue/25838). 672 // In those cases Checker.ident will report an error ("invalid use of type alias"). 673 var aliasList []*TypeName 674 var othersList []Object // everything that's not a type 675 // phase 1: non-alias type declarations 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 // phase 2: alias type declarations 688 for _, obj := range aliasList { 689 check.objDecl(obj, nil) 690 } 691 // phase 3: all other declarations 692 for _, obj := range othersList { 693 check.objDecl(obj, nil) 694 } 695 } 696 697 // At this point we may have a non-empty check.methods map; this means that not all 698 // entries were deleted at the end of typeDecl because the respective receiver base 699 // types were not found. In that case, an error was reported when declaring those 700 // methods. We can now safely discard this map. 701 check.methods = nil 702 } 703 704 // inSourceOrder implements the sort.Sort interface. 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 // unusedImports checks for unused imports. 712 func (check *Checker) unusedImports() { 713 // If function bodies are not checked, packages' uses are likely missing - don't check. 714 if check.conf.IgnoreFuncBodies { 715 return 716 } 717 718 // spec: "It is illegal (...) to directly import a package without referring to 719 // any of its exported identifiers. To import a package solely for its side-effects 720 // (initialization), use the blank identifier as explicit package name." 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 // If the package was imported with a name other than the final 731 // import path element, show it explicitly in the error message. 732 // Note that this handles both renamed imports and imports of 733 // packages containing unconventional package declarations. 734 // Note that this uses / always, even on Windows, because Go import 735 // paths always use forward slashes. 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 // dir makes a good-faith attempt to return the directory 749 // portion of path. If path is empty, the result is ".". 750 // (Per the go/build package dependency tests, we cannot import 751 // path/filepath and simply use filepath.Dir.) 752 func dir(path string) string { 753 if i := strings.LastIndexAny(path, `/\`); i > 0 { 754 return path[:i] 755 } 756 // i <= 0 757 return "." 758 }