Commit b81e01dc authored by Robert Griesemer's avatar Robert Griesemer

go/types: print package path in error messages if package name is not unique

Change package qualification to print the full package path for packages
that have non-unique names (that is, where multiple different packages
have the same name). Use the package name as qualifier in all other cases
(but don't print any qualification if we're talking about the package
being type-checked).

This matches the behavior of the compiler.

Fixes #35895.

Change-Id: I33ab8e7adfae1378907c01e33cabda114f65887f
Reviewed-on: https://go-review.googlesource.com/c/go/+/209578
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 5fd75810
...@@ -79,6 +79,7 @@ type Checker struct { ...@@ -79,6 +79,7 @@ type Checker struct {
objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info
impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
posMap map[*Interface][]token.Pos // maps interface types to lists of embedded interface positions posMap map[*Interface][]token.Pos // maps interface types to lists of embedded interface positions
pkgCnt map[string]int // counts number of imported packages with a given name (for better error messages)
// information collected during type-checking of a set of package files // information collected during type-checking of a set of package files
// (initialized by Files, valid only for the duration of check.Files; // (initialized by Files, valid only for the duration of check.Files;
...@@ -190,6 +191,7 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch ...@@ -190,6 +191,7 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
objMap: make(map[Object]*declInfo), objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package), impMap: make(map[importKey]*Package),
posMap: make(map[*Interface][]token.Pos), posMap: make(map[*Interface][]token.Pos),
pkgCnt: make(map[string]int),
} }
} }
......
...@@ -10,7 +10,7 @@ import ( ...@@ -10,7 +10,7 @@ import (
"fmt" "fmt"
"go/ast" "go/ast"
"go/token" "go/token"
"path" "strconv"
"strings" "strings"
) )
...@@ -25,8 +25,13 @@ func unreachable() { ...@@ -25,8 +25,13 @@ func unreachable() {
} }
func (check *Checker) qualifier(pkg *Package) string { func (check *Checker) qualifier(pkg *Package) string {
// Qualify the package unless it's the package being type-checked.
if pkg != check.pkg { if pkg != check.pkg {
return path.Base(pkg.path) // avoid excessively long path names in error messages // If the same package name was used by multiple packages, display the full path.
if check.pkgCnt[pkg.name] > 1 {
return strconv.Quote(pkg.path)
}
return pkg.name
} }
return "" return ""
} }
......
...@@ -188,6 +188,7 @@ func (check *Checker) importPackage(pos token.Pos, path, dir string) *Package { ...@@ -188,6 +188,7 @@ func (check *Checker) importPackage(pos token.Pos, path, dir string) *Package {
// package should be complete or marked fake, but be cautious // package should be complete or marked fake, but be cautious
if imp.complete || imp.fake { if imp.complete || imp.fake {
check.impMap[key] = imp check.impMap[key] = imp
check.pkgCnt[imp.name]++
return imp return imp
} }
......
...@@ -4,8 +4,12 @@ ...@@ -4,8 +4,12 @@
package issues package issues
import "fmt" import (
import syn "cmd/compile/internal/syntax" "fmt"
syn "cmd/compile/internal/syntax"
t1 "text/template"
t2 "html/template"
)
func issue7035() { func issue7035() {
type T struct{ X int } type T struct{ X int }
...@@ -316,7 +320,7 @@ func issue28281g() (... /* ERROR expected type */ TT) ...@@ -316,7 +320,7 @@ func issue28281g() (... /* ERROR expected type */ TT)
// Issue #26234: Make various field/method lookup errors easier to read by matching cmd/compile's output // Issue #26234: Make various field/method lookup errors easier to read by matching cmd/compile's output
func issue26234a(f *syn.File) { func issue26234a(f *syn.File) {
// The error message below should refer to the actual package path base (syntax) // The error message below should refer to the actual package name (syntax)
// not the local package name (syn). // not the local package name (syn).
f.foo /* ERROR f.foo undefined \(type \*syntax.File has no field or method foo\) */ f.foo /* ERROR f.foo undefined \(type \*syntax.File has no field or method foo\) */
} }
...@@ -337,3 +341,15 @@ func issue26234b(x T) { ...@@ -337,3 +341,15 @@ func issue26234b(x T) {
func issue26234c() { func issue26234c() {
T.x /* ERROR T.x undefined \(type T has no method x\) */ () T.x /* ERROR T.x undefined \(type T has no method x\) */ ()
} }
func issue35895() {
// T is defined in this package, don't qualify its name with the package name.
var _ T = 0 // ERROR cannot convert 0 \(untyped int constant\) to T
// There is only one package with name syntax imported, only use the (global) package name in error messages.
var _ *syn.File = 0 // ERROR cannot convert 0 \(untyped int constant\) to \*syntax.File
// Because both t1 and t2 have the same global package name (template),
// qualify packages with full path name in this case.
var _ t1.Template = t2 /* ERROR cannot use .* \(value of type "html/template".Template\) as "text/template".Template */ .Template{}
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment