Skip to content

Commit

Permalink
go/types, types2: don't lose position info of interface embeddings
Browse files Browse the repository at this point in the history
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 (golang#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 golang#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>
  • Loading branch information
griesemer authored and ezz-no committed Feb 17, 2024
1 parent 14408ad commit 25af0da
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 2 deletions.
17 changes: 17 additions & 0 deletions src/cmd/compile/internal/types2/issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
1 change: 1 addition & 0 deletions src/cmd/compile/internal/types2/subst.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion src/cmd/compile/internal/types2/typeset.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
17 changes: 17 additions & 0 deletions src/go/types/issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
1 change: 1 addition & 0 deletions src/go/types/subst.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion src/go/types/typeset.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 25af0da

Please sign in to comment.