I tracked it down to the attempt to prevent cyclical dependencies. Using the sample code provided in Steps to Reproduce, I was able to maybe fix this by removing the defer and adding a filter onto the children:
private init(
_reflecting subject: Any,
label: String?,
seenObjects: inout [ObjectIdentifier: AnyObject]
) {
...
if shouldIncludeChildren, !mirror.children.isEmpty || isCollection {
children = mirror.children.**filter { child in
!seenObjects.contains(ObjectIdentifier(child as AnyObject))
}**.map { child in
Self(_reflecting: child.value, label: child.label, seenObjects: &seenObjects)
}
}
}
But I'm unsure if this has any unintended side effects (specifically, the comment callout about multiple references to the same object in the same subject). Logging a Value(reflecting: a) in the makeA() method returns me a Value instance that looks to properly stop traversing future references of the same type after it traverses first one.
Expected behavior
Cyclical graphs of any complexity should resolve their reflection correctly
Actual behavior
Once 3 classes are introduced into the graph, the initializer enters an infinite loop
Steps to reproduce
Attempt to run the following Test:
class A {
private var c: C!
private var c2: C!
private var b: B!
func setup(b: B, c: C) {
self.b = b
self.c = c
c2 = c
}
}
class B {
private var a: A!
private var c: C!
func setup(a: A, c: C) {
self.a = a
self.c = c
}
}
class C {
private var a: A!
private var b: B!
func setup(a: A, b: B) {
self.a = a
self.b = b
}
}
@Suite
struct TestingAppTests {
@Test(arguments: [makeA()]) func example(foo _: A) async throws {
// Write your test here and use APIs like #expect(...) to check expected conditions.
expect(true)
}
static func makeA() -> A {
let a = A()
let b = B()
let c = C()
a.setup(b: b, c: c)
b.setup(a: a, c: c)
c.setup(a: a, b: b)
return a
}
}
2. Observe the process crashes after the return of `makeA()` and before the main test begins
### swift-testing version/commit hash
Xcode's version of swift-testing
### Swift & OS version (output of `swift --version ; uname -a`)
swift-driver version: 1.115 Apple Swift version 6.0.2 (swiftlang-6.0.2.1.2 clang-1600.0.26.4)
Target: arm64-apple-macosx15.0
Darwin <private>.local 24.2.0 Darwin Kernel Version 24.2.0: Tue Oct 15 18:15:36 PDT 2024; root:xnu-11215.60.364.501.5~3/RELEASE_ARM64_T6000 arm64
Description
Initializing an
argument
that contains 3 or more cyclical classes causes an infinite recursion within__Expression.Value
's private init:I tracked it down to the attempt to prevent cyclical dependencies. Using the sample code provided in Steps to Reproduce, I was able to maybe fix this by removing the
defer
and adding afilter
onto the children:But I'm unsure if this has any unintended side effects (specifically, the comment callout about multiple references to the same object in the same subject). Logging a
Value(reflecting: a)
in themakeA()
method returns me aValue
instance that looks to properly stop traversing future references of the same type after it traverses first one.Expected behavior
Cyclical graphs of any complexity should resolve their reflection correctly
Actual behavior
Once 3 classes are introduced into the graph, the initializer enters an infinite loop
Steps to reproduce
Attempt to run the following Test:
class B { private var a: A! private var c: C!
}
class C { private var a: A! private var b: B!
}
@Suite struct TestingAppTests { @Test(arguments: [makeA()]) func example(foo _: A) async throws { // Write your test here and use APIs like
#expect(...)
to check expected conditions.expect(true)
}