aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Freeman <mark@golang.org>2026-01-07 16:40:53 -0500
committerGopher Robot <gobot@golang.org>2026-01-08 08:31:50 -0800
commit5facb3b24b1c388176572eb95239f94d6ed4017d (patch)
treef51a8e3d293fec3a323d2077baaf1f2a1698c343
parent28147b528312055b535c6a69d0d4492bd502e1b0 (diff)
downloadgo-5facb3b24b1c388176572eb95239f94d6ed4017d.tar.xz
internal/types: add test for cycles in value context
Exposition is also added to outline a difference between syntax which can / cannot produce values of incomplete types. For us to enforce non-nilness of type RHS and remove the pending type mechanism, I suspect we would need to add completeness guards to the syntax which *can*. Enforcing non-nilness of type RHS currently breaks the below test cases, but I suspect that is simply an implementation artifact. In other words, they just call Underlying at a bad time. - T0 - T3 - T6 / T7 - T10 - T12 If we also remove pendingType, all of these test cases break; again, we would need guards in the appropriate syntax logic. Change-Id: Ibe22042232e542de1d38b923dd1d5cc50dce08cb Reviewed-on: https://go-review.googlesource.com/c/go/+/734600 TryBot-Bypass: Mark Freeman <markfreeman@google.com> Reviewed-by: Robert Griesemer <gri@google.com> Auto-Submit: Mark Freeman <markfreeman@google.com>
-rw-r--r--src/internal/types/testdata/check/cycles6.go71
1 files changed, 71 insertions, 0 deletions
diff --git a/src/internal/types/testdata/check/cycles6.go b/src/internal/types/testdata/check/cycles6.go
new file mode 100644
index 0000000000..e5635ed456
--- /dev/null
+++ b/src/internal/types/testdata/check/cycles6.go
@@ -0,0 +1,71 @@
+// Copyright 2026 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.
+
+package p
+
+import "unsafe"
+
+// Below are the pieces of syntax corresponding to functions which can produce a
+// type T without first having a value of type T. Notice that each causes a
+// value of type T to be passed to unsafe.Sizeof while T is incomplete.
+
+// literal on type
+type T0 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(T0{})]int
+// literal on value (not applicable)
+// literal on pointer (not applicable)
+
+// call on type
+type T1 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(T1(42))]int
+// call on value
+func f2() T2
+type T2 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(f2())]int
+// call on pointer (not applicable)
+
+// assert on type
+var i3 interface{}
+type T3 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(i3.(T3))]int
+// assert on value (not applicable)
+// assert on pointer (not applicable)
+
+// receive on type (not applicable)
+// receive on value
+func f4() <-chan T4
+type T4 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(<-f4())]int
+// receive on pointer (not applicable)
+
+// star on type (not applicable)
+// star on value (not applicable)
+// star on pointer
+func f5() *T5
+type T5 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(*f5())]int
+
+// Below is additional syntax which interacts with incomplete types. Notice that
+// each of the below falls into 1 of 3 cases:
+// 1. It cannot produce a value of (incomplete) type T.
+// 2. It can, but only because it already has a value of type T.
+// 3. It can, but only because it performs an implicit dereference.
+
+// select on type (case 1)
+// select on value (case 2)
+type T6 /* ERROR "invalid recursive type" */ struct {
+ f T7
+}
+type T7 [unsafe.Sizeof(T6{}.f)]int
+// select on pointer (case 3)
+type T8 /* ERROR "invalid recursive type" */ struct {
+ f T9
+}
+type T9 [unsafe.Sizeof(new(T8).f)]int
+
+// slice on type (not applicable)
+// slice on value (case 2)
+type T10 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(T10{}[:])]int
+// slice on pointer (case 3)
+type T11 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(new(T11)[:])]int
+
+// index on type (case 1)
+// index on value (case 2)
+type T12 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(T12{}[42])]int
+// index on pointer (case 3)
+type T13 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(new(T13)[42])]int