Skip to content

Restore the CoreFoundation Swift overlay on non-Darwin - #5519

Draft
Kyle-Ye wants to merge 1 commit into
swiftlang:mainfrom
Kyle-Ye:codex/fix-cfdictionary-hashable
Draft

Restore the CoreFoundation Swift overlay on non-Darwin#5519
Kyle-Ye wants to merge 1 commit into
swiftlang:mainfrom
Kyle-Ye:codex/fix-cfdictionary-hashable

Conversation

@Kyle-Ye

@Kyle-Ye Kyle-Ye commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Restore the CoreFoundation Swift overlay on non-Darwin platforms so imported
Core Foundation reference types regain their Equatable and Hashable
conformances.

Motivation:

On Darwin, imported Core Foundation reference types conform to the
compiler-known CoreFoundation._CFObject protocol. That protocol inherits
Hashable and supplies equality and hashing with CFEqual and CFHash.

The non-Darwin Core Foundation module is currently Clang-only and does not
provide _CFObject. Although the Clang importer still synthesizes the
conformance for recognized CF reference types, it has no protocol to attach,
leaving types such as CFDictionary, CFArray, CFSet, and CFString
without Equatable or Hashable conformance.

Fixes #5518.

Modifications:

  • Add a non-Darwin CoreFoundation Swift overlay that restores _CFObject
    and its CFEqual/CFHash default witnesses.
  • Build the overlay as a CMake object target whose emitted Swift module remains
    named CoreFoundation, then link its implementation into Foundation.
  • Install the generated CoreFoundation.swiftmodule and .swiftdoc, including
    the static toolchain layout and required autolink behavior.
  • Keep the CMake-only Swift overlay and its test sources out of SwiftPM targets,
    which cannot mix the existing C sources and the new Swift source in one
    target.
  • Add a Linux CMake test covering representative immutable and mutable Core
    Foundation reference types, plus runtime equality and set deduplication for
    CFDictionary.

Result:

Clients importing CoreFoundation on non-Darwin platforms can use recognized
Core Foundation reference types as Equatable and Hashable, matching the
Darwin overlay behavior. The fix applies to the CF reference type family rather
than adding a CFDictionary-specific retroactive conformance in Foundation.

Testing:

  • Swift 6.2.4 on aarch64 Linux: compiled the overlay and ran a standalone
    client importing only CoreFoundation.
  • Swift development snapshot on aarch64 Linux: completed a shared CMake
    libFoundation.so build and passed CoreFoundation.Hashable with CTest.
  • Verified CFDictionary, CFMutableDictionary, CFArray, CFMutableArray,
    CFSet, CFMutableSet, CFString, CFMutableString, CFData, and
    CFMutableData satisfy Hashable.
  • Verified the static CMake configuration includes the overlay object and
    autolinks both Foundation and the separate CoreFoundation archive.
  • Verified the Darwin CMake build excludes the non-Darwin overlay.
  • Ran swift package dump-package and git diff --check.

@compnerd compnerd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the test limited to Linux? Can you split up Hashable on _CFObject? That allows you to more easily see the implementation of the requirements. Also, make Equatable explicit on the protocol as an explicit extension with the operator implementation.

@Kyle-Ye

Kyle-Ye commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review. @compnerd

Why is the test limited to Linux?

The test prepends the freshly built Foundation library directory to LD_LIBRARY_PATH because the Swift toolchain also contains a libFoundation.so. Without that override, the generated RUNPATH resolves the toolchain library first, and the test executable fails at runtime because that library does not contain the new _CFObject symbols.

I limited the runnable test to Linux because that is the environment in which I could validate the dynamic-library setup. I do not currently have a local Windows environment to verify the corresponding test behavior.

If you have a convenient Windows setup, I would very much welcome a commit on this PR that adapts the runtime setup as needed and removes the Linux-only restriction for Windows.

Can you split up Hashable on _CFObject? That allows you to more easily see the implementation of the requirements.
Also, make Equatable explicit on the protocol as an explicit extension with the operator implementation.

Do you mean something like this?

// MARK: - _CFObject

public protocol _CFObject: AnyObject, Equatable, Hashable {}

// MARK: - _CFObject + Equatable

extension _CFObject {
    public static func == (lhs: Self, rhs: Self) -> Bool {
        CFEqual(lhs, rhs)
    }
}

// MARK: - _CFObject + Hashable

extension _CFObject {
    public var hashValue: Int {
        Int(bitPattern: CFHash(self))
    }

    public func hash(into hasher: inout Hasher) {
        hasher.combine(hashValue)
    }
}

@Kyle-Ye

Kyle-Ye commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

Looks like the new test case I added here will not run by the CI since it is swiftpm based test. I'll create a swiftlang/swift multi-repo PR to update test entry and coordinate it.

@compnerd

Copy link
Copy Markdown
Member

Thanks for the review. @compnerd

Why is the test limited to Linux?

The test prepends the freshly built Foundation library directory to LD_LIBRARY_PATH because the Swift toolchain also contains a libFoundation.so. Without that override, the generated RUNPATH resolves the toolchain library first, and the test executable fails at runtime because that library does not contain the new _CFObject symbols.

Path is the lever to use on windows - there is no DT_RUNPATH equivalent. With the r3cent SxS work, the embedded manifest should also help bind the right version,

I limited the runnable test to Linux because that is the environment in which I could validate the dynamic-library setup. I do not currently have a local Windows environment to verify the corresponding test behavior.

If you have a convenient Windows setup, I would very much welcome a commit on this PR that adapts the runtime setup as needed and removes the Linux-only restriction for Windows.

My environment is currently setup for COM work, so it is difficult to switch.

Can you split up Hashable on _CFObject? That allows you to more easily see the implementation of the requirements.

Also, make Equatable explicit on the protocol as an explicit extension with the operator implementation.

Do you mean something like this?

// MARK: - _CFObject



public protocol _CFObject: AnyObject, Equatable, Hashable {}



// MARK: - _CFObject + Equatable



extension _CFObject {

    public static func == (lhs: Self, rhs: Self) -> Bool {

        CFEqual(lhs, rhs)

    }

}

You can also move the conformance here:

extension _CFObject: Equatable {
 ...
}

// MARK: - _CFObject + Hashable

extension _CFObject {

public var hashValue: Int {

    Int(bitPattern: CFHash(self))

}



public func hash(into hasher: inout Hasher) {

    hasher.combine(hashValue)

}

}

Likewise.

@Kyle-Ye

Kyle-Ye commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

You can also move the conformance here:

extension _CFObject: Equatable {
  ...
}

No. Protocol is not allowed to do so IIRC. @compnerd

And I test it:

protocol A {}
extension A: Hashable { // ❌ Extension of protocol 'A' cannot have an inheritance clause
...
}

My environment is currently setup for COM work, so it is difficult to switch.

Got it. I'll try it without platform limitation first. If I can solve the CI issue that's fine. If windows platform is bumping some strange issues, I'll decide what to do then.

@parkera

parkera commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Clients importing CoreFoundation on non-Darwin platforms

Wait a minute - why is this a goal?

@parkera

parkera commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

We specifically do not want people to use the C library on non-Darwin platforms. The Swift library is the API. The C library is an implementation detail (and one we are working towards removing by reimplementing its functionality in Swift).

@Kyle-Ye

Kyle-Ye commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

We specifically do not want people to use the C library on non-Darwin platforms. The Swift library is the API. The C library is an implementation detail (and one we are working towards removing by reimplementing its functionality in Swift).

I completely agree with the long-term direction.

My point is simply that, today, the C library is still available on Linux and Android, and many existing packages depend on it.

We should certainly deprecate it gradually and encourage migration.

But as long as it's still part of the shipped implementation, fixing inconsistencies seems worthwhile. It improves compatibility for existing code without encouraging new dependencies on the C API. @parkera

@compnerd

Copy link
Copy Markdown
Member

@Kyle-Ye another option: follow Windows and later platforms and drop CF accessibility. The C interfaces are an implementation detail that are not meant to be available for users of Foundation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Core Foundation reference types are not Hashable on non-Darwin platforms

3 participants