Skip to content

Commit 83b2b47

Browse files
griesemergopherbot
authored andcommitted
go/types, types2: do not overwrite nest entries in Checker.validType
In Checker.validType, when we encounter a type parameter, we evaluate the validity of the respective type argument in the "type nest" of the enclosing type (at the nesting depth at which the type argument was passed) (*). Specifically, we call validType recursively, with the slice representing the type nest shortened by 1. This recursive call continues to use the nest slice and in the process may overwrite the (previously) last entry. Upon return of that recursive call, validType proceeds with the old length, possibly using an incorrect last nest entry. In the concrete example for this issue we have the type S type S[T any] struct { a T b time.Time } instantiated with time.Time. When validType encounters the type parameter T inside the struct (S is in the type nest) it evaluates the type argument (time.Time) in the empty type nest (outside of S). In the process of evaluating the time.Time struct, the time.Time type is appended to the (shortened) nest slice and overwrites the previous last nest entry (S). Once processing of T is done, validType continues with struct field b, using the original-length nest slice, which now has time.Time rather than S as a last element. The type of b has type time.Time, which now appears to be nested in time.Time (rather than S), which (incorrectly) means that there's a type cycle. validType proceeds with reporting the error. But time.Time is an imported type, imported types are correct (otherwise they could not be imported in the first place), and the assertion checking that package of time.Time is local fails. The fix is trivial: restore the last entry of the nest slice when it may have been overwriten. (*) In hindsight we may be able to sigificantly simplify validType by evaluating type arguments when they are passed instead of when the respective type parameters are encountered. For another CL. Fixes #66323. Change-Id: I3bf23acb8ed14d349db342ca5c886323a6c7af58 Reviewed-on: https://go-review.googlesource.com/c/go/+/571836 Reviewed-by: Russ Cox <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Robert Griesemer <[email protected]>
1 parent d98b444 commit 83b2b47

File tree

3 files changed

+33
-6
lines changed

3 files changed

+33
-6
lines changed

src/cmd/compile/internal/types2/validtype.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ func (check *Checker) validType0(pos syntax.Pos, typ Type, nest, path []*Named)
158158
// A type parameter stands for the type (argument) it was instantiated with.
159159
// Check the corresponding type argument for validity if we are in an
160160
// instantiated type.
161-
if len(nest) > 0 {
162-
inst := nest[len(nest)-1] // the type instance
161+
if d := len(nest) - 1; d >= 0 {
162+
inst := nest[d] // the type instance
163163
// Find the corresponding type argument for the type parameter
164164
// and proceed with checking that type argument.
165165
for i, tparam := range inst.TypeParams().list() {
@@ -173,7 +173,12 @@ func (check *Checker) validType0(pos syntax.Pos, typ Type, nest, path []*Named)
173173
// the current (instantiated) type (see the example
174174
// at the end of this file).
175175
// For error reporting we keep the full path.
176-
return check.validType0(pos, targ, nest[:len(nest)-1], path)
176+
res := check.validType0(pos, targ, nest[:d], path)
177+
// The check.validType0 call with nest[:d] may have
178+
// overwritten the entry at the current depth d.
179+
// Restore the entry (was issue go.dev/issue/66323).
180+
nest[d] = inst
181+
return res
177182
}
178183
}
179184
}

src/go/types/validtype.go

Lines changed: 8 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package p
6+
7+
import "time"
8+
9+
// This type declaration must not cause problems with
10+
// the type validity checker.
11+
12+
type S[T any] struct {
13+
a T
14+
b time.Time
15+
}
16+
17+
var _ S[time.Time]

0 commit comments

Comments
 (0)