Skip to content
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

Calling NSDecimalString function crashes the Swift compiler (also FB14697842) #75752

Open
flockoffiles opened this issue Aug 7, 2024 · 12 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels

Comments

@flockoffiles
Copy link

Description

The following code that calls NSDecimalString crashes the compiler with the message:

SILFunction type mismatch for 'NSDecimalString': '$@convention(c) (UnsafePointer, Optional) -> @autoreleased Optional' != '$@convention(c) (UnsafePointer, Optional) -> @autoreleased NSString'

Reproduction

import Foundation
var tmpDecimal: Decimal = 5.5
let decimalString = NSDecimalString(&tmpDecimal, Locale.current)

Stack dump

Stack dump:
0.	Program arguments: /Applications/Xcode-beta5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -frontend -c /Users/gl68pl/Developer/Temp/DecimalStringBug/DecimalStringBug/ViewController.swift -primary-file /Users/gl68pl/Developer/Temp/DecimalStringBug/DecimalStringBug/AppDelegate.swift /Users/gl68pl/Developer/Temp/DecimalStringBug/DecimalStringBug/SceneDelegate.swift /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/DerivedSources/GeneratedAssetSymbols.swift -emit-dependencies-path /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/Objects-normal/arm64/AppDelegate.d -emit-const-values-path /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/Objects-normal/arm64/AppDelegate.swiftconstvalues -emit-reference-dependencies-path /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/Objects-normal/arm64/AppDelegate.swiftdeps -serialize-diagnostics-path /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/Objects-normal/arm64/AppDelegate.dia -emit-localized-strings -emit-localized-strings-path /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/Objects-normal/arm64 -target arm64-apple-ios18.0 -Xllvm -aarch64-use-tbi -enable-objc-interop -stack-check -sdk /Applications/Xcode-beta5.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk -I /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Products/Debug-iphoneos -F /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Products/Debug-iphoneos -no-color-diagnostics -enable-testing -g -debug-info-format=dwarf -dwarf-version=5 -module-cache-path /Users/gl68pl/Library/Developer/Xcode/DerivedData/ModuleCache.noindex -swift-version 5 -enforce-exclusivity=checked -Onone -D DEBUG -serialize-debugging-options -const-gather-protocols-file /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/Objects-normal/arm64/DecimalStringBug_const_extract_protocols.json -enable-experimental-feature DebugDescriptionMacro -enable-experimental-feature OpaqueTypeErasure -enable-bare-slash-regex -empty-abi-descriptor -validate-clang-modules-once -clang-build-session-file /Users/gl68pl/Library/Developer/Xcode/DerivedData/ModuleCache.noindex/Session.modulevalidation -Xcc -working-directory -Xcc /Users/gl68pl/Developer/Temp/DecimalStringBug -resource-dir /Applications/Xcode-beta5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift -enable-anonymous-context-mangled-names -file-compilation-dir /Users/gl68pl/Developer/Temp/DecimalStringBug -Xcc -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG -Xcc -ivfsstatcache -Xcc /Users/gl68pl/Library/Developer/Xcode/DerivedData/SDKStatCaches.noindex/iphoneos18.0-22A5326g-db8e1de5f26549a68b1cfeeb5c021498.sdkstatcache -Xcc -I/Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/swift-overrides.hmap -Xcc -iquote -Xcc /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/DecimalStringBug-generated-files.hmap -Xcc -I/Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/DecimalStringBug-own-target-headers.hmap -Xcc -I/Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/DecimalStringBug-all-target-headers.hmap -Xcc -iquote -Xcc /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/DecimalStringBug-project-headers.hmap -Xcc -I/Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Products/Debug-iphoneos/include -Xcc -I/Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/DerivedSources-normal/arm64 -Xcc -I/Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/DerivedSources/arm64 -Xcc -I/Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/DerivedSources -Xcc -DDEBUG=1 -module-name DecimalStringBug -frontend-parseable-output -disable-clang-spi -target-sdk-version 18.0 -target-sdk-name iphoneos18.0 -external-plugin-path /Applications/Xcode-beta5.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/lib/swift/host/plugins#/Applications/Xcode-beta5.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode-beta5.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/local/lib/swift/host/plugins#/Applications/Xcode-beta5.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/swift-plugin-server -plugin-path /Applications/Xcode-beta5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/host/plugins -plugin-path /Applications/Xcode-beta5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/local/lib/swift/host/plugins -o /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Build/Intermediates.noindex/DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/Objects-normal/arm64/AppDelegate.o -index-unit-output-path /DecimalStringBug.build/Debug-iphoneos/DecimalStringBug.build/Objects-normal/arm64/AppDelegate.o -index-store-path /Users/gl68pl/Library/Developer/Xcode/DerivedData/DecimalStringBug-aauwvbqieqteiaeknfmiqmgohuwq/Index.noindex/DataStore -index-system-modules
1.	Apple Swift version 6.0 (swiftlang-6.0.0.7.6 clang-1600.0.24.1)
2.	Compiling with effective version 5.10
3.	While evaluating request ExecuteSILPipelineRequest(Run pipelines { Mandatory Diagnostic Passes + Enabling Optimization Passes } on SIL for DecimalStringBug)
4.	While running pass #847 SILModuleTransform "MandatorySILLinker".
5.	While deserializing SIL function "NSDecimalString"
6.	*** DESERIALIZATION FAILURE ***
*** If any module named here was modified in the SDK, please delete the ***
*** new swiftmodule files from the SDK and keep only swiftinterfaces.   ***
module 'Foundation', builder version '6.0(5.10)/Apple Swift version 6.0 (swiftlang-6.0.0.7.6 clang-1600.0.24.1)', built from swiftinterface, resilient, loaded from '/Applications/Xcode-beta5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos/prebuilt-modules/18.0/Foundation.swiftmodule/arm64-apple-ios.swiftmodule'
SILFunction type mismatch for 'NSDecimalString': '$@convention(c) (UnsafePointer<Decimal>, Optional<AnyObject>) -> @autoreleased Optional<NSString>' != '$@convention(c) (UnsafePointer<Decimal>, Optional<AnyObject>) -> @autoreleased NSString'


Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  swift-frontend           0x0000000105b6d194 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x0000000105b6b3e8 llvm::sys::RunSignalHandlers() + 112
2  swift-frontend           0x0000000105b6d760 SignalHandler(int) + 292
3  libsystem_platform.dylib 0x000000018b612584 _sigtramp + 56
4  libsystem_pthread.dylib  0x000000018b5e1c20 pthread_kill + 288
5  libsystem_c.dylib        0x000000018b4eea30 abort + 180
6  swift-frontend           0x0000000100c9b658 swift::ModuleFileSharedCore::outputDiagnosticInfo(llvm::raw_ostream&) const + 0
7  swift-frontend           0x0000000100c2fab4 swift::ModuleFile::getSourceLoc() const + 0
8  swift-frontend           0x0000000100c77ce8 swift::SILDeserializer::readSILFunctionChecked(llvm::PointerEmbeddedInt<unsigned int, 31>, swift::SILFunction*, llvm::StringRef, bool, bool) + 1916
9  swift-frontend           0x0000000100c869d8 swift::SILDeserializer::lookupSILFunction(swift::SILFunction*, bool) + 452
10 swift-frontend           0x0000000100d48c24 swift::SILLinkerVisitor::maybeAddFunctionToWorklist(swift::SILFunction*, swift::SerializedKind_t) + 360
11 swift-frontend           0x0000000100d48e44 swift::SILLinkerVisitor::process() + 476
12 swift-frontend           0x0000000100dc3d0c swift::SILModule::linkFunction(swift::SILFunction*, swift::SILModule::LinkingMode) + 120
13 swift-frontend           0x000000010147f8f0 (anonymous namespace)::SILLinker::run() + 64
14 swift-frontend           0x0000000101357a4c swift::SILPassManager::executePassPipelinePlan(swift::SILPassPipelinePlan const&) + 13436
15 swift-frontend           0x00000001013909dc swift::SimpleRequest<swift::ExecuteSILPipelineRequest, std::__1::tuple<> (swift::SILPipelineExecutionDescriptor), (swift::RequestFlags)1>::evaluateRequest(swift::ExecuteSILPipelineRequest const&, swift::Evaluator&) + 56
16 swift-frontend           0x0000000101374340 swift::ExecuteSILPipelineRequest::OutputType swift::Evaluator::getResultUncached<swift::ExecuteSILPipelineRequest, swift::ExecuteSILPipelineRequest::OutputType swift::evaluateOrFatal<swift::ExecuteSILPipelineRequest>(swift::Evaluator&, swift::ExecuteSILPipelineRequest)::'lambda'()>(swift::ExecuteSILPipelineRequest const&, swift::ExecuteSILPipelineRequest::OutputType swift::evaluateOrFatal<swift::ExecuteSILPipelineRequest>(swift::Evaluator&, swift::ExecuteSILPipelineRequest)::'lambda'()) + 412
17 swift-frontend           0x0000000101376abc swift::runSILDiagnosticPasses(swift::SILModule&) + 612
18 swift-frontend           0x00000001008f42cc swift::CompilerInstance::performSILProcessing(swift::SILModule*) + 84
19 swift-frontend           0x0000000100520268 performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 1376
20 swift-frontend           0x000000010051f474 swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 984
21 swift-frontend           0x0000000100522728 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 1680
22 swift-frontend           0x0000000100521458 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 3572
23 swift-frontend           0x00000001004a850c swift::mainEntry(int, char const**) + 3680
24 dyld                     0x000000018b257154 start + 2476
Command SwiftCompile failed with a nonzero exit code

Expected behavior

I expect it compile without a crash.

Environment

swift-driver version: 1.113 Apple Swift version 6.0 (swiftlang-6.0.0.7.6 clang-1600.0.24.1)
Target: arm64-apple-macosx14.0

Additional information

DecimalStringBug.zip

@flockoffiles flockoffiles added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels labels Aug 7, 2024
@aehlke
Copy link

aehlke commented Aug 9, 2024

Do you have a workaround?

@flockoffiles
Copy link
Author

The only workaround I know is going back to Xcode 16 beta 4 (and praying that this issue gets fixed soon).

@Cedrick84
Copy link

Experiencing the same issue.

@flockoffiles
Copy link
Author

ok. There seems to be a work-around. It's quite verbose, but it works:

    let decimalNumber = NSDecimalNumber(decimal: tmpDecimal)
    let numberFormatter = NumberFormatter()
    numberFormatter.numberStyle = .decimal
    numberFormatter.locale = locale
    let formattedString = numberFormatter.string(from: decimalNumber) ?? "\(tmpDecimal)"

@alvesmarcel
Copy link

alvesmarcel commented Sep 4, 2024

EDIT: Please see @robertmryan's comment below before choosing to use the approach I suggested here. Decimal.FormatStyle behaves differently from NumberFormatter in some scenarios.


It seems this is a known issue on Xcode 16.

According to the release notes, the suggested workaround is to use Decimal.FormatStyle. If you're supporting iOS 15.0 and above, you can do something like this too:

let decimalNumber: Decimal = 12345.67
let formatStyle = Decimal.FormatStyle(locale: locale)
let formattedNumber = decimalNumber.formatted(formatStyle)
let formattedNumberStr = String(formattedNumber)

The main advantage of this approach is that you don't have to deal with optionals.

@robertmryan
Copy link

I agree that for now we can just avoid using NSDecimalString, but, FWIW, the error message tells us what the problem is: The Swift interface indicates that the result is not optional, as indicated in the docs, but clearly elsewhere behind the scenes, it is being inferred as optional.

@robertmryan
Copy link

robertmryan commented Sep 13, 2024

@alvesmarcel

It seems this is a known issue on Xcode 16.

According to the release notes, the suggested workaround is to use Decimal.FormatStyle. If you're supporting iOS 15.0 and above, you can do something like this too:

let decimalNumber: Decimal = 12345.67
let formatStyle = Decimal.FormatStyle(locale: locale)
let formattedNumber = decimalNumber.formatted(formatStyle)
let formattedNumberStr = String(formattedNumber)

The main advantage of this approach is that you don't have to deal with optionals.

I would be cautious with this: If the locale is your current locale, this will use the default numeric format for that locale, but it will ignore whatever custom number formatting you may have changed in settings. NumberFormatter will honor the device settings, but Decimal.FormatStyle will not. If you’re trying to generate some invariant style (a la en_US_POSIX), this doesn’t matter. But if trying to localize in a manner to honor the device settings, this is problematic.

@aehlke
Copy link

aehlke commented Sep 13, 2024

@robertmryan that solution has merged so you might want to copy your feedback to that PR or share an alternative

@robertmryan
Copy link

robertmryan commented Sep 13, 2024

@aehlke

Are you talking about [swift5] Fix Xcode 16 compilation crash with Extensions.swift generation #19564? All those changes were using Locale(identifier: "en_US"). (Personally, I would have advised Locale(identifier: "en_US_POSIX"), but that distinction is subtle and beyond the scope of this conversation.) Using a fixed locale is fine. The limitations of formatted(_:) with Decimal.FormatStyle with locale of .current (or, worse, formatted()) only manifest themselves in those cases where one might reasonably assume that it would honor not only the device locale (which it will), but also any override settings of the “number format” in “Settings” (which it doesn't).

Or is there some other PR that you are referencing?

@Knapiii
Copy link

Knapiii commented Sep 16, 2024

Got the same issue on 16.0 RC
I have some SPM created by OpenAPI for our app, and the SDKs created there uses NSDecimalString.
So I can't manually change these

Can I go back to a 16.0 beta where this is not an issue?

OpenAPITools/openapi-generator#19459

@alvesmarcel
Copy link

@alvesmarcel

It seems this is a known issue on Xcode 16.
According to the release notes, the suggested workaround is to use Decimal.FormatStyle. If you're supporting iOS 15.0 and above, you can do something like this too:

let decimalNumber: Decimal = 12345.67
let formatStyle = Decimal.FormatStyle(locale: locale)
let formattedNumber = decimalNumber.formatted(formatStyle)
let formattedNumberStr = String(formattedNumber)

The main advantage of this approach is that you don't have to deal with optionals.

I would be cautious with this: If the locale is your current locale, this will use the default numeric format for that locale, but it will ignore whatever custom number formatting you may have changed in settings. NumberFormatter will honor the device settings, but Decimal.FormatStyle will not. If you’re trying to generate some invariant style (a la en_US_POSIX), this doesn’t matter. But if trying to localize in a manner to honor the device settings, this is problematic.

Thanks for pointing that out, @robertmryan! I wasn’t aware of that important difference in behavior. Do you know if there’s a way for Decimal.FormatStyle to behave like NumberFormatter? I’m asking because the documentation suggests Decimal.FormatStyle as an alternative to NumberFormatter, so I’m wondering if I’m missing something in my implementation.

@robertmryan
Copy link

robertmryan commented Sep 16, 2024

Thanks for pointing that out, @robertmryan! I wasn’t aware of that important difference in behavior. Do you know if there’s a way for Decimal.FormatStyle to behave like NumberFormatter? I’m asking because the documentation suggests Decimal.FormatStyle as an alternative to NumberFormatter, so I’m wondering if I’m missing something in my implementation.

@alvesmarcel – No, I don’t. So, when trying to format for the end-user’s preferred format, I stick with NumberFormatter. I only use this formatted function when dealing with fixed locales, like en_US_POSIX.

To make using NumberFormatter a little more natural with string interpolation, I personally extend default string interpolation behavior to support NumberFormatter:

extension String.StringInterpolation {
    mutating func appendInterpolation<T: Numeric>(_ value: T, using formatter: NumberFormatter) {
        if let formattedValue = formatter.string(for: value) {
            appendLiteral(formattedValue)
        }
    }
}

Then I can use NumberFormatter in my string interpolation:

let string = "\(value, using: formatter)")

FWIW, with floating points, you can use the specifier alternative and that seems to localize properly:

let string = "\(value, specifier: "%.2f")"

But that does not work with Decimal, hence my NumberFormatter approach outlined above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels
Projects
None yet
Development

No branches or pull requests

6 participants