]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/go/types/resolver.go
[dev.typeparams] merge master (2f0da6d) into dev.typeparams
[gostls13.git] / src / go / types / resolver.go
index 4f09237692837c3fb81275e7e9149feb0653bede..36f9a45cca2b6d5f27d2fc4dccf48a7540eb348f 100644 (file)
@@ -259,14 +259,6 @@ func (check *Checker) collectObjects() {
                                        return
                                }
 
-                               // add package to list of explicit imports
-                               // (this functionality is provided as a convenience
-                               // for clients; it is not needed for type-checking)
-                               if !pkgImports[imp] {
-                                       pkgImports[imp] = true
-                                       pkg.imports = append(pkg.imports, imp)
-                               }
-
                                // local name overrides imported package name
                                name := imp.name
                                if d.spec.Name != nil {
@@ -276,27 +268,41 @@ func (check *Checker) collectObjects() {
                                                check.errorf(d.spec.Name, _ImportCRenamed, `cannot rename import "C"`)
                                                return
                                        }
-                                       if name == "init" {
-                                               check.errorf(d.spec.Name, _InvalidInitDecl, "cannot declare init - must be func")
-                                               return
-                                       }
                                }
 
-                               obj := NewPkgName(d.spec.Pos(), pkg, name, imp)
+                               if name == "init" {
+                                       check.errorf(d.spec.Name, _InvalidInitDecl, "cannot import package as init - init must be a func")
+                                       return
+                               }
+
+                               // add package to list of explicit imports
+                               // (this functionality is provided as a convenience
+                               // for clients; it is not needed for type-checking)
+                               if !pkgImports[imp] {
+                                       pkgImports[imp] = true
+                                       pkg.imports = append(pkg.imports, imp)
+                               }
+
+                               pkgName := NewPkgName(d.spec.Pos(), pkg, name, imp)
                                if d.spec.Name != nil {
                                        // in a dot-import, the dot represents the package
-                                       check.recordDef(d.spec.Name, obj)
+                                       check.recordDef(d.spec.Name, pkgName)
                                } else {
-                                       check.recordImplicit(d.spec, obj)
+                                       check.recordImplicit(d.spec, pkgName)
                                }
 
                                if path == "C" {
                                        // match cmd/compile (not prescribed by spec)
-                                       obj.used = true
+                                       pkgName.used = true
                                }
 
                                // add import to file scope
+                               check.imports = append(check.imports, pkgName)
                                if name == "." {
+                                       // dot-import
+                                       if check.dotImportMap == nil {
+                                               check.dotImportMap = make(map[dotImportKey]*PkgName)
+                                       }
                                        // merge imported scope with file scope
                                        for _, obj := range imp.scope.elems {
                                                // A package scope may contain non-exported objects,
@@ -310,16 +316,15 @@ func (check *Checker) collectObjects() {
                                                        if alt := fileScope.Insert(obj); alt != nil {
                                                                check.errorf(d.spec.Name, _DuplicateDecl, "%s redeclared in this block", obj.Name())
                                                                check.reportAltDecl(alt)
+                                                       } else {
+                                                               check.dotImportMap[dotImportKey{fileScope, obj}] = pkgName
                                                        }
                                                }
                                        }
-                                       // add position to set of dot-import positions for this file
-                                       // (this is only needed for "imported but not used" errors)
-                                       check.addUnusedDotImport(fileScope, imp, d.spec)
                                } else {
                                        // declare imported package object in file scope
                                        // (no need to provide s.Name since we called check.recordDef earlier)
-                                       check.declare(fileScope, nil, obj, token.NoPos)
+                                       check.declare(fileScope, nil, pkgName, token.NoPos)
                                }
                        case constDecl:
                                // declare all constants
@@ -654,39 +659,30 @@ func (check *Checker) unusedImports() {
        // any of its exported identifiers. To import a package solely for its side-effects
        // (initialization), use the blank identifier as explicit package name."
 
-       // check use of regular imported packages
-       for _, scope := range check.pkg.scope.children /* file scopes */ {
-               for _, obj := range scope.elems {
-                       if obj, ok := obj.(*PkgName); ok {
-                               // Unused "blank imports" are automatically ignored
-                               // since _ identifiers are not entered into scopes.
-                               if !obj.used {
-                                       path := obj.imported.path
-                                       base := pkgName(path)
-                                       if obj.name == base {
-                                               check.softErrorf(obj, _UnusedImport, "%q imported but not used", path)
-                                       } else {
-                                               check.softErrorf(obj, _UnusedImport, "%q imported but not used as %s", path, obj.name)
-                                       }
-                               }
-                       }
-               }
-       }
-
-       // check use of dot-imported packages
-       for _, unusedDotImports := range check.unusedDotImports {
-               for pkg, pos := range unusedDotImports {
-                       check.softErrorf(pos, _UnusedImport, "%q imported but not used", pkg.path)
+       for _, obj := range check.imports {
+               if !obj.used && obj.name != "_" {
+                       check.errorUnusedPkg(obj)
                }
        }
 }
 
-// pkgName returns the package name (last element) of an import path.
-func pkgName(path string) string {
-       if i := strings.LastIndex(path, "/"); i >= 0 {
-               path = path[i+1:]
+func (check *Checker) errorUnusedPkg(obj *PkgName) {
+       // If the package was imported with a name other than the final
+       // import path element, show it explicitly in the error message.
+       // Note that this handles both renamed imports and imports of
+       // packages containing unconventional package declarations.
+       // Note that this uses / always, even on Windows, because Go import
+       // paths always use forward slashes.
+       path := obj.imported.path
+       elem := path
+       if i := strings.LastIndex(elem, "/"); i >= 0 {
+               elem = elem[i+1:]
+       }
+       if obj.name == "" || obj.name == "." || obj.name == elem {
+               check.softErrorf(obj, _UnusedImport, "%q imported but not used", path)
+       } else {
+               check.softErrorf(obj, _UnusedImport, "%q imported but not used as %s", path, obj.name)
        }
-       return path
 }
 
 // dir makes a good-faith attempt to return the directory