[release-branch.go1.21] go/types, types2: don't do version checks for embedded types of imported interfaces

Imported interfaces don't have position information for embedded types.
When computing the type set of such interfaces, doing a version check
may fail because it will rely on the Go version of the current package.

We must not do a version check for features of types from imported
packages - those types have already been typechecked and are "correct".
The version check code does look at packages to avoid such incorrect
version checks, but we don't have the package information available
in an interface type (divorced from its object).

Instead, for now rely on the fact that imported interfaces don't have
position information for embedded types: if the position is unknown,
don't do a version check.

We may want to assert that positions are known in all other cases,
but since this is an older release, don't add such additional changes
to avoid introducing other bugs.

Fixes #66064.

Change-Id: I773d57e5410c3d4a911ab3e018b3233c2972b3c9
Reviewed-on: https://go-review.googlesource.com/c/go/+/571075
Reviewed-by: Robert Findley <rfindley@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2024-03-12 09:31:06 -07:00 committed by Gopher Robot
parent 63992defa8
commit 6d229889d8
3 changed files with 25 additions and 12 deletions

View File

@ -255,9 +255,8 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
allTerms := allTermlist allTerms := allTermlist
allComparable := false allComparable := false
for i, typ := range ityp.embeddeds { for i, typ := range ityp.embeddeds {
// The embedding position is nil for imported interfaces // The embedding position is nil for imported interfaces.
// and also for interface copies after substitution (but // We don't need to do version checks in those cases.
// in that case we don't need to report errors again).
var pos syntax.Pos // embedding position var pos syntax.Pos // embedding position
if ityp.embedPos != nil { if ityp.embedPos != nil {
pos = (*ityp.embedPos)[i] pos = (*ityp.embedPos)[i]
@ -270,7 +269,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
assert(!isTypeParam(typ)) assert(!isTypeParam(typ))
tset := computeInterfaceTypeSet(check, pos, u) tset := computeInterfaceTypeSet(check, pos, u)
// If typ is local, an error was already reported where typ is specified/defined. // If typ is local, an error was already reported where typ is specified/defined.
if check != nil && check.isImportedConstraint(typ) && !check.verifyVersionf(pos, go1_18, "embedding constraint interface %s", typ) { if pos.IsKnown() && check != nil && check.isImportedConstraint(typ) && !check.verifyVersionf(pos, go1_18, "embedding constraint interface %s", typ) {
continue continue
} }
comparable = tset.comparable comparable = tset.comparable
@ -279,7 +278,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
} }
terms = tset.terms terms = tset.terms
case *Union: case *Union:
if check != nil && !check.verifyVersionf(pos, go1_18, "embedding interface element %s", u) { if pos.IsKnown() && check != nil && !check.verifyVersionf(pos, go1_18, "embedding interface element %s", u) {
continue continue
} }
tset := computeUnionTypeSet(check, unionSets, pos, u) tset := computeUnionTypeSet(check, unionSets, pos, u)
@ -293,7 +292,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
if u == Typ[Invalid] { if u == Typ[Invalid] {
continue continue
} }
if check != nil && !check.verifyVersionf(pos, go1_18, "embedding non-interface type %s", typ) { if pos.IsKnown() && check != nil && !check.verifyVersionf(pos, go1_18, "embedding non-interface type %s", typ) {
continue continue
} }
terms = termlist{{false, typ}} terms = termlist{{false, typ}}

View File

@ -253,9 +253,8 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T
allTerms := allTermlist allTerms := allTermlist
allComparable := false allComparable := false
for i, typ := range ityp.embeddeds { for i, typ := range ityp.embeddeds {
// The embedding position is nil for imported interfaces // The embedding position is nil for imported interfaces.
// and also for interface copies after substitution (but // We don't need to do version checks in those cases.
// in that case we don't need to report errors again).
var pos token.Pos // embedding position var pos token.Pos // embedding position
if ityp.embedPos != nil { if ityp.embedPos != nil {
pos = (*ityp.embedPos)[i] pos = (*ityp.embedPos)[i]
@ -268,7 +267,7 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T
assert(!isTypeParam(typ)) assert(!isTypeParam(typ))
tset := computeInterfaceTypeSet(check, pos, u) tset := computeInterfaceTypeSet(check, pos, u)
// If typ is local, an error was already reported where typ is specified/defined. // If typ is local, an error was already reported where typ is specified/defined.
if check != nil && check.isImportedConstraint(typ) && !check.verifyVersionf(atPos(pos), go1_18, "embedding constraint interface %s", typ) { if pos.IsValid() && check != nil && check.isImportedConstraint(typ) && !check.verifyVersionf(atPos(pos), go1_18, "embedding constraint interface %s", typ) {
continue continue
} }
comparable = tset.comparable comparable = tset.comparable
@ -277,7 +276,7 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T
} }
terms = tset.terms terms = tset.terms
case *Union: case *Union:
if check != nil && !check.verifyVersionf(atPos(pos), go1_18, "embedding interface element %s", u) { if pos.IsValid() && check != nil && !check.verifyVersionf(atPos(pos), go1_18, "embedding interface element %s", u) {
continue continue
} }
tset := computeUnionTypeSet(check, unionSets, pos, u) tset := computeUnionTypeSet(check, unionSets, pos, u)
@ -291,7 +290,7 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T
if u == Typ[Invalid] { if u == Typ[Invalid] {
continue continue
} }
if check != nil && !check.verifyVersionf(atPos(pos), go1_18, "embedding non-interface type %s", typ) { if pos.IsValid() && check != nil && !check.verifyVersionf(atPos(pos), go1_18, "embedding non-interface type %s", typ) {
continue continue
} }
terms = termlist{{false, typ}} terms = termlist{{false, typ}}

View File

@ -0,0 +1,15 @@
// -lang=go1.16
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.21
package main
import "slices"
func main() {
_ = slices.Clone([]string{}) // no error should be reported here
}