Skip to content

Added CVarArg support to NSString and String #2821

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 3, 2020

Conversation

Molanda
Copy link
Contributor

@Molanda Molanda commented Jun 9, 2020

This adds CVarArg protocol support to NSString and String.

print(String(format: "Testing %@ %@ %@", "One", "Two", "Three"))

Testing One Two Three

NSString support was easy since %@ already exists for CFString in CoreFoundation.

String was a little bit more challenging, since withVaList doesn't provide an autorelease pool to retain the required NSString instance, which is needed for the CFString.

I solved this by using OperationQueue to schedule the release. I'm not sure if there are any other options at this point.

This resolves SR-957.

@Molanda
Copy link
Contributor Author

Molanda commented Jun 11, 2020

I created Swift PR #32311 to implement a new _CVarArgObject protocol to retain the NSString.

This PR depends on that one to be approved and merged first.

@millenomi
Copy link
Contributor

Please test with the following:
swiftlang/swift#32311

@swift-ci please test

@Molanda
Copy link
Contributor Author

Molanda commented Aug 22, 2020

Adding a reminder that this PR may need to be updated to match the new ObjC constraint on the _CVarArgObject protocol.

@Molanda
Copy link
Contributor Author

Molanda commented Sep 11, 2020

With Swift PR #32311 merged into master, we can now proceed on this one.

It is my understanding that this implementation of Foundation expects that there will never by any Objective-C runtime (at least that is what the introductory README states). However, I did find some cases of #if !_runtime(_ObjC) in the code.

I can think of a few options...

  1. Leave this as it is currently, as my understanding is correct.
  2. #if out the String extension when using ObjC runtime. My best guess is this would be to test the build for an Apple platform rather than actually making something usable, since Apple platforms have their own implementation of Foundation.
  3. #if the String extension to provide an autorelease implementation when using ObjC runtime. Is this even possible?

@Molanda
Copy link
Contributor Author

Molanda commented Sep 12, 2020

To play it safe, I picked #2. This allows it to build in Xcode using stock Swift without the _CVarArgObject protocol.

@Molanda
Copy link
Contributor Author

Molanda commented Sep 16, 2020

@millenomi Would you mind running the tests when you get a moment?

@MaxDesiatov
Copy link
Contributor

@swift-ci please test

@millenomi
Copy link
Contributor

@Molanda we support running SCF for debugging/patch writing purposes only on Darwin (via the Xcode workspace/project in the repository), so please make sure you don't break that. Note that it's a bit of a weird environment, but you will not have Swift code importing the 'real' Darwin Foundation in your process, so it will likely be safe to have the extension around — and you may actually need it since you are using SCF and the bundled CF.

@millenomi
Copy link
Contributor

@swift-ci please test

@Molanda
Copy link
Contributor Author

Molanda commented Sep 16, 2020

Thank you.

The builds failed with...

/Users/buildnode/jenkins/workspace/swift-corelibs-foundation-PR-macOS/branch-master/swift-corelibs-foundation/Sources/Foundation/NSString.swift:1651:59: error: class 'CFString' cannot be used in an '@inlinable' function because 'CoreFoundation' was imported implementation-only
18:25:01         return _encodeBitsAsWords(unsafeBitCast(self, to: CFString.self))

It seems @_implementationOnly is a recent change. Any advice on how this should be handled now?

For %@ to work, _cVarArgEncoding needs to return a CFString.

@Molanda
Copy link
Contributor Author

Molanda commented Sep 16, 2020

I can build with the @_implementationOnly change if I remove @inlinable from the extension functions.

On the Swift stdlib side, lorentey had made this suggestion...

...and I'm 99% sure we'd also want to remove @inlinable from all builder methods. (Exposing the vararg builder's class members in the ABI was a regrettable step.)

@millenomi do you agree with removing @inlinable or do you have a different suggestion?

(An unrelated note... while looking at the recent merges, I noticed RunLoop.swift has os(Linux) but not os(Android) in the #if conditional.)

@millenomi
Copy link
Contributor

@Molanda sorry for the on-and-off; yes, please remove @inlinable here, or use unsafeBitCast(…, to: AnyObject.self) instead.

@millenomi
Copy link
Contributor

millenomi commented Oct 1, 2020

(CFString and AnyObject have the same representation — an unmodified pointer to the object.)

@MaxDesiatov MaxDesiatov changed the base branch from master to main October 1, 2020 21:12
@MaxDesiatov
Copy link
Contributor

@swift-ci please test

@millenomi
Copy link
Contributor

The failing test is LLDB, not us.

@millenomi
Copy link
Contributor

@swift-ci please test linux

@Molanda
Copy link
Contributor Author

Molanda commented Oct 3, 2020

@millenomi Looks good. Thank you for the help!

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.

3 participants