aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2024-01-10 15:49:33 -0800
committerCherry Mui <cherryyz@google.com>2024-01-25 17:49:05 +0000
commit00f974eb1f1ecbdf0d16667cd82a5aec16216d7f (patch)
treecb0513dc12783c47ba699553dab64c468196c5cc
parent2f91c16e68b8c82e4ca2e422bf9a520ec46f817c (diff)
downloadgo-00f974eb1f1ecbdf0d16667cd82a5aec16216d7f.tar.gz
go-00f974eb1f1ecbdf0d16667cd82a5aec16216d7f.zip
[release-branch.go1.21] go/types, types2: don't lose position info of interface embeddings
Accurate position information for embedded types in interfaces is crucial to identify the corresponding source file, and with that the Go language version associated with that file. (The position information is also important for proper error messages.) Before this CL, the position information for embedded types was discarded after type set computation, in the assumption that it was not needed anymore. However, substitutions that update the interface may lead to repeated type set computations which then won't have the correct position information. This CL does preserve the position information for embedded types until the end of type checking (cleanup phase), and also copy the position information during a substitution of the interface. The respective bug (#64759) doesn't seem to appear in 1.22 (most likely because it's hidden by some of the changes made with respect to the file version logic), but the existing code is still wrong. The backport of this code to 1.21 and 1.20 fixes the issue in those releases. For #64759. Fixes #65053. Change-Id: I80f4004c9d79cb02eac6739c324c477706615102 Reviewed-on: https://go-review.googlesource.com/c/go/+/555296 Run-TryBot: Robert Griesemer <gri@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com> Reviewed-by: Robert Griesemer <gri@google.com> Reviewed-on: https://go-review.googlesource.com/c/go/+/555415 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
-rw-r--r--src/cmd/compile/internal/types2/issues_test.go17
-rw-r--r--src/cmd/compile/internal/types2/subst.go1
-rw-r--r--src/cmd/compile/internal/types2/typeset.go1
-rw-r--r--src/go/types/issues_test.go17
-rw-r--r--src/go/types/subst.go1
-rw-r--r--src/go/types/typeset.go1
6 files changed, 36 insertions, 2 deletions
diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go
index 3ac345729b..9d0adae8df 100644
--- a/src/cmd/compile/internal/types2/issues_test.go
+++ b/src/cmd/compile/internal/types2/issues_test.go
@@ -964,3 +964,20 @@ func f[I *T, T any]() {
t.Fatalf("types of v and T are not pointer-identical: %p != %p", v.Type().(*TypeParam), T)
}
}
+
+func TestIssue64759(t *testing.T) {
+ const src = `
+//go:build go1.18
+package p
+
+func f[S ~[]E, E any](S) {}
+
+func _() {
+ f([]string{})
+}
+`
+ // Per the go:build directive, the source must typecheck
+ // even though the (module) Go version is set to go1.17.
+ conf := Config{GoVersion: "go1.17"}
+ mustTypecheck(src, &conf, nil)
+}
diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go
index 74d6294dff..a750403855 100644
--- a/src/cmd/compile/internal/types2/subst.go
+++ b/src/cmd/compile/internal/types2/subst.go
@@ -169,6 +169,7 @@ func (subst *subster) typ(typ Type) Type {
if mcopied || ecopied {
iface := subst.check.newInterface()
iface.embeddeds = embeddeds
+ iface.embedPos = t.embedPos
iface.implicit = t.implicit
iface.complete = t.complete
// If we've changed the interface type, we may need to replace its
diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go
index 70b9e36aef..8d33597ffd 100644
--- a/src/cmd/compile/internal/types2/typeset.go
+++ b/src/cmd/compile/internal/types2/typeset.go
@@ -304,7 +304,6 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
// separately. Here we only need to intersect the term lists and comparable bits.
allTerms, allComparable = intersectTermLists(allTerms, allComparable, terms, comparable)
}
- ityp.embedPos = nil // not needed anymore (errors have been reported)
ityp.tset.comparable = allComparable
if len(allMethods) != 0 {
diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go
index 4a559cbab3..282939d641 100644
--- a/src/go/types/issues_test.go
+++ b/src/go/types/issues_test.go
@@ -974,3 +974,20 @@ func f[I *T, T any]() {
t.Fatalf("types of v and T are not pointer-identical: %p != %p", v.Type().(*TypeParam), T)
}
}
+
+func TestIssue64759(t *testing.T) {
+ const src = `
+//go:build go1.18
+package p
+
+func f[S ~[]E, E any](S) {}
+
+func _() {
+ f([]string{})
+}
+`
+ // Per the go:build directive, the source must typecheck
+ // even though the (module) Go version is set to go1.17.
+ conf := Config{GoVersion: "go1.17"}
+ mustTypecheck(src, &conf, nil)
+}
diff --git a/src/go/types/subst.go b/src/go/types/subst.go
index 30c48e1bad..96bc341a5f 100644
--- a/src/go/types/subst.go
+++ b/src/go/types/subst.go
@@ -171,6 +171,7 @@ func (subst *subster) typ(typ Type) Type {
if mcopied || ecopied {
iface := subst.check.newInterface()
iface.embeddeds = embeddeds
+ iface.embedPos = t.embedPos
iface.implicit = t.implicit
iface.complete = t.complete
// If we've changed the interface type, we may need to replace its
diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go
index 206aa3da08..4cd118a226 100644
--- a/src/go/types/typeset.go
+++ b/src/go/types/typeset.go
@@ -302,7 +302,6 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T
// separately. Here we only need to intersect the term lists and comparable bits.
allTerms, allComparable = intersectTermLists(allTerms, allComparable, terms, comparable)
}
- ityp.embedPos = nil // not needed anymore (errors have been reported)
ityp.tset.comparable = allComparable
if len(allMethods) != 0 {