]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: don't lose position info of interface embeddings
authorRobert Griesemer <gri@golang.org>
Wed, 10 Jan 2024 23:49:33 +0000 (15:49 -0800)
committerRobert Griesemer <gri@google.com>
Thu, 11 Jan 2024 17:47:50 +0000 (17:47 +0000)
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>
src/cmd/compile/internal/types2/issues_test.go
src/cmd/compile/internal/types2/subst.go
src/cmd/compile/internal/types2/typeset.go
src/go/types/issues_test.go
src/go/types/subst.go
src/go/types/typeset.go

index a8893cf6de36ee8c9acb5aa82d04dc5dda395a39..0117571f7b043c3f027626d663079743be92f82f 100644 (file)
@@ -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)
+}
index aefa53603ff91e7005a6160bf7a133225dcfea10..09dc58527a11f1061cabe76fa20eb0a0baa91ebd 100644 (file)
@@ -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
index 719041657cbb33d6a4eb3f5fff63ba839a2d8df5..a6ccfdb80cc727744c92c44d4cd5f92c6fcdefa4 100644 (file)
@@ -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 {
index b4c8218bc4f75667cfd1f25168dbcceadaa77a1e..6f9d5978e7ff22ee5d47ed87abbef7b0d6f6e53f 100644 (file)
@@ -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)
+}
index 13d3dcbf1eac6e77a808221312aae44c1eeb838b..1934ebab2b1a4f962836d7fe0986b5db59e2e18f 100644 (file)
@@ -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
index 8d8c490c6aee3ff580e94625a130a7ef2dc86c07..d164749996e22304d318536d10affac7a1fcd260 100644 (file)
@@ -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 {