resolver.go raw

   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  	"cmp"
   9  	"fmt"
  10  	"go/ast"
  11  	"go/constant"
  12  	"go/token"
  13  	. "internal/types/errors"
  14  	"slices"
  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  	version   goVersion     // Go version of file containing this declaration
  24  	lhs       []*Var        // lhs of n:1 variable declarations, or nil
  25  	vtyp      ast.Expr      // type, or nil (for const and var declarations only)
  26  	init      ast.Expr      // init/orig expression, or nil (for const and var declarations only)
  27  	inherited bool          // if set, the init expression is inherited from a previous constant declaration
  28  	tdecl     *ast.TypeSpec // type declaration, or nil
  29  	fdecl     *ast.FuncDecl // func declaration, or nil
  30  
  31  	// The deps field tracks initialization expression dependencies.
  32  	deps map[Object]bool // lazily initialized
  33  }
  34  
  35  // hasInitializer reports whether the declared object has an initialization
  36  // expression or function body.
  37  func (d *declInfo) hasInitializer() bool {
  38  	return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
  39  }
  40  
  41  // addDep adds obj to the set of objects d's init expression depends on.
  42  func (d *declInfo) addDep(obj Object) {
  43  	m := d.deps
  44  	if m == nil {
  45  		m = make(map[Object]bool)
  46  		d.deps = m
  47  	}
  48  	m[obj] = true
  49  }
  50  
  51  // arityMatch checks that the lhs and rhs of a const or var decl
  52  // have the appropriate number of names and init exprs. For const
  53  // decls, init is the value spec providing the init exprs; for
  54  // var decls, init is nil (the init exprs are in s in this case).
  55  func (check *Checker) arityMatch(s, init *ast.ValueSpec) {
  56  	l := len(s.Names)
  57  	r := len(s.Values)
  58  	if init != nil {
  59  		r = len(init.Values)
  60  	}
  61  
  62  	const code = WrongAssignCount
  63  	switch {
  64  	case init == nil && r == 0:
  65  		// var decl w/o init expr
  66  		if s.Type == nil {
  67  			check.error(s, code, "missing type or init expr")
  68  		}
  69  	case l < r:
  70  		if l < len(s.Values) {
  71  			// init exprs from s
  72  			n := s.Values[l]
  73  			check.errorf(n, code, "extra init expr %s", n)
  74  			// TODO(gri) avoid declared and not used error here
  75  		} else {
  76  			// init exprs "inherited"
  77  			check.errorf(s, code, "extra init expr at %s", check.fset.Position(init.Pos()))
  78  			// TODO(gri) avoid declared and not used error here
  79  		}
  80  	case l > r && (init != nil || r != 1):
  81  		n := s.Names[r]
  82  		check.errorf(n, code, "missing init expr for %s", n)
  83  	}
  84  }
  85  
  86  func validatedImportPath(path string) (string, error) {
  87  	s, err := strconv.Unquote(path)
  88  	if err != nil {
  89  		return "", err
  90  	}
  91  	if s == "" {
  92  		return "", fmt.Errorf("empty string")
  93  	}
  94  	const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
  95  	for _, r := range s {
  96  		if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
  97  			return s, fmt.Errorf("invalid character %#U", r)
  98  		}
  99  	}
 100  	return s, nil
 101  }
 102  
 103  // declarePkgObj declares obj in the package scope, records its ident -> obj mapping,
 104  // and updates check.objMap. The object must not be a function or method.
 105  func (check *Checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) {
 106  	assert(ident.Name == obj.Name())
 107  
 108  	// spec: "A package-scope or file-scope identifier with name init
 109  	// may only be declared to be a function with this (func()) signature."
 110  	if ident.Name == "init" {
 111  		check.error(ident, InvalidInitDecl, "cannot declare init - must be func")
 112  		return
 113  	}
 114  
 115  	// spec: "The main package must have package name main and declare
 116  	// a function main that takes no arguments and returns no value."
 117  	if ident.Name == "main" && check.pkg.name == "main" {
 118  		check.error(ident, InvalidMainDecl, "cannot declare main - must be func")
 119  		return
 120  	}
 121  
 122  	check.declare(check.pkg.scope, ident, obj, nopos)
 123  	check.objMap[obj] = d
 124  	obj.setOrder(uint32(len(check.objMap)))
 125  }
 126  
 127  // filename returns a filename suitable for debugging output.
 128  func (check *Checker) filename(fileNo int) string {
 129  	file := check.files[fileNo]
 130  	if pos := file.Pos(); pos.IsValid() {
 131  		return check.fset.File(pos).Name()
 132  	}
 133  	return fmt.Sprintf("file[%d]", fileNo)
 134  }
 135  
 136  func (check *Checker) importPackage(at positioner, path, dir string) *Package {
 137  	// If we already have a package for the given (path, dir)
 138  	// pair, use it instead of doing a full import.
 139  	// Checker.impMap only caches packages that are marked Complete
 140  	// or fake (dummy packages for failed imports). Incomplete but
 141  	// non-fake packages do require an import to complete them.
 142  	key := importKey{path, dir}
 143  	imp := check.impMap[key]
 144  	if imp != nil {
 145  		return imp
 146  	}
 147  
 148  	// no package yet => import it
 149  	if path == "C" && (check.conf.FakeImportC || check.conf.go115UsesCgo) {
 150  		if check.conf.FakeImportC && check.conf.go115UsesCgo {
 151  			check.error(at, BadImportPath, "cannot use FakeImportC and go115UsesCgo together")
 152  		}
 153  		imp = NewPackage("C", "C")
 154  		imp.fake = true // package scope is not populated
 155  		imp.cgo = check.conf.go115UsesCgo
 156  	} else {
 157  		// ordinary import
 158  		var err error
 159  		if importer := check.conf.Importer; importer == nil {
 160  			err = fmt.Errorf("Config.Importer not installed")
 161  		} else if importerFrom, ok := importer.(ImporterFrom); ok {
 162  			imp, err = importerFrom.ImportFrom(path, dir, 0)
 163  			if imp == nil && err == nil {
 164  				err = fmt.Errorf("Config.Importer.ImportFrom(%s, %s, 0) returned nil but no error", path, dir)
 165  			}
 166  		} else {
 167  			imp, err = importer.Import(path)
 168  			if imp == nil && err == nil {
 169  				err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path)
 170  			}
 171  		}
 172  		// make sure we have a valid package name
 173  		// (errors here can only happen through manipulation of packages after creation)
 174  		if err == nil && imp != nil && (imp.name == "_" || imp.name == "") {
 175  			err = fmt.Errorf("invalid package name: %q", imp.name)
 176  			imp = nil // create fake package below
 177  		}
 178  		if err != nil {
 179  			check.errorf(at, BrokenImport, "could not import %s (%s)", path, err)
 180  			if imp == nil {
 181  				// create a new fake package
 182  				// come up with a sensible package name (heuristic)
 183  				name := path
 184  				if i := len(name); i > 0 && name[i-1] == '/' {
 185  					name = name[:i-1]
 186  				}
 187  				if i := strings.LastIndex(name, "/"); i >= 0 {
 188  					name = name[i+1:]
 189  				}
 190  				imp = NewPackage(path, name)
 191  			}
 192  			// continue to use the package as best as we can
 193  			imp.fake = true // avoid follow-up lookup failures
 194  		}
 195  	}
 196  
 197  	// package should be complete or marked fake, but be cautious
 198  	if imp.complete || imp.fake {
 199  		check.impMap[key] = imp
 200  		// Once we've formatted an error message, keep the pkgPathMap
 201  		// up-to-date on subsequent imports. It is used for package
 202  		// qualification in error messages.
 203  		if check.pkgPathMap != nil {
 204  			check.markImports(imp)
 205  		}
 206  		return imp
 207  	}
 208  
 209  	// something went wrong (importer may have returned incomplete package without error)
 210  	return nil
 211  }
 212  
 213  // collectObjects collects all file and package objects and inserts them
 214  // into their respective scopes. It also performs imports and associates
 215  // methods with receiver base type names.
 216  func (check *Checker) collectObjects() {
 217  	pkg := check.pkg
 218  
 219  	// pkgImports is the set of packages already imported by any package file seen
 220  	// so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate
 221  	// it (pkg.imports may not be empty if we are checking test files incrementally).
 222  	// Note that pkgImports is keyed by package (and thus package path), not by an
 223  	// importKey value. Two different importKey values may map to the same package
 224  	// which is why we cannot use the check.impMap here.
 225  	var pkgImports = make(map[*Package]bool)
 226  	for _, imp := range pkg.imports {
 227  		pkgImports[imp] = true
 228  	}
 229  
 230  	type methodInfo struct {
 231  		obj  *Func      // method
 232  		ptr  bool       // true if pointer receiver
 233  		recv *ast.Ident // receiver type name
 234  	}
 235  	var methods []methodInfo // collected methods with valid receivers and non-blank _ names
 236  
 237  	fileScopes := make([]*Scope, len(check.files)) // fileScopes[i] corresponds to check.files[i]
 238  	for fileNo, file := range check.files {
 239  		check.version = asGoVersion(check.versions[file])
 240  
 241  		// The package identifier denotes the current package,
 242  		// but there is no corresponding package object.
 243  		check.recordDef(file.Name, nil)
 244  
 245  		// Use the actual source file extent rather than *ast.File extent since the
 246  		// latter doesn't include comments which appear at the start or end of the file.
 247  		// Be conservative and use the *ast.File extent if we don't have a *token.File.
 248  		pos, end := file.Pos(), file.End()
 249  		if f := check.fset.File(file.Pos()); f != nil {
 250  			pos, end = token.Pos(f.Base()), token.Pos(f.Base()+f.Size())
 251  		}
 252  		fileScope := NewScope(pkg.scope, pos, end, check.filename(fileNo))
 253  		fileScopes[fileNo] = fileScope
 254  		check.recordScope(file, fileScope)
 255  
 256  		// determine file directory, necessary to resolve imports
 257  		// FileName may be "" (typically for tests) in which case
 258  		// we get "." as the directory which is what we would want.
 259  		fileDir := dir(check.fset.Position(file.Name.Pos()).Filename)
 260  
 261  		check.walkDecls(file.Decls, func(d decl) {
 262  			switch d := d.(type) {
 263  			case importDecl:
 264  				// import package
 265  				if d.spec.Path.Value == "" {
 266  					return // error reported by parser
 267  				}
 268  				path, err := validatedImportPath(d.spec.Path.Value)
 269  				if err != nil {
 270  					check.errorf(d.spec.Path, BadImportPath, "invalid import path (%s)", err)
 271  					return
 272  				}
 273  
 274  				imp := check.importPackage(d.spec.Path, path, fileDir)
 275  				if imp == nil {
 276  					return
 277  				}
 278  
 279  				// local name overrides imported package name
 280  				name := imp.name
 281  				if d.spec.Name != nil {
 282  					name = d.spec.Name.Name
 283  					if path == "C" {
 284  						// match 1.17 cmd/compile (not prescribed by spec)
 285  						check.error(d.spec.Name, ImportCRenamed, `cannot rename import "C"`)
 286  						return
 287  					}
 288  				}
 289  
 290  				if name == "init" {
 291  					check.error(d.spec, InvalidInitDecl, "cannot import package as init - init must be a func")
 292  					return
 293  				}
 294  
 295  				// add package to list of explicit imports
 296  				// (this functionality is provided as a convenience
 297  				// for clients; it is not needed for type-checking)
 298  				if !pkgImports[imp] {
 299  					pkgImports[imp] = true
 300  					pkg.imports = append(pkg.imports, imp)
 301  				}
 302  
 303  				pkgName := NewPkgName(d.spec.Pos(), pkg, name, imp)
 304  				if d.spec.Name != nil {
 305  					// in a dot-import, the dot represents the package
 306  					check.recordDef(d.spec.Name, pkgName)
 307  				} else {
 308  					check.recordImplicit(d.spec, pkgName)
 309  				}
 310  
 311  				if imp.fake {
 312  					// match 1.17 cmd/compile (not prescribed by spec)
 313  					check.usedPkgNames[pkgName] = true
 314  				}
 315  
 316  				// add import to file scope
 317  				check.imports = append(check.imports, pkgName)
 318  				if name == "." {
 319  					// dot-import
 320  					if check.dotImportMap == nil {
 321  						check.dotImportMap = make(map[dotImportKey]*PkgName)
 322  					}
 323  					// merge imported scope with file scope
 324  					for name, obj := range imp.scope.elems {
 325  						// Note: Avoid eager resolve(name, obj) here, so we only
 326  						// resolve dot-imported objects as needed.
 327  
 328  						// A package scope may contain non-exported objects,
 329  						// do not import them!
 330  						if token.IsExported(name) {
 331  							// declare dot-imported object
 332  							// (Do not use check.declare because it modifies the object
 333  							// via Object.setScopePos, which leads to a race condition;
 334  							// the object may be imported into more than one file scope
 335  							// concurrently. See go.dev/issue/32154.)
 336  							if alt := fileScope.Lookup(name); alt != nil {
 337  								err := check.newError(DuplicateDecl)
 338  								err.addf(d.spec.Name, "%s redeclared in this block", alt.Name())
 339  								err.addAltDecl(alt)
 340  								err.report()
 341  							} else {
 342  								fileScope.insert(name, obj)
 343  								check.dotImportMap[dotImportKey{fileScope, name}] = pkgName
 344  							}
 345  						}
 346  					}
 347  				} else {
 348  					// declare imported package object in file scope
 349  					// (no need to provide s.Name since we called check.recordDef earlier)
 350  					check.declare(fileScope, nil, pkgName, nopos)
 351  				}
 352  			case constDecl:
 353  				// declare all constants
 354  				for i, name := range d.spec.Names {
 355  					obj := NewConst(name.Pos(), pkg, name.Name, nil, constant.MakeInt64(int64(d.iota)))
 356  
 357  					var init ast.Expr
 358  					if i < len(d.init) {
 359  						init = d.init[i]
 360  					}
 361  
 362  					d := &declInfo{file: fileScope, version: check.version, vtyp: d.typ, init: init, inherited: d.inherited}
 363  					check.declarePkgObj(name, obj, d)
 364  				}
 365  
 366  			case varDecl:
 367  				lhs := make([]*Var, len(d.spec.Names))
 368  				// If there's exactly one rhs initializer, use
 369  				// the same declInfo d1 for all lhs variables
 370  				// so that each lhs variable depends on the same
 371  				// rhs initializer (n:1 var declaration).
 372  				var d1 *declInfo
 373  				if len(d.spec.Values) == 1 {
 374  					// The lhs elements are only set up after the for loop below,
 375  					// but that's ok because declareVar only collects the declInfo
 376  					// for a later phase.
 377  					d1 = &declInfo{file: fileScope, version: check.version, lhs: lhs, vtyp: d.spec.Type, init: d.spec.Values[0]}
 378  				}
 379  
 380  				// declare all variables
 381  				for i, name := range d.spec.Names {
 382  					obj := newVar(PackageVar, name.Pos(), pkg, name.Name, nil)
 383  					lhs[i] = obj
 384  
 385  					di := d1
 386  					if di == nil {
 387  						// individual assignments
 388  						var init ast.Expr
 389  						if i < len(d.spec.Values) {
 390  							init = d.spec.Values[i]
 391  						}
 392  						di = &declInfo{file: fileScope, version: check.version, vtyp: d.spec.Type, init: init}
 393  					}
 394  
 395  					check.declarePkgObj(name, obj, di)
 396  				}
 397  			case typeDecl:
 398  				obj := NewTypeName(d.spec.Name.Pos(), pkg, d.spec.Name.Name, nil)
 399  				check.declarePkgObj(d.spec.Name, obj, &declInfo{file: fileScope, version: check.version, tdecl: d.spec})
 400  			case funcDecl:
 401  				name := d.decl.Name.Name
 402  				obj := NewFunc(d.decl.Name.Pos(), pkg, name, nil) // signature set later
 403  				hasTParamError := false                           // avoid duplicate type parameter errors
 404  				if d.decl.Recv.NumFields() == 0 {
 405  					// regular function
 406  					if d.decl.Recv != nil {
 407  						check.error(d.decl.Recv, BadRecv, "method has no receiver")
 408  						// treat as function
 409  					}
 410  					if name == "init" || (name == "main" && check.pkg.name == "main") {
 411  						code := InvalidInitDecl
 412  						if name == "main" {
 413  							code = InvalidMainDecl
 414  						}
 415  						if d.decl.Type.TypeParams.NumFields() != 0 {
 416  							check.softErrorf(d.decl.Type.TypeParams.List[0], code, "func %s must have no type parameters", name)
 417  							hasTParamError = true
 418  						}
 419  						if t := d.decl.Type; t.Params.NumFields() != 0 || t.Results != nil {
 420  							// TODO(rFindley) Should this be a hard error?
 421  							check.softErrorf(d.decl.Name, code, "func %s must have no arguments and no return values", name)
 422  						}
 423  					}
 424  					if name == "init" {
 425  						// don't declare init functions in the package scope - they are invisible
 426  						obj.parent = pkg.scope
 427  						check.recordDef(d.decl.Name, obj)
 428  						if d.decl.Body == nil {
 429  							check.softErrorf(obj, MissingInitBody, "func init must have a body")
 430  						}
 431  					} else {
 432  						check.declare(pkg.scope, d.decl.Name, obj, nopos)
 433  					}
 434  				} else {
 435  					// method
 436  
 437  					// TODO(rFindley) earlier versions of this code checked that methods
 438  					//                have no type parameters, but this is checked later
 439  					//                when type checking the function type. Confirm that
 440  					//                we don't need to check tparams here.
 441  
 442  					ptr, base, _ := check.unpackRecv(d.decl.Recv.List[0].Type, false)
 443  					// (Methods with invalid receiver cannot be associated to a type, and
 444  					// methods with blank _ names are never found; no need to collect any
 445  					// of them. They will still be type-checked with all the other functions.)
 446  					if recv, _ := base.(*ast.Ident); recv != nil && name != "_" {
 447  						methods = append(methods, methodInfo{obj, ptr, recv})
 448  					}
 449  					check.recordDef(d.decl.Name, obj)
 450  				}
 451  				_ = d.decl.Type.TypeParams.NumFields() != 0 && !hasTParamError && check.verifyVersionf(d.decl.Type.TypeParams.List[0], go1_18, "type parameter")
 452  				info := &declInfo{file: fileScope, version: check.version, fdecl: d.decl}
 453  				// Methods are not package-level objects but we still track them in the
 454  				// object map so that we can handle them like regular functions (if the
 455  				// receiver is invalid); also we need their fdecl info when associating
 456  				// them with their receiver base type, below.
 457  				check.objMap[obj] = info
 458  				obj.setOrder(uint32(len(check.objMap)))
 459  			}
 460  		})
 461  	}
 462  
 463  	// verify that objects in package and file scopes have different names
 464  	for _, scope := range fileScopes {
 465  		for name, obj := range scope.elems {
 466  			if alt := pkg.scope.Lookup(name); alt != nil {
 467  				obj = resolve(name, obj)
 468  				err := check.newError(DuplicateDecl)
 469  				if pkg, ok := obj.(*PkgName); ok {
 470  					err.addf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported())
 471  					err.addAltDecl(pkg)
 472  				} else {
 473  					err.addf(alt, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
 474  					// TODO(gri) dot-imported objects don't have a position; addAltDecl won't print anything
 475  					err.addAltDecl(obj)
 476  				}
 477  				err.report()
 478  			}
 479  		}
 480  	}
 481  
 482  	// Now that we have all package scope objects and all methods,
 483  	// associate methods with receiver base type name where possible.
 484  	// Ignore methods that have an invalid receiver. They will be
 485  	// type-checked later, with regular functions.
 486  	if methods == nil {
 487  		return
 488  	}
 489  
 490  	check.methods = make(map[*TypeName][]*Func)
 491  	for i := range methods {
 492  		m := &methods[i]
 493  		// Determine the receiver base type and associate m with it.
 494  		ptr, base := check.resolveBaseTypeName(m.ptr, m.recv)
 495  		if base != nil {
 496  			m.obj.hasPtrRecv_ = ptr
 497  			check.methods[base] = append(check.methods[base], m.obj)
 498  		}
 499  	}
 500  }
 501  
 502  // unpackRecv unpacks a receiver type expression and returns its components: ptr indicates
 503  // whether rtyp is a pointer receiver, base is the receiver base type expression stripped
 504  // of its type parameters (if any), and tparams are its type parameter names, if any. The
 505  // type parameters are only unpacked if unpackParams is set. For instance, given the rtyp
 506  //
 507  //	*T[A, _]
 508  //
 509  // ptr is true, base is T, and tparams is [A, _] (assuming unpackParams is set).
 510  // Note that base may not be a *ast.Ident for erroneous programs.
 511  func (check *Checker) unpackRecv(rtyp ast.Expr, unpackParams bool) (ptr bool, base ast.Expr, tparams []*ast.Ident) {
 512  	// unpack receiver type
 513  	base = ast.Unparen(rtyp)
 514  	if t, _ := base.(*ast.StarExpr); t != nil {
 515  		ptr = true
 516  		base = ast.Unparen(t.X)
 517  	}
 518  
 519  	// unpack type parameters, if any
 520  	switch base.(type) {
 521  	case *ast.IndexExpr, *ast.IndexListExpr:
 522  		ix := unpackIndexedExpr(base)
 523  		base = ix.x
 524  		if unpackParams {
 525  			for _, arg := range ix.indices {
 526  				var par *ast.Ident
 527  				switch arg := arg.(type) {
 528  				case *ast.Ident:
 529  					par = arg
 530  				case *ast.BadExpr:
 531  					// ignore - error already reported by parser
 532  				case nil:
 533  					check.error(ix.orig, InvalidSyntaxTree, "parameterized receiver contains nil parameters")
 534  				default:
 535  					check.errorf(arg, BadDecl, "receiver type parameter %s must be an identifier", arg)
 536  				}
 537  				if par == nil {
 538  					par = &ast.Ident{NamePos: arg.Pos(), Name: "_"}
 539  				}
 540  				tparams = append(tparams, par)
 541  			}
 542  		}
 543  	}
 544  
 545  	return
 546  }
 547  
 548  // resolveBaseTypeName returns the non-alias base type name for the given name, and whether
 549  // there was a pointer indirection to get to it. The base type name must be declared
 550  // in package scope, and there can be at most one pointer indirection. Traversals
 551  // through generic alias types are not permitted. If no such type name exists, the
 552  // returned base is nil.
 553  func (check *Checker) resolveBaseTypeName(ptr bool, name *ast.Ident) (ptr_ bool, base *TypeName) {
 554  	// Algorithm: Starting from name, which is expected to denote a type,
 555  	// we follow that type through non-generic alias declarations until
 556  	// we reach a non-alias type name.
 557  	var seen map[*TypeName]bool
 558  	for name != nil {
 559  		// name must denote an object found in the current package scope
 560  		// (note that dot-imported objects are not in the package scope!)
 561  		obj := check.pkg.scope.Lookup(name.Name)
 562  		if obj == nil {
 563  			break
 564  		}
 565  
 566  		// the object must be a type name...
 567  		tname, _ := obj.(*TypeName)
 568  		if tname == nil {
 569  			break
 570  		}
 571  
 572  		// ... which we have not seen before
 573  		if seen[tname] {
 574  			break
 575  		}
 576  
 577  		// we're done if tdecl describes a defined type (not an alias)
 578  		tdecl := check.objMap[tname].tdecl // must exist for objects in package scope
 579  		if !tdecl.Assign.IsValid() {
 580  			return ptr, tname
 581  		}
 582  
 583  		// an alias must not be generic
 584  		// (importantly, we must not collect such methods - was https://go.dev/issue/70417)
 585  		if tdecl.TypeParams != nil {
 586  			break
 587  		}
 588  
 589  		// otherwise, remember this type name and continue resolving
 590  		if seen == nil {
 591  			seen = make(map[*TypeName]bool)
 592  		}
 593  		seen[tname] = true
 594  
 595  		// The go/parser keeps parentheses; strip them, if any.
 596  		typ := ast.Unparen(tdecl.Type)
 597  
 598  		// dereference a pointer type
 599  		if pexpr, _ := typ.(*ast.StarExpr); pexpr != nil {
 600  			// if we've already seen a pointer, we're done
 601  			if ptr {
 602  				break
 603  			}
 604  			ptr = true
 605  			typ = ast.Unparen(pexpr.X) // continue with pointer base type
 606  		}
 607  
 608  		// After dereferencing, typ must be a locally defined type name.
 609  		// Referring to other packages (qualified identifiers) or going
 610  		// through instantiated types (index expressions) is not permitted,
 611  		// so we can ignore those.
 612  		name, _ = typ.(*ast.Ident)
 613  		if name == nil {
 614  			break
 615  		}
 616  	}
 617  
 618  	// no base type found
 619  	return false, nil
 620  }
 621  
 622  // packageObjects typechecks all package objects, but not function bodies.
 623  func (check *Checker) packageObjects() {
 624  	// process package objects in source order for reproducible results
 625  	objList := make([]Object, len(check.objMap))
 626  	i := 0
 627  	for obj := range check.objMap {
 628  		objList[i] = obj
 629  		i++
 630  	}
 631  	slices.SortFunc(objList, func(a, b Object) int {
 632  		return cmp.Compare(a.order(), b.order())
 633  	})
 634  
 635  	// add new methods to already type-checked types (from a prior Checker.Files call)
 636  	for _, obj := range objList {
 637  		if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil {
 638  			check.collectMethods(obj)
 639  		}
 640  	}
 641  
 642  	if false && check.conf._EnableAlias {
 643  		// With Alias nodes we can process declarations in any order.
 644  		//
 645  		// TODO(adonovan): unfortunately, Alias nodes
 646  		// (GODEBUG=gotypesalias=1) don't entirely resolve
 647  		// problems with cycles. For example, in
 648  		// GOROOT/test/typeparam/issue50259.go,
 649  		//
 650  		// 	type T[_ any] struct{}
 651  		// 	type A T[B]
 652  		// 	type B = T[A]
 653  		//
 654  		// TypeName A has Type Named during checking, but by
 655  		// the time the unified export data is written out,
 656  		// its Type is Invalid.
 657  		//
 658  		// Investigate and reenable this branch.
 659  		for _, obj := range objList {
 660  			check.objDecl(obj, nil)
 661  		}
 662  	} else {
 663  		// Without Alias nodes, we process non-alias type declarations first, followed by
 664  		// alias declarations, and then everything else. This appears to avoid most situations
 665  		// where the type of an alias is needed before it is available.
 666  		// There may still be cases where this is not good enough (see also go.dev/issue/25838).
 667  		// In those cases Checker.ident will report an error ("invalid use of type alias").
 668  		var aliasList []*TypeName
 669  		var othersList []Object // everything that's not a type
 670  		// phase 1: non-alias type declarations
 671  		for _, obj := range objList {
 672  			if tname, _ := obj.(*TypeName); tname != nil {
 673  				if check.objMap[tname].tdecl.Assign.IsValid() {
 674  					aliasList = append(aliasList, tname)
 675  				} else {
 676  					check.objDecl(obj, nil)
 677  				}
 678  			} else {
 679  				othersList = append(othersList, obj)
 680  			}
 681  		}
 682  		// phase 2: alias type declarations
 683  		for _, obj := range aliasList {
 684  			check.objDecl(obj, nil)
 685  		}
 686  		// phase 3: all other declarations
 687  		for _, obj := range othersList {
 688  			check.objDecl(obj, nil)
 689  		}
 690  	}
 691  
 692  	// At this point we may have a non-empty check.methods map; this means that not all
 693  	// entries were deleted at the end of typeDecl because the respective receiver base
 694  	// types were not found. In that case, an error was reported when declaring those
 695  	// methods. We can now safely discard this map.
 696  	check.methods = nil
 697  }
 698  
 699  // unusedImports checks for unused imports.
 700  func (check *Checker) unusedImports() {
 701  	// If function bodies are not checked, packages' uses are likely missing - don't check.
 702  	if check.conf.IgnoreFuncBodies {
 703  		return
 704  	}
 705  
 706  	// spec: "It is illegal (...) to directly import a package without referring to
 707  	// any of its exported identifiers. To import a package solely for its side-effects
 708  	// (initialization), use the blank identifier as explicit package name."
 709  
 710  	for _, obj := range check.imports {
 711  		if obj.name != "_" && !check.usedPkgNames[obj] {
 712  			check.errorUnusedPkg(obj)
 713  		}
 714  	}
 715  }
 716  
 717  func (check *Checker) errorUnusedPkg(obj *PkgName) {
 718  	// If the package was imported with a name other than the final
 719  	// import path element, show it explicitly in the error message.
 720  	// Note that this handles both renamed imports and imports of
 721  	// packages containing unconventional package declarations.
 722  	// Note that this uses / always, even on Windows, because Go import
 723  	// paths always use forward slashes.
 724  	path := obj.imported.path
 725  	elem := path
 726  	if i := strings.LastIndex(elem, "/"); i >= 0 {
 727  		elem = elem[i+1:]
 728  	}
 729  	if obj.name == "" || obj.name == "." || obj.name == elem {
 730  		check.softErrorf(obj, UnusedImport, "%q imported and not used", path)
 731  	} else {
 732  		check.softErrorf(obj, UnusedImport, "%q imported as %s and not used", path, obj.name)
 733  	}
 734  }
 735  
 736  // dir makes a good-faith attempt to return the directory
 737  // portion of path. If path is empty, the result is ".".
 738  // (Per the go/build package dependency tests, we cannot import
 739  // path/filepath and simply use filepath.Dir.)
 740  func dir(path string) string {
 741  	if i := strings.LastIndexAny(path, `/\`); i > 0 {
 742  		return path[:i]
 743  	}
 744  	// i <= 0
 745  	return "."
 746  }
 747