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 5package types 6 7import ( 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// A declInfo describes a package-level const, type, var, or func declaration. 21type 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. 36func (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. 41func (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). 54func (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 85func 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. 104func (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. 127func (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 135func (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 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 // package scope is not populated 154 imp.cgo = check.conf.go115UsesCgo 155 } else { 156 // ordinary import 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 // make sure we have a valid package name 172 // (errors here can only happen through manipulation of packages after creation) 173 if err == nil && imp != nil && (imp.name == "_" || imp.name == "") { 174 err = fmt.Errorf("invalid package name: %q", imp.name) 175 imp = nil // create fake package below 176 } 177 if err != nil { 178 check.errorf(at, BrokenImport, "could not import %s (%s)", path, err) 179 if imp == nil { 180 // create a new fake package 181 // come up with a sensible package name (heuristic) 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 // continue to use the package as best as we can 192 imp.fake = true // avoid follow-up lookup failures 193 } 194 } 195 196 // package should be complete or marked fake, but be cautious 197 if imp.complete || imp.fake { 198 check.impMap[key] = imp 199 // Once we've formatted an error message, keep the pkgPathMap 200 // up-to-date on subsequent imports. It is used for package 201 // qualification in error messages. 202 if check.pkgPathMap != nil { 203 check.markImports(imp) 204 } 205 return imp 206 } 207 208 // something went wrong (importer may have returned incomplete package without error) 209 return nil 210} 211 212// collectObjects collects all file and package objects and inserts them 213// into their respective scopes. It also performs imports and associates 214// methods with receiver base type names. 215func (check *Checker) collectObjects() { 216 pkg := check.pkg 217 218 // pkgImports is the set of packages already imported by any package file seen 219 // so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate 220 // it (pkg.imports may not be empty if we are checking test files incrementally). 221 // Note that pkgImports is keyed by package (and thus package path), not by an 222 // importKey value. Two different importKey values may map to the same package 223 // which is why we cannot use the check.impMap here. 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 // method 231 ptr bool // true if pointer receiver 232 recv *ast.Ident // receiver type name 233 } 234 var methods []methodInfo // collected methods with valid receivers and non-blank _ names 235 var fileScopes []*Scope 236 for fileNo, file := range check.files { 237 // The package identifier denotes the current package, 238 // but there is no corresponding package object. 239 check.recordDef(file.Name, nil) 240 241 // Use the actual source file extent rather than *ast.File extent since the 242 // latter doesn't include comments which appear at the start or end of the file. 243 // Be conservative and use the *ast.File extent if we don't have a *token.File. 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 // determine file directory, necessary to resolve imports 253 // FileName may be "" (typically for tests) in which case 254 // we get "." as the directory which is what we would want. 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 // import package 261 if d.spec.Path.Value == "" { 262 return // error reported by parser 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 // local name overrides imported package name 276 name := imp.name 277 if d.spec.Name != nil { 278 name = d.spec.Name.Name 279 if path == "C" { 280 // match 1.17 cmd/compile (not prescribed by spec) 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 // add package to list of explicit imports 292 // (this functionality is provided as a convenience 293 // for clients; it is not needed for type-checking) 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 // in a dot-import, the dot represents the package 302 check.recordDef(d.spec.Name, pkgName) 303 } else { 304 check.recordImplicit(d.spec, pkgName) 305 } 306 307 if imp.fake { 308 // match 1.17 cmd/compile (not prescribed by spec) 309 pkgName.used = true 310 } 311 312 // add import to file scope 313 check.imports = append(check.imports, pkgName) 314 if name == "." { 315 // dot-import 316 if check.dotImportMap == nil { 317 check.dotImportMap = make(map[dotImportKey]*PkgName) 318 } 319 // merge imported scope with file scope 320 for name, obj := range imp.scope.elems { 321 // Note: Avoid eager resolve(name, obj) here, so we only 322 // resolve dot-imported objects as needed. 323 324 // A package scope may contain non-exported objects, 325 // do not import them! 326 if token.IsExported(name) { 327 // declare dot-imported object 328 // (Do not use check.declare because it modifies the object 329 // via Object.setScopePos, which leads to a race condition; 330 // the object may be imported into more than one file scope 331 // concurrently. See go.dev/issue/32154.) 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 // declare imported package object in file scope 345 // (no need to provide s.Name since we called check.recordDef earlier) 346 check.declare(fileScope, nil, pkgName, nopos) 347 } 348 case constDecl: 349 // declare all constants 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 // If there's exactly one rhs initializer, use 365 // the same declInfo d1 for all lhs variables 366 // so that each lhs variable depends on the same 367 // rhs initializer (n:1 var declaration). 368 var d1 *declInfo 369 if len(d.spec.Values) == 1 { 370 // The lhs elements are only set up after the for loop below, 371 // but that's ok because declareVar only collects the declInfo 372 // for a later phase. 373 d1 = &declInfo{file: fileScope, lhs: lhs, vtyp: d.spec.Type, init: d.spec.Values[0]} 374 } 375 376 // declare all variables 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 // individual assignments 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) // signature set later 399 hasTParamError := false // avoid duplicate type parameter errors 400 if d.decl.Recv.NumFields() == 0 { 401 // regular function 402 if d.decl.Recv != nil { 403 check.error(d.decl.Recv, BadRecv, "method has no receiver") 404 // treat as function 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 // TODO(rFindley) Should this be a hard error? 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 // don't declare init functions in the package scope - they are invisible 422 obj.parent = pkg.scope 423 check.recordDef(d.decl.Name, obj) 424 // init functions must have a body 425 if d.decl.Body == nil { 426 // TODO(gri) make this error message consistent with the others above 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 // method 434 435 // TODO(rFindley) earlier versions of this code checked that methods 436 // have no type parameters, but this is checked later 437 // when type checking the function type. Confirm that 438 // we don't need to check tparams here. 439 440 ptr, recv, _ := check.unpackRecv(d.decl.Recv.List[0].Type, false) 441 // (Methods with invalid receiver cannot be associated to a type, and 442 // methods with blank _ names are never found; no need to collect any 443 // of them. They will still be type-checked with all the other functions.) 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 // Methods are not package-level objects but we still track them in the 452 // object map so that we can handle them like regular functions (if the 453 // receiver is invalid); also we need their fdecl info when associating 454 // them with their receiver base type, below. 455 check.objMap[obj] = info 456 obj.setOrder(uint32(len(check.objMap))) 457 } 458 }) 459 } 460 461 // verify that objects in package and file scopes have different names 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 // TODO(gri) dot-imported objects don't have a position; addAltDecl won't print anything 473 err.addAltDecl(obj) 474 } 475 err.report() 476 } 477 } 478 } 479 480 // Now that we have all package scope objects and all methods, 481 // associate methods with receiver base type name where possible. 482 // Ignore methods that have an invalid receiver. They will be 483 // type-checked later, with regular functions. 484 if methods == nil { 485 return // nothing to do 486 } 487 check.methods = make(map[*TypeName][]*Func) 488 for i := range methods { 489 m := &methods[i] 490 // Determine the receiver base type and associate m with it. 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// unpackRecv unpacks a receiver type and returns its components: ptr indicates whether 500// rtyp is a pointer receiver, rname is the receiver type name, and tparams are its 501// type parameters, if any. The type parameters are only unpacked if unpackParams is 502// set. If rname is nil, the receiver is unusable (i.e., the source has a bug which we 503// cannot easily work around). 504func (check *Checker) unpackRecv(rtyp ast.Expr, unpackParams bool) (ptr bool, rname *ast.Ident, tparams []*ast.Ident) { 505L: // unpack receiver type 506 // This accepts invalid receivers such as ***T and does not 507 // work for other invalid receivers, but we don't care. The 508 // validity of receiver expressions is checked elsewhere. 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 // unpack type parameters, if any 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 // ignore - error already reported by parser 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 // unpack receiver name 548 if name, _ := rtyp.(*ast.Ident); name != nil { 549 rname = name 550 } 551 552 return 553} 554 555// resolveBaseTypeName returns the non-alias base type name for typ, and whether 556// there was a pointer indirection to get to it. The base type name must be declared 557// in package scope, and there can be at most one pointer indirection. If no such type 558// name exists, the returned base is nil. 559func (check *Checker) resolveBaseTypeName(seenPtr bool, typ ast.Expr, fileScopes []*Scope) (ptr bool, base *TypeName) { 560 // Algorithm: Starting from a type expression, which may be a name, 561 // we follow that type through alias declarations until we reach a 562 // non-alias type name. If we encounter anything but pointer types or 563 // parentheses we're done. If we encounter more than one pointer type 564 // we're done. 565 ptr = seenPtr 566 var seen map[*TypeName]bool 567 for { 568 // Note: this differs from types2, but is necessary. The syntax parser 569 // strips unnecessary parens. 570 typ = ast.Unparen(typ) 571 572 // check if we have a pointer type 573 if pexpr, _ := typ.(*ast.StarExpr); pexpr != nil { 574 // if we've already seen a pointer, we're done 575 if ptr { 576 return false, nil 577 } 578 ptr = true 579 typ = ast.Unparen(pexpr.X) // continue with pointer base type 580 } 581 582 // typ must be a name, or a C.name cgo selector. 583 var name string 584 switch typ := typ.(type) { 585 case *ast.Ident: 586 name = typ.Name 587 case *ast.SelectorExpr: 588 // C.struct_foo is a valid type name for packages using cgo. 589 // 590 // Detect this case, and adjust name so that the correct TypeName is 591 // resolved below. 592 if ident, _ := typ.X.(*ast.Ident); ident != nil && ident.Name == "C" { 593 // Check whether "C" actually resolves to an import of "C", by looking 594 // in the appropriate file scope. 595 var obj Object 596 for _, scope := range fileScopes { 597 if scope.Contains(ident.Pos()) { 598 obj = scope.Lookup(ident.Name) 599 } 600 } 601 // If Config.go115UsesCgo is set, the typechecker will resolve Cgo 602 // selectors to their cgo name. We must do the same here. 603 if pname, _ := obj.(*PkgName); pname != nil { 604 if pname.imported.cgo { // only set if Config.go115UsesCgo is set 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 // name must denote an object found in the current package scope 617 // (note that dot-imported objects are not in the package scope!) 618 obj := check.pkg.scope.Lookup(name) 619 if obj == nil { 620 return false, nil 621 } 622 623 // the object must be a type name... 624 tname, _ := obj.(*TypeName) 625 if tname == nil { 626 return false, nil 627 } 628 629 // ... which we have not seen before 630 if seen[tname] { 631 return false, nil 632 } 633 634 // we're done if tdecl defined tname as a new type 635 // (rather than an alias) 636 tdecl := check.objMap[tname].tdecl // must exist for objects in package scope 637 if !tdecl.Assign.IsValid() { 638 return ptr, tname 639 } 640 641 // otherwise, continue resolving 642 typ = tdecl.Type 643 if seen == nil { 644 seen = make(map[*TypeName]bool) 645 } 646 seen[tname] = true 647 } 648} 649 650// packageObjects typechecks all package objects, but not function bodies. 651func (check *Checker) packageObjects() { 652 // process package objects in source order for reproducible results 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 // add new methods to already type-checked types (from a prior Checker.Files call) 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 // With Alias nodes we can process declarations in any order. 670 // 671 // TODO(adonovan): unfortunately, Alias nodes 672 // (GODEBUG=gotypesalias=1) don't entirely resolve 673 // problems with cycles. For example, in 674 // GOROOT/test/typeparam/issue50259.go, 675 // 676 // type T[_ any] struct{} 677 // type A T[B] 678 // type B = T[A] 679 // 680 // TypeName A has Type Named during checking, but by 681 // the time the unified export data is written out, 682 // its Type is Invalid. 683 // 684 // Investigate and reenable this branch. 685 for _, obj := range objList { 686 check.objDecl(obj, nil) 687 } 688 } else { 689 // Without Alias nodes, we process non-alias type declarations first, followed by 690 // alias declarations, and then everything else. This appears to avoid most situations 691 // where the type of an alias is needed before it is available. 692 // There may still be cases where this is not good enough (see also go.dev/issue/25838). 693 // In those cases Checker.ident will report an error ("invalid use of type alias"). 694 var aliasList []*TypeName 695 var othersList []Object // everything that's not a type 696 // phase 1: non-alias type declarations 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 // phase 2: alias type declarations 709 for _, obj := range aliasList { 710 check.objDecl(obj, nil) 711 } 712 // phase 3: all other declarations 713 for _, obj := range othersList { 714 check.objDecl(obj, nil) 715 } 716 } 717 718 // At this point we may have a non-empty check.methods map; this means that not all 719 // entries were deleted at the end of typeDecl because the respective receiver base 720 // types were not found. In that case, an error was reported when declaring those 721 // methods. We can now safely discard this map. 722 check.methods = nil 723} 724 725// inSourceOrder implements the sort.Sort interface. 726type inSourceOrder []Object 727 728func (a inSourceOrder) Len() int { return len(a) } 729func (a inSourceOrder) Less(i, j int) bool { return a[i].order() < a[j].order() } 730func (a inSourceOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 731 732// unusedImports checks for unused imports. 733func (check *Checker) unusedImports() { 734 // If function bodies are not checked, packages' uses are likely missing - don't check. 735 if check.conf.IgnoreFuncBodies { 736 return 737 } 738 739 // spec: "It is illegal (...) to directly import a package without referring to 740 // any of its exported identifiers. To import a package solely for its side-effects 741 // (initialization), use the blank identifier as explicit package name." 742 743 for _, obj := range check.imports { 744 if !obj.used && obj.name != "_" { 745 check.errorUnusedPkg(obj) 746 } 747 } 748} 749 750func (check *Checker) errorUnusedPkg(obj *PkgName) { 751 // If the package was imported with a name other than the final 752 // import path element, show it explicitly in the error message. 753 // Note that this handles both renamed imports and imports of 754 // packages containing unconventional package declarations. 755 // Note that this uses / always, even on Windows, because Go import 756 // paths always use forward slashes. 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// dir makes a good-faith attempt to return the directory 770// portion of path. If path is empty, the result is ".". 771// (Per the go/build package dependency tests, we cannot import 772// path/filepath and simply use filepath.Dir.) 773func dir(path string) string { 774 if i := strings.LastIndexAny(path, `/\`); i > 0 { 775 return path[:i] 776 } 777 // i <= 0 778 return "." 779} 780