aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2024-01-10 15:49:33 -0800
committerRobert Griesemer <gri@google.com>2024-01-11 17:47:50 +0000
commit25c5f6f15988f1abb9738bfdfd10331afefd8ec1 (patch)
treeaed6e97c7f12b53fdd5e6050701c67acffb2c4ce
parentd1674cb4c6531df6573bc3be136b302d2b362c56 (diff)
downloadgo-25c5f6f15988f1abb9738bfdfd10331afefd8ec1.tar.gz
go-25c5f6f15988f1abb9738bfdfd10331afefd8ec1.zip
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. 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>
-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 a8893cf6de..0117571f7b 100644
--- a/src/cmd/compile/internal/types2/issues_test.go
+++ b/src/cmd/compile/internal/types2/issues_test.go
@@ -1076,3 +1076,20 @@ func TestIssue59831(t *testing.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 aefa53603f..09dc58527a 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
assert(t.complete) // otherwise we are copying incomplete data
iface.complete = t.complete
diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go
index 719041657c..a6ccfdb80c 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 b4c8218bc4..6f9d5978e7 100644
--- a/src/go/types/issues_test.go
+++ b/src/go/types/issues_test.go
@@ -1086,3 +1086,20 @@ func TestIssue59831(t *testing.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 13d3dcbf1e..1934ebab2b 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
assert(t.complete) // otherwise we are copying incomplete data
iface.complete = t.complete
diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go
index 8d8c490c6a..d164749996 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 {