From 28d59add07eadb92ae8a3cddebfd1ef2bc2ac804 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Sun, 27 Jul 2025 00:06:14 -0700 Subject: [PATCH] [SWUtil] PropertyListItem: Clarify use of `init` overloads that take array and dictionary The original comment that these overloads can be removed was incorrect because the existential of `PropertyListItemConvertible` doesn't self conform. The overloads are still needed to support collections with heterogeneous values but nothing else and so they should be disfavored. Turns out that some of the expressions that used to take advantage of these overloads only work due to the solver producing a valid solution from the "diagnostic" mode. For example: ``` public var propertyListItem: PropertyListItem { return .init(entries .sorted { $0.identifier < $1.identifier } .map { [ "bundle-id": .plString($0.identifier), "tags": PropertyListItem($0.tags.sorted()), "bundle-path": .plString($0.path.str), ] }) } ``` This expression should have been ambiguous because it can match both `.init(any ...)` and `.init([any ...])` overloads due to an existential conversion that is bi-directional for the closure. For `.init(any ...)`, result of the closure is going to be erased to existential inside of the body of the `.map` closure and for `.init([any ...])`, this erasure is going to happen outside but both are equally valid. --- Sources/SWBUtil/PropertyList.swift | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Sources/SWBUtil/PropertyList.swift b/Sources/SWBUtil/PropertyList.swift index 71cd3cb0..3e96dbdd 100644 --- a/Sources/SWBUtil/PropertyList.swift +++ b/Sources/SWBUtil/PropertyList.swift @@ -362,16 +362,24 @@ extension Dictionary: PropertyListItemConvertible where Key == String, Value: Pr } public extension PropertyListItem { - init(_ x: any PropertyListItemConvertible) { + init(_ x: T) where T: PropertyListItemConvertible { self = x.propertyListItem } - // Will remove this with rdar://problem/44204273 + /// This overload is intended only to support arrays with heterogeneous values. + /// For example: ["", 42] can be represented as [any PropertyListItemConvertible] + /// but `any PropertyListItemConvertible` doesn't actually conform to + /// `PropertyListItemConvertible` hence we cannot use the overload above. + @_disfavoredOverload init(_ x: [any PropertyListItemConvertible]) { self = .plArray(x.map{$0.propertyListItem}) } - // Will remove this with rdar://problem/44204273 + /// This overload is intended only to support dictionaries with heterogeneous values. + /// For example: ["q": "", "a": 42] can be represented as [String: any PropertyListItemConvertible] + /// but `any PropertyListItemConvertible` doesn't actually conform to + /// `PropertyListItemConvertible`. + @_disfavoredOverload init(_ x: [String: any PropertyListItemConvertible]) { self = .plDict(x.mapValues { $0.propertyListItem }) }