]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: fix a bug in package qualification logic
authorRob Findley <rfindley@google.com>
Thu, 24 Jun 2021 15:01:49 +0000 (11:01 -0400)
committerRobert Findley <rfindley@google.com>
Fri, 25 Jun 2021 01:08:06 +0000 (01:08 +0000)
CL 313035 had a bug, initializing pkgPathMap by walking the imported
package being considered rather than check.pkg.

Fix this, and enhance our tests to exercise this bug as well as other
edge cases.

Also fix error assertions in issues.src to not use quotation marks
inside the error regexp. The check tests only matched the error regexp
up to the first quotation mark.

Fixes #46905

Change-Id: I6aa8eae4bec6495006a5c03fc063db0d66b44cd6
Reviewed-on: https://go-review.googlesource.com/c/go/+/330629
Trust: Robert Findley <rfindley@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/go/types/check_test.go
src/go/types/errors.go
src/go/types/issues_test.go
src/go/types/testdata/check/issues.src

index 5a3e57ba44d39cd5d4a7a3298381a5a3c7cf9b92..c85a8e46fbb6f9fb01f29f915641d9dcdfaf9632 100644 (file)
@@ -202,7 +202,7 @@ func asGoVersion(s string) string {
        return ""
 }
 
-func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string, srcs [][]byte, manual bool) {
+func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string, srcs [][]byte, manual bool, imp Importer) {
        if len(filenames) == 0 {
                t.Fatal("no source files")
        }
@@ -252,7 +252,10 @@ func checkFiles(t *testing.T, sizes Sizes, goVersion string, filenames []string,
                }
        }
 
-       conf.Importer = importer.Default()
+       conf.Importer = imp
+       if imp == nil {
+               conf.Importer = importer.Default()
+       }
        conf.Error = func(err error) {
                if *haltOnError {
                        defer panic(err)
@@ -322,7 +325,7 @@ func TestManual(t *testing.T) {
 func TestLongConstants(t *testing.T) {
        format := "package longconst\n\nconst _ = %s\nconst _ = %s // ERROR excessively long constant"
        src := fmt.Sprintf(format, strings.Repeat("1", 9999), strings.Repeat("1", 10001))
-       checkFiles(t, nil, "", []string{"longconst.go"}, [][]byte{[]byte(src)}, false)
+       checkFiles(t, nil, "", []string{"longconst.go"}, [][]byte{[]byte(src)}, false, nil)
 }
 
 // TestIndexRepresentability tests that constant index operands must
@@ -330,7 +333,7 @@ func TestLongConstants(t *testing.T) {
 // represent larger values.
 func TestIndexRepresentability(t *testing.T) {
        const src = "package index\n\nvar s []byte\nvar _ = s[int64 /* ERROR \"int64\\(1\\) << 40 \\(.*\\) overflows int\" */ (1) << 40]"
-       checkFiles(t, &StdSizes{4, 4}, "", []string{"index.go"}, [][]byte{[]byte(src)}, false)
+       checkFiles(t, &StdSizes{4, 4}, "", []string{"index.go"}, [][]byte{[]byte(src)}, false, nil)
 }
 
 func TestIssue46453(t *testing.T) {
@@ -338,7 +341,7 @@ func TestIssue46453(t *testing.T) {
                t.Skip("type params are enabled")
        }
        const src = "package p\ntype _ comparable // ERROR \"undeclared name: comparable\""
-       checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false)
+       checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false, nil)
 }
 
 func TestCheck(t *testing.T)     { DefPredeclaredTestFuncs(); testDir(t, "check") }
@@ -388,5 +391,5 @@ func testPkg(t *testing.T, filenames []string, goVersion string, manual bool) {
                }
                srcs[i] = src
        }
-       checkFiles(t, nil, goVersion, filenames, srcs, manual)
+       checkFiles(t, nil, goVersion, filenames, srcs, manual, nil)
 }
index 19e9ae8d44abaa415789f639ad61ccfec942aa9a..226310641733ae833e91e63064ec6a8db71ea469 100644 (file)
@@ -31,7 +31,7 @@ func (check *Checker) qualifier(pkg *Package) string {
                if check.pkgPathMap == nil {
                        check.pkgPathMap = make(map[string]map[string]bool)
                        check.seenPkgMap = make(map[*Package]bool)
-                       check.markImports(pkg)
+                       check.markImports(check.pkg)
                }
                // If the same package name was used by multiple packages, display the full path.
                if len(check.pkgPathMap[pkg.name]) > 1 {
index 44926919efe06162dcc20e65d3fa2d987941e7e7..519e19953645d8e8c4f97d0058cd29ebdb9ffdc3 100644 (file)
@@ -577,42 +577,64 @@ func TestIssue44515(t *testing.T) {
 }
 
 func TestIssue43124(t *testing.T) {
-       // TODO(rFindley) enhance the testdata tests to be able to express this type
-       //                of setup.
+       // TODO(rFindley) move this to testdata by enhancing support for importing.
 
        // All involved packages have the same name (template). Error messages should
        // disambiguate between text/template and html/template by printing the full
        // path.
        const (
                asrc = `package a; import "text/template"; func F(template.Template) {}; func G(int) {}`
-               bsrc = `package b; import ("a"; "html/template"); func _() { a.F(template.Template{}) }`
-               csrc = `package c; import ("a"; "html/template"); func _() { a.G(template.Template{}) }`
+               bsrc = `
+package b
+
+import (
+       "a"
+       "html/template"
+)
+
+func _() {
+       // Packages should be fully qualified when there is ambiguity within the
+       // error string itself.
+       a.F(template /* ERROR cannot use.*html/template.* as .*text/template */ .Template{})
+}
+`
+               csrc = `
+package c
+
+import (
+       "a"
+       "fmt"
+       "html/template"
+)
+
+// Issue #46905: make sure template is not the first package qualified.
+var _ fmt.Stringer = 1 // ERROR cannot use 1.*as fmt\.Stringer
+
+// Packages should be fully qualified when there is ambiguity in reachable
+// packages. In this case both a (and for that matter html/template) import
+// text/template.
+func _() { a.G(template /* ERROR cannot use .*html/template.*Template */ .Template{}) }
+`
+
+               tsrc = `
+package template
+
+import "text/template"
+
+type T int
+
+// Verify that the current package name also causes disambiguation.
+var _ T = template /* ERROR cannot use.*text/template.* as T value */.Template{}
+`
        )
 
        a, err := pkgFor("a", asrc, nil)
        if err != nil {
                t.Fatalf("package a failed to typecheck: %v", err)
        }
-       conf := Config{Importer: importHelper{pkg: a, fallback: importer.Default()}}
-
-       // Packages should be fully qualified when there is ambiguity within the
-       // error string itself.
-       bast := mustParse(t, bsrc)
-       _, err = conf.Check(bast.Name.Name, fset, []*ast.File{bast}, nil)
-       if err == nil {
-               t.Fatal("package b had no errors")
-       }
-       if !strings.Contains(err.Error(), "text/template") || !strings.Contains(err.Error(), "html/template") {
-               t.Errorf("type checking error for b does not disambiguate package template: %q", err)
-       }
+       imp := importHelper{pkg: a, fallback: importer.Default()}
 
-       // ...and also when there is any ambiguity in reachable packages.
-       cast := mustParse(t, csrc)
-       _, err = conf.Check(cast.Name.Name, fset, []*ast.File{cast}, nil)
-       if err == nil {
-               t.Fatal("package c had no errors")
-       }
-       if !strings.Contains(err.Error(), "html/template") {
-               t.Errorf("type checking error for c does not disambiguate package template: %q", err)
-       }
+       checkFiles(t, nil, "", []string{"b.go"}, [][]byte{[]byte(bsrc)}, false, imp)
+       checkFiles(t, nil, "", []string{"c.go"}, [][]byte{[]byte(csrc)}, false, imp)
+       checkFiles(t, nil, "", []string{"t.go"}, [][]byte{[]byte(tsrc)}, false, imp)
 }
index e2ac06759ba10e5305e9aacf5b7660651e0980e7..74d185cbc34357e25fe9c7f593e016b81b2b7881 100644 (file)
@@ -332,7 +332,7 @@ func issue28281g() (... /* ERROR can only use ... with final parameter */ TT)
 func issue26234a(f *syn.File) {
        // The error message below should refer to the actual package name (syntax)
        // 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\) */
 }
 
 type T struct {
@@ -361,7 +361,7 @@ func issue35895() {
 
        // 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{}
+       var _ t1.Template = t2 /* ERROR cannot use .* \(value of type .html/template.\.Template\) as .text/template.\.Template */ .Template{}
 }
 
 func issue42989(s uint) {