From 871bfc926c7f19c91b4d8fe8cb1d70da2bc31765 Mon Sep 17 00:00:00 2001 From: James Moschou Date: Wed, 1 Jul 2026 16:58:02 +0200 Subject: [PATCH 1/3] Fix mismatched optional/static view aliases --- .../OpenSwiftUI/View/Configuration/ViewAlias.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/OpenSwiftUI/View/Configuration/ViewAlias.swift b/Sources/OpenSwiftUI/View/Configuration/ViewAlias.swift index 34200146b..b5a2adef0 100644 --- a/Sources/OpenSwiftUI/View/Configuration/ViewAlias.swift +++ b/Sources/OpenSwiftUI/View/Configuration/ViewAlias.swift @@ -225,12 +225,12 @@ private struct SourceFormula: AnySourceFormula where Source: View { return .init() } return if source.valueIsNil == nil { - Optional.makeDebuggableView( + Source.makeDebuggableView( view: _GraphValue(Attribute(identifier: attribute)), inputs: inputs ) } else { - Source.makeDebuggableView( + Optional.makeDebuggableView( view: _GraphValue(Attribute(identifier: attribute)), inputs: inputs ) @@ -246,12 +246,12 @@ private struct SourceFormula: AnySourceFormula where Source: View { return .emptyViewList(inputs: inputs) } return if source.valueIsNil == nil { - Optional.makeDebuggableViewList( + Source.makeDebuggableViewList( view: _GraphValue(Attribute(identifier: attribute)), inputs: inputs ) } else { - Source.makeDebuggableViewList( + Optional.makeDebuggableViewList( view: _GraphValue(Attribute(identifier: attribute)), inputs: inputs ) @@ -263,9 +263,9 @@ private struct SourceFormula: AnySourceFormula where Source: View { inputs: _ViewListCountInputs ) -> Int? { if source.valueIsNil == nil { - Optional._viewListCount(inputs: inputs) - } else { Source._viewListCount(inputs: inputs) + } else { + Optional._viewListCount(inputs: inputs) } } } From 04d1b1235cfc87c47181074cfb6faeab9110e538 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 13 Jul 2026 01:05:49 +0800 Subject: [PATCH 2/3] Add ViewAlias display list usage tests --- .../View/Configuration/ViewAlias.swift | 4 +- .../Render/DisplayListUtil.swift | 28 +++ .../View/Configuration/ViewAliasTests.swift | 199 ++++++++++++++---- 3 files changed, 192 insertions(+), 39 deletions(-) create mode 100644 Sources/OpenSwiftUITestsSupport/Render/DisplayListUtil.swift diff --git a/Sources/OpenSwiftUI/View/Configuration/ViewAlias.swift b/Sources/OpenSwiftUI/View/Configuration/ViewAlias.swift index b5a2adef0..9f804e365 100644 --- a/Sources/OpenSwiftUI/View/Configuration/ViewAlias.swift +++ b/Sources/OpenSwiftUI/View/Configuration/ViewAlias.swift @@ -2,7 +2,7 @@ // ViewAlias.swift // OpenSwiftUI // -// Audited for 6.0.87 +// Audited for 6.5.4 // Status: Complete // ID: D9F7AF928092578A4B8FA861B49E2161 (SwiftUI) @@ -25,8 +25,6 @@ protocol ViewAlias: PrimitiveView { init() } -// Audited for 6.5.4 - extension ViewAlias { nonisolated public static func _makeView(view: _GraphValue, inputs: _ViewInputs) -> _ViewOutputs { var inputs = inputs diff --git a/Sources/OpenSwiftUITestsSupport/Render/DisplayListUtil.swift b/Sources/OpenSwiftUITestsSupport/Render/DisplayListUtil.swift new file mode 100644 index 000000000..9d65089c6 --- /dev/null +++ b/Sources/OpenSwiftUITestsSupport/Render/DisplayListUtil.swift @@ -0,0 +1,28 @@ +// +// DisplayListUtil.swift +// OpenSwiftUITestsSupport + +import Foundation +package import OpenSwiftUICore + +package enum DisplayListUtil { + package static func renderDisplayList(_ content: Content) -> String { + let graph = ViewGraph( + rootViewType: Content.self, + requestedOutputs: [.displayList] + ) + graph.instantiateOutputs() + graph.setRootView(content) + graph.setProposedSize(CGSize(width: 100, height: 100)) + let (displayList, _) = graph.displayList() + return displayList.description + } + + package static func containsAnyColor(_ displayList: String) -> Bool { + displayList.contains("(color #") + } + + package static func containsColor(_ color: String, in displayList: String) -> Bool { + displayList.contains("(color \(color))") + } +} diff --git a/Tests/OpenSwiftUITests/View/Configuration/ViewAliasTests.swift b/Tests/OpenSwiftUITests/View/Configuration/ViewAliasTests.swift index 478c00b68..732629867 100644 --- a/Tests/OpenSwiftUITests/View/Configuration/ViewAliasTests.swift +++ b/Tests/OpenSwiftUITests/View/Configuration/ViewAliasTests.swift @@ -14,58 +14,186 @@ import OpenSwiftUITestsSupport @Suite(.disabled(if: attributeGraphVendor == .oag)) struct ViewAliasTests { @Test - func optionalViewAliasDynamicProperty() async throws { + func staticViewAliasUsageRendersSource() { + struct Alias: ViewAlias {} + struct ContentView: View { - var confirmation: Confirmation? + var body: some View { + Alias() + .viewAlias(Alias.self) { + Color.black + } + } + } - @OptionalViewAlias - private var alias: ChildView.Alias? + let displayList = DisplayListUtil.renderDisplayList(ContentView()) + #expect(displayList.contains(singleColorDisplayListRegex("#000000FF"))) + #expect(DisplayListUtil.containsColor("#000000FF", in: displayList)) + } + + @Test(arguments: [true, false]) + func optionalViewAliasUsage(sourceIsPresent: Bool) { + struct Alias: ViewAlias {} + + struct ContentView: View { + var source: Color? var body: some View { - ChildView(confirmation: confirmation) - .viewAlias(ChildView.Alias.self) { Color.red } - .onAppear { - #expect(alias == nil) - confirmation?() + Alias() + .optionalViewAlias(Alias.self) { + source } } } - struct ChildView: View { - var confirmation: Confirmation? + let source: Color? = sourceIsPresent ? .black : nil + let displayList = DisplayListUtil.renderDisplayList(ContentView(source: source)) + if sourceIsPresent { + #expect(displayList.contains(effectColorDisplayListRegex("#000000FF"))) + #expect(DisplayListUtil.containsColor("#000000FF", in: displayList)) + } else { + #expect(displayList.wholeMatch(of: emptyDisplayListRegex) != nil) + #expect(!DisplayListUtil.containsAnyColor(displayList)) + } + } - struct Alias: ViewAlias {} + @Test + func viewListUsageRendersStaticAndOptionalAliasSources() { + struct StaticAlias: ViewAlias {} + struct OptionalAlias: ViewAlias {} + struct StaticContentView: View { + var body: some View { + VStack { + StaticAlias() + } + .viewAlias(StaticAlias.self) { + Color.black + } + } + } + + struct OptionalContentView: View { + var source: Color? + + var body: some View { + VStack { + OptionalAlias() + } + .optionalViewAlias(OptionalAlias.self) { + source + } + } + } + + let staticDisplayList = DisplayListUtil.renderDisplayList(StaticContentView()) + #expect(staticDisplayList.contains(singleColorDisplayListRegex("#000000FF"))) + #expect(DisplayListUtil.containsColor("#000000FF", in: staticDisplayList)) + + let optionalPresentDisplayList = DisplayListUtil.renderDisplayList(OptionalContentView(source: .black)) + #expect(optionalPresentDisplayList.contains(effectColorDisplayListRegex("#000000FF"))) + #expect(DisplayListUtil.containsColor("#000000FF", in: optionalPresentDisplayList)) + + let optionalNilDisplayList = DisplayListUtil.renderDisplayList(OptionalContentView(source: nil)) + #expect(optionalNilDisplayList.wholeMatch(of: emptyDisplayListRegex) != nil) + #expect(!DisplayListUtil.containsAnyColor(optionalNilDisplayList)) + } + + @Test + func optionalViewAliasConsumerTracksPresentAndNilSource() { + struct Alias: ViewAlias {} + + struct AliasReader: View { @OptionalViewAlias private var alias: Alias? var body: some View { - Alias() - .onAppear { - #expect(alias != nil) - confirmation?() + if let alias { + alias + } else { + Color.white + } + } + } + + struct ContentView: View { + var source: Color? + + var body: some View { + AliasReader() + .optionalViewAlias(Alias.self) { + source } } } - #if canImport(Darwin) - try await triggerLayoutWithWindow(expectedCount: 2) { confirmation in - PlatformHostingController( - rootView: ContentView( - confirmation: confirmation - ) - ) + + let presentDisplayList = DisplayListUtil.renderDisplayList(ContentView(source: .black)) + #expect(presentDisplayList.contains(effectColorDisplayListRegex("#000000FF"))) + #expect(DisplayListUtil.containsColor("#000000FF", in: presentDisplayList)) + #expect(!presentDisplayList.contains(effectColorDisplayListRegex("#FFFFFFFF"))) + #expect(!DisplayListUtil.containsColor("#FFFFFFFF", in: presentDisplayList)) + + let nilDisplayList = DisplayListUtil.renderDisplayList(ContentView(source: nil)) + #expect(nilDisplayList.contains(effectColorDisplayListRegex("#FFFFFFFF"))) + #expect(DisplayListUtil.containsColor("#FFFFFFFF", in: nilDisplayList)) + #expect(!nilDisplayList.contains(effectColorDisplayListRegex("#000000FF"))) + #expect(!DisplayListUtil.containsColor("#000000FF", in: nilDisplayList)) + } + + @Test + func optionalViewAliasDynamicProperty() { + struct ContentView: View { + @OptionalViewAlias + private var alias: ChildView.Alias? + + var body: some View { + if alias == nil { + ChildView() + .viewAlias(ChildView.Alias.self) { Color.black } + } else { + Color.red + } + } + } + + struct ChildView: View { + struct Alias: ViewAlias {} + + @OptionalViewAlias + private var alias: Alias? + + var body: some View { + if let alias { + alias + } else { + Color.white + } + } } - #endif - let graph = ViewGraph( - rootViewType: ContentView.self, - requestedOutputs: [.displayList] - ) - graph.instantiateOutputs() - graph.setRootView(ContentView()) - graph.setProposedSize(CGSize(width: 100, height: 100)) - let (displayList, _) = graph.displayList() - print(displayList.description) - let expectRegex = try! Regex(#""" + + let displayList = DisplayListUtil.renderDisplayList(ContentView()) + #expect(displayList.contains(effectColorDisplayListRegex("#000000FF"))) + #expect(DisplayListUtil.containsColor("#000000FF", in: displayList)) + #expect(!DisplayListUtil.containsColor("#FF3B30FF", in: displayList)) + #expect(!DisplayListUtil.containsColor("#FFFFFFFF", in: displayList)) + } + + private var emptyDisplayListRegex: Regex { + try! Regex(#"\(display-list\)"#) + } + + private func singleColorDisplayListRegex(_ color: String) -> Regex { + try! Regex(#""" + \(display-list + \(item #:identity \d+ #:version \d+ + \(frame \([^)]+\)\) + \(content-seed \d+\) + \(color \#(color)\)\)\) + """#) + } + + private func effectColorDisplayListRegex(_ color: String) -> Regex { + try! Regex(#""" \(display-list \(item #:identity \d+ #:version \d+ \(frame \([^)]+\)\) @@ -73,8 +201,7 @@ struct ViewAliasTests { \(item #:identity \d+ #:version \d+ \(frame \([^)]+\)\) \(content-seed \d+\) - \(color #[0-9A-F]{8}\)\)\)\)\) + \(color \#(color)\)\)\)\)\) """#) - #expect(displayList.description.contains(expectRegex)) } } From edab6bc18dbe50ff6792c107845a140f6c0d3f1a Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 13 Jul 2026 01:06:12 +0800 Subject: [PATCH 3/3] Support display list compatibility tests --- .../Platform/cocoa/SwiftUI_SPI.swiftinterface | 22 +++++++++++++++++++ Package.resolved | 4 ++-- Package.swift | 8 +++++-- .../Render/DisplayListUtil.swift | 4 ++++ .../DisplayListUtilCompatibilityTests.swift | 15 +++++++++++++ 5 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 Tests/OpenSwiftUICompatibilityTests/Render/DisplayListUtilCompatibilityTests.swift diff --git a/Example/Modules/Platform/cocoa/SwiftUI_SPI.swiftinterface b/Example/Modules/Platform/cocoa/SwiftUI_SPI.swiftinterface index 872753ffd..d01ddb69d 100644 --- a/Example/Modules/Platform/cocoa/SwiftUI_SPI.swiftinterface +++ b/Example/Modules/Platform/cocoa/SwiftUI_SPI.swiftinterface @@ -15,6 +15,28 @@ public class CAHostingLayer : QuartzCore.CALayer where Content : SwiftU } } +public struct DisplayList : Swift.CustomStringConvertible { + public struct Version {} + public var description: Swift.String { + get + } +} + +public final class ViewGraph { + public struct Outputs : Swift.OptionSet { + public let rawValue: Swift.UInt8 + public init(rawValue: Swift.UInt8) + public static var displayList: ViewGraph.Outputs { + get + } + } + public init(rootViewType: Root.Type, requestedOutputs: ViewGraph.Outputs) where Root : SwiftUI.View + public func instantiateOutputs() + public func setRootView(_ view: Root) where Root : SwiftUI.View + public func setProposedSize(_ size: CoreGraphics.CGSize) + public func displayList() -> (DisplayList, DisplayList.Version) +} + @available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, visionOS 1.0, *) extension SwiftUI.View { public func variableBlur(maxRadius: CoreGraphics.CGFloat, mask: SwiftUI.Image, opaque: Swift.Bool = false) -> some SwiftUI.View diff --git a/Package.resolved b/Package.resolved index c6be5c6d3..e01cd0381 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "dbf61ba06c70969d5e404fc5b587cedcaa2261a1ae45df2605a24a6afcc52954", + "originHash" : "13632f122dbb85cdf5116b25776b9d61aa9318fd2f2f321e8a38c4b885ec58c4", "pins" : [ { "identity" : "darwinprivateframeworks", @@ -7,7 +7,7 @@ "location" : "https://github.com/OpenSwiftUIProject/DarwinPrivateFrameworks.git", "state" : { "branch" : "main", - "revision" : "3052c4709ceb8678d107677d6b5c5d4404fcd380" + "revision" : "d93839821ebebdab22081fbc0f3d0b8cb0e30b2f" } }, { diff --git a/Package.swift b/Package.swift index 984174a99..751da200c 100644 --- a/Package.swift +++ b/Package.swift @@ -654,7 +654,9 @@ let openSwiftUITestsSupportTarget = Target.target( dependencies: (compatibilityTestCondition ? [] : ["OpenSwiftUI"]), cSettings: sharedCSettings, cxxSettings: sharedCxxSettings, - swiftSettings: sharedSwiftSettings + swiftSettings: sharedSwiftSettings + (compatibilityTestCondition ? [ + .unsafeFlags(["-I", "\(Context.packageDirectory)/Example/Modules/Platform/cocoa"]), + ] : []) ) let openSwiftUIExtensionTarget = Target.target( @@ -688,7 +690,9 @@ let openSwiftUICompatibilityTestTarget = Target.testTarget( exclude: ["README.md"], cSettings: sharedCSettings, cxxSettings: sharedCxxSettings, - swiftSettings: sharedSwiftSettings + swiftSettings: sharedSwiftSettings + (compatibilityTestCondition ? [ + .unsafeFlags(["-I", "\(Context.packageDirectory)/Example/Modules/Platform/cocoa"]), + ] : []) ) // MARK: - OpenSwiftUIBridge Target diff --git a/Sources/OpenSwiftUITestsSupport/Render/DisplayListUtil.swift b/Sources/OpenSwiftUITestsSupport/Render/DisplayListUtil.swift index 9d65089c6..f9eded51c 100644 --- a/Sources/OpenSwiftUITestsSupport/Render/DisplayListUtil.swift +++ b/Sources/OpenSwiftUITestsSupport/Render/DisplayListUtil.swift @@ -3,7 +3,11 @@ // OpenSwiftUITestsSupport import Foundation +#if OPENSWIFTUI package import OpenSwiftUICore +#else +package import SwiftUI_SPI +#endif package enum DisplayListUtil { package static func renderDisplayList(_ content: Content) -> String { diff --git a/Tests/OpenSwiftUICompatibilityTests/Render/DisplayListUtilCompatibilityTests.swift b/Tests/OpenSwiftUICompatibilityTests/Render/DisplayListUtilCompatibilityTests.swift new file mode 100644 index 000000000..158113676 --- /dev/null +++ b/Tests/OpenSwiftUICompatibilityTests/Render/DisplayListUtilCompatibilityTests.swift @@ -0,0 +1,15 @@ +// +// DisplayListUtilCompatibilityTests.swift +// OpenSwiftUICompatibilityTests + +import OpenSwiftUITestsSupport +import Testing + +@MainActor +struct DisplayListUtilCompatibilityTests { + @Test + func rendersColor() { + let displayList = DisplayListUtil.renderDisplayList(Color.red) + #expect(DisplayListUtil.containsAnyColor(displayList)) + } +}