}
}
}
+
+// TODO(markfreeman): Can the value cached on Named be used in validType / hasVarSize?
+
+// finiteSize returns whether a type has finite size.
+func (check *Checker) finiteSize(t Type) (b bool) {
+ switch t := Unalias(t).(type) {
+ case *Named:
+ if t.finite != nil {
+ return *t.finite
+ }
+
+ defer func() {
+ t.finite = &b
+ }()
+
+ if i, ok := check.objPathIdx[t.obj]; ok {
+ cycle := check.objPath[i:]
+ check.cycleError(cycle, firstInSrc(cycle))
+ return false
+ }
+ check.push(t.obj)
+ defer check.pop()
+
+ return check.finiteSize(t.fromRHS)
+
+ case *Array:
+ // The array length is already computed. If it was a valid length, it
+ // is finite; else, an error was reported in the computation.
+ return check.finiteSize(t.elem)
+
+ case *Struct:
+ for _, f := range t.fields {
+ if !check.finiteSize(f.typ) {
+ return false
+ }
+ }
+ }
+
+ return true
+}
if x.mode == invalid || x.mode == novalue {
return
}
- if n, ok := Unalias(x.typ).(*Named); ok {
- if i, ok := check.objPathIdx[n.obj]; ok {
- check.cycleError(check.objPath, i)
- x.mode = invalid
- x.typ = Typ[Invalid]
- }
+ if !check.finiteSize(x.typ) {
+ x.mode = invalid
+ x.typ = Typ[Invalid]
}
}
allowNilRHS bool // same as below, as well as briefly during checking of a type declaration
allowNilUnderlying bool // may be true from creation via [NewNamed] until [Named.SetUnderlying]
- inst *instance // information for instantiated types; nil otherwise
+ inst *instance // information for instantiated types; nil otherwise
+ finite *bool // whether the type has finite size, or nil
mu sync.Mutex // guards all fields below
state_ uint32 // the current state of this type; must only be accessed atomically or when mu is held
{Interface{}, 40, 80},
{Map{}, 16, 32},
{Chan{}, 12, 24},
- {Named{}, 64, 120},
+ {Named{}, 68, 128},
{TypeParam{}, 28, 48},
{term{}, 12, 24},
}
}
}
+
+// TODO(markfreeman): Can the value cached on Named be used in validType / hasVarSize?
+
+// finiteSize returns whether a type has finite size.
+func (check *Checker) finiteSize(t Type) (b bool) {
+ switch t := Unalias(t).(type) {
+ case *Named:
+ if t.finite != nil {
+ return *t.finite
+ }
+
+ defer func() {
+ t.finite = &b
+ }()
+
+ if i, ok := check.objPathIdx[t.obj]; ok {
+ cycle := check.objPath[i:]
+ check.cycleError(cycle, firstInSrc(cycle))
+ return false
+ }
+ check.push(t.obj)
+ defer check.pop()
+
+ return check.finiteSize(t.fromRHS)
+
+ case *Array:
+ // The array length is already computed. If it was a valid length, it
+ // is finite; else, an error was reported in the computation.
+ return check.finiteSize(t.elem)
+
+ case *Struct:
+ for _, f := range t.fields {
+ if !check.finiteSize(f.typ) {
+ return false
+ }
+ }
+ }
+
+ return true
+}
if x.mode == invalid || x.mode == novalue {
return
}
- if n, ok := Unalias(x.typ).(*Named); ok {
- if i, ok := check.objPathIdx[n.obj]; ok {
- check.cycleError(check.objPath, i)
- x.mode = invalid
- x.typ = Typ[Invalid]
- }
+ if !check.finiteSize(x.typ) {
+ x.mode = invalid
+ x.typ = Typ[Invalid]
}
}
allowNilRHS bool // same as below, as well as briefly during checking of a type declaration
allowNilUnderlying bool // may be true from creation via [NewNamed] until [Named.SetUnderlying]
- inst *instance // information for instantiated types; nil otherwise
+ inst *instance // information for instantiated types; nil otherwise
+ finite *bool // whether the type has finite size, or nil
mu sync.Mutex // guards all fields below
state_ uint32 // the current state of this type; must only be accessed atomically or when mu is held
{Interface{}, 40, 80},
{Map{}, 16, 32},
{Chan{}, 12, 24},
- {Named{}, 64, 120},
+ {Named{}, 68, 128},
{TypeParam{}, 28, 48},
{term{}, 12, 24},
_ = unsafe.Sizeof(struct{ T[P] }{})
}
-// TODO(gri) This is a follow-on error due to T[int] being invalid.
-// We should try to avoid it.
-const _ = unsafe /* ERROR "not constant" */ .Sizeof(T[int]{})
+const _ = unsafe.Sizeof(T /* ERROR "invalid recursive type" */ [int]{})
--- /dev/null
+// Copyright 2025 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"
+
+type A /* ERROR "invalid recursive type" */ [unsafe.Sizeof(S{})]byte
+
+type S struct {
+ a A
+}
--- /dev/null
+// Copyright 2025 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"
+
+type A /* ERROR "invalid recursive type" */ [unsafe.Sizeof(B{})]int
+type B A
+
+type C /* ERROR "invalid recursive type" */ [unsafe.Sizeof(f())]int
+func f() D {
+ return D{}
+}
+type D C
+
+type E /* ERROR "invalid recursive type" */ [unsafe.Sizeof(g[F]())]int
+func g[P any]() P {
+ panic(0)
+}
+type F struct {
+ f E
+}
+