From 02d7ec27e0328aea8407fba290fdb14eee37f3dd Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Tue, 28 May 2024 09:32:27 -0700 Subject: [PATCH 001/165] [embedded] Add a section on Strings into the User Manual --- docs/EmbeddedSwift/EmbeddedSwiftStatus.md | 10 ++-- docs/EmbeddedSwift/UserManual.md | 71 ++++++++++++++++++++--- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/docs/EmbeddedSwift/EmbeddedSwiftStatus.md b/docs/EmbeddedSwift/EmbeddedSwiftStatus.md index 35e347b6d84a8..4d85cf4b6e217 100644 --- a/docs/EmbeddedSwift/EmbeddedSwiftStatus.md +++ b/docs/EmbeddedSwift/EmbeddedSwiftStatus.md @@ -34,7 +34,7 @@ This status table describes which of the following standard library features can | Codable, Encodable, Decodable | No | | Collection + related protocols | Yes | | Collection algorithms (sort, reverse) | Yes | -| CustomStringConvertible, CustomDebugStringConvertible | No | +| CustomStringConvertible, CustomDebugStringConvertible | Yes, except those that require reflection (e.g. Array's .description) | | Dictionary (dynamic heap-allocated container) | Yes | | FixedWidthInteger + related protocols | Yes | | Hashable, Equatable, Comparable protocols | Yes | @@ -45,15 +45,15 @@ This status table describes which of the following standard library features can | Mirror (runtime reflection) | No, intentionally unsupported long-term | | Objective-C bridging | No, intentionally unsupported long-term | | Optional | Yes | -| print / debugPrint | Partial (only StaticStrings and integers) | +| print / debugPrint | Partial (only String, string interpolation, StaticStrings, integers, pointers and booleans) | | Range, ClosedRange, Stride | Yes | | Result | Yes | | Set (dynamic heap-allocated container) | Yes | | SIMD types | Yes | | StaticString | Yes | -| String (dynamic) | No (work in progress) | -| String Interpolations | No (work in progress) | -| Unicode | No | +| String (dynamic) | Yes | +| String Interpolations | Yes | +| Unicode | Yes | | Unsafe\[Mutable\]\[Raw\]\[Buffer\]Pointer | Yes | | VarArgs | No | diff --git a/docs/EmbeddedSwift/UserManual.md b/docs/EmbeddedSwift/UserManual.md index 46ad35a850887..b4d932d520b97 100644 --- a/docs/EmbeddedSwift/UserManual.md +++ b/docs/EmbeddedSwift/UserManual.md @@ -20,13 +20,13 @@ The following document explains how to use Embedded Swift's support in the Swift A typical setup and build + run cycle for an embedded development board involves: - (1) Getting an SDK with the C compilers, headers and libraries for the target -- (2) Building the C source code, and Swift source code +- (2) Building the C source code, and Swift source code into object files. - (3) Linking all the libraries, C object files, and Swift object files. - (4) Post-processing the linked firmware into a flashable format (UD2, BIN, or bespoke formats) - (5) Uploading the flashable binary to the board over a USB cable using some vendor-provided JTAG/SWD tool or by copying it to a fake USB Mass Storage volume presented by the board. - (6) Restarting the board, observing physical effects of the firmware (LEDs light up) or UART output over USB, or presence on network, etc. -Most of these steps are out of scope for this document, instead refer to the vendor provided documentation and get familiar with the details of firmware development for your board without Swift in the mix first. Even if you want to build a completely pure Swift firmware, you are still very likely going to need the vendor provided tooling for linking, post-processing, uploading, etc. +Most of these steps are out of scope for this document, instead refer to the vendor provided documentation. This document only focuses on (2) from the list above, and it's important that you first get familiar with the details of firmware development for your board without Swift in the mix. Even if you want to build a completely pure Swift firmware, you are still going to need the vendor provided tooling for linking, post-processing, uploading, etc. ## Building code using Embedded Swift @@ -49,7 +49,7 @@ $ swiftc -target armv7-apple-none-macho -enable-experimental-feature Embedded -w input1.swift input2.swift ... -c -o output.o # To build an ARMv7 ELF object file: -$ swiftc -target armv7-unknown-none-eabi -enable-experimental-feature Embedded -wmo \ +$ swiftc -target armv7-none-none-eabi -enable-experimental-feature Embedded -wmo \ input1.swift input2.swift ... -c -o output.o ``` @@ -59,7 +59,7 @@ For example, a Raspberry Pi Pico / Pico W should target the ARMv6-M architecture ```bash # To build an ELF object file for ARMv6-M with soft float ABI (floating-point arguments passed in integer registers) and "short enums": -$ swiftc -target armv6m-unknown-none-eabi -enable-experimental-feature Embedded -wmo \ +$ swiftc -target armv6m-none-none-eabi -enable-experimental-feature Embedded -wmo \ -Xcc -mfloat-abi=soft -Xcc -fshort-enums \ input1.swift input2.swift ... -c -o output.o ``` @@ -98,6 +98,57 @@ Segment __TEXT: 16384 ... ``` +## Strings + +Both StaticString and String types are available in Embedded Swift. As is the case in desktop Swift, certain operations on strings require Unicode data tables for strict Unicode compliance. In Embedded Swift. these data tables are provided as a separate static library (libUnicodeDataTables.a) that users need to link in manually – if they need to use these string operations. If the library is required, linking will fail due to missing on one or more of the following symbols: + +``` +_swift_stdlib_getAge +_swift_stdlib_getBinaryProperties +_swift_stdlib_getCaseMapping +_swift_stdlib_getComposition +_swift_stdlib_getDecompositionEntry +_swift_stdlib_getGeneralCategory +_swift_stdlib_getGraphemeBreakProperty +_swift_stdlib_getMapping +_swift_stdlib_getMphIdx +_swift_stdlib_getNameAlias +_swift_stdlib_getNormData +_swift_stdlib_getNumericType +_swift_stdlib_getNumericValue +_swift_stdlib_getScalarBitArrayIdx +_swift_stdlib_getScalarName +_swift_stdlib_getScript +_swift_stdlib_getScriptExtensions +_swift_stdlib_getSpecialMapping +_swift_stdlib_getWordBreakProperty +_swift_stdlib_isLinkingConsonant +_swift_stdlib_nfd_decompositions +``` + +To resolve this, link in the libswiftUnicodeDataTables.a that's in Swift toolchain's resource directory (`lib/swift/`) under the target triple that you're using: + +```bash +$ swiftc -target armv6m-none-none-eabi -enable-experimental-feature Embedded -wmo -c -o output.o +$ ld ... -o binary output.o $(dirname `which swiftc`)/../lib/swift/embedded/armv6m-none-none-eabi/libswiftUnicodeDataTables.a +``` + +**Unicode data tables are required for (list not exhaustive):** + +- Comparing String objects for equality +- Using String's hash values, and in particular using String as dictionary keys +- Using String's .count property +- Using Unicode-aware string processing APIs (.split(), iterating characters, indexing) +- Using Unicode-aware conversion String APIs (.uppercased(), .lowercased(), etc.) + +**For contrast, unicode data tables are *not required for* (list not exhaustive):** + +- Using StaticString +- Creating, concatenating, string interpolating, and printing String objects +- Using .utf8, .utf16, and .unicodeScalars views of strings, including their .count property, using them as dictionary keys + +Manually linking libUnicodeDataTables.a is required for several reasons, including acknowledging that the data tables are desirable: Since they have a non-negligible size, it's useful to be aware that you are using them. + ## Conditionalizing compilation for Embedded Swift It's often useful to have source code be compilable under both regular Swift and Embedded Swift. The following syntax is available for that (but note that as the rest of Embedded Swift, it's experimental, subject to change and not considered source stable): @@ -133,8 +184,7 @@ Features that are not available: - **Not available**: Runtime reflection (`Mirror` APIs). - **Not available**: Values of protocol types ("existentials"), e.g. `let a: Hashable = ...`, are not allowed. `Any` and `AnyObject` are also not allowed. - **Not available**: Metatypes, e.g. `let t = SomeClass.Type` or `type(of: value)` are not allowed. -- **Not available yet (under development)**: The print() function for types other than StaticString and integers. -- **Not available yet (under development)**: String. (StaticString **is** available). +- **Not available**: Printing and stringifation of arbitrary types (archieved via reflection in desktop Swift). - **Not available yet (under development)**: Swift Concurrency. For a more complete list of supported features in Embedded Swift, see [Embedded Swift -- Status](EmbeddedSwiftStatus.md). @@ -159,7 +209,14 @@ The Embedded Swift standard library is distributed in the toolchain the same way ## Allocating and non-allocating Embedded Swift mode -Embedded Swift does allow instantiating and using reference types (classes) which are refcounted objects allocated on the heap. A common case of needing those is for dynamic containers like arrays and sets (they use dynamically-sized heap-allocated class instances as their storage). Outside of creating class instances and explicitly calling allocation APIs (e.g. `UnsafeMutablePointer.allocate()`), Embedded Swift does not perform allocations or cause heap usage. +Embedded Swift does allow instantiating and using reference types (classes) which are refcounted objects allocated on the heap. A common case of needing those is for dynamic containers like arrays and sets (they use dynamically-sized heap-allocated class instances as their storage). There is only a handful of Swift language features that cause allocations: + +- creating class instances, +- escaping a closure that captures local variables, +- creating an indirect enum case with a payload referencing the enum itself +- explicitly calling allocation APIs (e.g. `UnsafeMutablePointer.allocate()`). + +Outside of those cases, Embedded Swift does not perform allocations or cause heap usage. Some embedded platforms don't have and/or don't want *any heap allocations whatsoever* and don't provide a heap at all. The `-no-allocations` compiler flag can be used to match that, which will cause the compiler to produce an error at compile time when creating class instances or calling allocation APIs. From a9d149b9be47be4dbd669fa5c7bcd4d37a259aa6 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Tue, 28 May 2024 16:21:59 -0700 Subject: [PATCH 002/165] [embedded] Add a summary of the Embedded Swift ABI --- docs/EmbeddedSwift/ABI.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 docs/EmbeddedSwift/ABI.md diff --git a/docs/EmbeddedSwift/ABI.md b/docs/EmbeddedSwift/ABI.md new file mode 100644 index 0000000000000..857cdec8dd05c --- /dev/null +++ b/docs/EmbeddedSwift/ABI.md @@ -0,0 +1,29 @@ +# Embedded Swift -- ABI + +**⚠️ Embedded Swift is experimental. This document might be out of date with latest development.** + +**‼️ Use the latest downloadable 'Trunk Development' snapshot from swift.org to use Embedded Swift. Public releases of Swift do not yet support Embedded Swift.** + +For an introduction and motivation into Embedded Swift, please see "[A Vision for Embedded Swift](https://github.com/apple/swift-evolution/blob/main/visions/embedded-swift.md)", a Swift Evolution document highlighting the main goals and approaches. + +## Calling convention of Embedded Swift + +As of today, Embedded Swift has identical calling convention to full Swift. However, this does not need to continue in the future, and there should not be expectations that the ABI of Embedded Swift is compatible with full Swift. + +## Metadata ABI of Embedded Swift + +Embedded Swift eliminates almost all metadata compared to full Swift. However, class metadata is still used, because those serve as vtables for dynamic dispatch of methods to implement runtime polymorphism. The layout of Embedded Swift's class metadata is *different* from full Swift: + +- The **super pointer** pointing to the class metadata record for the superclass is stored at **offset 0**. If the class is a root class, it is null. +- The **destructor pointer** is stored at **offset 1**. This function is invoked by Swift's deallocator when the class instance is destroyed. +- The **ivar destroyer** is stored at **offset 2**. This function is invoked to destroy instance members when creation of the object is cancelled (e.g. in a failable initializer). +- Lastly, the **vtable** is stored at **offset 3**: For each Swift class in the class's inheritance hierarchy, in order starting + from the root class and working down to the most derived class, the function pointers to the implementation of every method of the class in declaration order in stored. + +## Heap object layout in Embedded Swift + +Heap objects have the following layout in Embedded Swift: + +- The **isa pointer** (pointer to the class metadata) is stored at **offset 0**. +- The **refcount** is stored inline at **offset 1**. +- Normal stored properties follow. From d5f537b0847246598a3d28ddcf7b1d6a220aa8fa Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Wed, 15 May 2024 16:14:47 -0700 Subject: [PATCH 003/165] [update-checkout] main, rebranch, next: Update swift-system to 1.3.0 --- utils/update_checkout/update-checkout-config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index f1c91b5707482..9171093cd4a40 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -128,7 +128,7 @@ "swift-log": "1.5.4", "swift-numerics": "1.0.2", "swift-syntax": "main", - "swift-system": "1.2.1", + "swift-system": "1.3.0", "swift-stress-tester": "main", "swift-corelibs-xctest": "main", "swift-corelibs-foundation": "main", @@ -274,7 +274,7 @@ "swift-log": "1.5.4", "swift-numerics": "1.0.2", "swift-syntax": "main", - "swift-system": "1.2.1", + "swift-system": "1.3.0", "swift-stress-tester": "main", "swift-corelibs-xctest": "main", "swift-corelibs-foundation": "main", @@ -656,7 +656,7 @@ "swift-log": "1.5.4", "swift-numerics": "1.0.2", "swift-syntax": "main", - "swift-system": "1.2.1", + "swift-system": "1.3.0", "swift-stress-tester": "main", "swift-corelibs-xctest": "main", "swift-corelibs-foundation": "main", From 5dc3cf1296a173195ec8f73dc581162eb957ba5c Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 6 Jun 2024 16:48:46 -0700 Subject: [PATCH 004/165] [LifetimeCompletion] Removed "with leaks" mode. Now that the two known issues which resulted in invalid SIL being provided to lifetime completion have been addressed, tighten up the completion done on the availability boundary not to allow leaks. --- include/swift/SIL/OSSALifetimeCompletion.h | 17 +------ lib/SIL/Utils/OSSALifetimeCompletion.cpp | 45 +++++-------------- lib/SILOptimizer/Mandatory/SILGenCleanup.cpp | 5 +-- .../Utils/CanonicalizeOSSALifetime.cpp | 3 +- 4 files changed, 15 insertions(+), 55 deletions(-) diff --git a/include/swift/SIL/OSSALifetimeCompletion.h b/include/swift/SIL/OSSALifetimeCompletion.h index ba8d9e05c830c..3365c8e44f746 100644 --- a/include/swift/SIL/OSSALifetimeCompletion.h +++ b/include/swift/SIL/OSSALifetimeCompletion.h @@ -57,11 +57,6 @@ class OSSALifetimeCompletion { // Availability: "As late as possible." Consume the value in the last blocks // beyond the non-consuming uses in which the value has been // consumed on no incoming paths. - // AvailabilityWithLeaks: "As late as possible or later." Consume the value - // in the last blocks beyond the non-consuming uses in - // which the value has been consumed on no incoming - // paths, unless that block's terminator isn't an - // unreachable, in which case, don't consume it there. // // This boundary works around bugs where SILGen emits // illegal OSSA lifetimes. @@ -69,7 +64,6 @@ class OSSALifetimeCompletion { enum Value : uint8_t { Liveness, Availability, - AvailabilityWithLeaks, }; Value value; @@ -115,11 +109,6 @@ class OSSALifetimeCompletion { : LifetimeCompletion::AlreadyComplete; } - enum AllowLeaks_t : bool { - AllowLeaks = true, - DoNotAllowLeaks = false, - }; - enum class LifetimeEnd : uint8_t { /// The lifetime ends at the boundary. Boundary, @@ -128,8 +117,7 @@ class OSSALifetimeCompletion { }; static void visitAvailabilityBoundary( - SILValue value, AllowLeaks_t allowLeaks, - const SSAPrunedLiveness &liveness, + SILValue value, const SSAPrunedLiveness &liveness, llvm::function_ref visit); protected: @@ -187,9 +175,6 @@ operator<<(llvm::raw_ostream &OS, OSSALifetimeCompletion::Boundary boundary) { case OSSALifetimeCompletion::Boundary::Availability: OS << "availability"; break; - case OSSALifetimeCompletion::Boundary::AvailabilityWithLeaks: - OS << "availability_with_leaks"; - break; } return OS; } diff --git a/lib/SIL/Utils/OSSALifetimeCompletion.cpp b/lib/SIL/Utils/OSSALifetimeCompletion.cpp index fa6cf09c53e4f..ba6a338431c29 100644 --- a/lib/SIL/Utils/OSSALifetimeCompletion.cpp +++ b/lib/SIL/Utils/OSSALifetimeCompletion.cpp @@ -168,21 +168,14 @@ class AvailabilityBoundaryVisitor { /// The value whose dead-end block lifetime ends are to be visited. SILValue value; - /// Whether to allow leaks. - /// - /// Here, that entails allowing walks to reach non-unreachable terminators and - /// not creating lifetime ends before them. - OSSALifetimeCompletion::AllowLeaks_t allowLeaks; - /// The non-lifetime-ending boundary of `value`. BasicBlockSet starts; /// The region between (inclusive) the `starts` and the unreachable blocks. BasicBlockSetVector region; public: - AvailabilityBoundaryVisitor(SILValue value, - OSSALifetimeCompletion::AllowLeaks_t allowLeaks) - : value(value), allowLeaks(allowLeaks), starts(value->getFunction()), + AvailabilityBoundaryVisitor(SILValue value) + : value(value), starts(value->getFunction()), region(value->getFunction()) {} using Visit = llvm::function_ref(block->getTerminator()) || allowLeaks); + assert(isa(block->getTerminator())); } for (auto *successor : block->getSuccessorBlocks()) { regionWorklist.pushIfNotVisited(successor); @@ -379,12 +369,6 @@ void AvailabilityBoundaryVisitor::visitAvailabilityBoundary( if (!block->succ_empty() && !hasUnavailableSuccessor()) { continue; } - if (allowLeaks && block->succ_empty() && - !isa(block->getTerminator())) { - // Availability extends to the end of a function-exiting-normally block. - // If leaks are allowed, don't visit. - continue; - } assert(hasUnavailableSuccessor() || isa(block->getTerminator())); visit(block->getTerminator(), @@ -394,10 +378,10 @@ void AvailabilityBoundaryVisitor::visitAvailabilityBoundary( } // end anonymous namespace void OSSALifetimeCompletion::visitAvailabilityBoundary( - SILValue value, AllowLeaks_t allowLeaks, const SSAPrunedLiveness &liveness, + SILValue value, const SSAPrunedLiveness &liveness, llvm::function_ref visit) { - AvailabilityBoundaryVisitor visitor(value, allowLeaks); + AvailabilityBoundaryVisitor visitor(value); AvailabilityBoundaryVisitor::Result result(value->getFunction()); visitor.visit(liveness, result, visit); @@ -410,12 +394,12 @@ void OSSALifetimeCompletion::visitAvailabilityBoundary( }); } -static bool endLifetimeAtAvailabilityBoundary( - SILValue value, OSSALifetimeCompletion::AllowLeaks_t allowLeaks, - const SSAPrunedLiveness &liveness) { +static bool +endLifetimeAtAvailabilityBoundary(SILValue value, + const SSAPrunedLiveness &liveness) { bool changed = false; OSSALifetimeCompletion::visitAvailabilityBoundary( - value, allowLeaks, liveness, [&](auto *unreachable, auto end) { + value, liveness, [&](auto *unreachable, auto end) { SILBuilderWithScope builder(unreachable); endOSSALifetime(value, end, builder); changed = true; @@ -442,12 +426,7 @@ bool OSSALifetimeCompletion::analyzeAndUpdateLifetime(SILValue value, changed |= endLifetimeAtLivenessBoundary(value, liveness.getLiveness()); break; case Boundary::Availability: - changed |= endLifetimeAtAvailabilityBoundary(value, DoNotAllowLeaks, - liveness.getLiveness()); - break; - case Boundary::AvailabilityWithLeaks: - changed |= endLifetimeAtAvailabilityBoundary(value, AllowLeaks, - liveness.getLiveness()); + changed |= endLifetimeAtAvailabilityBoundary(value, liveness.getLiveness()); break; } // TODO: Rebuild outer adjacent phis on demand (SILGen does not currently @@ -472,9 +451,7 @@ static FunctionTest OSSALifetimeCompletionTest( arguments.takeString()) .Case("liveness", OSSALifetimeCompletion::Boundary::Liveness) .Case("availability", - OSSALifetimeCompletion::Boundary::Availability) - .Case("availability_with_leaks", - OSSALifetimeCompletion::Boundary::AvailabilityWithLeaks); + OSSALifetimeCompletion::Boundary::Availability); llvm::outs() << "OSSA lifetime completion on " << kind << " boundary: " << value; OSSALifetimeCompletion completion(&function, /*domInfo*/ nullptr); diff --git a/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp b/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp index caf325df576ea..446b4ced4280e 100644 --- a/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp +++ b/lib/SILOptimizer/Mandatory/SILGenCleanup.cpp @@ -118,8 +118,7 @@ bool SILGenCleanup::completeOSSALifetimes(SILFunction *function) { for (SILInstruction &inst : reverse(*block)) { for (auto result : inst.getResults()) { if (completion.completeOSSALifetime( - result, - OSSALifetimeCompletion::Boundary::AvailabilityWithLeaks) == + result, OSSALifetimeCompletion::Boundary::Availability) == LifetimeCompletion::WasCompleted) { changed = true; } @@ -128,7 +127,7 @@ bool SILGenCleanup::completeOSSALifetimes(SILFunction *function) { for (SILArgument *arg : block->getArguments()) { assert(!arg->isReborrow() && "reborrows not legal at this SIL stage"); if (completion.completeOSSALifetime( - arg, OSSALifetimeCompletion::Boundary::AvailabilityWithLeaks) == + arg, OSSALifetimeCompletion::Boundary::Availability) == LifetimeCompletion::WasCompleted) { changed = true; } diff --git a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp index 8db93617a9612..aad69dd8df034 100644 --- a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp +++ b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp @@ -274,8 +274,7 @@ void CanonicalizeOSSALifetime::extendLivenessToDeinitBarriers() { } OSSALifetimeCompletion::visitAvailabilityBoundary( - getCurrentDef(), OSSALifetimeCompletion::DoNotAllowLeaks, - completeLiveness, [&](auto *unreachable, auto end) { + getCurrentDef(), completeLiveness, [&](auto *unreachable, auto end) { if (end == OSSALifetimeCompletion::LifetimeEnd::Boundary) { recordUnreachableLifetimeEnd(unreachable); } From e2fcdb4524f26919bcb5390b10fe80e6dda82adf Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 6 Jun 2024 18:16:42 -0700 Subject: [PATCH 005/165] [MoveOnlyAddressChecker] Handle init_exi_addr. It's a pass-through for FSPL's purposes. rdar://128900124 --- lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp | 6 ++++++ ...r125864434.swift => moveonly_existentials.swift} | 13 +++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) rename test/Interpreter/{rdar125864434.swift => moveonly_existentials.swift} (55%) diff --git a/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp b/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp index 837e575fc9273..c90701d0bbaae 100644 --- a/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp +++ b/lib/SIL/Utils/FieldSensitivePrunedLiveness.cpp @@ -164,6 +164,12 @@ SubElementOffset::computeForAddress(SILValue projectionDerivedFromRoot, continue; } + if (auto *iea = + dyn_cast(projectionDerivedFromRoot)) { + projectionDerivedFromRoot = iea->getOperand(); + continue; + } + if (auto *teai = dyn_cast(projectionDerivedFromRoot)) { SILType tupleType = teai->getOperand()->getType(); diff --git a/test/Interpreter/rdar125864434.swift b/test/Interpreter/moveonly_existentials.swift similarity index 55% rename from test/Interpreter/rdar125864434.swift rename to test/Interpreter/moveonly_existentials.swift index b5050eae2bde0..929d7942fa1bb 100644 --- a/test/Interpreter/rdar125864434.swift +++ b/test/Interpreter/moveonly_existentials.swift @@ -7,15 +7,24 @@ protocol Boopable: ~Copyable { func boop() + mutating func bonk() } struct S: ~Copyable, Boopable { func boop() { print("boop") } + mutating func bonk() { print("hmm") } } -func check(_ b: borrowing any Boopable & ~Copyable) { +func borrow(_ b: borrowing any Boopable & ~Copyable) { b.boop() } +func mutate(_ b: inout any Boopable & ~Copyable) { + b.bonk() +} + // CHECK: boop -check(S()) +// CHECK: hmm +borrow(S()) +var s = S() as any Boopable & ~Copyable +mutate(&s) From a079bebc59e2fe76e64be6cba09b1f45d3070e73 Mon Sep 17 00:00:00 2001 From: Hiroshi Yamauchi Date: Fri, 7 Jun 2024 09:48:50 -0700 Subject: [PATCH 006/165] Fix the cross-compiling Windows ARM64 build. Fix the path to use the build arch instead of the host arch when invoking the built swift compiler. This fixes the build failure that's currently worked around with extra path setting. --- utils/build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/build.ps1 b/utils/build.ps1 index 440d28c3cb4fd..ac30ce0c00acd 100644 --- a/utils/build.ps1 +++ b/utils/build.ps1 @@ -866,7 +866,7 @@ function Build-CMakeProject { } if ($UseBuiltCompilers.Contains("Swift")) { - $env:Path = "$($HostArch.SDKInstallRoot)\usr\bin;$($HostArch.BinaryCache)\cmark-gfm-0.29.0.gfm.13\src;$($HostArch.ToolchainInstallRoot)\usr\bin;${env:Path}" + $env:Path = "$($BuildArch.SDKInstallRoot)\usr\bin;$($BuildArch.BinaryCache)\cmark-gfm-0.29.0.gfm.13\src;$($BuildArch.ToolchainInstallRoot)\usr\bin;${env:Path}" } elseif ($UsePinnedCompilers.Contains("Swift")) { $env:Path = "$(Get-PinnedToolchainRuntime);${env:Path}" } From f819bed190e4e3cb945a04061d5ce9a32eabab37 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Fri, 7 Jun 2024 14:20:47 -0700 Subject: [PATCH 007/165] Make BorrowingSwitch a LANGUAGE_FEATURE. It doesn't guard any source breaks, so it doesn't need to be an UPCOMING_FEATURE. rdar://129417451 --- include/swift/Basic/Features.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 9535de9ab727d..b04cd4cadd814 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -198,6 +198,7 @@ SUPPRESSIBLE_LANGUAGE_FEATURE(BitwiseCopyable2, 426, "BitwiseCopyable feature") LANGUAGE_FEATURE(BodyMacros, 415, "Function body macros") LANGUAGE_FEATURE(TransferringArgsAndResults, 430, "Transferring args and results") SUPPRESSIBLE_LANGUAGE_FEATURE(SendingArgsAndResults, 430, "Sending arg and results") +LANGUAGE_FEATURE(BorrowingSwitch, 432, "Noncopyable type pattern matching") // Swift 6 UPCOMING_FEATURE(ConciseMagicFile, 274, 6) @@ -215,7 +216,6 @@ UPCOMING_FEATURE(RegionBasedIsolation, 414, 6) UPCOMING_FEATURE(DynamicActorIsolation, 423, 6) UPCOMING_FEATURE(NonfrozenEnumExhaustivity, 192, 6) UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6) -UPCOMING_FEATURE(BorrowingSwitch, 432, 6) // Swift 7 UPCOMING_FEATURE(ExistentialAny, 335, 7) From 956243cd7ed3fb96ddee1bf207afba78b3927c2a Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 7 Jun 2024 14:54:20 -0700 Subject: [PATCH 008/165] Teach `#isolation` to respect the flow-sensitive nature of actor initializers Actor initializers have a flow-sensitive property where they are isolated to the actor being initialized only after the actor instance itself is fully-initialized. However, this behavior was not being reflected in the expansion of `#isolation`, which was always expanding to `self`, even before `self` is fully formed. This led to a source compatibility issue with code that used the async for..in loop within an actor initializer *prior* to the point where the actor was fully initialized, because the type checker is introducing the `#isolation` (SE-0421) but Definite Initialization properly rejects the use of `self` before it is initialized. Address this issue by delaying the expansion of `#isolation` until after the actor is fully initialized. In SILGen, we introduce a new builtin for this case (and *just* this case) called `flowSensitiveSelfIsolation`, which takes in `self` as its argument and produces an `(any Actor)?`. Definite initialization does not treat this as a use of `self`. Rather, it tracks these builtins and replaces them either with `self` (if it is fully-initialized at this point) or `nil` (if it is not fully-initialized at this point), mirroring the flow-sensitive isolation semantics described in SE-0327. Fixes rdar://127080037. --- include/swift/AST/Builtins.def | 8 ++++ lib/AST/Builtins.cpp | 13 +++++ lib/SIL/IR/OperandOwnership.cpp | 1 + lib/SIL/IR/ValueOwnership.cpp | 1 + lib/SILGen/SILGenExpr.cpp | 32 +++++++++++++ .../Mandatory/DIMemoryUseCollector.cpp | 11 +++++ .../Mandatory/DIMemoryUseCollector.h | 7 ++- .../Mandatory/DefiniteInitialization.cpp | 47 +++++++++++++++++++ .../AccessEnforcementReleaseSinking.cpp | 1 + test/SILGen/init_actor_isolation.swift | 29 ++++++++++++ ...inite_init_flow_sensitive_actor_self.swift | 32 +++++++++++++ 11 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 test/SILGen/init_actor_isolation.swift create mode 100644 test/SILOptimizer/definite_init_flow_sensitive_actor_self.swift diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index 6d4a8de8651e9..c96d1fb469910 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -899,6 +899,14 @@ BUILTIN_MISC_OPERATION(StartAsyncLetWithLocalBuffer, "startAsyncLetWithLocalBuff /// This is only supported under the task-to-thread concurrency model. BUILTIN_MISC_OPERATION(TaskRunInline, "taskRunInline", "", Special) +/// flowSensitiveSelfIsolation(_ actor: T) -> T? +/// +/// Used only in actor initializers, this builtin lowers to either 'actor' +/// (wrapped in an optional) or 'nil' depending on whether 'self' has been +/// initialized at this point. 'actor' is always an alias for the 'self' +/// being initialized. +BUILTIN_MISC_OPERATION(FlowSensitiveSelfIsolation, "flowSensitiveSelfIsolation", "", Special) + /// endAsyncLet(): (Builtin.RawPointer) -> Void /// /// DEPRECATED. The swift_asyncLet_finish intrinsic and endAsyncLetLifetime diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index cffba1fb45d3a..7de93057ec24f 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -2089,6 +2089,16 @@ static ValueDecl *getHopToActor(ASTContext &ctx, Identifier id) { return builder.build(id); } +static ValueDecl *getFlowSensitiveSelfIsolation(ASTContext &ctx, Identifier id) { + BuiltinFunctionBuilder builder(ctx); + return getBuiltinFunction(ctx, id, _thin, + _generics(_unrestricted, + _conformsToDefaults(0), + _conformsTo(_typeparam(0), _actor)), + _parameters(_typeparam(0)), + _optional(_existential(_actor))); +} + static ValueDecl *getDistributedActorAsAnyActor(ASTContext &ctx, Identifier id) { BuiltinFunctionBuilder builder(ctx); auto *distributedActorProto = ctx.getProtocol(KnownProtocolKind::DistributedActor); @@ -3191,6 +3201,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::HopToActor: return getHopToActor(Context, Id); + case BuiltinValueKind::FlowSensitiveSelfIsolation: + return getFlowSensitiveSelfIsolation(Context, Id); + case BuiltinValueKind::AutoDiffCreateLinearMapContextWithType: return getAutoDiffCreateLinearMapContext(Context, Id); diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index 70baa169c7917..01de24cb7a985 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -906,6 +906,7 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, EndAsyncLetLifetime) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CreateTaskGroup) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CreateTaskGroupWithFlags) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, DestroyTaskGroup) +BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FlowSensitiveSelfIsolation) BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, COWBufferForReading) diff --git a/lib/SIL/IR/ValueOwnership.cpp b/lib/SIL/IR/ValueOwnership.cpp index 335b17e4cab95..885fdf12bc438 100644 --- a/lib/SIL/IR/ValueOwnership.cpp +++ b/lib/SIL/IR/ValueOwnership.cpp @@ -630,6 +630,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, CreateTaskGroup) CONSTANT_OWNERSHIP_BUILTIN(None, CreateTaskGroupWithFlags) CONSTANT_OWNERSHIP_BUILTIN(None, DestroyTaskGroup) CONSTANT_OWNERSHIP_BUILTIN(None, TaskRunInline) +CONSTANT_OWNERSHIP_BUILTIN(Owned, FlowSensitiveSelfIsolation) CONSTANT_OWNERSHIP_BUILTIN(None, GetEnumTag) CONSTANT_OWNERSHIP_BUILTIN(None, InjectEnumTag) CONSTANT_OWNERSHIP_BUILTIN(Owned, DistributedActorAsAnyActor) diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 468f9b422800f..3d9af9141cf6f 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -6743,6 +6743,38 @@ RValue RValueEmitter::visitMacroExpansionExpr(MacroExpansionExpr *E, RValue RValueEmitter::visitCurrentContextIsolationExpr( CurrentContextIsolationExpr *E, SGFContext C) { + // If we are in an actor initializer that is isolated to, the current context + // isolation flow-sensitive: before 'self' has been initialized, it will be + // nil. After 'self' has been initialized, it will be 'self'. Introduce a + // custom builtin that Definite Initialization will rewrite appropriately. + if (auto ctor = dyn_cast_or_null( + SGF.F.getDeclRef().getDecl())) { + auto isolation = getActorIsolation(ctor); + if (ctor->isDesignatedInit() && + isolation == ActorIsolation::ActorInstance && + isolation.getActorInstance() == ctor->getImplicitSelfDecl()) { + ASTContext &ctx = SGF.getASTContext(); + auto builtinName = ctx.getIdentifier( + getBuiltinName(BuiltinValueKind::FlowSensitiveSelfIsolation)); + SILType resultTy = SGF.getLoweredType(E->getType()); + + auto injection = cast(E->getActor()); + auto erasure = cast(injection->getSubExpr()); + auto conformance = erasure->getConformances()[0]; + SGF.SGM.useConformance(conformance); + + auto origActorExpr = erasure->getSubExpr(); + auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor); + SubstitutionMap subs = SubstitutionMap::getProtocolSubstitutions( + actorProto, origActorExpr->getType(), conformance); + auto origActor = SGF.maybeEmitValueOfLocalVarDecl( + ctor->getImplicitSelfDecl(), AccessKind::Read).getValue(); + auto call = SGF.B.createBuiltin(E, builtinName, resultTy, subs, origActor); + return RValue(SGF, E, + ManagedValue::forForwardedRValue(SGF, call)); + } + } + return visit(E->getActor(), C); } diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp index cb3615c3a564c..4ec0eb89b8bfb 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp @@ -1709,6 +1709,17 @@ void ElementUseCollector::collectClassSelfUses( Kind = DIUseKind::Escape; } + // Track flow-sensitive 'self' isolation builtins separately, because they + // aren't really uses of 'self' until after DI, once we've decided whether + // they have a fully-formed 'self' to use. + if (auto builtin = dyn_cast(User)) { + if (auto builtinKind = builtin->getBuiltinKind()) { + if (*builtinKind == BuiltinValueKind::FlowSensitiveSelfIsolation) { + Kind = DIUseKind::FlowSensitiveSelfIsolation; + } + } + } + trackUse(DIMemoryUse(User, Kind, 0, TheMemory.getNumElements())); } } diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h index 860b6a0261a3c..c89167d99bde9 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h @@ -298,7 +298,12 @@ enum DIUseKind { LoadForTypeOfSelf, /// This instruction is a value_metatype on the address of 'self'. - TypeOfSelf + TypeOfSelf, + + /// This instruction is the builtin for flow-sensitive current isolation + /// within an actor initializer. It will be replaced with either a copy of + /// its argument (injected into an (any Actor)?) or nil. + FlowSensitiveSelfIsolation, }; /// This struct represents a single classified access to the memory object diff --git a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp index 494c613d65c2e..0b9d4c31bef33 100644 --- a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp +++ b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp @@ -491,6 +491,7 @@ namespace { void handleTypeOfSelfUse(DIMemoryUse &Use); void handleInOutUse(const DIMemoryUse &Use); void handleEscapeUse(const DIMemoryUse &Use); + void handleFlowSensitiveActorIsolationUse(const DIMemoryUse &Use); bool diagnoseReturnWithoutInitializingStoredProperties( const SILInstruction *Inst, SILLocation loc, const DIMemoryUse &Use); @@ -565,6 +566,7 @@ LifetimeChecker::LifetimeChecker(const DIMemoryObjectInfo &TheMemory, case DIUseKind::LoadForTypeOfSelf: case DIUseKind::TypeOfSelf: case DIUseKind::Escape: + case DIUseKind::FlowSensitiveSelfIsolation: continue; case DIUseKind::Assign: case DIUseKind::Set: @@ -1160,6 +1162,10 @@ void LifetimeChecker::doIt() { case DIUseKind::BadExplicitStore: diagnoseBadExplicitStore(Inst); break; + + case DIUseKind::FlowSensitiveSelfIsolation: + handleFlowSensitiveActorIsolationUse(Use); + break; } } @@ -1344,6 +1350,47 @@ void LifetimeChecker::handleTypeOfSelfUse(DIMemoryUse &Use) { } } +void LifetimeChecker::handleFlowSensitiveActorIsolationUse( + const DIMemoryUse &Use) { + bool IsSuperInitComplete, FailedSelfUse; + + ASTContext &ctx = F.getASTContext(); + auto builtinInst = cast(Use.Inst); + SILBuilderWithScope B(builtinInst); + SILValue replacement; + SILType optExistentialType = builtinInst->getType(); + SILLocation loc = builtinInst->getLoc(); + if (isInitializedAtUse(Use, &IsSuperInitComplete, &FailedSelfUse)) { + // 'self' is initialized, so replace this builtin with an injection of the + // argument into (any Actor)?. + + // Create a copy of the actor argument, which we intentionally did not + // copy in SILGen. + SILValue actor = B.createCopyValue(loc, builtinInst->getArguments()[0]); + + // Inject 'self' into 'any Actor'. + ProtocolConformanceRef conformances[1] = { + builtinInst->getSubstitutions().getConformances()[0] + }; + SILType existentialType = optExistentialType.getOptionalObjectType(); + SILValue existentialBox = B.createInitExistentialRef( + loc, existentialType, actor->getType().getASTType(), actor, + ctx.AllocateCopy(conformances)); + + // Then, wrap it in an optional. + replacement = B.createEnum( + loc, existentialBox, ctx.getOptionalSomeDecl(), optExistentialType); + } else { + // 'self' is not initialized yet, so use 'nil'. + replacement = B.createEnum( + loc, SILValue(), ctx.getOptionalNoneDecl(), optExistentialType); + } + + // Introduce the replacement. + InstModCallbacks callbacks; + replaceAllUsesAndErase(builtinInst, replacement, callbacks); +} + void LifetimeChecker::emitSelfConsumedDiagnostic(SILInstruction *Inst) { if (!shouldEmitError(Inst)) return; diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp index 516fdccb836a6..ff2458207e5f5 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp @@ -159,6 +159,7 @@ static bool isBarrier(SILInstruction *inst) { case BuiltinValueKind::GetEnumTag: case BuiltinValueKind::InjectEnumTag: case BuiltinValueKind::ExtractFunctionIsolation: + case BuiltinValueKind::FlowSensitiveSelfIsolation: case BuiltinValueKind::AddressOfRawLayout: return false; diff --git a/test/SILGen/init_actor_isolation.swift b/test/SILGen/init_actor_isolation.swift new file mode 100644 index 0000000000000..c7fa8f565aa77 --- /dev/null +++ b/test/SILGen/init_actor_isolation.swift @@ -0,0 +1,29 @@ +// RUN: %target-swift-frontend -emit-silgen %s -module-name test -swift-version 5 | %FileCheck %s +// REQUIRES: concurrency + +@available(SwiftStdlib 5.1, *) +func f(isolatedTo actor: isolated (any Actor)?) async -> Int { 0 } + +@available(SwiftStdlib 5.1, *) +actor A { + let number: Int + + // CHECK-LABEL: sil hidden [available 10.15] [ossa] @$s4test1ACACyYacfc : $@convention(method) @async (@sil_isolated @owned A) -> @owned A + init() async { + // First use of #isolation. + // CHECK: [[ISOLATION_1:%.*]] = builtin "flowSensitiveSelfIsolation" + // CHECK: [[F_1:%.*]] = function_ref @$s4test1f10isolatedToSiScA_pSgYi_tYaF + // CHECK-NEXT: [[F_RESULT:%.*]] = apply [[F_1]]([[ISOLATION_1]]) + + // Assignment to "number" of the result. + // CHECK: [[NUMBER:%.*]] = ref_element_addr {{%.*}} : $A, #A.number + // CHECK: assign [[F_RESULT]] to [[NUMBER]] + self.number = await f(isolatedTo: #isolation) + + // Second use of #isolation. + // CHECK: [[ISOLATION_2:%.*]] = builtin "flowSensitiveSelfIsolation" + // CHECK: [[F_2:%.*]] = function_ref @$s4test1f10isolatedToSiScA_pSgYi_tYaF + // CHECK-NEXT: apply [[F_2]]([[ISOLATION_2]]) + _ = await f(isolatedTo: #isolation) + } +} diff --git a/test/SILOptimizer/definite_init_flow_sensitive_actor_self.swift b/test/SILOptimizer/definite_init_flow_sensitive_actor_self.swift new file mode 100644 index 0000000000000..b8be8edf9e761 --- /dev/null +++ b/test/SILOptimizer/definite_init_flow_sensitive_actor_self.swift @@ -0,0 +1,32 @@ +// RUN: %target-swift-frontend -emit-sil %s -module-name test -swift-version 5 -sil-verify-all | %FileCheck %s +// REQUIRES: concurrency + +@available(SwiftStdlib 5.1, *) +func f(isolatedTo actor: isolated (any Actor)?) async -> Int { 0 } + +@available(SwiftStdlib 5.1, *) +actor A { + let number: Int + + // CHECK-LABEL: sil hidden [available 10.15] @$s4test1ACACyYacfc : $@convention(method) @async (@sil_isolated @owned A) -> @owned A + init() async { + // First use of #isolation, which is replaced by 'nil'. + // CHECK: [[ISOLATION_1:%.*]] = enum $Optional, #Optional.none!enumelt + // CHECK: [[F_1:%.*]] = function_ref @$s4test1f10isolatedToSiScA_pSgYi_tYaF + // CHECK-NEXT: [[F_RESULT:%.*]] = apply [[F_1]]([[ISOLATION_1]]) + + // Assignment to "number" of the result. + // CHECK: [[NUMBER:%.*]] = ref_element_addr {{%.*}} : $A, #A.number + // CHECK: store [[F_RESULT]] to [[NUMBER]] + self.number = await f(isolatedTo: #isolation) + + // Second use of #isolation, which uses 'self' injected into (any Actor)?. + // CHECK: [[ACTOR_COPY:%.*]] = end_init_let_ref %0 : $A + // CHECK: strong_retain [[ACTOR_COPY]] : $A + // CHECK: [[ACTOR_EXISTENTIAL:%.*]] = init_existential_ref [[ACTOR_COPY]] : $A : $A, $any Actor + // CHECK: [[ISOLATION_2:%.*]] = enum $Optional, #Optional.some!enumelt, [[ACTOR_EXISTENTIAL]] + // CHECK: [[F_2:%.*]] = function_ref @$s4test1f10isolatedToSiScA_pSgYi_tYaF + // CHECK-NEXT: apply [[F_2]]([[ISOLATION_2]]) + _ = await f(isolatedTo: #isolation) + } +} From d23fad953c90c9c60fe304f960f0dae82e42ab5e Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Wed, 15 May 2024 16:08:08 -0700 Subject: [PATCH 009/165] [update-checkout] main, rebranch, next: Update to swift-collections 1.1.1 --- utils/update_checkout/update-checkout-config.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 5ee039c43c3d2..10071956788aa 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -125,7 +125,7 @@ "swiftpm": "main", "swift-argument-parser": "1.2.3", "swift-atomics": "1.2.0", - "swift-collections": "1.0.5", + "swift-collections": "1.1.1", "swift-crypto": "3.0.0", "swift-certificates": "1.0.1", "swift-asn1": "1.0.0", @@ -274,7 +274,7 @@ "swiftpm": "main", "swift-argument-parser": "1.2.3", "swift-atomics": "1.2.0", - "swift-collections": "1.0.5", + "swift-collections": "1.1.1", "swift-crypto": "3.0.0", "swift-certificates": "1.0.1", "swift-asn1": "1.0.0", @@ -657,7 +657,7 @@ "swift-argument-parser": "1.2.3", "swift-async-algorithms": "1.0.0", "swift-atomics": "1.2.0", - "swift-collections": "1.0.5", + "swift-collections": "1.1.1", "swift-crypto": "3.0.0", "swift-certificates": "1.0.1", "swift-asn1": "1.0.0", From 814a093ef2b1d57ce60d521a414c2bc0025c45b0 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 7 Jun 2024 16:53:15 -0700 Subject: [PATCH 010/165] Fixup test --- test/SILGen/init_actor_isolation.swift | 2 +- test/SILOptimizer/definite_init_flow_sensitive_actor_self.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/SILGen/init_actor_isolation.swift b/test/SILGen/init_actor_isolation.swift index c7fa8f565aa77..1ac63a6fb8f81 100644 --- a/test/SILGen/init_actor_isolation.swift +++ b/test/SILGen/init_actor_isolation.swift @@ -8,7 +8,7 @@ func f(isolatedTo actor: isolated (any Actor)?) async -> Int { 0 } actor A { let number: Int - // CHECK-LABEL: sil hidden [available 10.15] [ossa] @$s4test1ACACyYacfc : $@convention(method) @async (@sil_isolated @owned A) -> @owned A + // CHECK-LABEL: sil hidden{{.*}}[ossa] @$s4test1ACACyYacfc : $@convention(method) @async (@sil_isolated @owned A) -> @owned A init() async { // First use of #isolation. // CHECK: [[ISOLATION_1:%.*]] = builtin "flowSensitiveSelfIsolation" diff --git a/test/SILOptimizer/definite_init_flow_sensitive_actor_self.swift b/test/SILOptimizer/definite_init_flow_sensitive_actor_self.swift index b8be8edf9e761..c3536e291d7f8 100644 --- a/test/SILOptimizer/definite_init_flow_sensitive_actor_self.swift +++ b/test/SILOptimizer/definite_init_flow_sensitive_actor_self.swift @@ -8,7 +8,7 @@ func f(isolatedTo actor: isolated (any Actor)?) async -> Int { 0 } actor A { let number: Int - // CHECK-LABEL: sil hidden [available 10.15] @$s4test1ACACyYacfc : $@convention(method) @async (@sil_isolated @owned A) -> @owned A + // CHECK-LABEL: sil hidden{{.*}}@$s4test1ACACyYacfc : $@convention(method) @async (@sil_isolated @owned A) -> @owned A init() async { // First use of #isolation, which is replaced by 'nil'. // CHECK: [[ISOLATION_1:%.*]] = enum $Optional, #Optional.none!enumelt From e3fbad50fed5fae5aa618ec9509cbdb45e492a07 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 7 Jun 2024 23:28:34 -0700 Subject: [PATCH 011/165] [SILGen] Forward addr self to borrow accessors. Utilize and expand the pre-existing peephole. rdar://127115078 --- lib/SILGen/SILGenApply.cpp | 17 ++- test/SILGen/boxed_existentials.swift | 9 +- test/SILGen/copy_expr.swift | 12 +- test/SILGen/dynamic_self.swift | 12 +- ...ntial_member_accesses_self_assoctype.swift | 129 +++++------------- .../generic_property_base_lifetime.swift | 12 +- test/SILGen/properties.swift | 15 +- test/SILGen/protocol_extensions.swift | 19 +-- test/SILGen/protocols.swift | 58 ++------ test/SILGen/struct_resilience.swift | 20 +-- test/SILGen/struct_resilience_testable.swift | 6 +- test/SILOptimizer/access_marker_verify.swift | 32 ++--- test/SILOptimizer/moveonly_accessors.swift | 24 ++++ .../sil_combine_protocol_conf.swift | 6 +- 14 files changed, 110 insertions(+), 261 deletions(-) create mode 100644 test/SILOptimizer/moveonly_accessors.swift diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 2eb9dbf3b97c7..9f042f04451c0 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -6858,22 +6858,21 @@ bool AccessorBaseArgPreparer::shouldLoadBaseAddress() const { ArgumentSource AccessorBaseArgPreparer::prepareAccessorAddressBaseArg() { // If the base is currently an address, we may have to copy it. if (shouldLoadBaseAddress()) { - if (selfParam.isConsumed() || - (base.getType().isAddressOnly(SGF.F) - // If a move-only base is borrowed, then we have to try our best to - // borrow it in-place without copying. - // TODO: Can we avoid copying a non-move-only value too in this - // circumstance? - && !base.getType().isMoveOnly())) { + if (selfParam.isConsumed() || base.getType().isAddressOnly(SGF.F)) { // The load can only be a take if the base is a +1 rvalue. auto shouldTake = IsTake_t(base.hasCleanup()); + auto isGuaranteed = selfParam.isGuaranteed(); + + auto context = + isGuaranteed ? SGFContext::AllowImmediatePlusZero : SGFContext(); + base = SGF.emitFormalAccessLoad(loc, base.forward(SGF), SGF.getTypeLowering(baseLoweredType), - SGFContext(), shouldTake); + context, shouldTake, isGuaranteed); return ArgumentSource(loc, RValue(SGF, loc, baseFormalType, base)); } - + // If the type is address-only, we can borrow the memory location as is. if (base.getType().isAddressOnly(SGF.F)) { return ArgumentSource(loc, RValue(SGF, loc, baseFormalType, base)); diff --git a/test/SILGen/boxed_existentials.swift b/test/SILGen/boxed_existentials.swift index d48adc9bdf251..b2428fb9696ea 100644 --- a/test/SILGen/boxed_existentials.swift +++ b/test/SILGen/boxed_existentials.swift @@ -64,13 +64,10 @@ func test_property(_ x: Error) -> String { // CHECK-LABEL: sil hidden [ossa] @$s18boxed_existentials13test_propertyySSs5Error_pF // CHECK: bb0([[ARG:%.*]] : @guaranteed $any Error): // CHECK: [[VALUE:%.*]] = open_existential_box [[ARG]] : $any Error to $*[[VALUE_TYPE:@opened\(.*, any Error\) Self]] -// FIXME: Extraneous copy here -// CHECK-NEXT: [[COPY:%[0-9]+]] = alloc_stack $[[VALUE_TYPE]] -// CHECK-NEXT: copy_addr [[VALUE]] to [init] [[COPY]] : $*[[VALUE_TYPE]] // CHECK: [[METHOD:%.*]] = witness_method $[[VALUE_TYPE]], #Error._domain!getter // -- self parameter of witness is @in_guaranteed; no need to copy since // value in box is immutable and box is guaranteed -// CHECK: [[RESULT:%.*]] = apply [[METHOD]]<[[VALUE_TYPE]]>([[COPY]]) +// CHECK: [[RESULT:%.*]] = apply [[METHOD]]<[[VALUE_TYPE]]>([[VALUE]]) // CHECK-NOT: destroy_value [[ARG]] // CHECK: return [[RESULT]] @@ -93,10 +90,8 @@ func test_property_of_lvalue(_ x: Error) -> String { // CHECK: [[COPY:%.*]] = alloc_stack $[[VALUE_TYPE]] // CHECK: copy_addr [[VALUE]] to [init] [[COPY]] // CHECK: destroy_value [[VALUE_BOX]] -// CHECK: [[BORROW:%.*]] = alloc_stack $[[VALUE_TYPE]] -// CHECK: copy_addr [[COPY]] to [init] [[BORROW]] // CHECK: [[METHOD:%.*]] = witness_method $[[VALUE_TYPE]], #Error._domain!getter -// CHECK: [[RESULT:%.*]] = apply [[METHOD]]<[[VALUE_TYPE]]>([[BORROW]]) +// CHECK: [[RESULT:%.*]] = apply [[METHOD]]<[[VALUE_TYPE]]>([[COPY]]) // CHECK: destroy_addr [[COPY]] // CHECK: dealloc_stack [[COPY]] // CHECK: end_borrow [[VAR_LIFETIME]] diff --git a/test/SILGen/copy_expr.swift b/test/SILGen/copy_expr.swift index 4126b7616303a..88cacd5b7964a 100644 --- a/test/SILGen/copy_expr.swift +++ b/test/SILGen/copy_expr.swift @@ -333,10 +333,8 @@ func testCallMethodOnLoadableGlobal() { // Calling computedK. It is borrowed. // CHECK: [[TEMP:%.*]] = alloc_stack $T // CHECK: explicit_copy_addr [[X]] to [init] [[TEMP]] -// CHECK: [[TEMP2:%.*]] = alloc_stack $T -// CHECK: copy_addr [[TEMP]] to [init] [[TEMP2]] // CHECK: [[FUNC:%.*]] = witness_method $T, #P.computedK!getter : (Self) -> () -> Klass : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Klass -// CHECK: apply [[FUNC]]<(T)>([[TEMP2]]) +// CHECK: apply [[FUNC]]<(T)>([[TEMP]]) // // Calling computed consuming getter. // CHECK: [[TEMP:%.*]] = alloc_stack $T @@ -378,10 +376,8 @@ func testCallMethodOnAddressOnlyLetCopy(_ t: T.Type) { // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] // CHECK: [[TEMP:%.*]] = alloc_stack $ // CHECK: explicit_copy_addr [[ACCESS]] to [init] [[TEMP]] -// CHECK: [[TEMP2:%.*]] = alloc_stack $ -// CHECK: copy_addr [[TEMP]] to [init] [[TEMP2]] // CHECK: [[FUNC:%.*]] = witness_method $T, #P.computedK!getter : (Self) -> () -> Klass : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Klass -// CHECK: apply [[FUNC]]<(T)>([[TEMP2]]) +// CHECK: apply [[FUNC]]<(T)>([[TEMP]]) // // Consuming computed getter. // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJECT]] @@ -423,10 +419,8 @@ func testCallMethodOnAddressOnlyVarCopy(_ t: T.Type) { // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ARG]] // CHECK: [[TEMP:%.*]] = alloc_stack $ // CHECK: explicit_copy_addr [[ACCESS]] to [init] [[TEMP]] -// CHECK: [[TEMP2:%.*]] = alloc_stack $ -// CHECK: copy_addr [[TEMP]] to [init] [[TEMP2]] // CHECK: [[FUNC:%.*]] = witness_method $T, #P.computedK!getter : (Self) -> () -> Klass : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Klass -// CHECK: apply [[FUNC]]<(T)>([[TEMP2]]) +// CHECK: apply [[FUNC]]<(T)>([[TEMP]]) // // Consuming computed getter. // CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ARG]] diff --git a/test/SILGen/dynamic_self.swift b/test/SILGen/dynamic_self.swift index d1047a6ef4f01..242ace6264cc8 100644 --- a/test/SILGen/dynamic_self.swift +++ b/test/SILGen/dynamic_self.swift @@ -96,27 +96,19 @@ func testExistentialDispatch(p: P) { // CHECK: [[PCOPY_ADDR:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*any P to $*@opened([[N:".*"]], any P) Self // CHECK: [[P_RESULT:%[0-9]+]] = alloc_stack $any P -// CHECK: [[PCOPY_ADDR_1:%[0-9]+]] = alloc_stack $@opened([[N]], any P) Self -// CHECK: copy_addr [[PCOPY_ADDR]] to [init] [[PCOPY_ADDR_1]] : $*@opened([[N]], any P) Self // CHECK: [[P_P_GETTER:%[0-9]+]] = witness_method $@opened([[N]], any P) Self, #P.p!getter : {{.*}}, [[PCOPY_ADDR]]{{.*}} : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 // CHECK: [[P_RESULT_ADDR2:%[0-9]+]] = init_existential_addr [[P_RESULT]] : $*any P, $@opened([[N]], any P) Self -// CHECK: apply [[P_P_GETTER]]<@opened([[N]], any P) Self>([[P_RESULT_ADDR2]], [[PCOPY_ADDR_1]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 -// CHECK: destroy_addr [[PCOPY_ADDR_1]] : $*@opened([[N]], any P) Self +// CHECK: apply [[P_P_GETTER]]<@opened([[N]], any P) Self>([[P_RESULT_ADDR2]], [[PCOPY_ADDR]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 // CHECK: destroy_addr [[P_RESULT]] : $*any P -// CHECK: dealloc_stack [[PCOPY_ADDR_1]] : $*@opened([[N]], any P) Self // CHECK: dealloc_stack [[P_RESULT]] : $*any P _ = p.p // CHECK: [[PCOPY_ADDR:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*any P to $*@opened([[N:".*"]], any P) Self // CHECK: [[P_RESULT:%[0-9]+]] = alloc_stack $any P -// CHECK: [[PCOPY_ADDR_1:%[0-9]+]] = alloc_stack $@opened([[N]], any P) Self -// CHECK: copy_addr [[PCOPY_ADDR]] to [init] [[PCOPY_ADDR_1]] : $*@opened([[N]], any P) Self // CHECK: [[P_SUBSCRIPT_GETTER:%[0-9]+]] = witness_method $@opened([[N]], any P) Self, #P.subscript!getter : {{.*}}, [[PCOPY_ADDR]]{{.*}} : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 // CHECK: [[P_RESULT_ADDR:%[0-9]+]] = init_existential_addr [[P_RESULT]] : $*any P, $@opened([[N]], any P) Self -// CHECK: apply [[P_SUBSCRIPT_GETTER]]<@opened([[N]], any P) Self>([[P_RESULT_ADDR]], [[PCOPY_ADDR_1]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 -// CHECK: destroy_addr [[PCOPY_ADDR_1]] : $*@opened([[N]], any P) Self +// CHECK: apply [[P_SUBSCRIPT_GETTER]]<@opened([[N]], any P) Self>([[P_RESULT_ADDR]], [[PCOPY_ADDR]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 // CHECK: destroy_addr [[P_RESULT]] : $*any P -// CHECK: dealloc_stack [[PCOPY_ADDR_1]] : $*@opened([[N]], any P) Self // CHECK: dealloc_stack [[P_RESULT]] : $*any P _ = p[] } diff --git a/test/SILGen/existential_member_accesses_self_assoctype.swift b/test/SILGen/existential_member_accesses_self_assoctype.swift index 51a949339ff6d..bbf3fbc907695 100644 --- a/test/SILGen/existential_member_accesses_self_assoctype.swift +++ b/test/SILGen/existential_member_accesses_self_assoctype.swift @@ -150,32 +150,25 @@ func testCovariantSelfMethod8(p: any P) { // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype26testCovariantSelfProperty11pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $any P, let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// FIXME: What's this copy for? -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantSelfProperty1!getter : (Self) -> () -> Self // CHECK: [[DEST:%[0-9]+]] = init_existential_addr [[LET]] : $*any P, $@opened([[OPENED_ID]], any P) Self -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[DEST]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[DEST]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 func testCovariantSelfProperty1(p: any P) { let x = p.covariantSelfProperty1 } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype26testCovariantSelfProperty21pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $Optional, let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantSelfProperty2!getter : (Self) -> () -> Self? -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPTIONAL:%[0-9]+]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPTIONAL:%[0-9]+]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> // CHECK: init_existential_addr %{{[0-9]+}} : $*any P, $@opened([[OPENED_ID]], any P) Self func testCovariantSelfProperty2(p: any P) { let x = p.covariantSelfProperty2 } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype26testCovariantSelfProperty31pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantSelfProperty3!getter : (Self) -> () -> Self.Type -// CHECK: [[META:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @thick τ_0_0.Type +// CHECK: [[META:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @thick τ_0_0.Type // CHECK: [[EXIST_META:%[0-9]+]] = init_existential_metatype [[META]] : $@thick (@opened([[OPENED_ID]], any P) Self).Type, $@thick any P.Type // CHECK: debug_value [[EXIST_META]] : $@thick any P.Type, let, name "x" func testCovariantSelfProperty3(p: any P) { @@ -184,10 +177,8 @@ func testCovariantSelfProperty3(p: any P) { // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype26testCovariantSelfProperty41pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $(any P, any P), let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantSelfProperty4!getter : (Self) -> () -> (Self, Self) -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[SRC_0:%[0-9]+]], [[SRC_1:%[0-9]+]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @out τ_0_0) +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[SRC_0:%[0-9]+]], [[SRC_1:%[0-9]+]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @out τ_0_0) // CHECK: [[DEST_0_INITED:%[0-9]+]] = init_existential_addr %{{[0-9]+}} : $*any P, $@opened([[OPENED_ID]], any P) Self // CHECK: [[DEST_1_INITED:%[0-9]+]] = init_existential_addr %{{[0-9]+}} : $*any P, $@opened([[OPENED_ID]], any P) Self func testCovariantSelfProperty4(p: any P) { @@ -195,10 +186,8 @@ func testCovariantSelfProperty4(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype26testCovariantSelfProperty51pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantSelfProperty5!getter : (Self) -> () -> Array -// CHECK: [[ARRAY:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Array<τ_0_0> +// CHECK: [[ARRAY:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Array<τ_0_0> // CHECK: [[ARRAY_UPCAST_FN:%[0-9]+]] = function_ref @$ss15_arrayForceCastySayq_GSayxGr0_lF : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1> // CHECK: [[RESULT:%[0-9]+]] = apply [[ARRAY_UPCAST_FN]]<@opened([[OPENED_ID]], any P) Self, any P>([[ARRAY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1> // CHECK: debug_value %{{[0-9]+}} : $Array, let, name "x" @@ -207,10 +196,8 @@ func testCovariantSelfProperty5(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype26testCovariantSelfProperty61pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantSelfProperty6!getter : (Self) -> () -> [String : Self] -// CHECK: [[DICT:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Dictionary +// CHECK: [[DICT:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Dictionary // CHECK: [[DICT_UPCAST_FN:%[0-9]+]] = function_ref @$ss17_dictionaryUpCastySDyq0_q1_GSDyxq_GSHRzSHR0_r2_lF : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3> // CHECK: [[RESULT:%[0-9]+]] = apply [[DICT_UPCAST_FN]]([[DICT]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3> // CHECK: debug_value %{{[0-9]+}} : $Dictionary, let, name "x" @@ -219,10 +206,8 @@ func testCovariantSelfProperty6(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype26testCovariantSelfProperty71pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantSelfProperty7!getter : (Self) -> () -> ((Self) -> ()) -> () -// CHECK: [[RESULT_FN:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0>) -> () for <τ_0_0> +// CHECK: [[RESULT_FN:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0>) -> () for <τ_0_0> // CHECK: [[STEP1:%[0-9]+]] = convert_function [[RESULT_FN]] : $@callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0>) -> () for <@opened([[OPENED_ID]], any P) Self> to $@callee_guaranteed (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <@opened([[OPENED_ID]], any P) Self>) -> () // CHECK: [[THUNK:%[0-9]+]] = function_ref @$sxRi_zRi0_zlyxIsgn_Iegg_42existential_member_accesses_self_assoctype1P_pIgn_Iegg_AaBRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed (@in_guaranteed any P) -> (), @guaranteed @callee_guaranteed (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0>) -> ()) -> () // CHECK: partial_apply [callee_guaranteed] [[THUNK]]<@opened([[OPENED_ID]], any P) Self>([[STEP1]]) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed (@in_guaranteed any P) -> (), @guaranteed @callee_guaranteed (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0>) -> ()) -> () @@ -232,10 +217,8 @@ func testCovariantSelfProperty7(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype26testCovariantSelfProperty81pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*[[OPENED_TY:@opened\("[0-9A-F-]+", any P\) Self]] -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $[[OPENED_TY]] -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*[[OPENED_TY]] // CHECK: [[WITNESS:%[0-9]+]] = witness_method $[[OPENED_TY]], #P.covariantSelfProperty8!getter : (Self) -> () -> ((Self...) -> ()) -> () -// CHECK: [[RESULT_FN:%[0-9]+]] = apply [[WITNESS]]<[[OPENED_TY]]>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0>) -> () for <τ_0_0> +// CHECK: [[RESULT_FN:%[0-9]+]] = apply [[WITNESS]]<[[OPENED_TY]]>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0>) -> () for <τ_0_0> // CHECK: [[STEP1:%[0-9]+]] = convert_function [[RESULT_FN]] : $@callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0>) -> () for <[[OPENED_TY]]> to $@callee_guaranteed (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <[[OPENED_TY]]>) -> () // CHECK: [[THUNK:%[0-9]+]] = function_ref @[[THUNK_NAME:\$[0-9a-zA-Z_]+]] : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed (@guaranteed Array) -> (), @guaranteed @callee_guaranteed (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0>) -> ()) -> () @@ -253,31 +236,25 @@ func testCovariantSelfProperty8(p: any P) { // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantSelfSubscript11pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $any P, let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> Self // CHECK: [[DEST:%[0-9]+]] = init_existential_addr [[LET]] : $*any P, $@opened([[OPENED_ID]], any P) Self -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[DEST]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[DEST]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0 func testCovariantSelfSubscript1(p: any P) { let x = p[covariantSelfSubscript1: ()] } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantSelfSubscript21pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $Optional, let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> Self? -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPTIONAL:%[0-9]+]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPTIONAL:%[0-9]+]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0> // CHECK: init_existential_addr %{{[0-9]+}} : $*any P, $@opened([[OPENED_ID]], any P) Self func testCovariantSelfSubscript2(p: any P) { let x = p[covariantSelfSubscript2: ()] } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantSelfSubscript31pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> Self.Type -// CHECK: [[META:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @thick τ_0_0.Type +// CHECK: [[META:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @thick τ_0_0.Type // CHECK: [[EXIST_META:%[0-9]+]] = init_existential_metatype [[META]] : $@thick (@opened([[OPENED_ID]], any P) Self).Type, $@thick any P.Type // CHECK: debug_value [[EXIST_META]] : $@thick any P.Type, let, name "x" func testCovariantSelfSubscript3(p: any P) { @@ -286,10 +263,8 @@ func testCovariantSelfSubscript3(p: any P) { // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantSelfSubscript41pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $(any P, any P), let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> (Self, Self) -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[SRC_0:%[0-9]+]], [[SRC_1:%[0-9]+]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @out τ_0_0) +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[SRC_0:%[0-9]+]], [[SRC_1:%[0-9]+]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> (@out τ_0_0, @out τ_0_0) // CHECK: init_existential_addr %{{[0-9]+}} : $*any P, $@opened([[OPENED_ID]], any P) Self // CHECK: init_existential_addr %{{[0-9]+}} : $*any P, $@opened([[OPENED_ID]], any P) Self func testCovariantSelfSubscript4(p: any P) { @@ -297,10 +272,8 @@ func testCovariantSelfSubscript4(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantSelfSubscript51pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> Array -// CHECK: [[ARRAY:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Array<τ_0_0> +// CHECK: [[ARRAY:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Array<τ_0_0> // CHECK: [[ARRAY_UPCAST_FN:%[0-9]+]] = function_ref @$ss15_arrayForceCastySayq_GSayxGr0_lF : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1> // CHECK: [[RESULT:%[0-9]+]] = apply [[ARRAY_UPCAST_FN]]<@opened([[OPENED_ID]], any P) Self, any P>([[ARRAY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1> // CHECK: debug_value %{{[0-9]+}} : $Array, let, name "x" @@ -309,10 +282,8 @@ func testCovariantSelfSubscript5(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantSelfSubscript61pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> [String : Self] -// CHECK: [[DICT:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Dictionary +// CHECK: [[DICT:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Dictionary // CHECK: [[DICT_UPCAST_FN:%[0-9]+]] = function_ref @$ss17_dictionaryUpCastySDyq0_q1_GSDyxq_GSHRzSHR0_r2_lF : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3> // CHECK: [[RESULT:%[0-9]+]] = apply [[DICT_UPCAST_FN]]([[DICT]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3> // CHECK: debug_value %{{[0-9]+}} : $Dictionary, let, name "x" @@ -325,10 +296,8 @@ func testCovariantSelfSubscript6(p: any P) { // CHECK: [[STEP1:%[0-9]+]] = partial_apply [callee_guaranteed] [[THUNK]]<@opened([[OPENED_ID]], any P) Self> // CHECK: [[STEP2:%[0-9]+]] = convert_function [[STEP1]] : $@callee_guaranteed (@in_guaranteed @opened([[OPENED_ID]], any P) Self) -> () to $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <@opened([[OPENED_ID]], any P) Self> // CHECK: [[STEP3:%[0-9]+]] = convert_escape_to_noescape [not_guaranteed] [[STEP2]] -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> ((Self) -> ()) -> () -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[STEP3]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0>, @in_guaranteed τ_0_0) -> () +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[STEP3]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0>, @in_guaranteed τ_0_0) -> () func testCovariantSelfSubscript7(p: any P) { _ = p[covariantSelfSubscript7: { _ in }] } @@ -338,10 +307,8 @@ func testCovariantSelfSubscript7(p: any P) { // CHECK: [[STEP1:%[0-9]+]] = partial_apply [callee_guaranteed] [[THUNK]]<[[OPENED_TY]]> // CHECK: [[STEP2:%[0-9]+]] = convert_function [[STEP1]] : $@callee_guaranteed (@guaranteed Array<[[OPENED_TY]]>) -> () to $@callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <[[OPENED_TY]]> // CHECK: [[STEP3:%[0-9]+]] = convert_escape_to_noescape [not_guaranteed] [[STEP2]] -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $[[OPENED_TY]] -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*[[OPENED_TY]] // CHECK: [[WITNESS:%[0-9]+]] = witness_method $[[OPENED_TY]], #P.subscript!getter : (Self) -> ((Self...) -> ()) -> () -// CHECK: apply [[WITNESS]]<[[OPENED_TY]]>([[STEP3]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0>, @in_guaranteed τ_0_0) -> () +// CHECK: apply [[WITNESS]]<[[OPENED_TY]]>([[STEP3]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0>, @in_guaranteed τ_0_0) -> () func testCovariantSelfSubscript8(p: any P) { _ = p[covariantSelfSubscript8: { _ in }] } @@ -435,31 +402,25 @@ func testCovariantAssocMethod8(p: any P) { // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantAssocProperty11pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $Any, let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantAssocProperty1!getter : (Self) -> () -> Self.A // CHECK: [[DEST:%[0-9]+]] = init_existential_addr [[LET]] : $*Any, $@opened([[OPENED_ID]], any P) Self.A -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[DEST]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.A +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[DEST]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.A func testCovariantAssocProperty1(p: any P) { let x = p.covariantAssocProperty1 } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantAssocProperty21pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $Optional, let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantAssocProperty2!getter : (Self) -> () -> Self.A? -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>(%{{[0-9]+}}, [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0.A> +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>(%{{[0-9]+}}, [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0.A> // CHECK: init_existential_addr %{{[0-9]+}} : $*Any, $@opened([[OPENED_ID]], any P) Self.A func testCovariantAssocProperty2(p: any P) { let x = p.covariantAssocProperty2 } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantAssocProperty31pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantAssocProperty3!getter : (Self) -> () -> Self.A.Type -// CHECK: [[META:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @thick τ_0_0.A.Type +// CHECK: [[META:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @thick τ_0_0.A.Type // CHECK: [[EXIST_META:%[0-9]+]] = init_existential_metatype [[META]] : $@thick (@opened([[OPENED_ID]], any P) Self.A).Type, $@thick any Any.Type // CHECK: debug_value [[EXIST_META]] : $@thick any Any.Type, let, name "x" func testCovariantAssocProperty3(p: any P) { @@ -468,10 +429,8 @@ func testCovariantAssocProperty3(p: any P) { // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantAssocProperty41pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $(Any, Any), let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantAssocProperty4!getter : (Self) -> () -> (Self.A, Self.A) -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>(%{{[0-9]+}}, %{{[0-9]+}}, [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> (@out τ_0_0.A, @out τ_0_0.A) +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>(%{{[0-9]+}}, %{{[0-9]+}}, [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> (@out τ_0_0.A, @out τ_0_0.A) // CHECK: init_existential_addr %{{[0-9]+}} : $*Any, $@opened([[OPENED_ID]], any P) Self.A // CHECK: init_existential_addr %{{[0-9]+}} : $*Any, $@opened([[OPENED_ID]], any P) Self.A func testCovariantAssocProperty4(p: any P) { @@ -479,10 +438,8 @@ func testCovariantAssocProperty4(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantAssocProperty51pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantAssocProperty5!getter : (Self) -> () -> Array -// CHECK: [[ARRAY:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Array<τ_0_0.A> +// CHECK: [[ARRAY:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Array<τ_0_0.A> // CHECK: [[ARRAY_UPCAST_FN:%[0-9]+]] = function_ref @$ss15_arrayForceCastySayq_GSayxGr0_lF : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1> // CHECK: [[RESULT:%[0-9]+]] = apply [[ARRAY_UPCAST_FN]]<@opened([[OPENED_ID]], any P) Self.A, Any>([[ARRAY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1> // CHECK: debug_value %{{[0-9]+}} : $Array, let, name "x" @@ -491,10 +448,8 @@ func testCovariantAssocProperty5(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantAssocProperty61pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantAssocProperty6!getter : (Self) -> () -> [String : Self.A] -// CHECK: [[DICT:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Dictionary +// CHECK: [[DICT:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Dictionary // CHECK: [[DICT_UPCAST_FN:%[0-9]+]] = function_ref @$ss17_dictionaryUpCastySDyq0_q1_GSDyxq_GSHRzSHR0_r2_lF : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3> // CHECK: [[RESULT:%[0-9]+]] = apply [[DICT_UPCAST_FN]]([[DICT]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3> // CHECK: debug_value %{{[0-9]+}} : $Dictionary, let, name "x" @@ -503,10 +458,8 @@ func testCovariantAssocProperty6(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantAssocProperty71pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.covariantAssocProperty7!getter : (Self) -> () -> ((Self.A) -> ()) -> () -// CHECK: [[RESULT_FN:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0>) -> () for <τ_0_0.A> +// CHECK: [[RESULT_FN:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0>) -> () for <τ_0_0.A> // CHECK: [[STEP1:%[0-9]+]] = convert_function [[RESULT_FN]] : $@callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0>) -> () for <@opened([[OPENED_ID]], any P) Self.A> to $@callee_guaranteed (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <@opened([[OPENED_ID]], any P) Self.A>) -> () // CHECK: [[THUNK:%[0-9]+]] = function_ref @$sxRi_zRi0_zly1A42existential_member_accesses_self_assoctype1PPQzIsgn_Iegg_ypIgn_Iegg_AbCRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed (@in_guaranteed Any) -> (), @guaranteed @callee_guaranteed (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0.A>) -> ()) -> () // CHECK: partial_apply [callee_guaranteed] [[THUNK]]<@opened([[OPENED_ID]], any P) Self>([[STEP1]]) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed (@in_guaranteed Any) -> (), @guaranteed @callee_guaranteed (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0.A>) -> ()) -> () @@ -516,10 +469,8 @@ func testCovariantAssocProperty7(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype27testCovariantAssocProperty81pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*[[OPENED_TY:@opened\("[0-9A-F-]+", any P\) Self]] -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $[[OPENED_TY]] -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*[[OPENED_TY]] // CHECK: [[WITNESS:%[0-9]+]] = witness_method $[[OPENED_TY]], #P.covariantAssocProperty8!getter : (Self) -> () -> ((Self.A...) -> ()) -> () -// CHECK: [[RESULT_FN:%[0-9]+]] = apply [[WITNESS]]<[[OPENED_TY]]>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0>) -> () for <τ_0_0.A> +// CHECK: [[RESULT_FN:%[0-9]+]] = apply [[WITNESS]]<[[OPENED_TY]]>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned @callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0>) -> () for <τ_0_0.A> // CHECK: [[STEP1:%[0-9]+]] = convert_function [[RESULT_FN]] : $@callee_guaranteed @substituted <τ_0_0> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0>) -> () for <[[OPENED_TY]].A> to $@callee_guaranteed (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <[[OPENED_TY]].A>) -> () // CHECK: [[THUNK:%[0-9]+]] = function_ref @[[THUNK_NAME:\$[0-9a-zA-Z_]+]] : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed (@guaranteed Array) -> (), @guaranteed @callee_guaranteed (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0.A>) -> ()) -> () // CHECK: partial_apply [callee_guaranteed] [[THUNK]]<[[OPENED_TY]]>([[STEP1]]) @@ -536,31 +487,25 @@ func testCovariantAssocProperty8(p: any P) { // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype28testCovariantAssocSubscript11pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $Any, let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> Self.A // CHECK: [[DEST:%[0-9]+]] = init_existential_addr [[LET]] : $*Any, $@opened([[OPENED_ID]], any P) Self.A -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[DEST]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.A +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[DEST]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out τ_0_0.A func testCovariantAssocSubscript1(p: any P) { let x = p[covariantAssocSubscript1: ()] } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype28testCovariantAssocSubscript21pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $Optional, let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> Self.A? -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>(%{{[0-9]+}}, [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0.A> +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>(%{{[0-9]+}}, [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0.A> // CHECK: init_existential_addr %{{[0-9]+}} : $*Any, $@opened([[OPENED_ID]], any P) Self.A func testCovariantAssocSubscript2(p: any P) { let x = p[covariantAssocSubscript2: ()] } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype28testCovariantAssocSubscript31pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> Self.A.Type -// CHECK: [[META:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @thick τ_0_0.A.Type +// CHECK: [[META:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @thick τ_0_0.A.Type // CHECK: [[EXIST_META:%[0-9]+]] = init_existential_metatype [[META]] : $@thick (@opened([[OPENED_ID]], any P) Self.A).Type, $@thick any Any.Type // CHECK: debug_value [[EXIST_META]] : $@thick any Any.Type, let, name "x" func testCovariantAssocSubscript3(p: any P) { @@ -569,10 +514,8 @@ func testCovariantAssocSubscript3(p: any P) { // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype28testCovariantAssocSubscript41pyAA1P_p_tF // CHECK: [[LET:%[0-9]+]] = alloc_stack [lexical] [var_decl] $(Any, Any), let, name "x" // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> (Self.A, Self.A) -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>(%{{[0-9]+}}, %{{[0-9]+}}, [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> (@out τ_0_0.A, @out τ_0_0.A) +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>(%{{[0-9]+}}, %{{[0-9]+}}, [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> (@out τ_0_0.A, @out τ_0_0.A) // CHECK: init_existential_addr %{{[0-9]+}} : $*Any, $@opened([[OPENED_ID]], any P) Self.A // CHECK: init_existential_addr %{{[0-9]+}} : $*Any, $@opened([[OPENED_ID]], any P) Self.A func testCovariantAssocSubscript4(p: any P) { @@ -580,10 +523,8 @@ func testCovariantAssocSubscript4(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype28testCovariantAssocSubscript51pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> Array -// CHECK: [[ARRAY:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Array<τ_0_0.A> +// CHECK: [[ARRAY:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Array<τ_0_0.A> // CHECK: [[ARRAY_UPCAST_FN:%[0-9]+]] = function_ref @$ss15_arrayForceCastySayq_GSayxGr0_lF : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1> // CHECK: [[RESULT:%[0-9]+]] = apply [[ARRAY_UPCAST_FN]]<@opened([[OPENED_ID]], any P) Self.A, Any>([[ARRAY]]) : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Array<τ_0_1> // CHECK: debug_value %{{[0-9]+}} : $Array, let, name "x" @@ -592,10 +533,8 @@ func testCovariantAssocSubscript5(p: any P) { } // CHECK-LABEL: sil hidden [ossa] @$s42existential_member_accesses_self_assoctype28testCovariantAssocSubscript61pyAA1P_p_tF // CHECK: [[OPENED:%[0-9]+]] = open_existential_addr immutable_access %0 : $*any P to $*@opened([[OPENED_ID:"[0-9A-F-]+"]], any P) Self -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> (()) -> [String : Self.A] -// CHECK: [[DICT:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Dictionary +// CHECK: [[DICT:%[0-9]+]] = apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> @owned Dictionary // CHECK: [[DICT_UPCAST_FN:%[0-9]+]] = function_ref @$ss17_dictionaryUpCastySDyq0_q1_GSDyxq_GSHRzSHR0_r2_lF : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3> // CHECK: [[RESULT:%[0-9]+]] = apply [[DICT_UPCAST_FN]]([[DICT]]) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Dictionary<τ_0_2, τ_0_3> // CHECK: debug_value %{{[0-9]+}} : $Dictionary, let, name "x" @@ -608,10 +547,8 @@ func testCovariantAssocSubscript6(p: any P) { // CHECK: [[STEP1:%[0-9]+]] = partial_apply [callee_guaranteed] [[THUNK]]<@opened([[OPENED_ID]], any P) Self> // CHECK: [[STEP2:%[0-9]+]] = convert_function [[STEP1]] : $@callee_guaranteed (@in_guaranteed @opened([[OPENED_ID]], any P) Self.A) -> () to $@callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <@opened([[OPENED_ID]], any P) Self.A> // CHECK: [[STEP3:%[0-9]+]] = convert_escape_to_noescape [not_guaranteed] [[STEP2]] -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $@opened([[OPENED_ID]], any P) Self -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*@opened([[OPENED_ID]], any P) Self // CHECK: [[WITNESS:%[0-9]+]] = witness_method $@opened([[OPENED_ID]], any P) Self, #P.subscript!getter : (Self) -> ((Self.A) -> ()) -> () -// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[STEP3]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0.A>, @in_guaranteed τ_0_0) -> () +// CHECK: apply [[WITNESS]]<@opened([[OPENED_ID]], any P) Self>([[STEP3]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> () for <τ_0_0.A>, @in_guaranteed τ_0_0) -> () func testCovariantAssocSubscript7(p: any P) { _ = p[covariantAssocSubscript7: { _ in }] } @@ -621,10 +558,8 @@ func testCovariantAssocSubscript7(p: any P) { // CHECK: [[STEP1:%[0-9]+]] = partial_apply [callee_guaranteed] [[THUNK]]<[[OPENED_TY]]> // CHECK: [[STEP2:%[0-9]+]] = convert_function [[STEP1]] : $@callee_guaranteed (@guaranteed Array<[[OPENED_TY]].A>) -> () to $@callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <[[OPENED_TY]].A> // CHECK: [[STEP3:%[0-9]+]] = convert_escape_to_noescape [not_guaranteed] [[STEP2]] -// CHECK: [[OPENED_COPY:%[0-9]+]] = alloc_stack $[[OPENED_TY]] -// CHECK: copy_addr [[OPENED]] to [init] [[OPENED_COPY]] : $*[[OPENED_TY]] // CHECK: [[WITNESS:%[0-9]+]] = witness_method $[[OPENED_TY]], #P.subscript!getter : (Self) -> ((Self.A...) -> ()) -> () -// CHECK: apply [[WITNESS]]<[[OPENED_TY]]>([[STEP3]], [[OPENED_COPY]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0.A>, @in_guaranteed τ_0_0) -> () +// CHECK: apply [[WITNESS]]<[[OPENED_TY]]>([[STEP3]], [[OPENED]]) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@guaranteed @noescape @callee_guaranteed @substituted <τ_0_0> (@guaranteed Array<τ_0_0>) -> () for <τ_0_0.A>, @in_guaranteed τ_0_0) -> () func testCovariantAssocSubscript8(p: any P) { _ = p[covariantAssocSubscript8: { _ in }] } diff --git a/test/SILGen/generic_property_base_lifetime.swift b/test/SILGen/generic_property_base_lifetime.swift index 4c8325326d98e..61d5643fc0f75 100644 --- a/test/SILGen/generic_property_base_lifetime.swift +++ b/test/SILGen/generic_property_base_lifetime.swift @@ -58,21 +58,13 @@ func setIntPropGeneric(_ a: T) { // CHECK-LABEL: sil hidden [ossa] @$s30generic_property_base_lifetime21getIntPropExistentialySiAA9ProtocolB_pF // CHECK: [[PROJECTION:%.*]] = open_existential_addr immutable_access %0 -// CHECK: [[STACK:%[0-9]+]] = alloc_stack $@opened({{".*"}}, any ProtocolB) Self -// CHECK: copy_addr [[PROJECTION]] to [init] [[STACK]] -// CHECK: apply {{%.*}}([[STACK]]) -// CHECK: destroy_addr [[STACK]] -// CHECK: dealloc_stack [[STACK]] +// CHECK: apply {{%.*}}([[PROJECTION]]) func getIntPropExistential(_ a: ProtocolB) -> Int { return a.intProp } // CHECK-LABEL: sil hidden [ossa] @$s30generic_property_base_lifetime17getIntPropGeneric{{[_0-9a-zA-Z]*}}F -// CHECK: [[STACK:%[0-9]+]] = alloc_stack $T -// CHECK: copy_addr %0 to [init] [[STACK]] -// CHECK: apply {{%.*}}([[STACK]]) -// CHECK: destroy_addr [[STACK]] -// CHECK: dealloc_stack [[STACK]] +// CHECK: apply {{%.*}}(%0) func getIntPropGeneric(_ a: T) -> Int { return a.intProp } diff --git a/test/SILGen/properties.swift b/test/SILGen/properties.swift index 7b3bd50a011db..ab429d86351cd 100644 --- a/test/SILGen/properties.swift +++ b/test/SILGen/properties.swift @@ -746,13 +746,9 @@ func addressOnlyNonmutatingProperty(_ x: AddressOnlyNonmutatingSet) } // CHECK-LABEL: sil hidden [ossa] @$s10properties30addressOnlyNonmutatingProperty{{[_0-9a-zA-Z]*}}F // CHECK: [[SET:%.*]] = function_ref @$s10properties25AddressOnlyNonmutatingSetV4propSivs -// CHECK: apply [[SET]]({{%.*}}, [[TMP:%[0-9]*]]) -// CHECK: destroy_addr [[TMP]] -// CHECK: dealloc_stack [[TMP]] +// CHECK: apply [[SET]]({{%.*}}, %0) // CHECK: [[GET:%.*]] = function_ref @$s10properties25AddressOnlyNonmutatingSetV4propSivg // CHECK: apply [[GET]]([[TMP:%[0-9]*]]) -// CHECK: destroy_addr [[TMP]] -// CHECK: dealloc_stack [[TMP]] protocol MakeAddressOnly {} struct AddressOnlyReadOnlySubscript { @@ -764,9 +760,8 @@ struct AddressOnlyReadOnlySubscript { // CHECK-LABEL: sil hidden [ossa] @$s10properties015addressOnlyReadC24SubscriptFromMutableBase // CHECK: [[BASE:%.*]] = alloc_box ${ var AddressOnlyReadOnlySubscript } // CHECK: copy_addr [[BASE:%.*]] to [init] [[COPY:%.*]] : -// CHECK: copy_addr [[COPY:%.*]] to [init] [[COPY2:%.*]] : // CHECK: [[GETTER:%.*]] = function_ref @$s10properties015AddressOnlyReadC9SubscriptV{{[_0-9a-zA-Z]*}}ig -// CHECK: apply [[GETTER]]({{%.*}}, [[COPY2]]) +// CHECK: apply [[GETTER]]({{%.*}}, [[COPY]]) func addressOnlyReadOnlySubscriptFromMutableBase(_ x: Int) { var base = AddressOnlyReadOnlySubscript() _ = base[x] @@ -834,13 +829,9 @@ protocol NonmutatingProtocol { // CHECK-NEXT: [[C_FIELD_COPY:%.*]] = alloc_stack $@opened("{{.*}}", any NonmutatingProtocol) Self // CHECK-NEXT: copy_addr [[C_FIELD_PAYLOAD]] to [init] [[C_FIELD_COPY]] : $*@opened("{{.*}}", any NonmutatingProtocol) Self // CHECK-NEXT: destroy_value [[C]] : $ReferenceType -// CHECK-NEXT: [[C_FIELD_BORROW:%.*]] = alloc_stack -// CHECK-NEXT: copy_addr [[C_FIELD_COPY]] to [init] [[C_FIELD_BORROW]] // CHECK-NEXT: [[GETTER:%.*]] = witness_method $@opened("{{.*}}", any NonmutatingProtocol) Self, #NonmutatingProtocol.x!getter : (Self) -> () -> Int, [[C_FIELD_PAYLOAD]] : $*@opened("{{.*}}", any NonmutatingProtocol) Self : $@convention(witness_method: NonmutatingProtocol) <τ_0_0 where τ_0_0 : NonmutatingProtocol> (@in_guaranteed τ_0_0) -> Int -// CHECK-NEXT: [[RESULT_VALUE:%.*]] = apply [[GETTER]]<@opened("{{.*}}", any NonmutatingProtocol) Self>([[C_FIELD_BORROW]]) : $@convention(witness_method: NonmutatingProtocol) <τ_0_0 where τ_0_0 : NonmutatingProtocol> (@in_guaranteed τ_0_0) -> Int -// CHECK-NEXT: destroy_addr [[C_FIELD_BORROW]] +// CHECK-NEXT: [[RESULT_VALUE:%.*]] = apply [[GETTER]]<@opened("{{.*}}", any NonmutatingProtocol) Self>([[C_FIELD_COPY]]) : $@convention(witness_method: NonmutatingProtocol) <τ_0_0 where τ_0_0 : NonmutatingProtocol> (@in_guaranteed τ_0_0) -> Int // CHECK-NEXT: destroy_addr [[C_FIELD_COPY]] : $*@opened("{{.*}}", any NonmutatingProtocol) Self -// CHECK-NEXT: dealloc_stack [[C_FIELD_BORROW]] // CHECK-NEXT: dealloc_stack [[C_FIELD_COPY]] : $*@opened("{{.*}}", any NonmutatingProtocol) Self // CHECK-NEXT: destroy_addr [[C_FIELD_BOX]] : $*any NonmutatingProtocol // CHECK-NEXT: dealloc_stack [[C_FIELD_BOX]] : $*any NonmutatingProtocol diff --git a/test/SILGen/protocol_extensions.swift b/test/SILGen/protocol_extensions.swift index 360f0fd03383d..88cc967033c09 100644 --- a/test/SILGen/protocol_extensions.swift +++ b/test/SILGen/protocol_extensions.swift @@ -507,20 +507,15 @@ func testExistentials1(_ p1: P1, b: Bool, i: Int64) { p1.f1() // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*any P1 to $*@opened([[UUID:".*"]], any P1) Self - // CHECK: copy_addr [[POPENED]] to [init] [[POPENED_COPY:%.*]] : // CHECK: [[GETTER:%[0-9]+]] = function_ref @$s19protocol_extensions2P1PAAEySbs5Int64Vcig - // CHECK: apply [[GETTER]]<@opened([[UUID]], any P1) Self>([[I]], [[POPENED_COPY]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Int64, @in_guaranteed τ_0_0) -> Bool + // CHECK: apply [[GETTER]]<@opened([[UUID]], any P1) Self>([[I]], [[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Int64, @in_guaranteed τ_0_0) -> Bool // CHECK: store{{.*}} : $*Bool - // CHECK: destroy_addr [[POPENED_COPY]] - // CHECK: dealloc_stack [[POPENED_COPY]] var b2 = p1[i] // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*any P1 to $*@opened([[UUID:".*"]], any P1) Self - // CHECK: copy_addr [[POPENED]] to [init] [[POPENED_COPY:%.*]] : // CHECK: [[GETTER:%[0-9]+]] = function_ref @$s19protocol_extensions2P1PAAE4propSbvg - // CHECK: apply [[GETTER]]<@opened([[UUID]], any P1) Self>([[POPENED_COPY]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> Bool + // CHECK: apply [[GETTER]]<@opened([[UUID]], any P1) Self>([[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> Bool // CHECK: store{{.*}} : $*Bool - // CHECK: dealloc_stack [[POPENED_COPY]] var b3 = p1.prop } @@ -541,15 +536,13 @@ func testExistentials2(_ p1: P1) { // CHECK: bb0([[P:%[0-9]+]] : $*any P1): func testExistentialsGetters(_ p1: P1) { // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*any P1 to $*@opened([[UUID:".*"]], any P1) Self - // CHECK: copy_addr [[POPENED]] to [init] [[POPENED_COPY:%.*]] : // CHECK: [[FN:%[0-9]+]] = function_ref @$s19protocol_extensions2P1PAAE5prop2Sbvg - // CHECK: [[B:%[0-9]+]] = apply [[FN]]<@opened([[UUID]], any P1) Self>([[POPENED_COPY]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> Bool + // CHECK: [[B:%[0-9]+]] = apply [[FN]]<@opened([[UUID]], any P1) Self>([[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> Bool let b: Bool = p1.prop2 // CHECK: [[POPENED:%[0-9]+]] = open_existential_addr immutable_access [[P]] : $*any P1 to $*@opened([[UUID:".*"]], any P1) Self - // CHECK: copy_addr [[POPENED]] to [init] [[POPENED_COPY:%.*]] : // CHECK: [[GETTER:%[0-9]+]] = function_ref @$s19protocol_extensions2P1PAAEyS2bcig - // CHECK: apply [[GETTER]]<@opened([[UUID]], any P1) Self>([[B]], [[POPENED_COPY]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @in_guaranteed τ_0_0) -> Bool + // CHECK: apply [[GETTER]]<@opened([[UUID]], any P1) Self>([[B]], [[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @in_guaranteed τ_0_0) -> Bool let b2: Bool = p1[b] } @@ -597,10 +590,8 @@ func testLogicalExistentialSetters(_ hasAP1: HasAP1, _ b: Bool) { // CHECK-NEXT: copy_addr [[HASP1]] to [init] [[PBHASP1]] : $*HasAP1 // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PBHASP1]] // CHECK: [[P1_COPY:%[0-9]+]] = alloc_stack $any P1 - // CHECK-NEXT: [[HASP1_COPY:%[0-9]+]] = alloc_stack $HasAP1 - // CHECK-NEXT: copy_addr [[WRITE]] to [init] [[HASP1_COPY]] : $*HasAP1 // CHECK: [[SOMEP1_GETTER:%[0-9]+]] = function_ref @$s19protocol_extensions6HasAP1V6someP1AA0F0_pvg : $@convention(method) (@in_guaranteed HasAP1) -> @out any P1 - // CHECK: [[RESULT:%[0-9]+]] = apply [[SOMEP1_GETTER]]([[P1_COPY]], [[HASP1_COPY]]) : $@convention(method) (@in_guaranteed HasAP1) -> @out any P1 + // CHECK: [[RESULT:%[0-9]+]] = apply [[SOMEP1_GETTER]]([[P1_COPY]], [[WRITE]]) : $@convention(method) (@in_guaranteed HasAP1) -> @out any P1 // CHECK: [[P1_OPENED:%[0-9]+]] = open_existential_addr mutable_access [[P1_COPY]] : $*any P1 to $*@opened([[UUID:".*"]], any P1) Self // CHECK: [[PROP2_SETTER:%[0-9]+]] = function_ref @$s19protocol_extensions2P1PAAE5prop2Sbvs : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @inout τ_0_0) -> () // CHECK: apply [[PROP2_SETTER]]<@opened([[UUID]], any P1) Self>([[B]], [[P1_OPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @inout τ_0_0) -> () diff --git a/test/SILGen/protocols.swift b/test/SILGen/protocols.swift index e21da956db147..4e9a78a57412d 100644 --- a/test/SILGen/protocols.swift +++ b/test/SILGen/protocols.swift @@ -28,13 +28,9 @@ func use_subscript_rvalue_get(_ i : Int) -> Int { // CHECK: [[ALLOCSTACK:%[0-9]+]] = alloc_stack $[[OPENED]] // CHECK: copy_addr [[PROJ]] to [init] [[ALLOCSTACK]] : $*[[OPENED]] // CHECK-NEXT: end_access [[READ]] : $*any SubscriptableGet -// CHECK-NEXT: [[TMP:%.*]] = alloc_stack -// CHECK-NEXT: copy_addr [[ALLOCSTACK]] to [init] [[TMP]] // CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #SubscriptableGet.subscript!getter -// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[METH]]<[[OPENED]]>(%0, [[TMP]]) -// CHECK-NEXT: destroy_addr [[TMP]] +// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[METH]]<[[OPENED]]>(%0, [[ALLOCSTACK]]) // CHECK-NEXT: destroy_addr [[ALLOCSTACK]] -// CHECK-NEXT: dealloc_stack [[TMP]] // CHECK-NEXT: dealloc_stack [[ALLOCSTACK]] : $*[[OPENED]] // CHECK-NEXT: return [[RESULT]] @@ -47,13 +43,9 @@ func use_subscript_lvalue_get(_ i : Int) -> Int { // CHECK: [[GLOB:%[0-9]+]] = global_addr @$s9protocols19subscriptableGetSetAA013SubscriptablecD0_pvp : $*any SubscriptableGetSet // CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[GLOB]] : $*any SubscriptableGetSet // CHECK: [[PROJ:%[0-9]+]] = open_existential_addr immutable_access [[READ]] : $*any SubscriptableGetSet to $*[[OPENED:@opened\(.*, any SubscriptableGetSet\) Self]] -// CHECK: [[ALLOCSTACK:%[0-9]+]] = alloc_stack $[[OPENED]] -// CHECK: copy_addr [[PROJ]] to [init] [[ALLOCSTACK]] : $*[[OPENED]] // CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #SubscriptableGetSet.subscript!getter -// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[METH]]<[[OPENED]]>(%0, [[ALLOCSTACK]]) -// CHECK-NEXT: destroy_addr [[ALLOCSTACK]] : $*[[OPENED]] +// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[METH]]<[[OPENED]]>(%0, [[PROJ]]) // CHECK-NEXT: end_access [[READ]] : $*any SubscriptableGetSet -// CHECK-NEXT: dealloc_stack [[ALLOCSTACK]] : $*[[OPENED]] // CHECK-NEXT: return [[RESULT]] func use_subscript_lvalue_set(_ i : Int) { @@ -78,12 +70,8 @@ func use_subscript_archetype_rvalue_get(_ generic : T, idx } // CHECK-LABEL: sil hidden [ossa] @{{.*}}use_subscript_archetype_rvalue_get // CHECK: bb0(%0 : $*T, %1 : $Int): -// CHECK: [[STACK:%[0-9]+]] = alloc_stack $T -// CHECK: copy_addr %0 to [init] [[STACK]] // CHECK: [[METH:%[0-9]+]] = witness_method $T, #SubscriptableGet.subscript!getter -// CHECK-NEXT: apply [[METH]](%1, [[STACK]]) -// CHECK-NEXT: destroy_addr [[STACK]] : $*T -// CHECK-NEXT: dealloc_stack [[STACK]] : $*T +// CHECK-NEXT: apply [[METH]](%1, %0) // CHECK: } // end sil function '${{.*}}use_subscript_archetype_rvalue_get @@ -93,13 +81,9 @@ func use_subscript_archetype_lvalue_get(_ generic: inou // CHECK-LABEL: sil hidden [ossa] @{{.*}}use_subscript_archetype_lvalue_get // CHECK: bb0(%0 : $*T, %1 : $Int): // CHECK: [[READ:%.*]] = begin_access [read] [unknown] %0 : $*T -// CHECK: [[GUARANTEEDSTACK:%[0-9]+]] = alloc_stack $T -// CHECK: copy_addr [[READ]] to [init] [[GUARANTEEDSTACK]] : $*T // CHECK: [[METH:%[0-9]+]] = witness_method $T, #SubscriptableGetSet.subscript!getter -// CHECK-NEXT: [[APPLYRESULT:%[0-9]+]] = apply [[METH]](%1, [[GUARANTEEDSTACK]]) -// CHECK-NEXT: destroy_addr [[GUARANTEEDSTACK]] : $*T +// CHECK-NEXT: [[APPLYRESULT:%[0-9]+]] = apply [[METH]](%1, [[READ]]) // CHECK-NEXT: end_access [[READ]] -// CHECK-NEXT: dealloc_stack [[GUARANTEEDSTACK]] : $*T // CHECK: return [[APPLYRESULT]] @@ -139,10 +123,8 @@ func use_property_rvalue_get() -> Int { // CHECK: [[COPY:%.*]] = alloc_stack $[[OPENED]] // CHECK-NEXT: copy_addr [[PROJ]] to [init] [[COPY]] : $*[[OPENED]] // CHECK-NEXT: end_access [[READ]] : $*any PropertyWithGetter -// CHECK: [[BORROW:%.*]] = alloc_stack $[[OPENED]] -// CHECK-NEXT: copy_addr [[COPY]] to [init] [[BORROW]] : $*[[OPENED]] // CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #PropertyWithGetter.a!getter -// CHECK-NEXT: apply [[METH]]<[[OPENED]]>([[BORROW]]) +// CHECK-NEXT: apply [[METH]]<[[OPENED]]>([[COPY]]) func use_property_lvalue_get() -> Int { return propertyGetSet.b @@ -151,10 +133,8 @@ func use_property_lvalue_get() -> Int { // CHECK: [[GLOB:%[0-9]+]] = global_addr @$s9protocols14propertyGetSetAA24PropertyWithGetterSetter_pvp : $*any PropertyWithGetterSetter // CHECK: [[READ:%.*]] = begin_access [read] [dynamic] [[GLOB]] : $*any PropertyWithGetterSetter // CHECK: [[PROJ:%[0-9]+]] = open_existential_addr immutable_access [[READ]] : $*any PropertyWithGetterSetter to $*[[OPENED:@opened\(.*, any PropertyWithGetterSetter\) Self]] -// CHECK: [[STACK:%[0-9]+]] = alloc_stack $[[OPENED]] -// CHECK: copy_addr [[PROJ]] to [init] [[STACK]] // CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #PropertyWithGetterSetter.b!getter -// CHECK-NEXT: apply [[METH]]<[[OPENED]]>([[STACK]]) +// CHECK: apply [[METH]]<[[OPENED]]>([[PROJ]]) func use_property_lvalue_set(_ x : Int) { propertyGetSet.b = x @@ -178,12 +158,8 @@ func use_property_archetype_rvalue_get(_ generic : T) -> // CHECK-LABEL: sil hidden [ossa] @{{.*}}use_property_archetype_rvalue_get // CHECK: bb0(%0 : $*T): -// CHECK: [[STACK:%[0-9]+]] = alloc_stack $T -// CHECK: copy_addr %0 to [init] [[STACK]] // CHECK: [[METH:%[0-9]+]] = witness_method $T, #PropertyWithGetter.a!getter -// CHECK-NEXT: apply [[METH]]([[STACK]]) -// CHECK-NEXT: destroy_addr [[STACK]] -// CHECK-NEXT: dealloc_stack [[STACK]] +// CHECK-NEXT: apply [[METH]](%0) // CHECK: } // end sil function '{{.*}}use_property_archetype_rvalue_get @@ -193,12 +169,8 @@ func use_property_archetype_lvalue_get(_ generic : // CHECK-LABEL: sil hidden [ossa] @{{.*}}use_property_archetype_lvalue_get // CHECK: bb0(%0 : $*T): -// CHECK: [[STACK:%[0-9]+]] = alloc_stack $T -// CHECK: copy_addr %0 to [init] [[STACK]] : $*T // CHECK: [[METH:%[0-9]+]] = witness_method $T, #PropertyWithGetterSetter.b!getter -// CHECK-NEXT: apply [[METH]]([[STACK]]) -// CHECK-NEXT: destroy_addr [[STACK]] : $*T -// CHECK-NEXT: dealloc_stack [[STACK]] : $*T +// CHECK-NEXT: apply [[METH]](%0) // CHECK: } // end sil function '${{.*}}use_property_archetype_lvalue_get @@ -382,18 +354,12 @@ func testExistentialPropertyRead(_ t: inout T) { // CHECK-LABEL: sil hidden [ossa] @$s9protocols27testExistentialPropertyRead{{[_0-9a-zA-Z]*}}F // CHECK: [[READ:%.*]] = begin_access [read] [unknown] %0 : $*T // CHECK: [[P_TEMP:%.*]] = alloc_stack $any PropertyWithGetterSetter -// CHECK: [[T_TEMP:%.*]] = alloc_stack $T -// CHECK: copy_addr [[READ]] to [init] [[T_TEMP]] : $*T // CHECK: [[P_GETTER:%.*]] = witness_method $T, #ExistentialProperty.p!getter : -// CHECK-NEXT: apply [[P_GETTER]]([[P_TEMP]], [[T_TEMP]]) -// CHECK-NEXT: destroy_addr [[T_TEMP]] +// CHECK-NEXT: apply [[P_GETTER]]([[P_TEMP]], [[READ]]) // CHECK-NEXT: [[OPEN:%.*]] = open_existential_addr immutable_access [[P_TEMP]] : $*any PropertyWithGetterSetter to $*[[P_OPENED:@opened\(.*, any PropertyWithGetterSetter\) Self]] -// CHECK-NEXT: [[T0:%.*]] = alloc_stack $[[P_OPENED]] -// CHECK-NEXT: copy_addr [[OPEN]] to [init] [[T0]] // CHECK-NEXT: [[B_GETTER:%.*]] = witness_method $[[P_OPENED]], #PropertyWithGetterSetter.b!getter -// CHECK-NEXT: apply [[B_GETTER]]<[[P_OPENED]]>([[T0]]) +// CHECK-NEXT: apply [[B_GETTER]]<[[P_OPENED]]>([[OPEN]]) // CHECK-NEXT: debug_value -// CHECK-NEXT: destroy_addr [[T0]] // CHECK-NOT: witness_method // CHECK: return @@ -438,10 +404,8 @@ protocol SelfReturningSubscript { public func testSelfReturningSubscript() { // CHECK-LABEL: sil private [ossa] @$s9protocols26testSelfReturningSubscriptyyFAA0cdE0_pAaC_pXEfU_ // CHECK: [[OPEN:%.*]] = open_existential_addr immutable_access - // CHECK: [[OPEN_ADDR:%.*]] = alloc_stack $@opened("{{.*}}", any SelfReturningSubscript) Self - // CHECK: copy_addr [[OPEN]] to [init] [[OPEN_ADDR]] : $*@opened("{{.*}}", any SelfReturningSubscript) Self // CHECK: [[WIT_M:%.*]] = witness_method $@opened("{{.*}}", any SelfReturningSubscript) Self, #SelfReturningSubscript.subscript!getter - // CHECK: apply [[WIT_M]]<@opened("{{.*}}", any SelfReturningSubscript) Self>({{%.*}}, {{%.*}}, [[OPEN_ADDR]]) + // CHECK: apply [[WIT_M]]<@opened("{{.*}}", any SelfReturningSubscript) Self>({{%.*}}, {{%.*}}, [[OPEN]]) _ = [String: SelfReturningSubscript]().mapValues { $0[2] } } diff --git a/test/SILGen/struct_resilience.swift b/test/SILGen/struct_resilience.swift index 2dc310e3554af..2587e3bccf4a5 100644 --- a/test/SILGen/struct_resilience.swift +++ b/test/SILGen/struct_resilience.swift @@ -16,17 +16,15 @@ func functionWithResilientTypes(_ s: Size, f: (Size) -> Size) -> Size { // CHECK: copy_addr %1 to [init] [[OTHER_SIZE_BOX:%[0-9]*]] : $*Size var s2 = s -// CHECK: copy_addr %1 to [init] [[SIZE_BOX:%.*]] : $*Size // CHECK: [[GETTER:%.*]] = function_ref @$s16resilient_struct4SizeV1wSivg : $@convention(method) (@in_guaranteed Size) -> Int -// CHECK: [[RESULT:%.*]] = apply [[GETTER]]([[SIZE_BOX]]) +// CHECK: [[RESULT:%.*]] = apply [[GETTER]](%1) // CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[OTHER_SIZE_BOX]] : $*Size // CHECK: [[SETTER:%.*]] = function_ref @$s16resilient_struct4SizeV1wSivs : $@convention(method) (Int, @inout Size) -> () // CHECK: apply [[SETTER]]([[RESULT]], [[WRITE]]) s2.w = s.w -// CHECK: copy_addr %1 to [init] [[SIZE_BOX:%.*]] : $*Size // CHECK: [[FN:%.*]] = function_ref @$s16resilient_struct4SizeV1hSivg : $@convention(method) (@in_guaranteed Size) -> Int -// CHECK: [[RESULT:%.*]] = apply [[FN]]([[SIZE_BOX]]) +// CHECK: [[RESULT:%.*]] = apply [[FN]](%1) _ = s.h // CHECK: apply {{.*}}(%0, %1) @@ -162,13 +160,8 @@ public func functionWithMyResilientTypes(_ s: MySize, f: (MySize) -> MySize) -> // Since the body of a public transparent function might be inlined into // other resilience domains, we have to use accessors -// CHECK: [[SELF:%.*]] = alloc_stack $MySize -// CHECK-NEXT: copy_addr %0 to [init] [[SELF]] - // CHECK: [[GETTER:%.*]] = function_ref @$s17struct_resilience6MySizeV1wSivg -// CHECK-NEXT: [[RESULT:%.*]] = apply [[GETTER]]([[SELF]]) -// CHECK-NEXT: destroy_addr [[SELF]] -// CHECK-NEXT: dealloc_stack [[SELF]] +// CHECK-NEXT: [[RESULT:%.*]] = apply [[GETTER]](%0) // CHECK-NEXT: return [[RESULT]] return s.w } @@ -203,13 +196,8 @@ public func functionWithMyResilientTypes(_ s: MySize, f: (MySize) -> MySize) -> // Since the body of a public transparent function might be inlined into // other resilience domains, we have to use accessors -// CHECK: [[SELF:%.*]] = alloc_stack $MySize -// CHECK-NEXT: copy_addr %0 to [init] [[SELF]] - // CHECK: [[GETTER:%.*]] = function_ref @$s17struct_resilience6MySizeV1wSivg -// CHECK-NEXT: [[RESULT:%.*]] = apply [[GETTER]]([[SELF]]) -// CHECK-NEXT: destroy_addr [[SELF]] -// CHECK-NEXT: dealloc_stack [[SELF]] +// CHECK-NEXT: [[RESULT:%.*]] = apply [[GETTER]](%0) // CHECK-NEXT: return [[RESULT]] return s.w diff --git a/test/SILGen/struct_resilience_testable.swift b/test/SILGen/struct_resilience_testable.swift index 4533010d86336..d79f4615afc46 100644 --- a/test/SILGen/struct_resilience_testable.swift +++ b/test/SILGen/struct_resilience_testable.swift @@ -5,12 +5,8 @@ @testable import resilient_struct // CHECK-LABEL: sil [ossa] @$s26struct_resilience_testable37takesResilientStructWithInternalFieldySi010resilient_A00eghI0VF : $@convention(thin) (@in_guaranteed ResilientWithInternalField) -> Int -// CHECK: [[COPY:%.*]] = alloc_stack $ResilientWithInternalField -// CHECK: copy_addr %0 to [init] [[COPY]] : $*ResilientWithInternalField // CHECK: [[FN:%.*]] = function_ref @$s16resilient_struct26ResilientWithInternalFieldV1xSivg : $@convention(method) (@in_guaranteed ResilientWithInternalField) -> Int -// CHECK: [[RESULT:%.*]] = apply [[FN]]([[COPY]]) -// CHECK: destroy_addr [[COPY]] -// CHECK: dealloc_stack [[COPY]] +// CHECK: [[RESULT:%.*]] = apply [[FN]](%0) // CHECK: return [[RESULT]] public func takesResilientStructWithInternalField(_ s: ResilientWithInternalField) -> Int { diff --git a/test/SILOptimizer/access_marker_verify.swift b/test/SILOptimizer/access_marker_verify.swift index 59e370019bafe..83bb26401df82 100644 --- a/test/SILOptimizer/access_marker_verify.swift +++ b/test/SILOptimizer/access_marker_verify.swift @@ -272,19 +272,15 @@ func testInitLValue(p: HasIntGetter) -> Int { // CHECK: alloc_box ${ var Int }, var, name "x" // CHECK: [[PROJ:%.*]] = project_box // CHECK: [[OPENED:%.*]] = open_existential_addr immutable_access %0 -// CHECK: [[X:%.*]] = alloc_stack $@opened -// CHECK-NOT: begin_access -// CHECK: copy_addr %{{.*}} to [init] [[X]] : $*@opened // CHECK: witness_method $@opened -// CHECK: apply %{{.*}}<@opened("{{.*}}", any HasIntGetter) Self>([[X]]) : $@convention(witness_method: HasIntGetter) <τ_0_0 where τ_0_0 : HasIntGetter> (@in_guaranteed τ_0_0) -> Int +// CHECK: [[VALUE:%.*]] = apply %{{.*}}<@opened("{{.*}}", any HasIntGetter) Self>([[OPENED]]) // CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[PROJ]] : $*Int -// CHECK: store %{{.*}} to [trivial] [[ACCESS]] : $*Int -// CHECK: end_access -// CHECK: destroy_addr -// CHECK: dealloc_stack -// CHECK: begin_access [read] [unknown] [[PROJ]] -// CHECK: load [trivial] -// CHECK: end_access +// CHECK: store [[VALUE]] to [trivial] [[ACCESS]] : $*Int +// CHECK: end_access [[ACCESS]] +// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJ]] +// CHECK: [[RELOAD:%.*]] = load [trivial] [[ACCESS]] +// CHECK: end_access [[ACCESS]] +// CHECK: return [[RELOAD]] // CHECK-LABEL: } // end sil function '$s20access_marker_verify14testInitLValue1pSiAA12HasIntGetter_p_tF' // --- initialize let. @@ -868,19 +864,11 @@ func testMixedTuple(p: HasClassGetter) -> (BaseClass, Any) { // CHECK-LABEL: sil hidden [ossa] @$s20access_marker_verify14testMixedTuple1pAA9BaseClassC_yptAA03HasH6Getter_p_tF : $@convention(thin) (@in_guaranteed any HasClassGetter) -> (@owned BaseClass, @out Any) { // CHECK: bb0(%0 : $*Any, %1 : $*any HasClassGetter): // CHECK: [[P1:%.*]] = open_existential_addr immutable_access %1 : $*any HasClassGetter to $*@opened -// CHECK: [[TEMP1:%.*]] = alloc_stack $@opened -// CHECK-NOT: begin_access -// CHECK: copy_addr [[P1]] to [init] [[TEMP1]] : $*@opened -// CHECK-NOT: begin_access -// CHECK: [[OUTC:%.*]] = apply {{.*}} $@convention(witness_method: HasClassGetter) <τ_0_0 where τ_0_0 : HasClassGetter> (@in_guaranteed τ_0_0) -> @owned BaseClass +// CHECK: [[OUTC:%.*]] = apply %{{.*}}<@opened("{{.*}}", any HasClassGetter) Self>([[P1]]) // CHECK: [[P2:%.*]] = open_existential_addr immutable_access %1 : $*any HasClassGetter to $*@opened -// CHECK: [[TEMP2:%.*]] = alloc_stack $@opened -// CHECK-NOT: begin_access -// CHECK: copy_addr [[P2]] to [init] [[TEMP2]] : $*@opened -// CHECK-NOT: begin_access -// CHECK: apply {{.*}} $@convention(witness_method: HasClassGetter) <τ_0_0 where τ_0_0 : HasClassGetter> (@in_guaranteed τ_0_0) -> @owned BaseClass +// CHECK: [[R2:%.*]] = apply %{{.*}}<@opened("{{.*}}", any HasClassGetter) Self>([[P2]]) // CHECK: [[OUTANY:%.*]] = init_existential_addr %0 : $*Any, $BaseClass -// CHECK: store %{{.*}} to [init] [[OUTANY]] : $*BaseClass +// CHECK: store [[R2]] to [init] [[OUTANY]] : $*BaseClass // CHECK: return [[OUTC]] : $BaseClass // CHECK-LABEL: } // end sil function '$s20access_marker_verify14testMixedTuple1pAA9BaseClassC_yptAA03HasH6Getter_p_tF' diff --git a/test/SILOptimizer/moveonly_accessors.swift b/test/SILOptimizer/moveonly_accessors.swift new file mode 100644 index 0000000000000..4ee5df91ce580 --- /dev/null +++ b/test/SILOptimizer/moveonly_accessors.swift @@ -0,0 +1,24 @@ +// RUN: %target-swift-frontend -sil-verify-all -verify -emit-sil %s + +struct AO { + borrowing func borrow2Borrow() -> Int { p1 } + borrowing func borrow2Consume() -> Int { // expected-error{{'self' is borrowed and cannot be consumed}} + p2 // expected-note{{consumed here}} + } + consuming func consume2Borrow() -> Int { p1 } + consuming func consume2Consume() -> Int { p2 } + let t: T + var p1 : Int { borrowing get { 666 } } + var p2: Int { consuming get { 666 } } +} + +// https://github.com/apple/swift/issues/73292 +struct Example { + protocol Proto { + var count: Int { borrowing get } + } + + func takeProto(_ p: borrowing some Proto) -> Int { + p.count + } +} diff --git a/test/SILOptimizer/sil_combine_protocol_conf.swift b/test/SILOptimizer/sil_combine_protocol_conf.swift index 289965e5e6d31..54adf1370f34d 100644 --- a/test/SILOptimizer/sil_combine_protocol_conf.swift +++ b/test/SILOptimizer/sil_combine_protocol_conf.swift @@ -247,10 +247,10 @@ public class OtherClass { // CHECK: load [[S11]] // CHECK: [[R2:%.*]] = ref_element_addr [[ARG]] : $OtherClass, #OtherClass.arg2 // CHECK: [[ACC2:%.*]] = begin_access [read] [static] [no_nested_conflict] [[R2]] -// CHECK: [[O2:%.*]] = open_existential_addr immutable_access [[ACC2]] : $*any GenericPropProtocol to $*@opened("{{.*}}", any GenericPropProtocol) Self -// CHECK: copy_addr [[O2]] to [init] [[T1:%[0-9]*]] +// CHECK: copy_addr [[ACC2]] to [init] [[T1:%[0-9]*]] +// CHECK: [[O2:%.*]] = open_existential_addr immutable_access [[T1]] : $*any GenericPropProtocol to $*@opened("{{.*}}", any GenericPropProtocol) Self // CHECK: [[W2:%.*]] = witness_method $@opened("{{.*}}", any GenericPropProtocol) Self, #GenericPropProtocol.val!getter : (Self) -> () -> Int, [[O2]] : $*@opened("{{.*}}", any GenericPropProtocol) Self : $@convention(witness_method: GenericPropProtocol) <τ_0_0 where τ_0_0 : GenericPropProtocol> (@in_guaranteed τ_0_0) -> Int -// CHECK: apply [[W2]]<@opened("{{.*}}", any GenericPropProtocol) Self>([[T1]]) : $@convention(witness_method: GenericPropProtocol) <τ_0_0 where τ_0_0 : GenericPropProtocol> (@in_guaranteed τ_0_0) -> Int +// CHECK: apply [[W2]]<@opened("{{.*}}", any GenericPropProtocol) Self>([[O2]]) : $@convention(witness_method: GenericPropProtocol) <τ_0_0 where τ_0_0 : GenericPropProtocol> (@in_guaranteed τ_0_0) -> Int // CHECK: struct_extract // CHECK: integer_literal // CHECK: builtin From 128a8bc942258eb99b8b74dde3c117c9c556508a Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sat, 8 Jun 2024 16:58:30 -0700 Subject: [PATCH 012/165] [Concurrency] Don't ignore mismatching isolation for overrides of Clang-imported superclass methods. --- lib/Sema/TypeCheckConcurrency.cpp | 11 +++++++++-- test/ClangImporter/objc_isolation_complete.swift | 16 ++++++++++++++++ test/Concurrency/actor_isolation.swift | 3 --- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 705ba0638e43d..e4fa80b81d166 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -2152,7 +2152,11 @@ namespace { .limitBehaviorUntilSwiftVersion(behavior, 6); } - // Always emit the note with fix-it. + // Overrides cannot be isolated to a global actor; the isolation + // must match the overridden decl. + if (fn->getOverriddenDecl()) + return false; + fn->diagnose(diag::add_globalactor_to_function, globalActor->getWithoutParens().getString(), fn, globalActor) @@ -4941,6 +4945,7 @@ static OverrideIsolationResult validOverrideIsolation( ValueDecl *overridden, ActorIsolation overriddenIsolation) { ConcreteDeclRef valueRef = getDeclRefInContext(value); auto declContext = value->getInnermostDeclContext(); + auto &ctx = declContext->getASTContext(); auto refResult = ActorReferenceResult::forReference( valueRef, SourceLoc(), declContext, std::nullopt, std::nullopt, isolation, @@ -4964,8 +4969,10 @@ static OverrideIsolationResult validOverrideIsolation( // If the overridden declaration is from Objective-C with no actor // annotation, allow it. - if (overridden->hasClangNode() && !overriddenIsolation) + if (ctx.LangOpts.StrictConcurrencyLevel != StrictConcurrency::Complete && + overridden->hasClangNode() && !overriddenIsolation) { return OverrideIsolationResult::Allowed; + } return OverrideIsolationResult::Disallowed; } diff --git a/test/ClangImporter/objc_isolation_complete.swift b/test/ClangImporter/objc_isolation_complete.swift index 251bad8fa9bfe..3bb95c4026895 100644 --- a/test/ClangImporter/objc_isolation_complete.swift +++ b/test/ClangImporter/objc_isolation_complete.swift @@ -15,3 +15,19 @@ func unsatisfiedPreconcurrencyIsolation(view: MyView) { // expected-warning@+1 {{main actor-isolated property 'isVisible' can not be referenced from a non-isolated context}} _ = view.isVisible } + +@preconcurrency @MainActor +class IsolatedSub: NXSender { + var mainActorState = 0 // expected-note {{property declared here}} + override func sendAny(_: any Sendable) -> any Sendable { + return mainActorState + // expected-warning@-1 {{main actor-isolated property 'mainActorState' can not be referenced from a non-isolated context}} + } + + @MainActor + override func sendOptionalAny(_: (any Sendable)?) -> (any Sendable)? { + // expected-warning@-1 {{main actor-isolated instance method 'sendOptionalAny' has different actor isolation from nonisolated overridden declaration; this is an error in the Swift 6 language mode}} + + return mainActorState + } +} diff --git a/test/Concurrency/actor_isolation.swift b/test/Concurrency/actor_isolation.swift index 15c209db04ce9..bc486815c5f7b 100644 --- a/test/Concurrency/actor_isolation.swift +++ b/test/Concurrency/actor_isolation.swift @@ -1492,9 +1492,6 @@ class None { // try to add inferred isolation while overriding @MainActor class MA_None1: None { - - // FIXME: bad note, since the problem is a mismatch in overridden vs inferred isolation; this wont help. - // expected-note@+1 {{add '@MainActor' to make instance method 'method()' part of global actor 'MainActor'}} override func method() { beets_ma() // expected-error {{call to main actor-isolated global function 'beets_ma()' in a synchronous nonisolated context}} } From d1ae73f43625824f6a2b78d4cade63eb4bfe9736 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Sun, 9 Jun 2024 22:48:43 -0700 Subject: [PATCH 013/165] Handle flow-sensitive `#isolation` in distributed actor initializers. Distributed actors can be treated as actors by accessing the `asLocalActor` property. When lowering `#isolation` in a distributed actor initializer, use a separate builtin `flowSensitiveDistributedSelfIsolation` to capture the conformance to `DistributedActor`, and have Definite Initialization introduce the call to the `asLocalActor` getter when needed. --- include/swift/AST/ASTSynthesis.h | 4 ++ include/swift/AST/Builtins.def | 13 +++- lib/AST/Builtins.cpp | 23 +++++--- lib/SIL/IR/OperandOwnership.cpp | 1 + lib/SIL/IR/ValueOwnership.cpp | 1 + lib/SILGen/SILGenExpr.cpp | 35 ++++++++--- .../Mandatory/DIMemoryUseCollector.cpp | 4 +- .../Mandatory/DefiniteInitialization.cpp | 59 ++++++++++++++----- .../AccessEnforcementReleaseSinking.cpp | 1 + ...low_sensitive_distributed_actor_self.swift | 37 ++++++++++++ 10 files changed, 144 insertions(+), 34 deletions(-) create mode 100644 test/SILOptimizer/definite_init_flow_sensitive_distributed_actor_self.swift diff --git a/include/swift/AST/ASTSynthesis.h b/include/swift/AST/ASTSynthesis.h index 6605cff3959cb..36526d35fd898 100644 --- a/include/swift/AST/ASTSynthesis.h +++ b/include/swift/AST/ASTSynthesis.h @@ -56,6 +56,7 @@ enum SingletonTypeSynthesizer { _serialExecutor, // the '_Concurrency.SerialExecutor' protocol _taskExecutor, // the '_Concurrency.TaskExecutor' protocol _actor, // the '_Concurrency.Actor' protocol + _distributedActor, // the 'Distributed.DistributedActor' protocol }; inline Type synthesizeType(SynthesisContext &SC, SingletonTypeSynthesizer kind) { @@ -82,6 +83,9 @@ inline Type synthesizeType(SynthesisContext &SC, case _actor: return SC.Context.getProtocol(KnownProtocolKind::Actor) ->getDeclaredInterfaceType(); + case _distributedActor: + return SC.Context.getProtocol(KnownProtocolKind::DistributedActor) + ->getDeclaredInterfaceType(); case _copyable: return SC.Context.getProtocol(KnownProtocolKind::Copyable) ->getDeclaredInterfaceType(); diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index c96d1fb469910..e654093a59e68 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -899,7 +899,7 @@ BUILTIN_MISC_OPERATION(StartAsyncLetWithLocalBuffer, "startAsyncLetWithLocalBuff /// This is only supported under the task-to-thread concurrency model. BUILTIN_MISC_OPERATION(TaskRunInline, "taskRunInline", "", Special) -/// flowSensitiveSelfIsolation(_ actor: T) -> T? +/// flowSensitiveSelfIsolation(_ actor: T) -> (any Actor)? /// /// Used only in actor initializers, this builtin lowers to either 'actor' /// (wrapped in an optional) or 'nil' depending on whether 'self' has been @@ -907,6 +907,17 @@ BUILTIN_MISC_OPERATION(TaskRunInline, "taskRunInline", "", Special) /// being initialized. BUILTIN_MISC_OPERATION(FlowSensitiveSelfIsolation, "flowSensitiveSelfIsolation", "", Special) +/// flowSensitiveDistributedSelfIsolation( +/// _ actor: T +/// ) -> (any Actor)? +/// +/// Used only in distributed actor initializers, this builtin lowers to either +/// 'actor.asLocalActor' or 'nil' depending on whether 'self' has been +/// initialized at this point. 'actor' is always an alias for the 'self' +/// being initialized. +BUILTIN_MISC_OPERATION(FlowSensitiveDistributedSelfIsolation, + "flowSensitiveDistributedSelfIsolation", "", Special) + /// endAsyncLet(): (Builtin.RawPointer) -> Void /// /// DEPRECATED. The swift_asyncLet_finish intrinsic and endAsyncLetLifetime diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index 7de93057ec24f..b630d5ce8dca5 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -2089,14 +2089,18 @@ static ValueDecl *getHopToActor(ASTContext &ctx, Identifier id) { return builder.build(id); } -static ValueDecl *getFlowSensitiveSelfIsolation(ASTContext &ctx, Identifier id) { +static ValueDecl *getFlowSensitiveSelfIsolation( + ASTContext &ctx, Identifier id, bool isDistributed +) { BuiltinFunctionBuilder builder(ctx); - return getBuiltinFunction(ctx, id, _thin, - _generics(_unrestricted, - _conformsToDefaults(0), - _conformsTo(_typeparam(0), _actor)), - _parameters(_typeparam(0)), - _optional(_existential(_actor))); + return getBuiltinFunction( + ctx, id, _thin, + _generics(_unrestricted, + _conformsToDefaults(0), + _conformsTo(_typeparam(0), + isDistributed ? _distributedActor : _actor)), + _parameters(_typeparam(0)), + _optional(_existential(_actor))); } static ValueDecl *getDistributedActorAsAnyActor(ASTContext &ctx, Identifier id) { @@ -3202,7 +3206,10 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { return getHopToActor(Context, Id); case BuiltinValueKind::FlowSensitiveSelfIsolation: - return getFlowSensitiveSelfIsolation(Context, Id); + return getFlowSensitiveSelfIsolation(Context, Id, false); + + case BuiltinValueKind::FlowSensitiveDistributedSelfIsolation: + return getFlowSensitiveSelfIsolation(Context, Id, true); case BuiltinValueKind::AutoDiffCreateLinearMapContextWithType: return getAutoDiffCreateLinearMapContext(Context, Id); diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index 01de24cb7a985..8d866b4950a33 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -907,6 +907,7 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CreateTaskGroup) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, CreateTaskGroupWithFlags) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, DestroyTaskGroup) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FlowSensitiveSelfIsolation) +BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, FlowSensitiveDistributedSelfIsolation) BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, COWBufferForReading) diff --git a/lib/SIL/IR/ValueOwnership.cpp b/lib/SIL/IR/ValueOwnership.cpp index 885fdf12bc438..0d3509365d56f 100644 --- a/lib/SIL/IR/ValueOwnership.cpp +++ b/lib/SIL/IR/ValueOwnership.cpp @@ -631,6 +631,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, CreateTaskGroupWithFlags) CONSTANT_OWNERSHIP_BUILTIN(None, DestroyTaskGroup) CONSTANT_OWNERSHIP_BUILTIN(None, TaskRunInline) CONSTANT_OWNERSHIP_BUILTIN(Owned, FlowSensitiveSelfIsolation) +CONSTANT_OWNERSHIP_BUILTIN(Owned, FlowSensitiveDistributedSelfIsolation) CONSTANT_OWNERSHIP_BUILTIN(None, GetEnumTag) CONSTANT_OWNERSHIP_BUILTIN(None, InjectEnumTag) CONSTANT_OWNERSHIP_BUILTIN(Owned, DistributedActorAsAnyActor) diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 3d9af9141cf6f..3abee825016bd 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -31,6 +31,7 @@ #include "swift/AST/CanTypeVisitor.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsCommon.h" +#include "swift/AST/DistributedDecl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" #include "swift/AST/ForeignErrorConvention.h" @@ -6755,23 +6756,41 @@ RValue RValueEmitter::visitCurrentContextIsolationExpr( isolation.getActorInstance() == ctor->getImplicitSelfDecl()) { ASTContext &ctx = SGF.getASTContext(); auto builtinName = ctx.getIdentifier( - getBuiltinName(BuiltinValueKind::FlowSensitiveSelfIsolation)); + isolation.isDistributedActor() + ? getBuiltinName(BuiltinValueKind::FlowSensitiveDistributedSelfIsolation) + : getBuiltinName(BuiltinValueKind::FlowSensitiveSelfIsolation)); SILType resultTy = SGF.getLoweredType(E->getType()); auto injection = cast(E->getActor()); - auto erasure = cast(injection->getSubExpr()); - auto conformance = erasure->getConformances()[0]; + ProtocolConformanceRef conformance; + Expr *origActorExpr; + if (isolation.isDistributedActor()) { + // Create a reference to the asLocalActor getter. + auto asLocalActorDecl = getDistributedActorAsLocalActorComputedProperty( + SGF.F.getDeclContext()->getParentModule()); + auto asLocalActorGetter = asLocalActorDecl->getAccessor(AccessorKind::Get); + SILDeclRef asLocalActorRef = SILDeclRef( + asLocalActorGetter, SILDeclRef::Kind::Func); + SGF.emitGlobalFunctionRef(E, asLocalActorRef); + + // Extract the base ('self') and the DistributedActor conformance. + auto memberRef = cast(injection->getSubExpr()); + conformance = memberRef->getDecl().getSubstitutions() + .getConformances()[0]; + origActorExpr = memberRef->getBase(); + } else { + auto erasure = cast(injection->getSubExpr()); + conformance = erasure->getConformances()[0]; + origActorExpr = erasure->getSubExpr(); + } SGF.SGM.useConformance(conformance); - auto origActorExpr = erasure->getSubExpr(); - auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor); SubstitutionMap subs = SubstitutionMap::getProtocolSubstitutions( - actorProto, origActorExpr->getType(), conformance); + conformance.getRequirement(), origActorExpr->getType(), conformance); auto origActor = SGF.maybeEmitValueOfLocalVarDecl( ctor->getImplicitSelfDecl(), AccessKind::Read).getValue(); auto call = SGF.B.createBuiltin(E, builtinName, resultTy, subs, origActor); - return RValue(SGF, E, - ManagedValue::forForwardedRValue(SGF, call)); + return RValue(SGF, E, ManagedValue::forForwardedRValue(SGF, call)); } } diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp index 4ec0eb89b8bfb..66566a5982ded 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp @@ -1714,7 +1714,9 @@ void ElementUseCollector::collectClassSelfUses( // they have a fully-formed 'self' to use. if (auto builtin = dyn_cast(User)) { if (auto builtinKind = builtin->getBuiltinKind()) { - if (*builtinKind == BuiltinValueKind::FlowSensitiveSelfIsolation) { + if (*builtinKind == BuiltinValueKind::FlowSensitiveSelfIsolation || + *builtinKind == + BuiltinValueKind::FlowSensitiveDistributedSelfIsolation) { Kind = DIUseKind::FlowSensitiveSelfIsolation; } } diff --git a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp index 0b9d4c31bef33..a42a85cd2f49f 100644 --- a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp +++ b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp @@ -15,6 +15,7 @@ #include "DIMemoryUseCollector.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsSIL.h" +#include "swift/AST/DistributedDecl.h" #include "swift/AST/Expr.h" #include "swift/AST/Stmt.h" #include "swift/ClangImporter/ClangModule.h" @@ -1361,25 +1362,51 @@ void LifetimeChecker::handleFlowSensitiveActorIsolationUse( SILType optExistentialType = builtinInst->getType(); SILLocation loc = builtinInst->getLoc(); if (isInitializedAtUse(Use, &IsSuperInitComplete, &FailedSelfUse)) { - // 'self' is initialized, so replace this builtin with an injection of the - // argument into (any Actor)?. - - // Create a copy of the actor argument, which we intentionally did not - // copy in SILGen. - SILValue actor = B.createCopyValue(loc, builtinInst->getArguments()[0]); - - // Inject 'self' into 'any Actor'. - ProtocolConformanceRef conformances[1] = { - builtinInst->getSubstitutions().getConformances()[0] - }; - SILType existentialType = optExistentialType.getOptionalObjectType(); - SILValue existentialBox = B.createInitExistentialRef( - loc, existentialType, actor->getType().getASTType(), actor, - ctx.AllocateCopy(conformances)); + // 'self' is initialized, so replace this builtin with the appropriate + // operation to produce `any Actor. + + SILValue anyActorValue; + auto conformance = builtinInst->getSubstitutions().getConformances()[0]; + if (builtinInst->getBuiltinKind() == BuiltinValueKind::FlowSensitiveSelfIsolation) { + // Create a copy of the actor argument, which we intentionally did not + // copy in SILGen. + SILValue actor = B.createCopyValue(loc, builtinInst->getArguments()[0]); + + // Inject 'self' into 'any Actor'. + ProtocolConformanceRef conformances[1] = { conformance }; + SILType existentialType = optExistentialType.getOptionalObjectType(); + anyActorValue = B.createInitExistentialRef( + loc, existentialType, actor->getType().getASTType(), actor, + ctx.AllocateCopy(conformances)); + } else { + // Borrow the actor argument, which we need to form the appropriate + // call to the asLocalActor getter. + SILValue actor = B.createBeginBorrow(loc, builtinInst->getArguments()[0]); + + // Dig out the getter for asLocalActor. + auto asLocalActorDecl = getDistributedActorAsLocalActorComputedProperty( + F.getDeclContext()->getParentModule()); + auto asLocalActorGetter = asLocalActorDecl->getAccessor(AccessorKind::Get); + SILDeclRef asLocalActorRef = SILDeclRef( + asLocalActorGetter, SILDeclRef::Kind::Func); + SILFunction *asLocalActorFunc = F.getModule() + .lookUpFunction(asLocalActorRef); + SILValue asLocalActorValue = B.createFunctionRef(loc, asLocalActorFunc); + + // Call asLocalActor. It produces an 'any Actor'. + anyActorValue = B.createApply( + loc, + asLocalActorValue, + SubstitutionMap::get(asLocalActorGetter->getGenericSignature(), + { actor->getType().getASTType() }, + { conformance }), + { actor }); + B.createEndBorrow(loc, actor); + } // Then, wrap it in an optional. replacement = B.createEnum( - loc, existentialBox, ctx.getOptionalSomeDecl(), optExistentialType); + loc, anyActorValue, ctx.getOptionalSomeDecl(), optExistentialType); } else { // 'self' is not initialized yet, so use 'nil'. replacement = B.createEnum( diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp index ff2458207e5f5..56b83125ef35a 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp @@ -160,6 +160,7 @@ static bool isBarrier(SILInstruction *inst) { case BuiltinValueKind::InjectEnumTag: case BuiltinValueKind::ExtractFunctionIsolation: case BuiltinValueKind::FlowSensitiveSelfIsolation: + case BuiltinValueKind::FlowSensitiveDistributedSelfIsolation: case BuiltinValueKind::AddressOfRawLayout: return false; diff --git a/test/SILOptimizer/definite_init_flow_sensitive_distributed_actor_self.swift b/test/SILOptimizer/definite_init_flow_sensitive_distributed_actor_self.swift new file mode 100644 index 0000000000000..48951bc5ede08 --- /dev/null +++ b/test/SILOptimizer/definite_init_flow_sensitive_distributed_actor_self.swift @@ -0,0 +1,37 @@ +// RUN: %target-swift-frontend -emit-sil %s -module-name test -swift-version 5 -sil-verify-all | %FileCheck %s +// REQUIRES: concurrency, distributed + +import Distributed + +@available(SwiftStdlib 5.1, *) +func f(isolatedTo actor: isolated (any Actor)?) async -> Int { 0 } + +@available(SwiftStdlib 5.7, *) +distributed actor NotCodableDA + where ActorSystem: DistributedActorSystem { + let number: Int + + // CHECK-LABEL: sil hidden{{.*}}@$s4test12NotCodableDAC11actorSystemACyxGx_tYacfc : $@convention(method) @async (@in ActorSystem, @sil_isolated @owned NotCodableDA) -> @owned NotCodableDA { + init(actorSystem: ActorSystem) async { + self.actorSystem = actorSystem + + // First use of #isolation, which is replaced by 'nil'. + // CHECK: [[ISOLATION_1:%.*]] = enum $Optional, #Optional.none!enumelt + // CHECK: [[F_1:%.*]] = function_ref @$s4test1f10isolatedToSiScA_pSgYi_tYaF + // CHECK-NEXT: [[F_RESULT:%.*]] = apply [[F_1]]([[ISOLATION_1]]) + + // Assignment to "number" of the result. + // CHECK: [[NUMBER:%.*]] = ref_element_addr {{%.*}} : $NotCodableDA, #NotCodableDA.number + // CHECK: store [[F_RESULT]] to [[NUMBER]] + self.number = await f(isolatedTo: #isolation) + + // Second use of #isolation, which uses 'self.asLocalActor'' + // CHECK: [[AS_LOCAL_ACTOR_FN:%.*]] = function_ref @$s11Distributed0A5ActorPAAE07asLocalB0ScA_pvg : $@convention(method) <τ_0_0 where τ_0_0 : DistributedActor> (@sil_isolated @guaranteed τ_0_0) -> @owned any Actor + // CHECK-NEXT: [[ACTOR_EXISTENTIAL:%.*]] = apply [[AS_LOCAL_ACTOR_FN]]>(%1) : $@convention(method) <τ_0_0 where τ_0_0 : DistributedActor> (@sil_isolated @guaranteed τ_0_0) -> @owned any Actor + // CHECK: [[ISOLATION_2:%.*]] = enum $Optional, #Optional.some!enumelt, [[ACTOR_EXISTENTIAL]] + // CHECK: [[F_2:%.*]] = function_ref @$s4test1f10isolatedToSiScA_pSgYi_tYaF + // CHECK-NEXT: apply [[F_2]]([[ISOLATION_2]]) + + _ = await f(isolatedTo: #isolation) + } +} From cd0b3f0d4df61384bc2603a6d93bf4fc469f19cc Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Mon, 10 Jun 2024 17:19:57 +0900 Subject: [PATCH 014/165] [docs] Remove line in Task docs that is an error in Swift 6 mode --- stdlib/public/Concurrency/Task.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/public/Concurrency/Task.swift b/stdlib/public/Concurrency/Task.swift index d9f67da42bc85..c940be05dc4eb 100644 --- a/stdlib/public/Concurrency/Task.swift +++ b/stdlib/public/Concurrency/Task.swift @@ -101,7 +101,6 @@ import Swift /// var result: Work? /// /// deinit { -/// assert(work != nil) /// // even though the task is still retained, /// // once it completes it no longer causes a reference cycle with the actor /// From d8cba034b3bdcdadc03dd600da8036bad2b590c9 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Mon, 10 Jun 2024 17:20:57 +0900 Subject: [PATCH 015/165] [docs] remove swift style code highlighting on non-swift snippet --- stdlib/public/Concurrency/Task.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/Concurrency/Task.swift b/stdlib/public/Concurrency/Task.swift index c940be05dc4eb..460d520b3ee3e 100644 --- a/stdlib/public/Concurrency/Task.swift +++ b/stdlib/public/Concurrency/Task.swift @@ -134,7 +134,7 @@ import Swift /// /// Therefore, the above call will consistently result in the following output: /// -/// ``` +/// ```other /// start task work /// completed task work /// deinit actor From 0135623d9a4b308d23814b2bbb8a73f845088f16 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Mon, 10 Jun 2024 17:21:47 +0900 Subject: [PATCH 016/165] [docs] fix typo in type name in code snippet --- stdlib/public/Concurrency/Task.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/Concurrency/Task.swift b/stdlib/public/Concurrency/Task.swift index 460d520b3ee3e..36380ac157bc0 100644 --- a/stdlib/public/Concurrency/Task.swift +++ b/stdlib/public/Concurrency/Task.swift @@ -123,7 +123,7 @@ import Swift /// And using it like this: /// /// ``` -/// await Actor().start() +/// await Worker().start() /// ``` /// /// Note that the actor is only retained by the start() method's use of `self`, From ab34a6dabfe53026b1c20d75643279106321362d Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 10 Jun 2024 10:06:42 +0100 Subject: [PATCH 017/165] [Completion] Check for callback rather than result of ResolveMacroRequest When doing solver-based completion, the request will fail, avoid falling back to a regular call expression in that case; we only care about whether we got the callback. rdar://129024996 --- lib/IDE/CodeCompletion.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 6135084c44799..5a66642d26639 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -1431,14 +1431,14 @@ void CodeCompletionCallbacksImpl::typeCheckWithLookup( /// decl it could be attached to. Type check it standalone. // First try to check it as an attached macro. - auto resolvedMacro = evaluateOrDefault( + (void)evaluateOrDefault( CurDeclContext->getASTContext().evaluator, ResolveMacroRequest{AttrWithCompletion, CurDeclContext}, ConcreteDeclRef()); // If that fails, type check as a call to the attribute's type. This is // how, e.g., property wrappers are modelled. - if (!resolvedMacro) { + if (!Lookup.gotCallback()) { ASTNode Call = CallExpr::create( CurDeclContext->getASTContext(), AttrWithCompletion->getTypeExpr(), AttrWithCompletion->getArgs(), /*implicit=*/true); From 98ba978953606a927a7b34eb953114fc26eec7f5 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 10 Jun 2024 10:06:42 +0100 Subject: [PATCH 018/165] [Completion] Handle inherited protocols in `isExtensionWithSelfBound` If the extension does not match the protocol type that we're doing the lookup for, check whether the `Self` type conforms to the protocol; in that case we have e.g an extension for an inherited protocol. rdar://129024996 --- lib/Sema/IDETypeCheckingRequests.cpp | 24 ++++++------- test/IDE/complete_rdar129024996.swift | 49 +++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 test/IDE/complete_rdar129024996.swift diff --git a/lib/Sema/IDETypeCheckingRequests.cpp b/lib/Sema/IDETypeCheckingRequests.cpp index 53488c7c9b3f7..b9c305fdcf9e7 100644 --- a/lib/Sema/IDETypeCheckingRequests.cpp +++ b/lib/Sema/IDETypeCheckingRequests.cpp @@ -116,29 +116,29 @@ class ContainsSpecializableArchetype : public TypeWalker { } }; -/// Returns `true` if `ED` is an extension of `PD` that binds `Self` to a -/// concrete type, like `extension MyProto where Self == MyStruct {}`. +/// Returns `true` if `ED` is an extension that binds `Self` to a +/// concrete type, like `extension MyProto where Self == MyStruct {}`. The +/// protocol being extended must either be `PD`, or `Self` must be a type +/// that conforms to `PD`. /// /// In these cases, it is possible to access static members defined in the /// extension when perfoming unresolved member lookup in a type context of /// `PD`. static bool isExtensionWithSelfBound(const ExtensionDecl *ED, ProtocolDecl *PD) { - if (!ED || !PD) { + if (!ED || !PD) return false; - } - if (ED->getExtendedNominal() != PD) { - return false; - } + GenericSignature genericSig = ED->getGenericSignature(); Type selfType = genericSig->getConcreteType(ED->getSelfInterfaceType()); - if (!selfType) { + if (!selfType) return false; - } - if (selfType->is()) { + + if (selfType->is()) return false; - } - return true; + + auto *M = ED->getParentModule(); + return ED->getExtendedNominal() == PD || M->checkConformance(selfType, PD); } static bool isExtensionAppliedInternal(const DeclContext *DC, Type BaseTy, diff --git a/test/IDE/complete_rdar129024996.swift b/test/IDE/complete_rdar129024996.swift new file mode 100644 index 0000000000000..d3f15c9b8539a --- /dev/null +++ b/test/IDE/complete_rdar129024996.swift @@ -0,0 +1,49 @@ +// RUN: %batch-code-completion + +protocol P {} +protocol Q : P {} + +// Applicable, S conforms to Q. +struct S : Q {} +extension P where Self == S { + static func foo() -> S { S() } +} + +// Not applicable, Q does not inherit from K. +protocol K {} +extension S : K {} +extension K where Self == S { + static func bar() -> S { S() } +} + +// Make sure we don't try and complete for this type's init. +struct R { + init(a: Int) {} +} + +// Not applicable, A does not conform to Q. +struct A: P {} +extension P where Self == A { + static func baz() -> A { A() } +} + +struct B: P {} +extension B: Q where T: Q {} + +// Applicable, B conforms to Q. +extension P where Self == B { + static func qux() -> Self { .init() } +} + +// Not applicable, B does not conform to Q. +extension P where Self == B { + static func flim() -> Self { .init() } +} + +@attached(peer) macro R(_: any Q) = #externalMacro(module: "", type: "") + +@R(.#^COMPLETE^#) +func bar() {} +// COMPLETE: Begin completions, 2 items +// COMPLETE-DAG: Decl[StaticMethod]/Super/TypeRelation[Convertible]: foo()[#S#]; name=foo() +// COMPLETE-DAG: Decl[StaticMethod]/Super/TypeRelation[Convertible]: qux()[#B#]; name=qux() From f245ecf45c787ba39a392fd9294e3be3421a1291 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Mon, 10 Jun 2024 18:29:38 +0900 Subject: [PATCH 019/165] [TaskGroup] Fix typo in code snippet --- stdlib/public/Concurrency/TaskGroup.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/Concurrency/TaskGroup.swift b/stdlib/public/Concurrency/TaskGroup.swift index 4692ad2451493..9566a60f41588 100644 --- a/stdlib/public/Concurrency/TaskGroup.swift +++ b/stdlib/public/Concurrency/TaskGroup.swift @@ -545,7 +545,7 @@ public struct TaskGroup { /// to wait for all the child tasks to complete, /// collecting the values they returned: /// - /// while let first = try await group.next() { + /// while let value = try await group.next() { /// collected += value /// } /// return collected From 53861a4e00b8301414754bccd843053bfe9e461e Mon Sep 17 00:00:00 2001 From: Gabor Horvath Date: Mon, 10 Jun 2024 12:35:44 +0100 Subject: [PATCH 020/165] [cxx-interop] Avoid emitting methods that cause name clash In Swift, we can have enum elements and methods with the same name, they are overloaded. Unfortunately, this feature is not supported by C++ interop at the moment. This patch avoids emitting the methods with name collisions to make sure the resulting header can be compiler. A proper fix should follow in a later PR. rdar://128162252 --- lib/PrintAsClang/PrintClangFunction.cpp | 15 +++++++- .../enum-element-method-name-clash.swift | 35 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 test/Interop/SwiftToCxx/enums/enum-element-method-name-clash.swift diff --git a/lib/PrintAsClang/PrintClangFunction.cpp b/lib/PrintAsClang/PrintClangFunction.cpp index a85ce54802d99..e45ac707cb4be 100644 --- a/lib/PrintAsClang/PrintClangFunction.cpp +++ b/lib/PrintAsClang/PrintClangFunction.cpp @@ -713,6 +713,18 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature( if (kind == FunctionSignatureKind::CxxInlineThunk) ClangSyntaxPrinter(os).printGenericSignature(Signature); } + if (const auto *enumDecl = FD->getDeclContext()->getSelfEnumDecl()) + { + // We cannot emit functions with the same name as an enum case yet, the resulting header + // does not compiler. + // FIXME: either do not emit cases as inline members, or rename the cases or the + // colliding functions. + for (const auto *enumElement : enumDecl->getAllElements()) { + auto elementName = enumElement->getName(); + if (!elementName.isSpecial() && elementName.getBaseIdentifier().str() == name) + return ClangRepresentation::unsupported; + } + } auto emittedModule = FD->getModuleContext(); OutputLanguageMode outputLang = kind == FunctionSignatureKind::CFunctionProto ? OutputLanguageMode::ObjC @@ -1521,7 +1533,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxMethod( auto result = printFunctionSignature( FD, signature, cxx_translation::getNameForCxx(FD), resultTy, FunctionSignatureKind::CxxInlineThunk, modifiers); - assert(!result.isUnsupported() && "C signature should be unsupported too"); + if (result.isUnsupported()) + return; declAndTypePrinter.printAvailability(os, FD); if (!isDefinition) { diff --git a/test/Interop/SwiftToCxx/enums/enum-element-method-name-clash.swift b/test/Interop/SwiftToCxx/enums/enum-element-method-name-clash.swift new file mode 100644 index 0000000000000..95162e70923a1 --- /dev/null +++ b/test/Interop/SwiftToCxx/enums/enum-element-method-name-clash.swift @@ -0,0 +1,35 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend %s -typecheck -module-name Enums -clang-header-expose-decls=all-public -emit-clang-header-path %t/enums.h +// RUN: %FileCheck %s < %t/enums.h + +public enum Foo: Hashable, Sendable { + case bar(Parameters) + + // We do not want to generate C++ wrappers for this function yet + // because its name clashes with the enum element above preventing + // the generated header from compilation. + public static func bar(version: Int) -> Self { + Self.bar(Parameters(version: version)) + } +} + +extension Foo { + public struct Parameters: Hashable, Sendable { + public var version: Int + + public init(version: Int) { + self.version = version + } + } +} + +// CHECK-NOT: Foo bar(swift::Int version) + +// CHECK: switch (_getEnumTag()) { +// CHECK-NEXT: case 0: return cases::bar; +// CHECK-NEXT: default: abort(); +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-EMPTY: +// Before the fix, we had the static method's thunk here. +// CHECK-NEXT: swift::Int getHashValue() const \ No newline at end of file From 064a7dd9a074e5bb2d54198939e9e7e2aef5e816 Mon Sep 17 00:00:00 2001 From: Gabor Horvath Date: Mon, 10 Jun 2024 14:18:54 +0100 Subject: [PATCH 021/165] Address review comments. --- lib/PrintAsClang/PrintClangFunction.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/PrintAsClang/PrintClangFunction.cpp b/lib/PrintAsClang/PrintClangFunction.cpp index e45ac707cb4be..f23887b341c1e 100644 --- a/lib/PrintAsClang/PrintClangFunction.cpp +++ b/lib/PrintAsClang/PrintClangFunction.cpp @@ -713,15 +713,14 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature( if (kind == FunctionSignatureKind::CxxInlineThunk) ClangSyntaxPrinter(os).printGenericSignature(Signature); } - if (const auto *enumDecl = FD->getDeclContext()->getSelfEnumDecl()) - { + if (const auto *enumDecl = FD->getDeclContext()->getSelfEnumDecl()) { // We cannot emit functions with the same name as an enum case yet, the resulting header // does not compiler. // FIXME: either do not emit cases as inline members, or rename the cases or the // colliding functions. for (const auto *enumElement : enumDecl->getAllElements()) { auto elementName = enumElement->getName(); - if (!elementName.isSpecial() && elementName.getBaseIdentifier().str() == name) + if (!elementName.isSpecial() && elementName.getBaseIdentifier().is(name)) return ClangRepresentation::unsupported; } } From 005b45c1cc925e93bc0270bb5cdb3df02fc37413 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Sun, 9 Jun 2024 19:33:18 -0700 Subject: [PATCH 022/165] [Sema] Diagnose deprecated default implementations in the witness checker. If a protocol provides a deprecated default implementation for a requirement that is not deprecated, the compiler should emit a warning so the programmer can provide an explicit implementation of the requirement. This is helpful for staging in new protocol requirements that should be implemented in conforming types. --- include/swift/AST/Attr.h | 4 ++ include/swift/AST/DiagnosticsSema.def | 5 +++ include/swift/AST/RequirementMatch.h | 6 ++- lib/Sema/TypeCheckProtocol.cpp | 43 ++++++++++++++++-- test/decl/protocol/req/deprecated.swift | 60 +++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 test/decl/protocol/req/deprecated.swift diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 8522e73fd9b20..8c268fbb2c154 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -2705,6 +2705,10 @@ class DeclAttributes { return getUnavailable(ctx) != nullptr; } + bool isDeprecated(const ASTContext &ctx) const { + return getDeprecated(ctx) != nullptr; + } + /// Determine whether there is a swiftVersionSpecific attribute that's /// unavailable relative to the provided language version. bool diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 2cf21b7d82ddc..4160d7a860327 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -3137,6 +3137,11 @@ ERROR(witness_unavailable,none, "unavailable %kind0 was used to satisfy a requirement of protocol %1%select{|: %2}2", (const ValueDecl *, Identifier, StringRef)) +WARNING(witness_deprecated,none, + "deprecated default implementation is used to satisfy %kind0 required by " + "protocol %1%select{|: %2}2", + (const ValueDecl *, Identifier, StringRef)) + ERROR(redundant_conformance,none, "redundant conformance of %0 to protocol %1", (Type, Identifier)) ERROR(redundant_conformance_conditional,none, diff --git a/include/swift/AST/RequirementMatch.h b/include/swift/AST/RequirementMatch.h index 128fd746511b4..b1443f29e571c 100644 --- a/include/swift/AST/RequirementMatch.h +++ b/include/swift/AST/RequirementMatch.h @@ -239,6 +239,10 @@ enum class CheckKind : unsigned { /// The witness itself is inaccessible. WitnessUnavailable, + + /// The witness is a deprecated default implementation provided by the + /// protocol. + DefaultWitnessDeprecated, }; /// Describes the suitability of the chosen witness for /// the requirement. @@ -464,4 +468,4 @@ struct RequirementMatch { } -#endif // SWIFT_AST_REQUIREMENTMATCH_H \ No newline at end of file +#endif // SWIFT_AST_REQUIREMENTMATCH_H diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 0785b7ef65069..a80e528aa9acf 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1740,6 +1740,8 @@ checkWitnessAvailability(ValueDecl *requirement, RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement, const RequirementMatch &match) { + auto &ctx = getASTContext(); + if (!match.OptionalAdjustments.empty()) return CheckKind::OptionalityConflict; @@ -1769,7 +1771,7 @@ RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement, return RequirementCheck(CheckKind::Availability, requiredAvailability); } - if (requirement->getAttrs().isUnavailable(getASTContext()) && + if (requirement->getAttrs().isUnavailable(ctx) && match.Witness->getDeclContext() == DC) { return RequirementCheck(CheckKind::Unavailable); } @@ -1792,11 +1794,11 @@ RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement, } } - if (match.Witness->getAttrs().isUnavailable(getASTContext()) && - !requirement->getAttrs().isUnavailable(getASTContext())) { + if (match.Witness->getAttrs().isUnavailable(ctx) && + !requirement->getAttrs().isUnavailable(ctx)) { auto nominalOrExtensionIsUnavailable = [&]() { if (auto extension = dyn_cast(DC)) { - if (extension->getAttrs().isUnavailable(getASTContext())) + if (extension->getAttrs().isUnavailable(ctx)) return true; } @@ -1813,6 +1815,20 @@ RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement, return CheckKind::WitnessUnavailable; } + // Warn about deprecated default implementations if the requirement is + // not deprecated, and the conformance is not deprecated. + bool isDefaultWitness = false; + if (auto *nominal = match.Witness->getDeclContext()->getSelfNominalTypeDecl()) + isDefaultWitness = isa(nominal); + if (isDefaultWitness && + match.Witness->getAttrs().isDeprecated(ctx) && + !requirement->getAttrs().isDeprecated(ctx)) { + auto conformanceContext = ExportContext::forConformance(DC, Proto); + if (!conformanceContext.isDeprecated()) { + return RequirementCheck(CheckKind::DefaultWitnessDeprecated); + } + } + return CheckKind::Success; } @@ -4374,6 +4390,25 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) { requirement->getName()); }); break; + + case CheckKind::DefaultWitnessDeprecated: + getASTContext().addDelayedConformanceDiag( + Conformance, /*isError=*/false, + [witness, requirement](NormalProtocolConformance *conformance) { + auto &ctx = witness->getASTContext(); + auto &diags = ctx.Diags; + SourceLoc diagLoc = getLocForDiagnosingWitness(conformance, witness); + auto *attr = witness->getAttrs().getDeprecated(ctx); + EncodedDiagnosticMessage EncodedMessage(attr->Message); + diags.diagnose(diagLoc, diag::witness_deprecated, + witness, conformance->getProtocol()->getName(), + EncodedMessage.Message); + emitDeclaredHereIfNeeded(diags, diagLoc, witness); + diags.diagnose(requirement, diag::kind_declname_declared_here, + DescriptiveDeclKind::Requirement, + requirement->getName()); + }); + break; } if (auto *classDecl = DC->getSelfClassDecl()) { diff --git a/test/decl/protocol/req/deprecated.swift b/test/decl/protocol/req/deprecated.swift new file mode 100644 index 0000000000000..dfbf524f65928 --- /dev/null +++ b/test/decl/protocol/req/deprecated.swift @@ -0,0 +1,60 @@ +// RUN: %target-typecheck-verify-swift + +protocol DeprecatedRequirement { + @available(*, deprecated) + func f() +} + +extension DeprecatedRequirement { + @available(*, deprecated) + func f() {} +} + +// No warning if both the requirement and the default implementation are deprecated +struct S1: DeprecatedRequirement {} + +protocol DeprecatedDefault { + func f() // expected-note {{requirement 'f()' declared here}} +} + +extension DeprecatedDefault { + @available(*, deprecated) + func f() {} // expected-note {{'f()' declared here}} +} + +// expected-warning@+1 {{deprecated default implementation is used to satisfy instance method 'f()' required by protocol 'DeprecatedDefault'}} +struct S2: DeprecatedDefault {} + +// No warning if the conformance itself is deprecated +@available(*, deprecated) +struct S3: DeprecatedDefault { +} + +struct S4: DeprecatedDefault { + func f() {} +} + +struct S5 {} + +// No warning if the conformance itself is deprecated +@available(*, deprecated) +extension S5: DeprecatedDefault {} + +@available(*, deprecated) +enum UnavailableEnum { + struct Nested: DeprecatedDefault {} +} + +// Include message string from @available attribute if provided +protocol DeprecatedDefaultWithMessage { + func f() // expected-note {{requirement 'f()' declared here}} +} + +extension DeprecatedDefaultWithMessage { + @available(*, deprecated, message: "write it yourself") + func f() {} // expected-note {{'f()' declared here}} +} + + +// expected-warning@+1 {{deprecated default implementation is used to satisfy instance method 'f()' required by protocol 'DeprecatedDefaultWithMessage': write it yourself}} +struct S6: DeprecatedDefaultWithMessage {} From 5da7ac6cbdfd34b833afbf76f0250282df82142b Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Mon, 10 Jun 2024 07:16:44 -0700 Subject: [PATCH 023/165] [NFC] Use `DeclAttributes::isDeprecated` in a few more places. --- lib/APIDigester/ModuleAnalyzerNodes.cpp | 2 +- lib/IDE/CodeCompletionResultBuilder.cpp | 2 +- lib/Sema/CSDiagnostics.cpp | 2 +- lib/Sema/TypeCheckAvailability.cpp | 2 +- tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/APIDigester/ModuleAnalyzerNodes.cpp b/lib/APIDigester/ModuleAnalyzerNodes.cpp index 029d5e8fa3576..12d67c3453f61 100644 --- a/lib/APIDigester/ModuleAnalyzerNodes.cpp +++ b/lib/APIDigester/ModuleAnalyzerNodes.cpp @@ -1474,7 +1474,7 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Decl *D): ObjCName(Ctx.getObjcName(D)), InitKind(Ctx.getInitKind(D)), IsImplicit(D->isImplicit()), - IsDeprecated(D->getAttrs().getDeprecated(D->getASTContext())), + IsDeprecated(D->getAttrs().isDeprecated(D->getASTContext())), IsABIPlaceholder(isABIPlaceholderRecursive(D)), IsFromExtension(isDeclaredInExtension(D)), DeclAttrs(collectDeclAttributes(D)) { diff --git a/lib/IDE/CodeCompletionResultBuilder.cpp b/lib/IDE/CodeCompletionResultBuilder.cpp index 955e297c8a71e..18cecab04c1de 100644 --- a/lib/IDE/CodeCompletionResultBuilder.cpp +++ b/lib/IDE/CodeCompletionResultBuilder.cpp @@ -212,7 +212,7 @@ void CodeCompletionResultBuilder::setAssociatedDecl(const Decl *D) { CurrentModule = MD; } - if (D->getAttrs().getDeprecated(D->getASTContext())) + if (D->getAttrs().isDeprecated(D->getASTContext())) setContextFreeNotRecommended(ContextFreeNotRecommendedReason::Deprecated); else if (D->getAttrs().getSoftDeprecated(D->getASTContext())) setContextFreeNotRecommended( diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index ad0bf49a0bb70..bc30da18c9287 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -4230,7 +4230,7 @@ findImportedCaseWithMatchingSuffix(Type instanceTy, DeclNameRef name) { // Is one more available than the other? WORSE(->getAttrs().isUnavailable(ctx)); - WORSE(->getAttrs().getDeprecated(ctx)); + WORSE(->getAttrs().isDeprecated(ctx)); // Does one have a shorter name (so the non-matching prefix is shorter)? WORSE(->getName().getBaseName().userFacingName().size()); diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index ec6312eb4f685..9f9c5b8391bfd 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -207,7 +207,7 @@ computeExportContextBits(ASTContext &Ctx, Decl *D, if (D->isImplicit() && !isDeferBody) *implicit = true; - if (D->getAttrs().getDeprecated(Ctx)) + if (D->getAttrs().isDeprecated(Ctx)) *deprecated = true; if (auto *A = D->getAttrs().getUnavailable(Ctx)) { diff --git a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp index b4b03957db391..fafeb80fa87bd 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp @@ -448,7 +448,7 @@ static bool initDocEntityInfo(const Decl *D, } Info.IsUnavailable = AvailableAttr::isUnavailable(D); - Info.IsDeprecated = D->getAttrs().getDeprecated(D->getASTContext()) != nullptr; + Info.IsDeprecated = D->getAttrs().isDeprecated(D->getASTContext()); Info.IsOptional = D->getAttrs().hasAttribute(); if (auto *AFD = dyn_cast(D)) { Info.IsAsync = AFD->hasAsync(); From 2200632a95ecbd740108213335aad0cb132f5d88 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Mon, 10 Jun 2024 16:19:47 +0200 Subject: [PATCH 024/165] SILGen: ignore unreachable var decls Fixes a crash in case a lazy var is declared after a return statement https://github.com/apple/swift/issues/73736 --- lib/SILGen/SILGenStmt.cpp | 11 ++++------- test/SILGen/local_decl_after_unreachable.swift | 2 ++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp index 3c183882bd187..b1a238ef3a9dd 100644 --- a/lib/SILGen/SILGenStmt.cpp +++ b/lib/SILGen/SILGenStmt.cpp @@ -323,7 +323,7 @@ void StmtEmitter::visitBraceStmt(BraceStmt *S) { // PatternBindingBecls represent local variable bindings that execute // as part of the function's execution. - if (!isa(D)) { + if (!isa(D) && !isa(D)) { // Other decls define entities that may be used by the program, such as // local function declarations. So handle them here, before checking for // reachability, and then continue looping. @@ -429,12 +429,9 @@ void StmtEmitter::visitBraceStmt(BraceStmt *S) { SGF.emitIgnoredExpr(E); } else { auto *D = ESD.get(); - - // Only PatternBindingDecls should be emitted here. - // Other decls were handled above. - auto PBD = cast(D); - - SGF.visit(PBD); + assert((isa(D) || isa(D)) && + "other decls should be handled before the reachability check"); + SGF.visit(D); } } } diff --git a/test/SILGen/local_decl_after_unreachable.swift b/test/SILGen/local_decl_after_unreachable.swift index 61c37ebff7a08..c99521c94ad6c 100644 --- a/test/SILGen/local_decl_after_unreachable.swift +++ b/test/SILGen/local_decl_after_unreachable.swift @@ -13,4 +13,6 @@ func foo() { // CHECK-LABEL: sil {{.*}} @{{.*}}3foo{{.*}}3bar{{.*}}F : {{.*}} { func bar(_: Any) {} + // Check that we don't crash here + lazy var v = 42 } From a3e3079fb6844e88a2133d3f6495febfd18cb7e7 Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 10 Jun 2024 16:22:36 +0100 Subject: [PATCH 025/165] [docs] Suggest `--skip-xros` in the Getting Started guide The Getting Started guide offers a build-script command that new contributors can use to quickly build a debug compiler on their local machine. The command already has `--skip-tvos` and `--skip-watchos` flags since most compiler contributors don't need to build for those platforms. This change adds `--skip-xros` flag to the command. --- docs/HowToGuides/GettingStarted.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/HowToGuides/GettingStarted.md b/docs/HowToGuides/GettingStarted.md index 8c05222bf9ad7..d8f83e084b20d 100644 --- a/docs/HowToGuides/GettingStarted.md +++ b/docs/HowToGuides/GettingStarted.md @@ -262,7 +262,7 @@ Build the toolchain with optimizations, debuginfo, and assertions, using Ninja: - macOS: ```sh utils/build-script --skip-build-benchmarks \ - --skip-ios --skip-watchos --skip-tvos --swift-darwin-supported-archs "$(uname -m)" \ + --skip-ios --skip-watchos --skip-tvos --skip-xros --swift-darwin-supported-archs "$(uname -m)" \ --sccache --release-debuginfo --swift-disable-dead-stripping \ --bootstrapping=hosttools ``` From e3a53abe132de75dfee5575ffc4fb9f7cc5b491c Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Mon, 10 Jun 2024 09:23:21 -0700 Subject: [PATCH 026/165] Don't use aarch64 hint for arm targets --- .../Synchronization/Mutex/SpinLoopHint.swift | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/stdlib/public/Synchronization/Mutex/SpinLoopHint.swift b/stdlib/public/Synchronization/Mutex/SpinLoopHint.swift index 940310f4fb4a6..0084e1d056892 100644 --- a/stdlib/public/Synchronization/Mutex/SpinLoopHint.swift +++ b/stdlib/public/Synchronization/Mutex/SpinLoopHint.swift @@ -17,6 +17,8 @@ var _tries: Int { 100 } +#if arch(arm) + // The following are acceptable operands to the aarch64 hint intrinsic from // 'llvm-project/llvm/lib/Target/ARM/ARMInstrInfo.td': // @@ -28,9 +30,27 @@ var _tries: Int { // `sevl` = 5 // // There are others, but for the sake of spin loops, we only care about 'wfe'. +@_extern(c, "llvm.arm.hint") +func _hint(_: UInt32) + +#else + +// The following are acceptable operands to the aarch64 hint intrinsic from +// 'llvm-project/llvm/lib/Target/AArch64/AArch64InstrInfo.td': +// +// `nop` = 0 +// `yield` = 1 +// `wfe` = 2 +// `wfi` = 3 +// `sev` = 4 +// `sevl` = 5 +// +// There are others, but for the sake of spin loops, we only care about 'wfe'. @_extern(c, "llvm.aarch64.hint") func _hint(_: UInt32) +#endif + @inline(__always) func _wfe() { _hint(2) From 717880e844b572b568716dd3e1c448c1a6cbc951 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Mon, 10 Jun 2024 18:23:31 +0200 Subject: [PATCH 027/165] PerformanceDiagnostics: avoid false meta-data alarms for non-loadable types Non-loadable types don't necessarily need metadata, for example, structs with `@_rawLayout` https://github.com/apple/swift/issues/73951 --- include/swift/SIL/SILType.h | 3 +++ lib/SIL/IR/SILType.cpp | 5 +++++ lib/SIL/Utils/InstructionUtils.cpp | 2 +- test/SILOptimizer/performance-annotations.swift | 15 ++++++++++++++- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index a9f730b2bd3b3..1394023105bfe 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -366,6 +366,9 @@ class SILType { /// address-only. This is the opposite of isLoadable. bool isAddressOnly(const SILFunction &F) const; + /// For details see the comment of `IsFixedABI_t`. + bool isFixedABI(const SILFunction &F) const; + /// True if the underlying AST type is trivial, meaning it is loadable and can /// be trivially copied, moved or destroyed. Returns false for address types /// even though they are technically trivial. diff --git a/lib/SIL/IR/SILType.cpp b/lib/SIL/IR/SILType.cpp index d223556c64b4a..a8bcbca9d7103 100644 --- a/lib/SIL/IR/SILType.cpp +++ b/lib/SIL/IR/SILType.cpp @@ -450,6 +450,11 @@ bool SILType::isAddressOnly(const SILFunction &F) const { return F.getTypeLowering(contextType).isAddressOnly(); } +bool SILType::isFixedABI(const SILFunction &F) const { + auto contextType = hasTypeParameter() ? F.mapTypeIntoContext(*this) : *this; + return F.getTypeLowering(contextType).isFixedABI(); +} + SILType SILType::substGenericArgs(SILModule &M, SubstitutionMap SubMap, TypeExpansionContext context) const { auto fnTy = castTo(); diff --git a/lib/SIL/Utils/InstructionUtils.cpp b/lib/SIL/Utils/InstructionUtils.cpp index b3cc52ef3d5f1..145ad02ae6e4c 100644 --- a/lib/SIL/Utils/InstructionUtils.cpp +++ b/lib/SIL/Utils/InstructionUtils.cpp @@ -618,7 +618,7 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType) case SILInstructionKind::StructElementAddrInst: case SILInstructionKind::IndexAddrInst: // TODO: hasArchetype() ? - if (!inst->getOperand(0)->getType().isLoadable(*inst->getFunction())) { + if (!inst->getOperand(0)->getType().isFixedABI(*inst->getFunction())) { impactType = inst->getOperand(0)->getType(); return RuntimeEffect::MetaData; } diff --git a/test/SILOptimizer/performance-annotations.swift b/test/SILOptimizer/performance-annotations.swift index 24dd54b2b90b3..1184ff7d7167e 100644 --- a/test/SILOptimizer/performance-annotations.swift +++ b/test/SILOptimizer/performance-annotations.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -parse-as-library -disable-availability-checking -import-objc-header %S/Inputs/perf-annotations.h -emit-sil %s -o /dev/null -verify +// RUN: %target-swift-frontend -parse-as-library -disable-availability-checking -enable-experimental-feature RawLayout -import-objc-header %S/Inputs/perf-annotations.h -emit-sil %s -o /dev/null -verify // REQUIRES: swift_stdlib_no_asserts,optimized_stdlib // REQUIRES: swift_in_compiler @@ -514,3 +514,16 @@ func testNonCopyable() { let t = NonCopyableStruct() t.foo() } + +public struct RawLayoutWrapper: ~Copyable { + private let x = RawLayout() + + @_noLocks func testit() { + x.test() + } +} + +@_rawLayout(like: T) +public struct RawLayout: ~Copyable { + public func test() {} +} From 0f420fe8a4756309ff8804b4dab0816bbd5ddb3a Mon Sep 17 00:00:00 2001 From: Egor Zhdan Date: Mon, 10 Jun 2024 17:48:44 +0100 Subject: [PATCH 028/165] [cxx-interop] Only run tests for reference types against a recent Swift runtime Having a Swift array of C++ reference types without crashing at runtime only became possible recently (https://github.com/apple/swift/pull/73615). When building against an older runtime, one would still see runtime crashes. This is expected because part of the fix is in the Swift runtime. This makes sure we don't try to run tests for C++ reference types with an older Swift runtime. rdar://128681137 --- test/Interop/Cxx/foreign-reference/reference-counted.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Interop/Cxx/foreign-reference/reference-counted.swift b/test/Interop/Cxx/foreign-reference/reference-counted.swift index 7a5127a7eb250..0555fa39c9816 100644 --- a/test/Interop/Cxx/foreign-reference/reference-counted.swift +++ b/test/Interop/Cxx/foreign-reference/reference-counted.swift @@ -4,8 +4,9 @@ // REQUIRES: executable_test // XFAIL: OS=windows-msvc -// Temporarily disable on arm64e (rdar://128681137) -// UNSUPPORTED: CPU=arm64e +// Temporarily disable when running with an older runtime (rdar://128681137) +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: back_deployment_runtime import StdlibUnittest import ReferenceCounted From 4a49e65368da122a3ff6b14ba5131bd9a4e79202 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 10 Jun 2024 20:29:16 +0100 Subject: [PATCH 029/165] [Sema] NFC: Replace a couple of closure parameters with ASTContext Make it a bit clearer which function actually cares about the closure it's handed. --- lib/Sema/MiscDiagnostics.cpp | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 789a6e02fc6b7..237ef57740e13 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -1745,7 +1745,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, ASTContext &ctx = inClosure->getASTContext(); auto requiresSelfQualification = - isClosureRequiringSelfQualification(inClosure, ctx); + isClosureRequiringSelfQualification(inClosure); // Metatype self captures don't extend the lifetime of an object. if (captureType->is()) { @@ -1783,7 +1783,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, // that defines self if present. if (validateSelfRebindings) { if (auto conditionalStmt = parentConditionalStmt(selfDecl)) { - if (!hasValidSelfRebinding(conditionalStmt, inClosure)) { + if (!hasValidSelfRebinding(conditionalStmt, ctx)) { return false; } } @@ -1793,7 +1793,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, // closure unwraps self. If not, implicit self is not allowed // in this closure or in any nested closure. if (closureHasWeakSelfCapture(inClosure) && - !hasValidSelfRebinding(parentConditionalStmt(selfDecl), inClosure)) { + !hasValidSelfRebinding(parentConditionalStmt(selfDecl), ctx)) { return false; } @@ -1967,7 +1967,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, static bool hasValidSelfRebinding(const LabeledConditionalStmt *conditionalStmt, - const AbstractClosureExpr *inClosure) { + ASTContext &ctx) { if (!conditionalStmt) { return false; } @@ -1980,8 +1980,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, // guard let self = self else { return } // method() // <- implicit self is not allowed // - return conditionalStmt->rebindsSelf(inClosure->getASTContext(), - /*requiresCaptureListRef*/ true); + return conditionalStmt->rebindsSelf(ctx, /*requiresCaptureListRef*/ true); } /// The `LabeledConditionalStmt` that contains the given `ValueDecl` if @@ -2064,8 +2063,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, /// Return true if this is a closure expression that will require explicit /// use or capture of "self." for qualification of member references. static bool - isClosureRequiringSelfQualification(const AbstractClosureExpr *CE, - ASTContext &Ctx) { + isClosureRequiringSelfQualification(const AbstractClosureExpr *CE) { if (closureHasWeakSelfCapture(CE)) { return true; } @@ -2253,7 +2251,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, // to use implicit self, even after fixing any invalid parents. auto isEscapingAutoclosure = isa(ACE) && - isClosureRequiringSelfQualification(ACE, Ctx); + isClosureRequiringSelfQualification(ACE); if (!isEscapingAutoclosure) { closureForDiagnostics = parentDisallowingImplicitSelf; } @@ -2390,7 +2388,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, return true; } - if (isUsageAlwaysPreviouslyRejected(selfDecl, ACE)) { + if (isUsageAlwaysPreviouslyRejected(selfDecl)) { return false; } @@ -2436,7 +2434,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, } if (auto condStmt = parentConditionalStmt(selfDecl)) { - auto isValidSelfRebinding = hasValidSelfRebinding(condStmt, ACE); + auto isValidSelfRebinding = hasValidSelfRebinding(condStmt, Ctx); // Swfit 5.8 permitted implicit self without validating any // parent closures. If implicit self is only disallowed due to @@ -2450,8 +2448,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, // If the binding is valid when only checking for a load expr, // then we must only warn. auto usesLoadExpr = - condStmt->rebindsSelf(ACE->getASTContext(), - /*requiresCaptureListRef*/ false, + condStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ false, /*requireLoadExpr*/ true); if (!isValidSelfRebinding && usesLoadExpr) { @@ -2464,12 +2461,11 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, /// Checks if this implicit self usage was always previously rejected as /// invalid, so can continue to be treated an error. - bool isUsageAlwaysPreviouslyRejected(ValueDecl *selfDecl, - AbstractClosureExpr *ACE) { + bool isUsageAlwaysPreviouslyRejected(ValueDecl *selfDecl) { // If the self decl refers to a weak self unwrap condition // in some parent closure, then there is no source-compatibility // requirement to avoid an error. - return hasValidSelfRebinding(parentConditionalStmt(selfDecl), ACE); + return hasValidSelfRebinding(parentConditionalStmt(selfDecl), Ctx); } /// Checks if this is a usage of implicit self in a strong self closure @@ -2507,7 +2503,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, // FIXME: This is happening too early, because closure->getType() isn't set. if (auto *closure = dyn_cast(DC)) if (closure->getType()) - if (DiagnoseWalker::isClosureRequiringSelfQualification(closure, ctx)) + if (DiagnoseWalker::isClosureRequiringSelfQualification(closure)) ACE = const_cast(closure); DC = DC->getParent(); } From fe272e6cdd41e25cbd687d9360f72ba50fd9720f Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 10 Jun 2024 20:29:16 +0100 Subject: [PATCH 030/165] [Sema] Restore 5.10 implicit self behavior prior to Swift 6 mode Unfortunately we've encountered another source breaking case here: ``` class C { func method() {} func foo() { Task { [weak self] in Task { method() } } } } ``` In 5.10 we'd only do the unqualified lookup for `self` when directly in a `weak self` closure, but with the implicit self rework, we'd start using the `weak self` here, leading to a type-checker error. At this point, adding more edge cases to the existing logic is going to make things much more complicated. Instead, reinstate the 5.10 implicit self lookup behavior and diagnostic logic, switching over to the new logic only under Swift 6 mode. rdar://129475277 --- lib/AST/UnqualifiedLookup.cpp | 20 +- lib/Sema/MiscDiagnostics.cpp | 262 +++++++++--------- test/attr/attr_noescape.swift | 24 +- test/expr/closure/closures.swift | 256 +++++++++-------- test/expr/closure/closures_swift6.swift | 39 +++ test/expr/closure/implicit_weak_capture.swift | 2 +- 6 files changed, 343 insertions(+), 260 deletions(-) diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 08bbf0441b549..4797510d6b3d7 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -369,13 +369,6 @@ ValueDecl *UnqualifiedLookupFactory::lookupBaseDecl(const DeclContext *baseDC) c return nullptr; } - auto selfDecl = ASTScope::lookupSingleLocalDecl( - DC->getParentSourceFile(), DeclName(Ctx.Id_self), Loc); - - if (!selfDecl) { - return nullptr; - } - bool capturesSelfWeakly = false; if (auto decl = closureExpr->getCapturedSelfDecl()) { if (auto a = decl->getAttrs().getAttribute()) { @@ -383,6 +376,17 @@ ValueDecl *UnqualifiedLookupFactory::lookupBaseDecl(const DeclContext *baseDC) c } } + // Previously we didn't perform the lookup of 'self' for anything outside + // of a '[weak self]' closure, maintain that behavior until Swift 6 mode. + if (!Ctx.LangOpts.isSwiftVersionAtLeast(6) && !capturesSelfWeakly) + return nullptr; + + auto selfDecl = ASTScope::lookupSingleLocalDecl(DC->getParentSourceFile(), + DeclName(Ctx.Id_self), Loc); + if (!selfDecl) { + return nullptr; + } + // In Swift 5 mode, implicit self is allowed within non-escaping // `weak self` closures even before self is unwrapped. // For example, this is allowed: @@ -407,7 +411,7 @@ ValueDecl *UnqualifiedLookupFactory::lookupBaseDecl(const DeclContext *baseDC) c // In these cases, using the Swift 6 lookup behavior doesn't affect // how the body is type-checked, so it can be used in Swift 5 mode // without breaking source compatibility for non-escaping closures. - if (capturesSelfWeakly && !Ctx.LangOpts.isSwiftVersionAtLeast(6) && + if (!Ctx.LangOpts.isSwiftVersionAtLeast(6) && !implicitSelfReferenceIsUnwrapped(selfDecl)) { return nullptr; } diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 237ef57740e13..44d87bf29fdb8 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -1715,6 +1715,91 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, Closures.push_back(ACE); } + static bool + implicitWeakSelfReferenceIsValid510(const DeclRefExpr *DRE, + const AbstractClosureExpr *inClosure) { + ASTContext &Ctx = DRE->getDecl()->getASTContext(); + + // Check if the implicit self decl refers to a var in a conditional stmt + LabeledConditionalStmt *conditionalStmt = nullptr; + if (auto var = dyn_cast(DRE->getDecl())) { + if (auto parentStmt = var->getParentPatternStmt()) { + conditionalStmt = dyn_cast(parentStmt); + } + } + + if (!conditionalStmt) { + return false; + } + + // Require `LoadExpr`s when validating the self binding. + // This lets us reject invalid examples like: + // + // let `self` = self ?? .somethingElse + // guard let self = self else { return } + // method() // <- implicit self is not allowed + // + return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ false, + /*requireLoadExpr*/ true); + } + + static bool + isEnclosingSelfReference510(VarDecl *var, + const AbstractClosureExpr *inClosure) { + if (var->isSelfParameter()) + return true; + + // Capture variables have a DC of the parent function. + if (inClosure && var->isSelfParamCapture() && + var->getDeclContext() != inClosure->getParent()) + return true; + + return false; + } + + static bool + selfDeclAllowsImplicitSelf510(DeclRefExpr *DRE, Type ty, + const AbstractClosureExpr *inClosure) { + // If this is an explicit `weak self` capture, then implicit self is + // allowed once the closure's self param is unwrapped. We need to validate + // that the unwrapped `self` decl specifically refers to an unwrapped copy + // of the closure's `self` param, and not something else like in `guard + // let self = .someOptionalVariable else { return }` or `let self = + // someUnrelatedVariable`. If self hasn't been unwrapped yet and is still + // an optional, we would have already hit an error elsewhere. + if (closureHasWeakSelfCapture(inClosure)) { + return implicitWeakSelfReferenceIsValid510(DRE, inClosure); + } + + // Metatype self captures don't extend the lifetime of an object. + if (ty->is()) + return true; + + // If self does not have reference semantics, it is very unlikely that + // capturing it will create a reference cycle. + if (!ty->hasReferenceSemantics()) + return true; + + if (auto closureExpr = dyn_cast(inClosure)) { + if (auto selfDecl = closureExpr->getCapturedSelfDecl()) { + // If this capture is using the name `self` actually referring + // to some other variable (e.g. with `[self = "hello"]`) + // then implicit self is not allowed. + if (!selfDecl->isSelfParamCapture()) { + return false; + } + } + } + + if (auto var = dyn_cast(DRE->getDecl())) { + if (!isEnclosingSelfReference510(var, inClosure)) { + return true; + } + } + + return false; + } + /// Whether or not implicit self is allowed for self decl static bool selfDeclAllowsImplicitSelf(Expr *E, const AbstractClosureExpr *inClosure) { @@ -1731,6 +1816,11 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, if (!ty) return true; + // Prior to Swift 6, use the old validation logic. + auto &ctx = inClosure->getASTContext(); + if (!ctx.isSwiftVersionAtLeast(6)) + return selfDeclAllowsImplicitSelf510(DRE, ty, inClosure); + return selfDeclAllowsImplicitSelf(DRE->getDecl(), ty, inClosure, /*validateParentClosures:*/ true, /*validateSelfRebindings:*/ true); @@ -2063,8 +2153,9 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, /// Return true if this is a closure expression that will require explicit /// use or capture of "self." for qualification of member references. static bool - isClosureRequiringSelfQualification(const AbstractClosureExpr *CE) { - if (closureHasWeakSelfCapture(CE)) { + isClosureRequiringSelfQualification(const AbstractClosureExpr *CE, + bool ignoreWeakSelf = false) { + if (!ignoreWeakSelf && closureHasWeakSelfCapture(CE)) { return true; } @@ -2110,9 +2201,20 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, bool shouldWalkCaptureInitializerExpressions() override { return true; } + bool shouldRecordClosure(const AbstractClosureExpr *E) { + // Record all closures in Swift 6 mode. + if (Ctx.isSwiftVersionAtLeast(6)) + return true; + + // Only record closures requiring self qualification prior to Swift 6 + // mode. + return isClosureRequiringSelfQualification(E); + } + PreWalkResult walkToExprPre(Expr *E) override { if (auto *CE = dyn_cast(E)) { - Closures.push_back(CE); + if (shouldRecordClosure(CE)) + Closures.push_back(CE); } // If we aren't in a closure, no diagnostics will be produced. @@ -2144,7 +2246,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, diag::property_use_in_closure_without_explicit_self, baseName.getIdentifier()) .warnUntilSwiftVersionIf( - invalidImplicitSelfShouldOnlyWarn(MRE->getBase(), ACE), 6); + invalidImplicitSelfShouldOnlyWarn510(MRE->getBase(), ACE), 6); } // Handle method calls with a specific diagnostic + fixit. @@ -2159,12 +2261,13 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, diag::method_call_in_closure_without_explicit_self, MethodExpr->getDecl()->getBaseIdentifier()) .warnUntilSwiftVersionIf( - invalidImplicitSelfShouldOnlyWarn(DSCE->getBase(), ACE), 6); + invalidImplicitSelfShouldOnlyWarn510(DSCE->getBase(), ACE), + 6); } if (memberLoc.isValid()) { const AbstractClosureExpr *parentDisallowingImplicitSelf = nullptr; - if (selfDRE && selfDRE->getDecl()) { + if (Ctx.isSwiftVersionAtLeast(6) && selfDRE && selfDRE->getDecl()) { parentDisallowingImplicitSelf = parentClosureDisallowingImplicitSelf( selfDRE->getDecl(), selfDRE->getType(), ACE); } @@ -2173,11 +2276,11 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, return Action::SkipNode(E); } - if (!selfDeclAllowsImplicitSelf(E, ACE)) + if (!selfDeclAllowsImplicitSelf(E, ACE)) { Diags.diagnose(E->getLoc(), diag::implicit_use_of_self_in_closure) - .warnUntilSwiftVersionIf(invalidImplicitSelfShouldOnlyWarn(E, ACE), - 6); - + .warnUntilSwiftVersionIf( + invalidImplicitSelfShouldOnlyWarn510(E, ACE), 6); + } return Action::Continue(E); } @@ -2187,9 +2290,10 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, return Action::Continue(E); } - assert(Closures.size() > 0); - Closures.pop_back(); - + if (shouldRecordClosure(ACE)) { + assert(Closures.size() > 0); + Closures.pop_back(); + } return Action::Continue(E); } @@ -2367,132 +2471,28 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E, /// Whether or not this invalid usage of implicit self should be a warning /// in Swift 5 mode, to preserve source compatibility. - bool invalidImplicitSelfShouldOnlyWarn(Expr *selfRef, - AbstractClosureExpr *ACE) { + bool invalidImplicitSelfShouldOnlyWarn510(Expr *selfRef, + AbstractClosureExpr *ACE) { auto DRE = dyn_cast_or_null(selfRef); - if (!DRE) { + if (!DRE) return false; - } auto selfDecl = dyn_cast_or_null(DRE->getDecl()); - auto ty = DRE->getType(); - if (!selfDecl) { - return false; - } - - if (isInTypePreviouslyLackingValidation(ty)) { - return true; - } - - if (isPreviouslyPermittedWeakSelfUsage(ACE, selfDecl, ty)) { - return true; - } - - if (isUsageAlwaysPreviouslyRejected(selfDecl)) { + if (!selfDecl) return false; - } - - if (isPreviouslyPermittedStrongSelfUsage(selfDecl, ACE)) { - return true; - } - - return false; - } - bool isInTypePreviouslyLackingValidation(Type ty) { - // We previously didn't validate captures at all in structs or metadata - // types, so we must only warn in this case. - return !ty->hasReferenceSemantics() || ty->is(); - } - - /// Checks if this usage of implicit self in a weak self closure - /// was previously permitted in Swift 5.8. - bool isPreviouslyPermittedWeakSelfUsage(AbstractClosureExpr *ACE, - ValueDecl *selfDecl, Type ty) { - auto weakSelfDecl = weakSelfCapture(ACE); - if (!weakSelfDecl) { - return false; - } - - // Implicit self was permitted for weak self captures in - // non-escaping closures in Swift 5.7, so we must only warn. - if (isNonEscaping(ACE)) { - return true; - } - - // Implicit self was also permitted for weak self captures in closures - // passed to @_implicitSelfCapture parameters in Swift 5.7. - if (auto *CE = dyn_cast(ACE)) { - if (CE->allowsImplicitSelfCapture()) - return true; - } - - // Invalid captures like `[weak self = somethingElse]` - // were permitted in Swift 5.8, so we must only warn. - if (!isSimpleSelfCapture(weakSelfDecl)) { - return true; - } - - if (auto condStmt = parentConditionalStmt(selfDecl)) { - auto isValidSelfRebinding = hasValidSelfRebinding(condStmt, Ctx); - - // Swfit 5.8 permitted implicit self without validating any - // parent closures. If implicit self is only disallowed due to - // an invalid parent, we must only warn. - if (isValidSelfRebinding && - implicitSelfDisallowedDueToInvalidParent(selfDecl, ty, ACE)) { - return true; - } - - // Swift 5.8 used `requiresLoadExpr` to validate self bindings. - // If the binding is valid when only checking for a load expr, - // then we must only warn. - auto usesLoadExpr = - condStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ false, - /*requireLoadExpr*/ true); - - if (!isValidSelfRebinding && usesLoadExpr) { - return true; - } - } - - return false; - } - - /// Checks if this implicit self usage was always previously rejected as - /// invalid, so can continue to be treated an error. - bool isUsageAlwaysPreviouslyRejected(ValueDecl *selfDecl) { - // If the self decl refers to a weak self unwrap condition - // in some parent closure, then there is no source-compatibility - // requirement to avoid an error. - return hasValidSelfRebinding(parentConditionalStmt(selfDecl), Ctx); - } - - /// Checks if this is a usage of implicit self in a strong self closure - /// that was previously permitted in older versions like Swift 5.3. - bool isPreviouslyPermittedStrongSelfUsage(VarDecl *selfDecl, - AbstractClosureExpr *ACE) { - // Implicit self was accidentially allowed in examples like this - // in Swift 5.3-5.5, so check for this case and emit a warning - // instead of an error: - // - // withEscaping { [self] in - // withEscaping { - // x += 1 - // } - // } - // - bool isEscapingClosureWithExplicitSelfCapture = false; - if (!isNonEscaping(ACE)) { - if (auto closureExpr = dyn_cast(ACE)) { - if (closureExpr->getCapturedSelfDecl()) { - isEscapingClosureWithExplicitSelfCapture = true; - } - } + // If this implicit self decl is from a closure that captured self + // weakly, then we should always emit an error, since implicit self was + // only allowed starting in Swift 5.8 and later. + if (closureHasWeakSelfCapture(ACE)) { + // Implicit self was incorrectly permitted for weak self captures + // in non-escaping closures in Swift 5.7, so in that case we can + // only warn until Swift 6. + return !isClosureRequiringSelfQualification(ACE, + /*ignoreWeakSelf*/ true); } - return !selfDecl->isSelfParameter() && - !isEscapingClosureWithExplicitSelfCapture; + return !selfDecl->isSelfParameter(); } }; diff --git a/test/attr/attr_noescape.swift b/test/attr/attr_noescape.swift index c14f74b0d4450..8bd3e5e227e42 100644 --- a/test/attr/attr_noescape.swift +++ b/test/attr/attr_noescape.swift @@ -89,29 +89,29 @@ class SomeClass { takesNoEscapeClosure { foo(); return 0 } } - let _: () -> Void = { // expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{26-26= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{26-26= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{26-26= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{26-26= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} + let _: () -> Void = { // expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{26-26= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{26-26= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{26-26= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{26-26= [self] in}} func inner() { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{22-22=self.}} - let inner2 = { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{22-22=self.}} + let inner2 = { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{21-21= [self] in}} expected-note{{reference 'self.' explicitly}} {{22-22=self.}} let _ = inner2 func multi() -> Int { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{29-29=self.}} - let multi2: () -> Int = { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{33-33=self.}} + let multi2: () -> Int = { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{32-32= [self] in}} expected-note{{reference 'self.' explicitly}} {{33-33=self.}} let _ = multi2 - doesEscape { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{20-20=self.}} + doesEscape { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{19-19= [self] in}} expected-note{{reference 'self.' explicitly}} {{20-20=self.}} takesNoEscapeClosure { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{30-30=self.}} - doesEscape { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{20-20=self.}} + doesEscape { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{19-19= [self] in}} expected-note{{reference 'self.' explicitly}} {{20-20=self.}} takesNoEscapeClosure { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{30-30=self.}} } - doesEscape { // expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{17-17= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{17-17= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{17-17= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{17-17= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} - func inner() { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{22-22=self.}} - let inner2 = { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{22-22=self.}} + doesEscape { //expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{17-17= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{17-17= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{17-17= [self] in}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{17-17= [self] in}} + func inner() { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{22-22=self.}} + let inner2 = { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{21-21= [self] in}} expected-note{{reference 'self.' explicitly}} {{22-22=self.}} _ = inner2 - func multi() -> Int { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{29-29=self.}} - let multi2: () -> Int = { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{33-33=self.}} + func multi() -> Int { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{29-29=self.}} + let multi2: () -> Int = { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{32-32= [self] in}} expected-note{{reference 'self.' explicitly}} {{33-33=self.}} _ = multi2 - doesEscape { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{20-20=self.}} + doesEscape { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{19-19= [self] in}} expected-note{{reference 'self.' explicitly}} {{20-20=self.}} takesNoEscapeClosure { foo() } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{30-30=self.}} - doesEscape { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{20-20=self.}} + doesEscape { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{19-19= [self] in}} expected-note{{reference 'self.' explicitly}} {{20-20=self.}} takesNoEscapeClosure { foo(); return 0 } // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} {{30-30=self.}} return 0 } diff --git a/test/expr/closure/closures.swift b/test/expr/closure/closures.swift index 9b75765bbac00..9a71e1748b680 100644 --- a/test/expr/closure/closures.swift +++ b/test/expr/closure/closures.swift @@ -171,14 +171,14 @@ class ExplicitSelfRequiredTest { doStuff({ [unowned(unsafe) self] in x+1 }) doStuff({ [unowned self = self] in x+1 }) doStuff({ x+1 }) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{14-14= [self] in}} expected-note{{reference 'self.' explicitly}} {{15-15=self.}} - doVoidStuff({ doStuff({ x+1 })}) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{18-18= [self] in}} expected-note{{reference 'self.' explicitly}} {{29-29=self.}} + doVoidStuff({ doStuff({ x+1 })}) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{28-28= [self] in}} expected-note{{reference 'self.' explicitly}} {{29-29=self.}} doVoidStuff({ [self] in doStuff({ x+1 })}) // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{38-38= [self] in}} expected-note{{reference 'self.' explicitly}} {{39-39=self.}} doVoidStuff({ x += 1 }) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{18-18= [self] in}} expected-note{{reference 'self.' explicitly}} {{19-19=self.}} doVoidStuff({ _ = "\(x)"}) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{18-18= [self] in}} expected-note{{reference 'self.' explicitly}} {{26-26=self.}} doVoidStuff({ [y = self] in x += 1 }) // expected-warning {{capture 'y' was never used}} expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{20-20=self, }} expected-note{{reference 'self.' explicitly}} {{33-33=self.}} doStuff({ [y = self] in x+1 }) // expected-warning {{capture 'y' was never used}} expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{16-16=self, }} expected-note{{reference 'self.' explicitly}} {{29-29=self.}} - doVoidStuff({ [self = ExplicitSelfRequiredTest()] in x += 1 }) // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} - doStuff({ [self = ExplicitSelfRequiredTest()] in x+1 }) // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + doVoidStuff({ [self = ExplicitSelfRequiredTest()] in x += 1 }) // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}} + doStuff({ [self = ExplicitSelfRequiredTest()] in x+1 }) // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}} // Methods follow the same rules as properties, uses of 'self' without capturing must be marked with "self." doStuff { method() } // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{14-14= [self] in}} expected-note{{reference 'self.' explicitly}} {{15-15=self.}} @@ -187,8 +187,8 @@ class ExplicitSelfRequiredTest { doVoidStuff { () -> () in _ = method() } // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{18-18= [self]}} expected-note{{reference 'self.' explicitly}} {{35-35=self.}} doVoidStuff { [y = self] in _ = method() } // expected-warning {{capture 'y' was never used}} expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{20-20=self, }} expected-note{{reference 'self.' explicitly}} {{37-37=self.}} doStuff({ [y = self] in method() }) // expected-warning {{capture 'y' was never used}} expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} {{16-16=self, }} expected-note{{reference 'self.' explicitly}} {{29-29=self.}} - doVoidStuff({ [self = ExplicitSelfRequiredTest()] in _ = method() }) // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} - doStuff({ [self = ExplicitSelfRequiredTest()] in method() }) // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} + doVoidStuff({ [self = ExplicitSelfRequiredTest()] in _ = method() }) // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}} + doStuff({ [self = ExplicitSelfRequiredTest()] in method() }) // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}} doVoidStuff { _ = self.method() } doVoidStuff { [self] in _ = method() } doVoidStuff { [self = self] in _ = method() } @@ -790,15 +790,15 @@ public class TestImplicitSelfForWeakSelfCapture { method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } - doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} - doVoidStuff { + doVoidStuff { + doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } } - doVoidStuff { [self] in + doVoidStuff { [self] in // expected-warning {{capture 'self' was never used}} doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} - method() // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} + method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } } } @@ -839,7 +839,7 @@ public class TestImplicitSelfForWeakSelfCapture { } doVoidStuffNonEscaping { [weak self] in - guard let self = self else { return } + guard let self = self else { return } // expected-warning {{value 'self' was defined but never used; consider replacing with boolean test}} doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } @@ -896,8 +896,8 @@ public class TestImplicitSelfForWeakSelfCapture { method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } - doVoidStuff { [self] in - method() + doVoidStuff { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} + method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} self.method() } @@ -1229,24 +1229,24 @@ class TestGithubIssue70089 { doVoidStuff { [weak self] in guard let self else { return } - doVoidStuff { [self] in - x += 1 + doVoidStuff { [self] in // expected-warning {{capture 'self' was never used}} expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} } doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } - doVoidStuff { [self = TestGithubIssue70089()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} + doVoidStuff { [self = TestGithubIssue70089()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 - doVoidStuff { - x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + doVoidStuff { // expected-note {{'self' explicitly to enable implicit 'self' in this closure}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} self.x += 1 } - doVoidStuff { [self] in + doVoidStuff { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } @@ -1262,8 +1262,8 @@ class TestGithubIssue70089 { self?.method() } - doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} - doVoidStuff { + doVoidStuff { + doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} self.x += 1 } @@ -1271,29 +1271,29 @@ class TestGithubIssue70089 { doVoidStuff { [self] in doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} - x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} self.x += 1 } } doVoidStuff { - doVoidStuff { [self] in - x += 1 + doVoidStuff { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } } doVoidStuff { [weak self] in - doVoidStuff { - x += 1 // expected-error {{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note{{reference 'self?.' explicitly}} + doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} self?.x += 1 } } doVoidStuff { [weak self] in doVoidStuffNonEscaping { - x += 1 // expected-error {{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note{{reference 'self?.' explicitly}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self?.x += 1 } } @@ -1302,27 +1302,27 @@ class TestGithubIssue70089 { // Since this unwrapping is invalid, implicit self is disallowed in all nested closures: guard let self = self ?? TestGithubIssue70089.staticOptional else { return } - doVoidStuff { [self] in + doVoidStuff { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } doVoidStuffNonEscaping { - x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } - doVoidStuff { [self = TestGithubIssue70089()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} - doVoidStuff { [self] in + doVoidStuff { [self = TestGithubIssue70089()] in + doVoidStuff { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } doVoidStuff { [self] in - doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} - doVoidStuff { + doVoidStuff { + doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} self.x += 1 } @@ -1348,51 +1348,55 @@ class TestGithubIssue69911 { doVoidStuff { [weak self] in guard let self else { return } + // This stops being an error in Swift 6 mode. doVoidStuffNonEscaping { - x += 1 + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } + // This stops being an error in Swift 6 mode. doVoidStuffNonEscaping { doVoidStuffNonEscaping { - x += 1 + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } - doVoidStuff { [self] in + // This stops being an error in Swift 6 mode. + doVoidStuff { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} doVoidStuffNonEscaping { - x += 1 + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } + // This stops being an error in Swift 6 mode. doVoidStuffNonEscaping { [self] in doVoidStuffNonEscaping { [self] in - x += 1 + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } doVoidStuffNonEscaping { [weak self] in - doVoidStuffNonEscaping { // expected-note{{capture 'self' explicitly to enable implicit 'self' in this closure}} + doVoidStuffNonEscaping { guard let self else { return } - x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} + x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } - doVoidStuffNonEscaping { [self = TestGithubIssue69911()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} - x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + doVoidStuffNonEscaping { [self = TestGithubIssue69911()] in + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 - doVoidStuff { [self] in + doVoidStuff { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} x += 1 // expected-error{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } doVoidStuffNonEscaping { - x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } @@ -1408,33 +1412,33 @@ class TestGithubIssue69911 { guard let self = self ?? TestGithubIssue69911.staticOptional else { return } doVoidStuffNonEscaping { - x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } doVoidStuffNonEscaping { doVoidStuffNonEscaping { - x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } - doVoidStuff { [self] in + doVoidStuff { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} doVoidStuffNonEscaping { - x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } doVoidStuffNonEscaping { [self] in doVoidStuffNonEscaping { [self] in - x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } - doVoidStuffNonEscaping { [self = TestGithubIssue69911()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} - x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + doVoidStuffNonEscaping { [self = TestGithubIssue69911()] in + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } @@ -1443,9 +1447,9 @@ class TestGithubIssue69911 { self?.x += 1 } - doVoidStuffNonEscaping { [self = TestGithubIssue69911()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} + doVoidStuffNonEscaping { [self = TestGithubIssue69911()] in doVoidStuffNonEscaping { [self] in - x += 1 // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + x += 1 // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} self.x += 1 } } @@ -1456,7 +1460,7 @@ class TestGithubIssue69911 { doVoidStuff { [weak self] in self?.x += 1 guard let self else { return } - x += 1 // expected-warning{{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + x += 1 // This refers to the 'self' of the function self.x += 1 } } @@ -1477,7 +1481,7 @@ final class AutoclosureTests { withNonEscapingAutoclosure(bar()) withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} - doVoidStuff { [self] in + doVoidStuff { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} << This is a false positive withNonEscapingAutoclosure(bar()) withEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} @@ -1493,8 +1497,9 @@ final class AutoclosureTests { withNonEscapingAutoclosure(bar()) } + // NOTE: This is a false positive doVoidStuffNonEscaping { [self] in - withNonEscapingAutoclosure(bar()) + withNonEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} } doVoidStuff { @@ -1510,35 +1515,35 @@ final class AutoclosureTests { } } - doVoidStuff { [weak self] in + doVoidStuff { [weak self] in // expected-warning {{variable 'self' was written to, but never read}} withNonEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} } - doVoidStuff { [weak self] in + doVoidStuff { [weak self] in // expected-warning {{variable 'self' was written to, but never read}} withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } - doVoidStuff { [weak self] in - doVoidStuff { - withNonEscapingAutoclosure(bar()) // expected-error {{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note {{reference 'self?.' explicitly}} + doVoidStuff { [weak self] in // expected-warning {{variable 'self' was written to, but never read}} + doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} + withNonEscapingAutoclosure(bar()) // expected-error {{all to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } } - doVoidStuff { [weak self] in + doVoidStuff { [weak self] in // expected-warning {{variable 'self' was written to, but never read}} doVoidStuff { - withEscapingAutoclosure(bar()) // expected-error {{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note {{reference 'self?.' explicitly}} + withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } } doVoidStuff { [weak self] in - doVoidStuff { [self] in - withNonEscapingAutoclosure(bar()) // expected-error {{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note {{reference 'self?.' explicitly}} + doVoidStuff { [self] in // expected-warning {{capture 'self' was never used}} expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} + withNonEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} } } doVoidStuff { [weak self] in - doVoidStuff { [self] in - withEscapingAutoclosure(bar()) // expected-error {{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note {{reference 'self?.' explicitly}} + doVoidStuff { [self] in // expected-warning {{capture 'self' was never used}} + withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } } @@ -1546,18 +1551,18 @@ final class AutoclosureTests { guard let self else { return } withNonEscapingAutoclosure(bar()) - withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} + withEscapingAutoclosure(bar()) doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} withNonEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } doVoidStuffNonEscaping { - withNonEscapingAutoclosure(bar()) + withNonEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} } - doVoidStuffNonEscaping { [self] in - withNonEscapingAutoclosure(bar()) + doVoidStuffNonEscaping { [self] in // expected-warning {{capture 'self' was never used}} + withNonEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} } doVoidStuff { @@ -1568,14 +1573,14 @@ final class AutoclosureTests { withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } - doVoidStuffNonEscaping { [self] in - withEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} + doVoidStuffNonEscaping { [self] in // expected-warning {{capture 'self' was never used}} + withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } } doVoidStuff { [weak self] in - doVoidStuff { [self] in - guard let self else { return } + doVoidStuff { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} + guard let self else { return } // expected-warning {{value 'self' was defined but never used; consider replacing with boolean test}} method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} } } @@ -1589,36 +1594,36 @@ final class AutoclosureTests { doVoidStuff { [weak self] in let someOptional: Self? = Self() - var `self` = self ?? someOptional + var `self` = self ?? someOptional // expected-warning {{'self' was never mutated; consider changing to 'let' constant}} guard let self = self else { return } // This is not supposed to be permitted, but has been allowed since Swift 5.8, // so we have to continue allowing it to maintain source compatibility. - method() // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} + method() } - doVoidStuff { + doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} let someOptional: Self? = Self() - guard case let self = someOptional else { return } - method() // expected-error{{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note {{reference 'self?.' explicitly}} + guard case let self = someOptional else { return } // expected-warning {{immutable value 'self' was never used; consider replacing with '_' or removing it}} + method() // expected-error{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } // This isn't supposed to be accepted, but has been accepted since Swift 5.8 doVoidStuff { [weak self = x] in guard let self else { return } - method() // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} + method() } doVoidStuff { [weak self] in - doVoidStuff { [self] in - guard let self else { return } + doVoidStuff { [self] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} + guard let self else { return } // expected-warning {{value 'self' was defined but never used; consider replacing with boolean test}} method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} } } doVoidStuff { [weak self] in doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} - guard let self = self else { return } - method() // expected-error{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note{{reference 'self.' explicitly}} + guard let self = self else { return } // expected-warning {{value 'self' was defined but never used; consider replacing with boolean test}} + method() // expected-error{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } } } @@ -1630,36 +1635,36 @@ class TestInvalidRebindingOutsideOfClosure { func testInvalidRebindingCondition() { guard case let self = TestInvalidRebindingOutsideOfClosure() else { return } // expected-warning {{'guard' condition is always true, body is unreachable}} - doVoidStuff { [self] in // expected-note{{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} + doVoidStuff { [self] in // expected-note{{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-warning {{capture 'self' was never used}} method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} } // Allowed in Swift 5 mode for source compatibility: - doVoidStuffNonEscaping { [self] in // expected-note{{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}} + doVoidStuffNonEscaping { [self] in // expected-warning {{capture 'self' was never used}} + method() } doVoidStuff() { [weak self] in guard let self else { return } - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}} + method() } doVoidStuffNonEscaping() { [weak self] in guard let self else { return } - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}} + method() } doVoidStuff { [weak self] in guard let self = self else { return } - doVoidStuff { [self] in + doVoidStuff { [self] in // expected-warning {{capture 'self' was never used}} expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} } } doVoidStuffNonEscaping { [weak self] in guard let self = self else { return } - doVoidStuffNonEscaping { [self] in - method() // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}} + doVoidStuffNonEscaping { [self] in // expected-warning {{capture 'self' was never used}} + method() // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} } } } @@ -1667,46 +1672,46 @@ class TestInvalidRebindingOutsideOfClosure { func testInvalidSelfWithBackticks() { let `self` = TestInvalidRebindingOutsideOfClosure() - doVoidStuff { [self] in // expected-note{{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} + doVoidStuff { [self] in // expected-note{{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-warning {{capture 'self' was never used}} method() // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} } // Allowed in Swift 5 mode for source compatibility: - doVoidStuffNonEscaping { [self] in // expected-note{{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}} + doVoidStuffNonEscaping { [self] in // expected-warning {{capture 'self' was never used}} + method() } doVoidStuff() { [weak self] in guard let self else { return } - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}} + method() } doVoidStuffNonEscaping() { [weak self] in guard let self else { return } - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}} + method() } } func testInvalidSelfWithBackticks2() { let `self` = self - doVoidStuff { [self] in // expected-note{{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} + doVoidStuff { [self] in // expected-note{{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} expected-warning {{capture 'self' was never used}} method() // expected-error{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} } // Allowed in Swift 5 mode for source compatibility: - doVoidStuffNonEscaping { [self] in // expected-note{{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} + doVoidStuffNonEscaping { [self] in // expected-warning {{capture 'self' was never used}} + method() } doVoidStuff() { [weak self] in guard let self else { return } - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} + method() } doVoidStuffNonEscaping() { [weak self] in guard let self else { return } - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} + method() } } @@ -1717,18 +1722,18 @@ struct TestInvalidSelfCaptureInStruct { func bar() { // To maintain source compatibility, we continue allowing this in Swift 5 mode: - doVoidStuff { [self = TestInvalidSelfCaptureInStruct()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}} + doVoidStuff { [self = TestInvalidSelfCaptureInStruct()] in + method() // This refers to the 'self' of the function. self.method() } - doVoidStuffNonEscaping { [self = TestInvalidSelfCaptureInStruct()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}} + doVoidStuffNonEscaping { [self = TestInvalidSelfCaptureInStruct()] in + method() // This refers to the 'self' of the function. self.method() } - doVoidStuffNonEscaping { [self = TestInvalidSelfCaptureInStruct()] in // expected-note {{variable other than 'self' captured here under the name 'self' does not enable implicit 'self'}} - method() // expected-warning{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit; this is an error in the Swift 6 language mode}} + doVoidStuffNonEscaping { [self = TestInvalidSelfCaptureInStruct()] in + method() // This refers to the 'self' of the function. self.method() } } @@ -1752,3 +1757,38 @@ struct TestAsyncLetInStruct { } } } + +// rdar://129475277 +class rdar129475277 { + func bar() -> Int { 0 } + func method() {} + + func test1() { + takesEscapingWithAllowedImplicitSelf { [weak self] in // expected-warning {{variable 'self' was written to, but never read}} + takesEscapingWithAllowedImplicitSelf { + method() // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} + } + } + + takesEscapingWithAllowedImplicitSelf { [weak self] in // expected-warning {{variable 'self' was written to, but never read}} + takesEscapingWithAllowedImplicitSelf { + doVoidStuffNonEscaping { + withNonEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} + } + } + } + + takesEscapingWithAllowedImplicitSelf { [weak self] in // expected-warning {{variable 'self' was written to, but never read}} + withNonEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} + } + } + + func test2() { + guard case let self: rdar129475277? = nil else { return } + // expected-warning@-1 {{'guard' condition is always true, body is unreachable}} + // expected-warning@-2 {{immutable value 'self' was never used}} + doVoidStuffNonEscaping { + method() + } + } +} diff --git a/test/expr/closure/closures_swift6.swift b/test/expr/closure/closures_swift6.swift index f8c1f8b8c3700..8d2f43097ba89 100644 --- a/test/expr/closure/closures_swift6.swift +++ b/test/expr/closure/closures_swift6.swift @@ -181,6 +181,11 @@ public final class TestImplicitSelfForWeakSelfCapture: Sendable { method() self.method() } + + doVoidStuff { [self] in + method() + self.method() + } } doVoidStuffNonEscaping { [weak self] in @@ -805,3 +810,37 @@ struct TestInvalidSelfCaptureInStruct { } } } + +// rdar://129475277 +class rdar129475277 { + func bar() -> Int { 0 } + func method() {} + + func test1() { + takesEscapingWithAllowedImplicitSelf { [weak self] in + takesEscapingWithAllowedImplicitSelf { + method() // expected-error {{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note {{reference 'self?.' explicitly}} + } + } + + takesEscapingWithAllowedImplicitSelf { [weak self] in + takesEscapingWithAllowedImplicitSelf { + doVoidStuffNonEscaping { + withNonEscapingAutoclosure(bar()) // expected-error {{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note {{reference 'self?.' explicitly}} + } + } + } + + takesEscapingWithAllowedImplicitSelf { [weak self] in + withNonEscapingAutoclosure(bar()) // expected-error {{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note {{reference 'self?.' explicitly}} + } + } + + func test2() { + guard case let self: rdar129475277? = nil else { return } + // expected-warning@-1 {{'guard' condition is always true, body is unreachable}} + doVoidStuffNonEscaping { + method() // expected-error {{explicit use of 'self' is required when 'self' is optional, to make control flow explicit}} expected-note {{reference 'self?.' explicitly}} + } + } +} diff --git a/test/expr/closure/implicit_weak_capture.swift b/test/expr/closure/implicit_weak_capture.swift index 905854f779f14..96b7688a1f20e 100644 --- a/test/expr/closure/implicit_weak_capture.swift +++ b/test/expr/closure/implicit_weak_capture.swift @@ -1,4 +1,4 @@ -// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking) +// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking -swift-version 6) // REQUIRES: concurrency // REQUIRES: executable_test From 9769418dfa60f4284d11118f2c12e158e9d403b2 Mon Sep 17 00:00:00 2001 From: iMostafa Date: Sun, 9 Jun 2024 22:11:23 +0200 Subject: [PATCH 031/165] Better message diagnostics for inout `@escaping` closure --- include/swift/AST/DiagnosticsSema.def | 3 +++ lib/Sema/TypeCheckType.cpp | 4 ++++ test/attr/escaping_inout_arugment.swift | 7 +++++++ 3 files changed, 14 insertions(+) create mode 100644 test/attr/escaping_inout_arugment.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 2cf21b7d82ddc..f2d304605d306 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4015,6 +4015,9 @@ ERROR(autoclosure_function_input_nonunit,none, ERROR(escaping_non_function_parameter,none, "@escaping attribute may only be used in function parameter position", ()) +ERROR(escaping_inout_parameter,none, + "inout expression is implicitly escaping", ()) + ERROR(escaping_optional_type_argument, none, "closure is already escaping in optional type argument", ()) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 136d7b769ce33..671ebeff5a248 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -3393,6 +3393,10 @@ TypeResolver::resolveAttributedType(TypeRepr *repr, TypeResolutionOptions option diagnoseInvalid(repr, repr->getLoc(), diag::escaping_optional_type_argument) .fixItRemove(attrRange); + } else if (options.is(TypeResolverContext::InoutFunctionInput)) { + diagnoseInvalid(repr, repr->getLoc(), + diag::escaping_inout_parameter) + .fixItRemove(attrRange); } else { diagnoseInvalid(repr, loc, diag::escaping_non_function_parameter) .fixItRemove(attrRange); diff --git a/test/attr/escaping_inout_arugment.swift b/test/attr/escaping_inout_arugment.swift new file mode 100644 index 0000000000000..8f72298352de9 --- /dev/null +++ b/test/attr/escaping_inout_arugment.swift @@ -0,0 +1,7 @@ +// RUN: %target-typecheck-verify-swift + +let _: (_ v: inout @escaping () -> Void) -> () +// expected-error@-1 {{inout expression is implicitly escaping}}{{20-30=}} + +func m(v: inout @escaping () -> Void) {} +// expected-error@-1 {{inout expression is implicitly escaping}}{{17-27=}} From cab0eeed650a95c62f7c2bce677286f1caf68dde Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jun 2024 13:34:03 -0700 Subject: [PATCH 032/165] [embedded] Expand ABI docs on C/C++ interop --- docs/EmbeddedSwift/ABI.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/EmbeddedSwift/ABI.md b/docs/EmbeddedSwift/ABI.md index 857cdec8dd05c..d7046239ceef6 100644 --- a/docs/EmbeddedSwift/ABI.md +++ b/docs/EmbeddedSwift/ABI.md @@ -6,10 +6,18 @@ For an introduction and motivation into Embedded Swift, please see "[A Vision for Embedded Swift](https://github.com/apple/swift-evolution/blob/main/visions/embedded-swift.md)", a Swift Evolution document highlighting the main goals and approaches. +## ABI stability + +The ABI of code generated by Embedded Swift is not currently stable. For a concrete compiler version, it will be consistent, but do not mix code built with different compiler versions. + +Similarly, do not mix Embedded Swift code with full Swift code, as the ABIs are different. Details are described in the following sections. + ## Calling convention of Embedded Swift As of today, Embedded Swift has identical calling convention to full Swift. However, this does not need to continue in the future, and there should not be expectations that the ABI of Embedded Swift is compatible with full Swift. +The compiler respects the ABIs and calling conventions of C and C++ when interoperating with code in those languages. Calling C/C++ functions from Embedded Swift code is supported, and similarly exporting Swift code via `@_extern`, `@_cdecl` or `@_expose` will match the right calling conventions that C/C++ expects. + ## Metadata ABI of Embedded Swift Embedded Swift eliminates almost all metadata compared to full Swift. However, class metadata is still used, because those serve as vtables for dynamic dispatch of methods to implement runtime polymorphism. The layout of Embedded Swift's class metadata is *different* from full Swift: From 772e066238a2288b04af73b120ae905f3b16bf92 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 10 Jun 2024 13:38:32 -0700 Subject: [PATCH 033/165] [embedded] Add 'sorting strings' to the list of ops that need Unicode data tables --- docs/EmbeddedSwift/UserManual.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/EmbeddedSwift/UserManual.md b/docs/EmbeddedSwift/UserManual.md index b4d932d520b97..b91956ffdc555 100644 --- a/docs/EmbeddedSwift/UserManual.md +++ b/docs/EmbeddedSwift/UserManual.md @@ -136,6 +136,7 @@ $ ld ... -o binary output.o $(dirname `which swiftc`)/../lib/swift/embedded/armv **Unicode data tables are required for (list not exhaustive):** - Comparing String objects for equality +- Sorting Strings - Using String's hash values, and in particular using String as dictionary keys - Using String's .count property - Using Unicode-aware string processing APIs (.split(), iterating characters, indexing) From 5e1721dd4a6937803aca56659742a52fef6d8b28 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Thu, 23 May 2024 17:54:03 -0700 Subject: [PATCH 034/165] [embedded] Make Mirror present but unavailable --- stdlib/public/core/CMakeLists.txt | 4 ++-- stdlib/public/core/EmbeddedStubs.swift | 7 +++---- stdlib/public/core/KeyValuePairs.swift | 2 ++ stdlib/public/core/Mirror.swift | 1 + test/embedded/mirror.swift | 14 ++++++++++++++ 5 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 test/embedded/mirror.swift diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt index dbd8a572cc54c..fe3ee513a19f0 100644 --- a/stdlib/public/core/CMakeLists.txt +++ b/stdlib/public/core/CMakeLists.txt @@ -98,7 +98,7 @@ split_embedded_sources( EMBEDDED Integers.swift NORMAL Join.swift EMBEDDED KeyPath.swift - NORMAL KeyValuePairs.swift + EMBEDDED KeyValuePairs.swift EMBEDDED LazyCollection.swift EMBEDDED LazySequence.swift NORMAL LegacyABI.swift @@ -227,7 +227,7 @@ split_embedded_sources( EMBEDDED FloatingPointRandom.swift EMBEDDED Instant.swift EMBEDDED Int128.swift - NORMAL Mirror.swift + EMBEDDED Mirror.swift NORMAL PlaygroundDisplay.swift NORMAL CommandLine.swift EMBEDDED SliceBuffer.swift diff --git a/stdlib/public/core/EmbeddedStubs.swift b/stdlib/public/core/EmbeddedStubs.swift index 07e5dcc5cc33c..a11aa28565927 100644 --- a/stdlib/public/core/EmbeddedStubs.swift +++ b/stdlib/public/core/EmbeddedStubs.swift @@ -15,10 +15,9 @@ import SwiftShims /// String @_unavailableInEmbedded -extension String { - public init(describing instance: Subject) { fatalError() } - public init(reflecting instance: Subject) { fatalError() } -} +internal func _print_unlocked(_ value: T, _ target: inout String) { fatalError() } +@_unavailableInEmbedded +public func _debugPrint_unlocked(_ value: T, _ target: inout String) { fatalError() } /// Codable diff --git a/stdlib/public/core/KeyValuePairs.swift b/stdlib/public/core/KeyValuePairs.swift index 7e7e4704c07dd..b074ed0aab1fd 100644 --- a/stdlib/public/core/KeyValuePairs.swift +++ b/stdlib/public/core/KeyValuePairs.swift @@ -125,6 +125,7 @@ extension KeyValuePairs: RandomAccessCollection { } } +@_unavailableInEmbedded extension KeyValuePairs: CustomStringConvertible { /// A string that represents the contents of the dictionary. public var description: String { @@ -132,6 +133,7 @@ extension KeyValuePairs: CustomStringConvertible { } } +@_unavailableInEmbedded extension KeyValuePairs: CustomDebugStringConvertible { /// A string that represents the contents of the dictionary, suitable for /// debugging. diff --git a/stdlib/public/core/Mirror.swift b/stdlib/public/core/Mirror.swift index 42faa37a5cdfd..5d94615ac7463 100644 --- a/stdlib/public/core/Mirror.swift +++ b/stdlib/public/core/Mirror.swift @@ -538,6 +538,7 @@ extension Mirror { //===--- General Utilities ------------------------------------------------===// +@_unavailableInEmbedded extension String { /// Creates a string representing the given value. /// diff --git a/test/embedded/mirror.swift b/test/embedded/mirror.swift new file mode 100644 index 0000000000000..c0352c20cf74b --- /dev/null +++ b/test/embedded/mirror.swift @@ -0,0 +1,14 @@ +// RUN: %target-swift-emit-ir -verify %s -enable-experimental-feature Embedded -wmo + +// REQUIRES: swift_in_compiler +// REQUIRES: optimized_stdlib +// REQUIRES: OS=macosx || OS=linux-gnu + +public struct MyStruct { + var a, b, c: Int +} + +public func foo(s: MyStruct) { + let mirror = Mirror(reflecting: s) // expected-error {{'Mirror' is unavailable}} + _ = mirror.children +} \ No newline at end of file From 03e0cfdf7a405b7402e4096a45e3c4785521b5b0 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Mon, 10 Jun 2024 14:37:58 -0700 Subject: [PATCH 035/165] Run moveonly checker + TSAN tests in a separate file. TSAN is not supported on all targets, so covering TSAN in the same file as the core tests makes them unnecessarily nonportable. rdar://129286269 --- .../moveonly_addresschecker.swift | 2 - ...structure_through_deinit_diagnostics.swift | 1 - .../moveonly_addresschecker_diagnostics.swift | 1 - .../moveonly_addresschecker_tsan.swift | 38 +++++++++++++++++++ 4 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 test/SILOptimizer/moveonly_addresschecker_tsan.swift diff --git a/test/SILOptimizer/moveonly_addresschecker.swift b/test/SILOptimizer/moveonly_addresschecker.swift index 35c2c9ce2c336..8752373ccf3f9 100644 --- a/test/SILOptimizer/moveonly_addresschecker.swift +++ b/test/SILOptimizer/moveonly_addresschecker.swift @@ -1,7 +1,5 @@ // RUN: %target-swift-emit-sil -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses %s -Xllvm -sil-print-final-ossa-module | %FileCheck %s // RUN: %target-swift-emit-sil -O -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses %s -// RUN: %target-swift-emit-sil -sanitize=thread -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses %s -Xllvm -sil-print-final-ossa-module | %FileCheck %s -// RUN: %target-swift-emit-sil -sanitize=thread -O -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses %s // This file contains tests that used to crash due to verifier errors. It must // be separate from moveonly_addresschecker_diagnostics since when we fail on diff --git a/test/SILOptimizer/moveonly_addresschecker_destructure_through_deinit_diagnostics.swift b/test/SILOptimizer/moveonly_addresschecker_destructure_through_deinit_diagnostics.swift index f4982dbcf2e16..bb16dcbe55fb8 100644 --- a/test/SILOptimizer/moveonly_addresschecker_destructure_through_deinit_diagnostics.swift +++ b/test/SILOptimizer/moveonly_addresschecker_destructure_through_deinit_diagnostics.swift @@ -1,5 +1,4 @@ // RUN: %target-swift-emit-sil -sil-verify-all -verify -enable-experimental-feature MoveOnlyClasses -enable-experimental-feature MoveOnlyTuples %s -// RUN: %target-swift-emit-sil -sanitize=thread -sil-verify-all -verify -enable-experimental-feature MoveOnlyClasses -enable-experimental-feature MoveOnlyTuples %s // This test validates that we properly emit errors if we partially invalidate // through a type with a deinit. diff --git a/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift b/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift index b7bdb08ad92f6..d3e49974c1a30 100644 --- a/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift +++ b/test/SILOptimizer/moveonly_addresschecker_diagnostics.swift @@ -1,5 +1,4 @@ // RUN: %target-swift-emit-sil %s -O -sil-verify-all -verify -enable-experimental-feature MoveOnlyPartialReinitialization -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses -// RUN: %target-swift-emit-sil -sanitize=thread %s -O -sil-verify-all -verify -enable-experimental-feature MoveOnlyPartialReinitialization -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses ////////////////// // Declarations // diff --git a/test/SILOptimizer/moveonly_addresschecker_tsan.swift b/test/SILOptimizer/moveonly_addresschecker_tsan.swift new file mode 100644 index 0000000000000..81e20f9f083ad --- /dev/null +++ b/test/SILOptimizer/moveonly_addresschecker_tsan.swift @@ -0,0 +1,38 @@ +// RUN: %target-swift-emit-sil -sanitize=thread -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses %s -Xllvm -sil-print-final-ossa-module | %FileCheck %s +// RUN: %target-swift-emit-sil -sanitize=thread -O -sil-verify-all -verify -enable-experimental-feature NoImplicitCopy -enable-experimental-feature MoveOnlyClasses %s +// REQUIRES: OS=macOS + +// This file contains tests that used to crash due to verifier errors. It must +// be separate from moveonly_addresschecker_diagnostics since when we fail on +// the diagnostics in that file, we do not actually run the verifier. + +struct TestTrivialReturnValue : ~Copyable { + var i: Int = 5 + + // We used to error on return buffer. + consuming func drain() -> Int { + let buffer = (consume self).i + self = .init(i: 5) + return buffer + } +} + + +////////////////////// +// MARK: Misc Tests // +////////////////////// + +func testAssertLikeUseDifferentBits() { + struct S : ~Copyable { + var s: [Int] = [] + var currentPosition = 5 + + // CHECK-LABEL: sil private @$s23moveonly_addresschecker30testAssertLikeUseDifferentBitsyyF1SL_V6resume2atySi_tF : $@convention(method) (Int, @inout S) -> () { + // CHECK-NOT: destroy_addr + // CHECK: } // end sil function '$s23moveonly_addresschecker30testAssertLikeUseDifferentBitsyyF1SL_V6resume2atySi_tF' + mutating func resume(at index: Int) { + assert(index >= currentPosition) + currentPosition = index + } + } +} From 1407980f6680b87fbe8a714547bfa18d27159729 Mon Sep 17 00:00:00 2001 From: Jeremy Schonfeld <1004103+jmschonfeld@users.noreply.github.com> Date: Mon, 10 Jun 2024 15:33:11 -0700 Subject: [PATCH 036/165] Don't pass foundation build path to swift-driver/swift-package-manager (#74217) --- .../swift_build_support/products/swiftdriver.py | 8 -------- .../swift_build_support/products/swiftpm.py | 9 --------- 2 files changed, 17 deletions(-) diff --git a/utils/swift_build_support/swift_build_support/products/swiftdriver.py b/utils/swift_build_support/swift_build_support/products/swiftdriver.py index 14363fc59f796..ff3e0f02506af 100644 --- a/utils/swift_build_support/swift_build_support/products/swiftdriver.py +++ b/utils/swift_build_support/swift_build_support/products/swiftdriver.py @@ -92,10 +92,6 @@ def run_build_script_helper(action, host_target, product, args): dispatch_build_dir = os.path.join( build_root, '%s-%s' % ('libdispatch', host_target)) - # Pass Foundation directory down if we built it - foundation_build_dir = os.path.join( - build_root, '%s-%s' % ('foundation', host_target)) - # Pass the swift lit tests if we're testing and the Swift tests were built swift_build_dir = os.path.join( build_root, 'swift-{}'.format(host_target)) @@ -118,10 +114,6 @@ def run_build_script_helper(action, host_target, product, args): helper_cmd += [ '--dispatch-build-dir', dispatch_build_dir ] - if os.path.exists(foundation_build_dir): - helper_cmd += [ - '--foundation-build-dir', foundation_build_dir - ] if os.path.exists(lit_test_dir) and action == 'test': helper_cmd += [ '--lit-test-dir', lit_test_dir diff --git a/utils/swift_build_support/swift_build_support/products/swiftpm.py b/utils/swift_build_support/swift_build_support/products/swiftpm.py index 6c698d22b58bd..c9024e64bdaab 100644 --- a/utils/swift_build_support/swift_build_support/products/swiftpm.py +++ b/utils/swift_build_support/swift_build_support/products/swiftpm.py @@ -84,15 +84,6 @@ def run_bootstrap_script(self, action, host_target, additional_params=[]): "--dispatch-build-dir", dispatch_build_dir ] - # Pass Foundation directory down if we built it - foundation_build_dir = os.path.join( - build_root, '%s-%s' % ("foundation", host_target)) - - if os.path.exists(foundation_build_dir): - helper_cmd += [ - "--foundation-build-dir", foundation_build_dir - ] - # Pass Cross compile host info if self.has_cross_compile_hosts(): if self.is_darwin_host(host_target): From 6a11171755c917532fd3ff2b4b38cf2057beaca9 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 11 Jun 2024 00:52:28 +0000 Subject: [PATCH 037/165] [ModuleInterface] Save `-public-autolink-library` module option Serialize the `-public-autolink-library ` option to the moduleinterface file because it can affect the LINK_LIBRARY entries in a swiftmodule file. Without saving the option, the library won't be linked when a module compiled from the moduleinterface is used. This change marks the `-public-autolink-library` option as a module interface option and reads it when building a swiftmodule by module loader. --- include/swift/Option/FrontendOptions.td | 7 ++++--- lib/Frontend/ModuleInterfaceBuilder.cpp | 2 ++ test/ModuleInterface/public-autolink-library.swift | 6 ++++++ 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 test/ModuleInterface/public-autolink-library.swift diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 1cbcc3e8a4341..2dc7e18b04240 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -207,9 +207,6 @@ def no_serialize_debugging_options : def autolink_library : Separate<["-"], "autolink-library">, HelpText<"Add dependent library">, Flags<[FrontendOption]>; -def public_autolink_library : Separate<["-"], "public-autolink-library">, - HelpText<"Add public dependent library">, Flags<[FrontendOption]>; - def disable_typo_correction : Flag<["-"], "disable-typo-correction">, HelpText<"Disable typo correction">; @@ -369,6 +366,10 @@ def enable_resilience : Flag<["-"], "enable-resilience">, def enable_experimental_async_top_level : Flag<["-"], "enable-experimental-async-top-level">, HelpText<"Enable experimental concurrency in top-level code">; + +def public_autolink_library : + Separate<["-"], "public-autolink-library">, + HelpText<"Add public dependent library">; } // HIDDEN FLAGS diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 23b7a496d1853..632b04008826f 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -276,6 +276,8 @@ std::error_code ExplicitModuleInterfaceBuilder::buildSwiftModuleFromInterface( SerializationOpts.ModuleLinkName = FEOpts.ModuleLinkName; SerializationOpts.AutolinkForceLoad = !Invocation.getIRGenOptions().ForceLoadSymbolName.empty(); + SerializationOpts.PublicDependentLibraries = + Invocation.getIRGenOptions().PublicLinkLibraries; SerializationOpts.UserModuleVersion = FEOpts.UserModuleVersion; SerializationOpts.AllowableClients = FEOpts.AllowableClients; StringRef SDKPath = Instance.getASTContext().SearchPathOpts.getSDKPath(); diff --git a/test/ModuleInterface/public-autolink-library.swift b/test/ModuleInterface/public-autolink-library.swift new file mode 100644 index 0000000000000..e19e02256a617 --- /dev/null +++ b/test/ModuleInterface/public-autolink-library.swift @@ -0,0 +1,6 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -typecheck -module-name Foo -emit-module-interface-path %t/Foo.swiftinterface %s -module-link-name Foo -enable-library-evolution -public-autolink-library Bar +// RUN: %target-swift-frontend -compile-module-from-interface -o %t/Foo.swiftmodule %t/Foo.swiftinterface +// RUN: %target-swift-ide-test -print-module-metadata -module-to-print Foo -I %t -source-filename %s | %FileCheck %s + +// CHECK: link library: Bar From 8848a52faeb42350b3063ea6d2c4068c43c507c9 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Mon, 10 Jun 2024 22:30:51 +0900 Subject: [PATCH 038/165] [Concurrency] CaseIterable synthesized allCases must be nonisolated --- lib/Sema/DerivedConformanceCaseIterable.cpp | 5 +++++ test/Concurrency/CaseIterableIsolation.swift | 21 +++++++++++++++++++ .../SILGen/synthesized_conformance_enum.swift | 1 + test/stdlib/CaseIterableTests.swift | 11 ++++++++++ 4 files changed, 38 insertions(+) create mode 100644 test/Concurrency/CaseIterableIsolation.swift diff --git a/lib/Sema/DerivedConformanceCaseIterable.cpp b/lib/Sema/DerivedConformanceCaseIterable.cpp index 9f92ab7717989..8681c0b268f78 100644 --- a/lib/Sema/DerivedConformanceCaseIterable.cpp +++ b/lib/Sema/DerivedConformanceCaseIterable.cpp @@ -79,6 +79,8 @@ static Type deriveCaseIterable_AllCases(DerivedConformance &derived) { } ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) { + auto &C = requirement->getASTContext(); + // Conformance can't be synthesized in an extension. if (checkAndDiagnoseDisallowedContext(requirement)) return nullptr; @@ -102,6 +104,9 @@ ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) { SynthesizedIntroducer::Var, Context.Id_allCases, returnTy, returnTy, /*isStatic=*/true, /*isFinal=*/true); + propDecl->getAttrs().add( + new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true)); + // Define the getter. auto *getterDecl = addGetterToReadOnlyDerivedProperty(propDecl, returnTy); diff --git a/test/Concurrency/CaseIterableIsolation.swift b/test/Concurrency/CaseIterableIsolation.swift new file mode 100644 index 0000000000000..9bbcfbf32b9f4 --- /dev/null +++ b/test/Concurrency/CaseIterableIsolation.swift @@ -0,0 +1,21 @@ +// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete +// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -enable-upcoming-feature RegionBasedIsolation + +// REQUIRES: executable_test +// REQUIRES: concurrency + +import StdlibUnittest + +var CaseIterableTests = TestSuite("CaseIterableTests") + +CaseIterableTests.test("MainActor Isolated Enums") { + @MainActor + enum EnumMainActor: CaseIterable { + case a, b + } + + expectEqual(EnumMainActor.allCases.count, 2) + expectEqual(EnumMainActor.allCases, [.a, .b]) +} + +runAllTests() diff --git a/test/SILGen/synthesized_conformance_enum.swift b/test/SILGen/synthesized_conformance_enum.swift index f1bf4d753777f..c168af1dea93b 100644 --- a/test/SILGen/synthesized_conformance_enum.swift +++ b/test/SILGen/synthesized_conformance_enum.swift @@ -56,6 +56,7 @@ extension Enum: Codable where T: Codable {} extension NoValues: CaseIterable {} // CHECK-LABEL: // static NoValues.allCases.getter +// CHECK-NEXT: // Isolation: nonisolated // CHECK-NEXT: sil hidden [ossa] @$s28synthesized_conformance_enum8NoValuesO8allCasesSayACGvgZ : $@convention(method) (@thin NoValues.Type) -> @owned Array { extension NoValues: Codable {} diff --git a/test/stdlib/CaseIterableTests.swift b/test/stdlib/CaseIterableTests.swift index 0e10bbbc21c63..687357938612e 100644 --- a/test/stdlib/CaseIterableTests.swift +++ b/test/stdlib/CaseIterableTests.swift @@ -1,5 +1,6 @@ // RUN: %target-run-simple-swift %t // REQUIRES: executable_test +// REQUIRES: concurrency import StdlibUnittest @@ -16,4 +17,14 @@ CaseIterableTests.test("Simple Enums") { expectEqual(SimpleEnum.allCases, [.bar, .baz, .quux]) } +CaseIterableTests.test("MainActor Isolated Enums") { + @MainActor + enum EnumMainActor: CaseIterable { + case a, b + } + + expectEqual(EnumMainActor.allCases.count, 2) + expectEqual(EnumMainActor.allCases, [.a, .b]) +} + runAllTests() From 12f402f7157d427746be0217fea0bbd9b8b4a72a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 11 Jun 2024 09:24:19 +0100 Subject: [PATCH 039/165] Revert "[AutoDiff] Fix custom derivative thunk for Optional (#71721)" (#74268) This reverts commit aa5dddb9529c57f4b573e50747cec03e23220cd0. Fixes `preset=buildbot,tools=RA,stdlib=DA` CI job, which without this revert fails on `AutoDiff/SILGen/nil_coalescing.swift` test. --- lib/SILGen/SILGenPoly.cpp | 9 ++---- .../Mandatory/Differentiation.cpp | 29 +++++++------------ test/AutoDiff/SILGen/nil_coalescing.swift | 25 ---------------- 3 files changed, 14 insertions(+), 49 deletions(-) delete mode 100644 test/AutoDiff/SILGen/nil_coalescing.swift diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 176b50f8df41f..09d95256b66fe 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -6347,13 +6347,10 @@ SILFunction *SILGenModule::getOrCreateCustomDerivativeThunk( arguments.push_back(indErrorRes.getLValueAddress()); forwardFunctionArguments(thunkSGF, loc, fnRefType, params, arguments); - SubstitutionMap subs = thunk->getForwardingSubstitutionMap(); - SILType substFnType = fnRef->getType().substGenericArgs( - M, subs, thunk->getTypeExpansionContext()); - // Apply function argument. - auto apply = - thunkSGF.emitApplyWithRethrow(loc, fnRef, substFnType, subs, arguments); + auto apply = thunkSGF.emitApplyWithRethrow( + loc, fnRef, /*substFnType*/ fnRef->getType(), + thunk->getForwardingSubstitutionMap(), arguments); // Self reordering thunk is necessary if wrt at least two parameters, // including self. diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index 3584fba568a3c..b8251eccfdd09 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -906,15 +906,6 @@ bool DifferentiationTransformer::canonicalizeDifferentiabilityWitness( traceMessage.c_str(), witness->getOriginalFunction()); assert(witness->isDefinition()); - SILFunction *orig = witness->getOriginalFunction(); - - // We can generate empty JVP / VJP for functions available externally. These - // functions have the same linkage as the original ones sans `external` - // flag. Important exception here hidden_external functions as they are - // serializable but corresponding hidden ones would be not and the SIL - // verifier will fail. Patch `serializeFunctions` for this case. - if (orig->getLinkage() == SILLinkage::HiddenExternal) - serializeFunctions = IsNotSerialized; // If the JVP doesn't exist, need to synthesize it. if (!witness->getJVP()) { @@ -923,8 +914,9 @@ bool DifferentiationTransformer::canonicalizeDifferentiabilityWitness( // - Functions with unsupported control flow. if (context.getASTContext() .LangOpts.hasFeature(Feature::ForwardModeDifferentiation) && - (diagnoseNoReturn(context, orig, invoker) || - diagnoseUnsupportedControlFlow(context, orig, invoker))) + (diagnoseNoReturn(context, witness->getOriginalFunction(), invoker) || + diagnoseUnsupportedControlFlow( + context, witness->getOriginalFunction(), invoker))) return true; // Create empty JVP. @@ -941,10 +933,10 @@ bool DifferentiationTransformer::canonicalizeDifferentiabilityWitness( !witness->getVJP()) { // JVP and differential generation do not currently support functions with // multiple basic blocks. - if (orig->size() > 1) { - context.emitNondifferentiabilityError(orig->getLocation().getSourceLoc(), - invoker, - diag::autodiff_jvp_control_flow_not_supported); + if (witness->getOriginalFunction()->size() > 1) { + context.emitNondifferentiabilityError( + witness->getOriginalFunction()->getLocation().getSourceLoc(), + invoker, diag::autodiff_jvp_control_flow_not_supported); return true; } // Emit JVP function. @@ -958,7 +950,7 @@ bool DifferentiationTransformer::canonicalizeDifferentiabilityWitness( "_fatalErrorForwardModeDifferentiationDisabled"); LLVM_DEBUG(getADDebugStream() << "Generated empty JVP for " - << orig->getName() << ":\n" + << witness->getOriginalFunction()->getName() << ":\n" << *jvp); } } @@ -968,8 +960,9 @@ bool DifferentiationTransformer::canonicalizeDifferentiabilityWitness( // Diagnose: // - Functions with no return. // - Functions with unsupported control flow. - if (diagnoseNoReturn(context, orig, invoker) || - diagnoseUnsupportedControlFlow(context, orig, invoker)) + if (diagnoseNoReturn(context, witness->getOriginalFunction(), invoker) || + diagnoseUnsupportedControlFlow( + context, witness->getOriginalFunction(), invoker)) return true; // Create empty VJP. diff --git a/test/AutoDiff/SILGen/nil_coalescing.swift b/test/AutoDiff/SILGen/nil_coalescing.swift deleted file mode 100644 index 994fbeed691fa..0000000000000 --- a/test/AutoDiff/SILGen/nil_coalescing.swift +++ /dev/null @@ -1,25 +0,0 @@ -// RUN: %target-swift-frontend -emit-sil -verify %s | %FileCheck %s - -import _Differentiation - -// CHECK: sil @test_nil_coalescing -// CHECK: bb0(%{{.*}} : $*T, %[[ARG_OPT:.*]] : $*Optional, %[[ARG_PB:.*]] : -// CHECK: $@noescape @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for ): -// CHECK: %[[ALLOC_OPT:.*]] = alloc_stack [lexical] $Optional -// CHECK: copy_addr %[[ARG_OPT]] to [init] %[[ALLOC_OPT]] : $*Optional -// CHECK: switch_enum_addr %[[ALLOC_OPT]] : $*Optional, case #Optional.some!enumelt: {{.*}}, case #Optional.none!enumelt: {{.*}} -// CHECK: try_apply %[[ARG_PB]](%{{.*}}) : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for , normal {{.*}}, error {{.*}} -// -@_silgen_name("test_nil_coalescing") -@derivative(of: ??) -@usableFromInline -func nilCoalescing(optional: T?, defaultValue: @autoclosure () throws -> T) - rethrows -> (value: T, pullback: (T.TangentVector) -> Optional.TangentVector) -{ - let hasValue = optional != nil - let value = try optional ?? defaultValue() - func pullback(_ v: T.TangentVector) -> Optional.TangentVector { - return hasValue ? .init(v) : .zero - } - return (value, pullback) -} From 353f0608f9d1a9a4164456c116f478b60dcecf2d Mon Sep 17 00:00:00 2001 From: Gabor Horvath Date: Tue, 11 Jun 2024 11:43:02 +0100 Subject: [PATCH 040/165] [cxx-interop] Fix unavailable generics triggering compilation error In some cases, the reverse interop generated both a forward declaration and a definition with unavailable attribute in the C++ header. Unfortunately, the kinds of these symbol did not match. The forward declaration was templated while the definition was not. The forward declaration has the correct kind, so this patch extends the printing of unavailable definitions to include the generic arguments. rdar://119835933 --- lib/PrintAsClang/ModuleContentsWriter.cpp | 5 ++ .../unsupported-generics-in-cxx.swift | 46 ++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/PrintAsClang/ModuleContentsWriter.cpp b/lib/PrintAsClang/ModuleContentsWriter.cpp index 1bc8e55811ced..f554639b1f7a1 100644 --- a/lib/PrintAsClang/ModuleContentsWriter.cpp +++ b/lib/PrintAsClang/ModuleContentsWriter.cpp @@ -874,6 +874,11 @@ class ModuleWriter { // Emit an unavailable stub for a Swift type. if (auto *nmtd = dyn_cast(vd)) { auto representation = cxx_translation::getDeclRepresentation(vd); + if (nmtd->isGeneric()) { + auto genericSignature = + nmtd->getGenericSignature().getCanonicalSignature(); + ClangSyntaxPrinter(os).printGenericSignature(genericSignature); + } os << "class "; ClangSyntaxPrinter(os).printBaseName(vd); os << " { } SWIFT_UNAVAILABLE_MSG(\""; diff --git a/test/Interop/SwiftToCxx/unsupported/unsupported-generics-in-cxx.swift b/test/Interop/SwiftToCxx/unsupported/unsupported-generics-in-cxx.swift index a3b9dbb9a9f5d..b0f3d8eadb75b 100644 --- a/test/Interop/SwiftToCxx/unsupported/unsupported-generics-in-cxx.swift +++ b/test/Interop/SwiftToCxx/unsupported/unsupported-generics-in-cxx.swift @@ -47,17 +47,61 @@ public class Class1 { public var index1: Struct1 { .init(rawValue: 123) } } +public struct GlyphIndex { + private var value: IntType + + init(value: IntType) { + self.value = value + } +} + +public struct QueryResult { + public var glyphIDs: [GlyphIndex] +} + +public func makeQueryResult() -> QueryResult { .init(glyphIDs: []) } + // CHECK: supported // CHECK: class SWIFT_SYMBOL("s:5Decls6Class1C") Class1 : public swift::_impl::RefCountedClass { // CHECK: 'index1' cannot be printed +// CHECK: namespace Decls SWIFT_PRIVATE_ATTR SWIFT_SYMBOL_MODULE("Decls") { +// CHECK: namespace Decls SWIFT_PRIVATE_ATTR SWIFT_SYMBOL_MODULE("Decls") { +// CHECK: SWIFT_INLINE_THUNK void supportedFunc(const T_0_0& x) noexcept SWIFT_SYMBOL("s:5Decls13supportedFuncyyxlF") { + +// CHECK: template +// CHECK-NEXT: #ifdef __cpp_concepts +// CHECK-NEXT: requires swift::isUsableInGenericContext +// CHECK-NEXT: #endif // __cpp_concepts +// CHECK-NEXT: class GlyphIndex { } SWIFT_UNAVAILABLE_MSG("generic requirements for generic struct 'GlyphIndex' can not yet be represented in C++"); + +// CHECK: class Proto { } SWIFT_UNAVAILABLE_MSG("protocol 'Proto' can not yet be represented in C++"); + +// CHECK: template +// CHECK-NEXT: #ifdef __cpp_concepts +// CHECK-NEXT: requires swift::isUsableInGenericContext +// CHECK-NEXT: #endif // __cpp_concepts +// CHECK-NEXT: class QueryResult { } SWIFT_UNAVAILABLE_MSG("generic requirements for generic struct 'QueryResult' can not yet be represented in C++"); + // CHECK: class Struct1 { } SWIFT_UNAVAILABLE_MSG("generic requirements for generic struct 'Struct1' can not yet be represented in C++"); // CHECK: // Unavailable in C++: Swift global function 'unsupportedFunc(_:)'. -// CHECK: class unsupportedGenericClass { } SWIFT_UNAVAILABLE_MSG("generic generic class 'unsupportedGenericClass' can not yet be exposed to C++"); +// CHECK: template +// CHECK-NEXT: #ifdef __cpp_concepts +// CHECK-NEXT: requires swift::isUsableInGenericContext +// CHECK-NEXT: #endif // __cpp_concepts +// CHECK-NEXT: class unsupportedGenericClass { } SWIFT_UNAVAILABLE_MSG("generic generic class 'unsupportedGenericClass' can not yet be exposed to C++"); // CHECK-EMPTY: +// CHECK-NEXT: template +// CHECK-NEXT: #ifdef __cpp_concepts +// CHECK-NEXT: requires swift::isUsableInGenericContext +// CHECK-NEXT: #endif // __cpp_concepts // CHECK-NEXT: class unsupportedGenericEnum { } SWIFT_UNAVAILABLE_MSG("generic requirements for generic enum 'unsupportedGenericEnum' can not yet be represented in C++"); // CHECK-EMPTY: +// CHECK-NEXT: template +// CHECK-NEXT: #ifdef __cpp_concepts +// CHECK-NEXT: requires swift::isUsableInGenericContext +// CHECK-NEXT: #endif // __cpp_concepts // CHECK-NEXT: class unsupportedGenericStruct { } SWIFT_UNAVAILABLE_MSG("generic requirements for generic struct 'unsupportedGenericStruct' can not yet be represented in C++"); From 0211fd7025b348a5e4f3ef70997372e9bfef9b50 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Jun 2024 17:39:25 -0400 Subject: [PATCH 041/165] AST: Make absence of discriminator into a fatal error ... even in noassert builds. This is always a miscompile and should be prevented. --- lib/AST/Expr.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 456e4738082f4..81657539820ea 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1934,7 +1934,12 @@ unsigned AbstractClosureExpr::getDiscriminator() const { Bits.AbstractClosureExpr.Discriminator = discriminator; } - assert(getRawDiscriminator() != InvalidDiscriminator); + if (getRawDiscriminator() == InvalidDiscriminator) { + llvm::errs() << "Closure does not have an assigned discriminator:\n"; + dump(llvm::errs()); + abort(); + } + return getRawDiscriminator(); } From 02e3b5a2e061a220334bf9aef9ad63972c96589c Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 10 Jun 2024 11:01:00 -0400 Subject: [PATCH 042/165] Sema: Remove unused variable --- lib/Sema/CSApply.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index c9ece81dcf7e2..618edb7c5503f 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5557,7 +5557,6 @@ namespace { assert(OpenedExistentials.empty()); auto &ctx = cs.getASTContext(); - auto *module = dc->getParentModule(); // Look at all of the suspicious optional injections for (auto injection : SuspiciousOptionalInjections) { From 322ce5a1ab238d55d09a393bd9e2cae72f6979eb Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 10 Jun 2024 10:56:07 -0400 Subject: [PATCH 043/165] SIL: Consistently drop substitution map when forming apply instructions Fixes rdar://129298104. --- include/swift/SIL/SILInstruction.h | 2 + lib/SILGen/SILGenApply.cpp | 10 +++++ lib/SILGen/SILGenDestructor.cpp | 14 +++++-- lib/SILGen/SILGenFunction.cpp | 8 +++- ...formance-annotations-noassert-stdlib.swift | 9 +++++ .../performance-annotations.swift | 40 ++++++++++++++++--- 6 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 test/SILOptimizer/performance-annotations-noassert-stdlib.swift diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 4d382b579de2d..eca51e2637680 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -2678,6 +2678,8 @@ class ApplyInstBase : public Base { SpecializationInfo(specializationInfo), NumCallArguments(args.size()), NumTypeDependentOperands(typeDependentOperands.size()), Substitutions(subs) { + assert(!!subs == !!callee->getType().castTo() + ->getInvocationGenericSignature()); // Initialize the operands. auto allOperands = getAllOperands(); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 9f042f04451c0..f4f0c292e110f 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -1886,6 +1886,11 @@ static void emitRawApply(SILGenFunction &SGF, SILValue indirectErrorAddr, SmallVectorImpl &rawResults, ExecutorBreadcrumb prevExecutor) { + // We completely drop the generic signature if all generic parameters were + // concrete. + if (subs && subs.getGenericSignature()->areAllParamsConcrete()) + subs = SubstitutionMap(); + SILFunctionConventions substFnConv(substFnType, SGF.SGM.M); // Get the callee value. bool isConsumed = substFnType->isCalleeConsumed(); @@ -5857,6 +5862,11 @@ SILValue SILGenFunction::emitApplyWithRethrow(SILLocation loc, SILValue fn, SILType substFnType, SubstitutionMap subs, ArrayRef args) { + // We completely drop the generic signature if all generic parameters were + // concrete. + if (subs && subs.getGenericSignature()->areAllParamsConcrete()) + subs = SubstitutionMap(); + CanSILFunctionType silFnType = substFnType.castTo(); SILFunctionConventions fnConv(silFnType, SGM.M); SILType resultType = fnConv.getSILResultType(getTypeExpansionContext()); diff --git a/lib/SILGen/SILGenDestructor.cpp b/lib/SILGen/SILGenDestructor.cpp index 0fe3d83a5d88c..b8cb75c75f43f 100644 --- a/lib/SILGen/SILGenDestructor.cpp +++ b/lib/SILGen/SILGenDestructor.cpp @@ -118,9 +118,16 @@ void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) { SILValue baseSelf = B.createUpcast(cleanupLoc, selfValue, baseSILTy); ManagedValue dtorValue; SILType dtorTy; + auto subMap = superclassTy->getContextSubstitutionMap(SGM.M.getSwiftModule(), superclass); + + // We completely drop the generic signature if all generic parameters were + // concrete. + if (subMap && subMap.getGenericSignature()->areAllParamsConcrete()) + subMap = SubstitutionMap(); + std::tie(dtorValue, dtorTy) = emitSiblingMethodRef(cleanupLoc, baseSelf, dtorConstant, subMap); @@ -191,12 +198,11 @@ void SILGenFunction::emitDeallocatingClassDestructor(DestructorDecl *dd) { // Form a reference to the destroying destructor. SILDeclRef dtorConstant(dd, SILDeclRef::Kind::Destroyer); auto classTy = initialSelfValue->getType(); - auto classDecl = classTy.getASTType()->getAnyNominal(); + + auto subMap = F.getForwardingSubstitutionMap(); + ManagedValue dtorValue; SILType dtorTy; - auto subMap = classTy.getASTType() - ->getContextSubstitutionMap(SGM.M.getSwiftModule(), - classDecl); std::tie(dtorValue, dtorTy) = emitSiblingMethodRef(loc, initialSelfValue, dtorConstant, subMap); diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 3a8e90bf1dcd2..de405a05206a1 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -987,7 +987,13 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, constant, loweredCaptureInfo, subs); } - if (subs) { + // We completely drop the generic signature if all generic parameters were + // concrete. + if (!pft->isPolymorphic()) { + subs = SubstitutionMap(); + } else { + assert(!subs.getGenericSignature()->areAllParamsConcrete()); + auto specialized = pft->substGenericArgs(F.getModule(), subs, getTypeExpansionContext()); functionTy = SILType::getPrimitiveObjectType(specialized); diff --git a/test/SILOptimizer/performance-annotations-noassert-stdlib.swift b/test/SILOptimizer/performance-annotations-noassert-stdlib.swift new file mode 100644 index 0000000000000..afab1348fb0af --- /dev/null +++ b/test/SILOptimizer/performance-annotations-noassert-stdlib.swift @@ -0,0 +1,9 @@ +// RUN: %target-swift-frontend -parse-as-library -disable-availability-checking -import-objc-header %S/Inputs/perf-annotations.h -emit-sil %s -o /dev/null -verify + +// REQUIRES: swift_in_compiler +// REQUIRES: swift_stdlib_no_asserts,optimized_stdlib + +@_noAllocation +func createEmptyArray() { + _ = [Int]() // expected-error {{ending the lifetime of a value of type}} +} \ No newline at end of file diff --git a/test/SILOptimizer/performance-annotations.swift b/test/SILOptimizer/performance-annotations.swift index 1184ff7d7167e..9df98be9d8a8f 100644 --- a/test/SILOptimizer/performance-annotations.swift +++ b/test/SILOptimizer/performance-annotations.swift @@ -1,6 +1,7 @@ // RUN: %target-swift-frontend -parse-as-library -disable-availability-checking -enable-experimental-feature RawLayout -import-objc-header %S/Inputs/perf-annotations.h -emit-sil %s -o /dev/null -verify -// REQUIRES: swift_stdlib_no_asserts,optimized_stdlib + // REQUIRES: swift_in_compiler +// REQUIRES: optimized_stdlib protocol P { func protoMethod(_ a: Int) -> Int @@ -233,11 +234,6 @@ func closueWhichModifiesLocalVar() -> Int { return x } -@_noAllocation -func createEmptyArray() { - _ = [Int]() // expected-error {{ending the lifetime of a value of type}} -} - struct Buffer { var p: UnsafeMutableRawBufferPointer @@ -527,3 +523,35 @@ public struct RawLayoutWrapper: ~Copyable { public struct RawLayout: ~Copyable { public func test() {} } + +func takesClosure(_: () -> ()) {} + +@_noLocks +func testClosureExpression(_ t: T) { + takesClosure { + // expected-error@-1 {{generic closures or local functions can cause metadata allocation or locks}} + _ = T.self + } +} + +@_noLocks +func testLocalFunction(_ t: T) { + func localFunc() { + _ = T.self + } + + takesClosure(localFunc) + // expected-error@-1 {{generic closures or local functions can cause metadata allocation or locks}} +} + +func takesGInt(_ x: G) {} + +struct G {} + +extension G where T == Int { + @_noAllocation func method() { + takesClosure { + takesGInt(self) // OK + } + } +} From dc131ee180ace65be78aa9a51f690e227aff8110 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 11 Jun 2024 08:57:47 -0700 Subject: [PATCH 044/165] Frontend: share the module cache path with clang Rather than trying to re-compute the cache path manually for the default, use the clang provided interface to home the module cache. This ensures that we do not write the files into a top-level directory on Windows. --- lib/Frontend/ArgsToFrontendOptionsConverter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index a0e2a2a167c3b..ec3d2544af6d6 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -14,6 +14,7 @@ #include "ArgsToFrontendInputsConverter.h" #include "ArgsToFrontendOutputsConverter.h" +#include "clang/Driver/Driver.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/Basic/Platform.h" #include "swift/Frontend/Frontend.h" @@ -68,7 +69,7 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.ExplicitModulesOutputPath = A->getValue(); } else { SmallString<128> defaultPath; - llvm::sys::path::cache_directory(defaultPath); + clang::driver::Driver::getDefaultModuleCachePath(defaultPath); Opts.ExplicitModulesOutputPath = defaultPath.str().str(); } if (const Arg *A = Args.getLastArg(OPT_backup_module_interface_path)) { From b86fe88c433047401d546e2edc142956f7a00aef Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Mon, 10 Jun 2024 15:31:49 -0400 Subject: [PATCH 045/165] [Runtime] Fix key argument indexing when checking invertible protocols. Track the key argument index separately from the generic parameter index when performing the invertible protocol checking in _checkGenericRequirements. This keeps the indexing correct when a non-key argument is followed by a key argument. rdar://128774651 --- stdlib/public/runtime/DynamicCast.cpp | 4 +-- stdlib/public/runtime/MetadataLookup.cpp | 24 +++++++-------- stdlib/public/runtime/Private.h | 8 +++-- stdlib/public/runtime/ProtocolConformance.cpp | 12 ++++---- .../conditional_conformances_runtime.swift | 30 +++++++++++++++++-- 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/stdlib/public/runtime/DynamicCast.cpp b/stdlib/public/runtime/DynamicCast.cpp index 7f7b6128a779e..b9e6f4675a101 100644 --- a/stdlib/public/runtime/DynamicCast.cpp +++ b/stdlib/public/runtime/DynamicCast.cpp @@ -1864,8 +1864,8 @@ static DynamicCastResult tryCastToExtendedExistential( [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index).Ptr; }, - [&substitutions](unsigned ordinal) { - return substitutions.getMetadataOrdinal(ordinal).Ptr; + [&substitutions](unsigned fullOrdinal, unsigned keyOrdinal) { + return substitutions.getMetadataKeyArgOrdinal(keyOrdinal).Ptr; }, [](const Metadata *type, unsigned index) -> const WitnessTable * { swift_unreachable("Resolution of witness tables is not supported"); diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 2bfce4254a6b3..3565f922af532 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -1195,7 +1195,7 @@ class SubstGenericParametersFromWrittenArgs { genericParamCounts(genericParamCounts) {} MetadataOrPack getMetadata(unsigned depth, unsigned index) const; - MetadataOrPack getMetadataOrdinal(unsigned ordinal) const; + MetadataOrPack getMetadataFullOrdinal(unsigned ordinal) const; const WitnessTable *getWitnessTable(const Metadata *type, unsigned index) const; }; @@ -1415,8 +1415,8 @@ _gatherGenericParameters(const ContextDescriptor *context, [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index).Ptr; }, - [&substitutions](unsigned ordinal) { - return substitutions.getMetadataOrdinal(ordinal).Ptr; + [&substitutions](unsigned fullOrdinal, unsigned keyOrdinal) { + return substitutions.getMetadataFullOrdinal(fullOrdinal).Ptr; }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); @@ -1849,12 +1849,12 @@ class DecodedMetadataBuilder { // FIXME: variadic generics return genArgs[index].getMetadata(); }, - [genArgs](unsigned ordinal) { - if (ordinal >= genArgs.size()) + [genArgs](unsigned fullOrdinal, unsigned keyOrdinal) { + if (fullOrdinal >= genArgs.size()) return (const Metadata*)nullptr; // FIXME: variadic generics - return genArgs[ordinal].getMetadata(); + return genArgs[fullOrdinal].getMetadata(); }, [](const Metadata *type, unsigned index) -> const WitnessTable * { swift_unreachable("never called"); @@ -2814,8 +2814,8 @@ swift_distributed_getWitnessTables(GenericEnvironmentDescriptor *genericEnv, [&substFn](unsigned depth, unsigned index) { return substFn.getMetadata(depth, index).Ptr; }, - [&substFn](unsigned ordinal) { - return substFn.getMetadataOrdinal(ordinal).Ptr; + [&substFn](unsigned fullOrdinal, unsigned keyOrdinal) { + return substFn.getMetadataKeyArgOrdinal(keyOrdinal).Ptr; }, [&substFn](const Metadata *type, unsigned index) { return substFn.getWitnessTable(type, index); @@ -3243,8 +3243,8 @@ SubstGenericParametersFromMetadata::getMetadata( return MetadataOrPack(genericArgs[flatIndex]); } -MetadataOrPack -SubstGenericParametersFromMetadata::getMetadataOrdinal(unsigned ordinal) const { +MetadataOrPack SubstGenericParametersFromMetadata::getMetadataKeyArgOrdinal( + unsigned ordinal) const { // Don't attempt anything if we have no generic parameters. if (genericArgs == nullptr) return MetadataOrPack(); @@ -3281,8 +3281,8 @@ MetadataOrPack SubstGenericParametersFromWrittenArgs::getMetadata( return MetadataOrPack(); } -MetadataOrPack SubstGenericParametersFromWrittenArgs::getMetadataOrdinal( - unsigned ordinal) const { +MetadataOrPack SubstGenericParametersFromWrittenArgs::getMetadataFullOrdinal( + unsigned ordinal) const { if (ordinal < allGenericArgs.size()) { return MetadataOrPack(allGenericArgs[ordinal]); } diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h index 2274fbb62dc69..03d88d5530a4c 100644 --- a/stdlib/public/runtime/Private.h +++ b/stdlib/public/runtime/Private.h @@ -295,11 +295,13 @@ class TypeInfo { std::function; /// Callback used to provide the substitution of a generic parameter - /// (described by the ordinal, or "flat index") to its metadata. + /// (described by the ordinal, or "flat index") to its metadata. The index may + /// be "full" or it may be only relative to key arguments. The call is + /// provided both indexes and may use the one it requires. /// /// The return type here is a lie; it's actually a MetadataOrPack. using SubstGenericParameterOrdinalFn = - std::function; + std::function; /// Callback used to provide the substitution of a witness table based on /// its index into the enclosing generic environment. @@ -460,7 +462,7 @@ class TypeInfo { const void * const *getGenericArgs() const { return genericArgs; } MetadataOrPack getMetadata(unsigned depth, unsigned index) const; - MetadataOrPack getMetadataOrdinal(unsigned ordinal) const; + MetadataOrPack getMetadataKeyArgOrdinal(unsigned ordinal) const; const WitnessTable *getWitnessTable(const Metadata *type, unsigned index) const; }; diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp index 92dc7f63a47fc..4efd4c3c46286 100644 --- a/stdlib/public/runtime/ProtocolConformance.cpp +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -340,8 +340,8 @@ ProtocolConformanceDescriptor::getWitnessTable(const Metadata *type) const { [&substitutions](unsigned depth, unsigned index) { return substitutions.getMetadata(depth, index).Ptr; }, - [&substitutions](unsigned ordinal) { - return substitutions.getMetadataOrdinal(ordinal).Ptr; + [&substitutions](unsigned fullOrdinal, unsigned keyOrdinal) { + return substitutions.getMetadataKeyArgOrdinal(keyOrdinal).Ptr; }, [&substitutions](const Metadata *type, unsigned index) { return substitutions.getWitnessTable(type, index); @@ -1843,8 +1843,8 @@ checkInvertibleRequirements(const Metadata *type, [&substFn](unsigned depth, unsigned index) { return substFn.getMetadata(depth, index).Ptr; }, - [&substFn](unsigned ordinal) { - return substFn.getMetadataOrdinal(ordinal).Ptr; + [&substFn](unsigned fullOrdinal, unsigned keyOrdinal) { + return substFn.getMetadataKeyArgOrdinal(keyOrdinal).Ptr; }, [&substFn](const Metadata *type, unsigned index) { return substFn.getWitnessTable(type, index); @@ -1886,6 +1886,7 @@ std::optional swift::_checkGenericRequirements( // Now, check all of the generic arguments for invertible protocols. unsigned numGenericParams = genericParams.size(); + unsigned keyIndex = 0; for (unsigned index = 0; index != numGenericParams; ++index) { // Non-key arguments don't need to be checked, because they are // aliased to another type. @@ -1896,7 +1897,7 @@ std::optional swift::_checkGenericRequirements( if (index < allSuppressed.size()) suppressed = allSuppressed[index]; - MetadataOrPack metadataOrPack(substGenericParamOrdinal(index)); + MetadataOrPack metadataOrPack(substGenericParamOrdinal(index, keyIndex)); switch (genericParams[index].getKind()) { case GenericParamKind::Type: { if (!metadataOrPack || metadataOrPack.isMetadataPack()) { @@ -1937,6 +1938,7 @@ std::optional swift::_checkGenericRequirements( return TYPE_LOOKUP_ERROR_FMT("unknown generic parameter kind %u", index); } + keyIndex++; } // Success! diff --git a/test/Interpreter/conditional_conformances_runtime.swift b/test/Interpreter/conditional_conformances_runtime.swift index fbb6223b85f78..8fdd7e9b41b8a 100644 --- a/test/Interpreter/conditional_conformances_runtime.swift +++ b/test/Interpreter/conditional_conformances_runtime.swift @@ -33,11 +33,35 @@ extension Dictionary: P where Value == (Key) -> Bool { let yx = Y(wrapped: X()) -assert(tryAsP(yx) == 11) +precondition(tryAsP(yx) == 11) let dict: [Int : (Int) -> Bool] = [:] -assert(tryAsP(dict) == 2) +precondition(tryAsP(dict) == 2) let yDict = Y(wrapped: dict) -assert(tryAsP(yDict) == 12) +precondition(tryAsP(yDict) == 12) +// Generic argument indexing runs off the end when a key +// argument comes after a non-key argument. +struct Outer {} + +extension Outer where T == Int { + struct Inner { + // Add some stored properties that will have field offsets in the metadata. + // If we read past the end of the generic arguments, we'll find these and + // crash on something that's definitely not a valid pointer. + var a: T? + var b: T? + var c: T? + var d: T? + } +} + +extension Outer.Inner: P where U == String { + func foo() -> Int { return 1 } +} + +let conformingInner: Any = Outer.Inner() +let nonconformingInner: Any = Outer.Inner() +precondition(conformingInner is P) +precondition(!(nonconformingInner is P)) From c14559173d59490f208fa5501572e17476241d34 Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Thu, 6 Jun 2024 15:42:02 -0700 Subject: [PATCH 046/165] Add dependsOn(immortal) --- include/swift/AST/DiagnosticsSema.def | 2 + include/swift/AST/LifetimeDependence.h | 25 +++++-- lib/AST/LifetimeDependence.cpp | 69 +++++++++++-------- lib/Parse/ParseDecl.cpp | 14 ++-- lib/Serialization/Deserialization.cpp | 10 +-- lib/Serialization/ModuleFormat.h | 4 +- lib/Serialization/Serialization.cpp | 2 +- ...licit_lifetime_dependence_specifiers.swift | 12 ++++ test/SILOptimizer/lifetime_dependence.sil | 12 +++- ...icit_lifetime_dependence_specifiers1.swift | 5 ++ .../def_explicit_lifetime_dependence.swift | 13 ++++ .../explicit_lifetime_dependence.swift | 4 ++ 12 files changed, 128 insertions(+), 44 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 2cf21b7d82ddc..f59bfe67f1b1b 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7973,6 +7973,8 @@ ERROR(lifetime_dependence_cannot_infer_ambiguous_candidate, none, "cannot infer lifetime dependence on a self which is BitwiseCopyable & " "Escapable", ()) +ERROR(lifetime_dependence_immortal_conflict_name, none, + "conflict between the parameter name and immortal keyword", ()) //===----------------------------------------------------------------------===// // MARK: Transferring diff --git a/include/swift/AST/LifetimeDependence.h b/include/swift/AST/LifetimeDependence.h index a4e12b8f61914..259b80c9ea527 100644 --- a/include/swift/AST/LifetimeDependence.h +++ b/include/swift/AST/LifetimeDependence.h @@ -43,7 +43,7 @@ enum class LifetimeDependenceKind : uint8_t { Inherit = 0, Scope }; class LifetimeDependenceSpecifier { public: - enum class SpecifierKind { Named, Ordered, Self }; + enum class SpecifierKind { Named, Ordered, Self, Immortal }; private: SourceLoc loc; @@ -76,6 +76,11 @@ class LifetimeDependenceSpecifier { return {loc, SpecifierKind::Named, kind, name}; } + static LifetimeDependenceSpecifier + getImmortalLifetimeDependenceSpecifier(SourceLoc loc) { + return {loc, SpecifierKind::Immortal, {}, {}}; + } + static LifetimeDependenceSpecifier getOrderedLifetimeDependenceSpecifier( SourceLoc loc, ParsedLifetimeDependenceKind kind, unsigned index) { return {loc, SpecifierKind::Ordered, kind, index}; @@ -113,6 +118,8 @@ class LifetimeDependenceSpecifier { return "self"; case SpecifierKind::Ordered: return std::to_string(value.Ordered.index); + case SpecifierKind::Immortal: + return "immortal"; } llvm_unreachable("Invalid LifetimeDependenceSpecifier::SpecifierKind"); } @@ -134,6 +141,7 @@ class LifetimeDependenceSpecifier { class LifetimeDependenceInfo { IndexSubset *inheritLifetimeParamIndices; IndexSubset *scopeLifetimeParamIndices; + bool immortal; static LifetimeDependenceInfo getForParamIndex(AbstractFunctionDecl *afd, unsigned index, @@ -149,12 +157,15 @@ class LifetimeDependenceInfo { public: LifetimeDependenceInfo() : inheritLifetimeParamIndices(nullptr), - scopeLifetimeParamIndices(nullptr) {} + scopeLifetimeParamIndices(nullptr), immortal(false) {} LifetimeDependenceInfo(IndexSubset *inheritLifetimeParamIndices, - IndexSubset *scopeLifetimeParamIndices) + IndexSubset *scopeLifetimeParamIndices, + bool isImmortal) : inheritLifetimeParamIndices(inheritLifetimeParamIndices), - scopeLifetimeParamIndices(scopeLifetimeParamIndices) { - assert(!empty()); + scopeLifetimeParamIndices(scopeLifetimeParamIndices), + immortal(isImmortal) { + assert(isImmortal || inheritLifetimeParamIndices || + scopeLifetimeParamIndices); assert(!inheritLifetimeParamIndices || !inheritLifetimeParamIndices->isEmpty()); assert(!scopeLifetimeParamIndices || !scopeLifetimeParamIndices->isEmpty()); @@ -163,10 +174,12 @@ class LifetimeDependenceInfo { operator bool() const { return !empty(); } bool empty() const { - return inheritLifetimeParamIndices == nullptr && + return !immortal && inheritLifetimeParamIndices == nullptr && scopeLifetimeParamIndices == nullptr; } + bool isImmortal() const { return immortal; } + bool hasInheritLifetimeParamIndices() const { return inheritLifetimeParamIndices != nullptr; } diff --git a/lib/AST/LifetimeDependence.cpp b/lib/AST/LifetimeDependence.cpp index aeca548950262..3ef2f162a6805 100644 --- a/lib/AST/LifetimeDependence.cpp +++ b/lib/AST/LifetimeDependence.cpp @@ -110,10 +110,12 @@ LifetimeDependenceInfo LifetimeDependenceInfo::getForParamIndex( auto indexSubset = IndexSubset::get(ctx, capacity, {index}); if (kind == LifetimeDependenceKind::Scope) { return LifetimeDependenceInfo{/*inheritLifetimeParamIndices*/ nullptr, - /*scopeLifetimeParamIndices*/ indexSubset}; + /*scopeLifetimeParamIndices*/ indexSubset, + /*isImmortal*/ false}; } return LifetimeDependenceInfo{/*inheritLifetimeParamIndices*/ indexSubset, - /*scopeLifetimeParamIndices*/ nullptr}; + /*scopeLifetimeParamIndices*/ nullptr, + /*isImmortal*/ false}; } void LifetimeDependenceInfo::getConcatenatedData( @@ -246,6 +248,18 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd) { for (auto specifier : lifetimeDependentRepr->getLifetimeDependencies()) { switch (specifier.getSpecifierKind()) { + case LifetimeDependenceSpecifier::SpecifierKind::Immortal: { + auto immortalParam = + std::find_if(afd->getParameters()->begin(), afd->getParameters()->end(), [](ParamDecl *param) { + return strcmp(param->getName().get(), "immortal") == 0; + }); + if (immortalParam != afd->getParameters()->end()) { + diags.diagnose(*immortalParam, + diag::lifetime_dependence_immortal_conflict_name); + } + + return LifetimeDependenceInfo(nullptr, nullptr, /*isImmortal*/ true); + } case LifetimeDependenceSpecifier::SpecifierKind::Named: { bool foundParamName = false; unsigned paramIndex = 0; @@ -315,7 +329,8 @@ LifetimeDependenceInfo::fromTypeRepr(AbstractFunctionDecl *afd) { : nullptr, scopeLifetimeParamIndices.any() ? IndexSubset::get(ctx, scopeLifetimeParamIndices) - : nullptr); + : nullptr, + /*isImmortal*/ false); } // This utility is similar to its overloaded version that builds the @@ -360,18 +375,29 @@ std::optional LifetimeDependenceInfo::fromTypeRepr( }; for (auto specifier : lifetimeDependentRepr->getLifetimeDependencies()) { - assert(specifier.getSpecifierKind() == - LifetimeDependenceSpecifier::SpecifierKind::Ordered); - auto index = specifier.getIndex(); - if (index > capacity) { - diags.diagnose(specifier.getLoc(), - diag::lifetime_dependence_invalid_param_index, index); - return std::nullopt; + switch (specifier.getSpecifierKind()) { + case LifetimeDependenceSpecifier::SpecifierKind::Ordered: { + auto index = specifier.getIndex(); + if (index > capacity) { + diags.diagnose(specifier.getLoc(), + diag::lifetime_dependence_invalid_param_index, index); + return std::nullopt; + } + auto param = params[index]; + auto paramConvention = param.getConvention(); + if (updateLifetimeDependenceInfo(specifier, index, paramConvention)) { + return std::nullopt; + } + break; } - auto param = params[index]; - auto paramConvention = param.getConvention(); - if (updateLifetimeDependenceInfo(specifier, index, paramConvention)) { - return std::nullopt; + case LifetimeDependenceSpecifier::SpecifierKind::Immortal: { + return LifetimeDependenceInfo(/*inheritLifetimeParamIndices*/ nullptr, + /*scopeLifetimeParamIndices*/ nullptr, + /*isImmortal*/ true); + } + default: + llvm_unreachable("SIL can only have ordered or immortal lifetime " + "dependence specifier kind"); } } @@ -381,7 +407,8 @@ std::optional LifetimeDependenceInfo::fromTypeRepr( : nullptr, scopeLifetimeParamIndices.any() ? IndexSubset::get(ctx, scopeLifetimeParamIndices) - : nullptr); + : nullptr, + /*isImmortal*/ false); } std::optional @@ -510,18 +537,6 @@ LifetimeDependenceInfo::get(AbstractFunctionDecl *afd) { return LifetimeDependenceInfo::infer(afd); } -LifetimeDependenceInfo -LifetimeDependenceInfo::get(ASTContext &ctx, - const SmallBitVector &inheritLifetimeIndices, - const SmallBitVector &scopeLifetimeIndices) { - return LifetimeDependenceInfo{ - inheritLifetimeIndices.any() - ? IndexSubset::get(ctx, inheritLifetimeIndices) - : nullptr, - scopeLifetimeIndices.any() ? IndexSubset::get(ctx, scopeLifetimeIndices) - : nullptr}; -} - std::optional LifetimeDependenceInfo::getLifetimeDependenceOnParam(unsigned paramIndex) { if (inheritLifetimeParamIndices) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 068c2be02cab8..db3e7c012a1c4 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -5122,10 +5122,16 @@ ParserStatus Parser::parseLifetimeDependenceSpecifiers( Identifier paramName; auto paramLoc = consumeIdentifier(paramName, /*diagnoseDollarPrefix=*/false); - specifierList.push_back( - LifetimeDependenceSpecifier:: - getNamedLifetimeDependenceSpecifier( - paramLoc, lifetimeDependenceKind, paramName)); + if (paramName.is("immortal")) { + specifierList.push_back( + LifetimeDependenceSpecifier:: + getImmortalLifetimeDependenceSpecifier(paramLoc)); + } else { + specifierList.push_back( + LifetimeDependenceSpecifier:: + getNamedLifetimeDependenceSpecifier( + paramLoc, lifetimeDependenceKind, paramName)); + } break; } case tok::integer_literal: { diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 6305c740c35f0..8baab8f33a000 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -8864,12 +8864,13 @@ ModuleFile::maybeReadLifetimeDependenceInfo(unsigned numParams) { return std::nullopt; } + bool isImmortal; bool hasInheritLifetimeParamIndices; bool hasScopeLifetimeParamIndices; ArrayRef lifetimeDependenceData; - LifetimeDependenceLayout::readRecord(scratch, hasInheritLifetimeParamIndices, - hasScopeLifetimeParamIndices, - lifetimeDependenceData); + LifetimeDependenceLayout::readRecord( + scratch, isImmortal, hasInheritLifetimeParamIndices, + hasScopeLifetimeParamIndices, lifetimeDependenceData); SmallBitVector inheritLifetimeParamIndices(numParams, false); SmallBitVector scopeLifetimeParamIndices(numParams, false); @@ -8898,5 +8899,6 @@ ModuleFile::maybeReadLifetimeDependenceInfo(unsigned numParams) { : nullptr, hasScopeLifetimeParamIndices ? IndexSubset::get(ctx, scopeLifetimeParamIndices) - : nullptr); + : nullptr, + isImmortal); } diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 9130c64b1b0ea..2ae35a9daae0c 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,8 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 877; // extend_lifetime instruction +const uint16_t SWIFTMODULE_VERSION_MINOR = + 878; // immortal bit in LifetimeDependence /// A standard hash seed used for all string hashes in a serialized module. /// @@ -2212,6 +2213,7 @@ namespace decls_block { using LifetimeDependenceLayout = BCRecordLayout, // isImmortal BCFixed<1>, // hasInheritLifetimeParamIndices BCFixed<1>, // hasScopeLifetimeParamIndices BCArray> // concatenated param indices diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 21dd5445f6165..51e4c1f74e2ad 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -2579,7 +2579,7 @@ void Serializer::writeLifetimeDependenceInfo( auto abbrCode = DeclTypeAbbrCodes[LifetimeDependenceLayout::Code]; LifetimeDependenceLayout::emitRecord( - Out, ScratchRecord, abbrCode, + Out, ScratchRecord, abbrCode, lifetimeDependenceInfo.isImmortal(), lifetimeDependenceInfo.hasInheritLifetimeParamIndices(), lifetimeDependenceInfo.hasScopeLifetimeParamIndices(), paramIndices); } diff --git a/test/Parse/explicit_lifetime_dependence_specifiers.swift b/test/Parse/explicit_lifetime_dependence_specifiers.swift index 9f221a7fa38b2..0f9561aeda470 100644 --- a/test/Parse/explicit_lifetime_dependence_specifiers.swift +++ b/test/Parse/explicit_lifetime_dependence_specifiers.swift @@ -153,3 +153,15 @@ struct Wrapper : ~Escapable { return view } } + +enum FakeOptional: ~Escapable { + case none, some(Wrapped) +} + +extension FakeOptional: Escapable where Wrapped: Escapable {} + +extension FakeOptional where Wrapped: ~Escapable { + init(nilLiteral: ()) -> dependsOn(immortal) Self { + self = .none + } +} diff --git a/test/SILOptimizer/lifetime_dependence.sil b/test/SILOptimizer/lifetime_dependence.sil index 6bbe541698c24..46cdbef3ca8c2 100644 --- a/test/SILOptimizer/lifetime_dependence.sil +++ b/test/SILOptimizer/lifetime_dependence.sil @@ -7,7 +7,7 @@ // REQUIRES: asserts // REQUIRES: swift_in_compiler -// Test the SIL representation for lifetime depenence. +// Test the SIL representation for lifetime dependence. sil_stage raw @@ -18,6 +18,7 @@ class C {} struct Nonescapable: ~Escapable {} sil @c_dependence : $@convention(thin) (@guaranteed C) -> _scope(0) @owned Nonescapable +sil @immortal_dependence : $@convention(thin) () -> _scope(immortal) @owned Nonescapable // Test that SILType.isEscpable does not crash on a generic box when NoncopyableGenerics is enabled. sil shared [serialized] [ossa] @testLocalFunc : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> () { @@ -42,3 +43,12 @@ bb0(%0 : @owned $C): %28 = tuple () return %28 : $() } + +sil [ossa] @test_immortal_dependence : $@convention(thin) () -> () { +bb0: + %f = function_ref @immortal_dependence : $@convention(thin) () -> _scope(immortal) @owned Nonescapable + %c = apply %f() : $@convention(thin) () -> _scope(immortal) @owned Nonescapable + destroy_value %c : $Nonescapable + %t = tuple () + return %t : $() +} diff --git a/test/Sema/explicit_lifetime_dependence_specifiers1.swift b/test/Sema/explicit_lifetime_dependence_specifiers1.swift index 66f24dff50aa0..1885846631520 100644 --- a/test/Sema/explicit_lifetime_dependence_specifiers1.swift +++ b/test/Sema/explicit_lifetime_dependence_specifiers1.swift @@ -231,3 +231,8 @@ extension RawBufferView { return BufferView(ptr) } } + +func immortalConflict(immortal: UnsafeRawBufferPointer ) -> dependsOn(immortal) BufferView { // expected-error{{conflict between the parameter name and immortal keyword}} + return BufferView(immortal) +} + diff --git a/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift b/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift index cdbd57b8e4e54..a8eb2ac7ee4ab 100644 --- a/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift +++ b/test/Serialization/Inputs/def_explicit_lifetime_dependence.swift @@ -68,3 +68,16 @@ public struct Wrapper : ~Escapable { } } } + +public enum FakeOptional: ~Escapable { + case none, some(Wrapped) +} + +extension FakeOptional: Escapable where Wrapped: Escapable {} + +extension FakeOptional where Wrapped: ~Escapable { + public init(_ nilLiteral: ()) -> dependsOn(immortal) Self { + self = .none + } +} + diff --git a/test/Serialization/explicit_lifetime_dependence.swift b/test/Serialization/explicit_lifetime_dependence.swift index 1285c006525ba..f450b2ccf6a64 100644 --- a/test/Serialization/explicit_lifetime_dependence.swift +++ b/test/Serialization/explicit_lifetime_dependence.swift @@ -44,6 +44,10 @@ func testReadAccessor() { } } +func testFakeOptional() { + _ = FakeOptional(()) +} + // CHECK: sil @$s32def_explicit_lifetime_dependence6deriveyAA10BufferViewVADYlsF : $@convention(thin) (@guaranteed BufferView) -> _scope(0) @owned BufferView // CHECK: sil @$s32def_explicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnYliF : $@convention(thin) (@owned BufferView) -> _inherit(0) @owned BufferView // CHECK: sil @$s32def_explicit_lifetime_dependence15borrowAndCreateyAA10BufferViewVADYlsF : $@convention(thin) (@guaranteed BufferView) -> _scope(0) @owned BufferView From 7ccd2adfb2c7fe4dbb0aa972541f1405aef44f09 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Tue, 11 Jun 2024 11:53:43 -0700 Subject: [PATCH 047/165] Revert "Update to ensure downgradeToWarning doesn't get reset" This reverts commit c4251d2f45c0465803dda8f887bb8daa7afc06a3. --- lib/Sema/ResilienceDiagnostics.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index 681d1e0ee4c48..9a7ba28908ce0 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -105,16 +105,6 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc, } DowngradeToWarning downgradeToWarning = DowngradeToWarning::No; - // Don't change the order of the getDisallowedOriginKind call; - // it can reset downgradeToWarning to NO so needs to be called here. - auto originKind = getDisallowedOriginKind(D, where, downgradeToWarning); - // For a default argument or property initializer, package type is - // allowed at the use site with package access scope. - auto allowedForPkgCtx = false; - if (originKind == DisallowedOriginKind::None || - originKind == DisallowedOriginKind::PackageImport) { - allowedForPkgCtx = where.isPackage() && declAccessScope.isPackage(); - } // Swift 4.2 did not perform any checks for type aliases. if (isa(D)) { @@ -134,12 +124,22 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc, if (isa(DC) && !Context.isSwiftVersionAtLeast(6)) downgradeToWarning = DowngradeToWarning::Yes; + AccessLevel diagAccessLevel = declAccessScope.accessLevelForDiagnostics(); + + auto allowedForPkgCtx = false; + auto originKind = getDisallowedOriginKind(D, where, downgradeToWarning); + // For a default argument or property initializer, package type is + // allowed at the use site with package access scope. + if (originKind == DisallowedOriginKind::None || + originKind == DisallowedOriginKind::PackageImport) { + allowedForPkgCtx = where.isPackage() && diagAccessLevel >= AccessLevel::Package; + } + if (!allowedForPkgCtx) { auto diagID = diag::resilience_decl_unavailable; if (downgradeToWarning == DowngradeToWarning::Yes) diagID = diag::resilience_decl_unavailable_warn; - AccessLevel diagAccessLevel = declAccessScope.accessLevelForDiagnostics(); Context.Diags.diagnose(loc, diagID, D, diagAccessLevel, fragileKind.getSelector()); From 6f5b40543dfa51041aae019ad6b5cccaf0db7573 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Tue, 11 Jun 2024 11:54:00 -0700 Subject: [PATCH 048/165] Revert "Handle package exportability." This reverts commit d182d01c28e79c2441e581a909b05955956b1504. --- include/swift/AST/DiagnosticsSema.def | 40 ++--- include/swift/AST/SourceFile.h | 4 - lib/AST/Decl.cpp | 6 +- lib/AST/DeclContext.cpp | 4 +- lib/AST/Module.cpp | 6 - lib/Sema/ResilienceDiagnostics.cpp | 125 +++++---------- lib/Sema/TypeCheckAccess.cpp | 145 ++++++++---------- lib/Sema/TypeCheckAccess.h | 3 +- lib/Sema/TypeCheckAvailability.cpp | 56 +++---- lib/Sema/TypeCheckAvailability.h | 17 +- ...s-level-import-classic-exportability.swift | 22 +-- .../access-level-import-conformances.swift | 71 ++------- test/Sema/access-level-import-inlinable.swift | 88 +---------- ...s-level-import-package-exportability.swift | 108 ------------- test/Sema/access-level-import-typealias.swift | 59 ------- test/Sema/superfluously-public-imports.swift | 6 +- .../attr_fixed_layout_property_wrapper.swift | 24 +-- 17 files changed, 177 insertions(+), 607 deletions(-) delete mode 100644 test/Sema/access-level-import-package-exportability.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index cb0a2d0a66b56..c9f84a778fefe 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2301,32 +2301,32 @@ ERROR(pattern_type_not_usable_from_inline,none, "type referenced from a '@usableFromInline' " "%select{%select{variable|constant}0|property}1 " "must be '@usableFromInline' or public", - (bool, bool, /*ignored*/bool)) + (bool, bool)) WARNING(pattern_type_not_usable_from_inline_warn,none, "type referenced from a '@usableFromInline' " "%select{%select{variable|constant}0|property}1 " "should be '@usableFromInline' or public", - (bool, bool, /*ignored*/bool)) + (bool, bool)) ERROR(pattern_type_not_usable_from_inline_frozen,none, - "type referenced from a stored property in a '@frozen%select{| package}2' struct must " - "be '@usableFromInline'%select{ or public|, public, or package}2", - (/*ignored*/bool, /*ignored*/bool, bool)) + "type referenced from a stored property in a '@frozen' struct must " + "be '@usableFromInline' or public", + (/*ignored*/bool, /*ignored*/bool)) ERROR(pattern_type_not_usable_from_inline_inferred,none, "type referenced from a '@usableFromInline' " "%select{%select{variable|constant}0|property}1 " "with inferred type %2 " "must be '@usableFromInline' or public", - (bool, bool, Type, /*ignored*/bool)) + (bool, bool, Type)) WARNING(pattern_type_not_usable_from_inline_inferred_warn,none, "type referenced from a '@usableFromInline' " "%select{%select{variable|constant}0|property}1 " "with inferred type %2 " "should be '@usableFromInline' or public", - (bool, bool, Type, /*ignored*/bool)) + (bool, bool, Type)) ERROR(pattern_type_not_usable_from_inline_inferred_frozen,none, "type referenced from a stored property with inferred type %2 in a " - "'@frozen%select{| package}3' struct must be '@usableFromInline'%select{ or public|, public, or package}3", - (/*ignored*/bool, /*ignored*/bool, Type, bool)) + "'@frozen' struct must be '@usableFromInline' or public", + (/*ignored*/bool, /*ignored*/bool, Type)) ERROR(pattern_binds_no_variables,none, "%select{property|global variable}0 declaration does not bind any " @@ -3648,8 +3648,6 @@ ERROR(decl_from_hidden_module,none, "cannot use %kind0 %select{here|as property wrapper here|" "as result builder here|" "in an extension with public or '@usableFromInline' members|" - "in an extension with conditional conformances|" - "in an extension with public, package, or '@usableFromInline' members|" "in an extension with conditional conformances}1; " "%select{%2 has been imported as implementation-only|" "it is an SPI imported from %2|" @@ -3657,9 +3655,7 @@ ERROR(decl_from_hidden_module,none, "%2 was imported for SPI only|" "%2 was not imported by this file|" "C++ types from imported module %2 do not support library evolution|" - "%2 was not imported publicly|" - "%2 was imported as package}3" - "%select{||||| or as package| or as package}1", + "%2 was not imported publicly}3", (const Decl *, unsigned, Identifier, unsigned)) ERROR(typealias_desugars_to_type_from_hidden_module,none, "%0 aliases '%1.%2' and cannot be used %select{here|" @@ -3675,8 +3671,7 @@ ERROR(typealias_desugars_to_type_from_hidden_module,none, "%4 was imported for SPI only|" "%4 was not imported by this file|" "C++ types from imported module %4 do not support library evolution|" - "%4 was not imported publicly|" - "%4 was imported as package}5", + "%4 was not imported publicly}5", (const TypeAliasDecl *, StringRef, StringRef, unsigned, Identifier, unsigned)) ERROR(conformance_from_implementation_only_module,none, "cannot use conformance of %0 to %1 %select{here|as property wrapper here|" @@ -3689,8 +3684,7 @@ ERROR(conformance_from_implementation_only_module,none, "%3 was imported for SPI only|" "%3 was not imported by this file|" "C++ types from imported module %3 do not support library evolution|" - "%3 was not imported publicly|" - "%3 was imported as package}4", + "%3 was not imported publicly}4", (Type, Identifier, unsigned, Identifier, unsigned)) NOTE(assoc_conformance_from_implementation_only_module,none, "in associated type %0 (inferred as %1)", (Type, Type)) @@ -6928,8 +6922,7 @@ ERROR(inlinable_decl_ref_from_hidden_module, "%2 was imported for SPI only|" "%2 was not imported by this file|" "C++ APIs from imported module %2 do not support library evolution|" - "%2 was not imported publicly|" - "%2 was imported as package}3", + "%2 was not imported publicly}3", (const ValueDecl *, unsigned, Identifier, unsigned)) WARNING(inlinable_decl_ref_from_hidden_module_warn, @@ -6947,8 +6940,7 @@ ERROR(inlinable_typealias_desugars_to_type_from_hidden_module, "%4 was imported for SPI only|" "%4 was not imported by this file|" "C++ types from imported module %4 do not support library evolution|" - "%4 was not imported publicly|" - "%4 was imported as package}5", + "%4 was not imported publicly}5", (const TypeAliasDecl *, StringRef, StringRef, unsigned, Identifier, unsigned)) NOTE(missing_import_inserted, @@ -6962,8 +6954,8 @@ ERROR(availability_macro_in_inlinable, none, #undef FRAGILE_FUNC_KIND NOTE(resilience_decl_declared_here, - none, "%kind0 is not '@usableFromInline'%select{ or public|, public, or package}1", - (const ValueDecl *, bool)) + none, "%kind0 is not '@usableFromInline' or public", + (const ValueDecl *)) ERROR(class_designated_init_inlinable_resilient,none, "initializer for class %0 is " diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index c4574f5152bd9..282565053774e 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -435,10 +435,6 @@ class SourceFile final : public FileUnit { void setImportUsedPreconcurrency( AttributedImport import); - /// True if the highest access level of the declarations referencing - /// this import in signature or inlinable code is internal or less. - bool isMaxAccessLevelUsingImportInternal(AttributedImport import) const; - /// Return the highest access level of the declarations referencing /// this import in signature or inlinable code. AccessLevel diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 4ecf953e9215d..daf2b8c759f68 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2314,7 +2314,7 @@ bool VarDecl::isLayoutExposedToClients() const { auto nominalAccess = parent->getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); - if (!nominalAccess.isPublicOrPackage()) return false; + if (!nominalAccess.isPublic()) return false; if (!parent->getAttrs().hasAttribute() && !parent->getAttrs().hasAttribute()) @@ -4680,10 +4680,8 @@ bool ValueDecl::isMoreVisibleThan(ValueDecl *other) const { if (scope.isPublic()) return !otherScope.isPublic(); - else if (scope.isPackage()) - return !otherScope.isPublicOrPackage(); else if (scope.isInternal()) - return !otherScope.isPublicOrPackage() && !otherScope.isInternal(); + return !otherScope.isPublic() && !otherScope.isInternal(); else return false; } diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 912bf50db0ad3..c55e6464f6712 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -486,7 +486,7 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator, auto effectiveAccess = VD->getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); - if (effectiveAccess.isPublicOrPackage()) { + if (effectiveAccess.isPublic()) { return {FragileFunctionKind::DefaultArgument}; } @@ -518,7 +518,7 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator, // If the function is not externally visible, we will not be serializing // its body. - if (!funcAccess.isPublicOrPackage()) { + if (!funcAccess.isPublic()) { return {FragileFunctionKind::None}; } diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 24deaf7fb1101..3bcac8cedc37d 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -2650,12 +2650,6 @@ void SourceFile::setImportUsedPreconcurrency( PreconcurrencyImportsUsed.insert(import); } -bool SourceFile::isMaxAccessLevelUsingImportInternal( - AttributedImport import) const { - auto maxLevel = getMaxAccessLevelUsingImport(import.module.importedModule); - return maxLevel < AccessLevel::Package; -} - AccessLevel SourceFile::getMaxAccessLevelUsingImport( const ModuleDecl *mod) const { diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index 9a7ba28908ce0..d3915ad77a3bf 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -66,22 +66,17 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc, ImportAccessLevel problematicImport = D->getImportAccessFrom(DC); if (problematicImport.has_value()) { auto SF = DC->getParentSourceFile(); - if (SF) { - // The max used access level previously registered might be Package, - // in which case, don't reset it to Public here; this ensures proper - // diags between public and package. - if (SF->isMaxAccessLevelUsingImportInternal(problematicImport.value())) - SF->registerAccessLevelUsingImport(problematicImport.value(), - AccessLevel::Public); - - if (Context.LangOpts.EnableModuleApiImportRemarks) { - ModuleDecl *importedVia = problematicImport->module.importedModule, - *sourceModule = D->getModuleContext(); - Context.Diags.diagnose(loc, diag::module_api_import, - D, importedVia, sourceModule, - importedVia == sourceModule, - /*isImplicit*/false); - } + if (SF) + SF->registerAccessLevelUsingImport(problematicImport.value(), + AccessLevel::Public); + + if (Context.LangOpts.EnableModuleApiImportRemarks) { + ModuleDecl *importedVia = problematicImport->module.importedModule, + *sourceModule = D->getModuleContext(); + Context.Diags.diagnose(loc, diag::module_api_import, + D, importedVia, sourceModule, + importedVia == sourceModule, + /*isImplicit*/false); } } @@ -124,27 +119,15 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc, if (isa(DC) && !Context.isSwiftVersionAtLeast(6)) downgradeToWarning = DowngradeToWarning::Yes; - AccessLevel diagAccessLevel = declAccessScope.accessLevelForDiagnostics(); + auto diagID = diag::resilience_decl_unavailable; + if (downgradeToWarning == DowngradeToWarning::Yes) + diagID = diag::resilience_decl_unavailable_warn; - auto allowedForPkgCtx = false; - auto originKind = getDisallowedOriginKind(D, where, downgradeToWarning); - // For a default argument or property initializer, package type is - // allowed at the use site with package access scope. - if (originKind == DisallowedOriginKind::None || - originKind == DisallowedOriginKind::PackageImport) { - allowedForPkgCtx = where.isPackage() && diagAccessLevel >= AccessLevel::Package; - } - - if (!allowedForPkgCtx) { - auto diagID = diag::resilience_decl_unavailable; - if (downgradeToWarning == DowngradeToWarning::Yes) - diagID = diag::resilience_decl_unavailable_warn; - - Context.Diags.diagnose(loc, diagID, D, diagAccessLevel, - fragileKind.getSelector()); + AccessLevel diagAccessLevel = declAccessScope.accessLevelForDiagnostics(); + Context.Diags.diagnose(loc, diagID, D, diagAccessLevel, + fragileKind.getSelector()); - Context.Diags.diagnose(D, diag::resilience_decl_declared_here, D, allowedForPkgCtx); - } + Context.Diags.diagnose(D, diag::resilience_decl_declared_here, D); if (problematicImport.has_value() && problematicImport->accessLevel < D->getFormalAccess()) { @@ -173,14 +156,10 @@ static bool diagnoseTypeAliasDeclRefExportability(SourceLoc loc, where.getDeclContext()); if (problematicImport.has_value()) { auto SF = where.getDeclContext()->getParentSourceFile(); - if (SF) { - // The max used access level previously registered might be Package, - // in which case, don't reset it to Public here; this ensures proper - // diags between public and package. - if (SF->isMaxAccessLevelUsingImportInternal(problematicImport.value())) - SF->registerAccessLevelUsingImport(problematicImport.value(), - AccessLevel::Public); - } + if (SF) + SF->registerAccessLevelUsingImport(problematicImport.value(), + AccessLevel::Public); + if (ctx.LangOpts.EnableModuleApiImportRemarks) { ModuleDecl *importedVia = problematicImport->module.importedModule, *sourceModule = D->getModuleContext(); @@ -207,8 +186,7 @@ static bool diagnoseTypeAliasDeclRefExportability(SourceLoc loc, auto definingModule = D->getModuleContext(); auto fragileKind = where.getFragileFunctionKind(); bool warnPreSwift6 = originKind != DisallowedOriginKind::SPIOnly && - originKind != DisallowedOriginKind::PackageImport && - originKind != DisallowedOriginKind::InternalOrLessImport; + originKind != DisallowedOriginKind::NonPublicImport; if (fragileKind.kind == FragileFunctionKind::None) { auto reason = where.getExportabilityReason(); ctx.Diags @@ -233,8 +211,7 @@ static bool diagnoseTypeAliasDeclRefExportability(SourceLoc loc, addMissingImport(loc, D, where); // If limited by an import, note which one. - if (originKind == DisallowedOriginKind::InternalOrLessImport || - originKind == DisallowedOriginKind::PackageImport) { + if (originKind == DisallowedOriginKind::NonPublicImport) { const DeclContext *DC = where.getDeclContext(); ImportAccessLevel limitImport = D->getImportAccessFrom(DC); assert(limitImport.has_value() && @@ -265,31 +242,22 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D, ImportAccessLevel import = D->getImportAccessFrom(DC); if (import.has_value() && reason.has_value()) { auto SF = DC->getParentSourceFile(); - if (SF) { - // The max used access level previously registered might be Package, - // in which case, don't reset it to Public here; this ensures proper - // diags between public and package. - if (SF->isMaxAccessLevelUsingImportInternal(import.value())) - SF->registerAccessLevelUsingImport(import.value(), - AccessLevel::Public); - } + if (SF) + SF->registerAccessLevelUsingImport(import.value(), + AccessLevel::Public); } // Access levels from imports are reported with the others access levels. // Except for extensions, we report them here. - if (originKind == DisallowedOriginKind::InternalOrLessImport || - originKind == DisallowedOriginKind::PackageImport) { - if (reason != ExportabilityReason::ExtensionWithPublicMembers && - reason != ExportabilityReason::ExtensionWithPackageMembers && - reason != ExportabilityReason::ExtensionWithConditionalConformances && - reason != ExportabilityReason::ExtensionWithPackageConditionalConformances) - return false; - } + if (originKind == DisallowedOriginKind::NonPublicImport && + reason != ExportabilityReason::ExtensionWithPublicMembers && + reason != ExportabilityReason::ExtensionWithConditionalConformances) + return false; if (ctx.LangOpts.EnableModuleApiImportRemarks && import.has_value() && where.isExported() && reason != ExportabilityReason::General && - originKind != DisallowedOriginKind::InternalOrLessImport) { + originKind != DisallowedOriginKind::NonPublicImport) { // These may be reported twice, for the Type and for the TypeRepr. ModuleDecl *importedVia = import->module.importedModule, *sourceModule = D->getModuleContext(); @@ -302,14 +270,6 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D, if (originKind == DisallowedOriginKind::None) return false; - // No diags needed for extensions with package members or - // conformance to types with package access scope. - if (originKind == DisallowedOriginKind::PackageImport) { - if (reason == ExportabilityReason::ExtensionWithPackageMembers || - reason == ExportabilityReason::ExtensionWithPackageConditionalConformances) - return false; - } - auto diagName = D->getName(); if (auto accessor = dyn_cast(D)) { // Only diagnose accessors if their disallowed origin kind differs from @@ -353,8 +313,7 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D, } // If limited by an import, note which one. - if (originKind == DisallowedOriginKind::InternalOrLessImport || - originKind == DisallowedOriginKind::PackageImport) { + if (originKind == DisallowedOriginKind::NonPublicImport) { assert(import.has_value() && import->accessLevel < AccessLevel::Public && "The import should still be non-public"); @@ -403,14 +362,10 @@ TypeChecker::diagnoseConformanceExportability(SourceLoc loc, ImportAccessLevel problematicImport = ext->getImportAccessFrom(where.getDeclContext()); if (problematicImport.has_value()) { auto SF = where.getDeclContext()->getParentSourceFile(); - if (SF) { - // The max used access level previously registered might be Package, - // in which case, don't reset it to Public here; this ensures proper - // diags between public and package. - if (SF->isMaxAccessLevelUsingImportInternal(problematicImport.value())) - SF->registerAccessLevelUsingImport(problematicImport.value(), - AccessLevel::Public); - } + if (SF) + SF->registerAccessLevelUsingImport(problematicImport.value(), + AccessLevel::Public); + if (ctx.LangOpts.EnableModuleApiImportRemarks) { ModuleDecl *importedVia = problematicImport->module.importedModule, *sourceModule = ext->getModuleContext(); @@ -437,8 +392,7 @@ TypeChecker::diagnoseConformanceExportability(SourceLoc loc, static_cast(originKind)) .warnUntilSwiftVersionIf((warnIfConformanceUnavailablePreSwift6 && originKind != DisallowedOriginKind::SPIOnly && - originKind != DisallowedOriginKind::PackageImport && - originKind != DisallowedOriginKind::InternalOrLessImport) || + originKind != DisallowedOriginKind::NonPublicImport) || originKind == DisallowedOriginKind::MissingImport, 6); @@ -447,8 +401,7 @@ TypeChecker::diagnoseConformanceExportability(SourceLoc loc, addMissingImport(loc, ext, where); // If limited by an import, note which one. - if (originKind == DisallowedOriginKind::InternalOrLessImport || - originKind == DisallowedOriginKind::PackageImport) { + if (originKind == DisallowedOriginKind::NonPublicImport) { const DeclContext *DC = where.getDeclContext(); ImportAccessLevel limitImport = ext->getImportAccessFrom(DC); assert(limitImport.has_value() && diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 91361a33c6b61..db37064b5feec 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -1424,16 +1424,13 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, ImportAccessLevel importLimit) { auto &Ctx = theVar->getASTContext(); auto diagID = diag::pattern_type_not_usable_from_inline_inferred; - auto hasPackageScope = false; if (fixedLayoutStructContext) { diagID = diag::pattern_type_not_usable_from_inline_inferred_frozen; - hasPackageScope = fixedLayoutStructContext->getFormalAccessScope(nullptr, true).isPackage(); } else if (!Ctx.isSwiftVersionAtLeast(5)) { diagID = diag::pattern_type_not_usable_from_inline_inferred_warn; } Ctx.Diags.diagnose(NP->getLoc(), diagID, theVar->isLet(), - isTypeContext, theVar->getInterfaceType(), - hasPackageScope); + isTypeContext, theVar->getInterfaceType()); noteLimitingImport(theVar, importLimit, complainRepr); }); } @@ -1466,14 +1463,12 @@ class UsableFromInlineChecker : public AccessControlCheckerBase, ImportAccessLevel importLimit) { auto &Ctx = anyVar->getASTContext(); auto diagID = diag::pattern_type_not_usable_from_inline; - auto hasPackageScope = false; - if (fixedLayoutStructContext) { + if (fixedLayoutStructContext) diagID = diag::pattern_type_not_usable_from_inline_frozen; - hasPackageScope = fixedLayoutStructContext->getFormalAccessScope(nullptr, true).isPackage(); - } else if (!Ctx.isSwiftVersionAtLeast(5)) + else if (!Ctx.isSwiftVersionAtLeast(5)) diagID = diag::pattern_type_not_usable_from_inline_warn; auto diag = Ctx.Diags.diagnose(TP->getLoc(), diagID, anyVar->isLet(), - isTypeContext, hasPackageScope); + isTypeContext); highlightOffendingType(diag, complainRepr); noteLimitingImport(anyVar, importLimit, complainRepr); }); @@ -2016,20 +2011,9 @@ swift::getDisallowedOriginKind(const Decl *decl, // Report non-public import last as it can be ignored by the caller. // See \c diagnoseValueDeclRefExportability. auto importSource = decl->getImportAccessFrom(where.getDeclContext()); - if (importSource.has_value()) { - if (importSource->accessLevel == AccessLevel::Package) { - auto kind = where.getFragileFunctionKind().kind; - if (where.isPackage() && - (kind == FragileFunctionKind::None || - kind == FragileFunctionKind::DefaultArgument || - kind == FragileFunctionKind::PropertyInitializer)) - return DisallowedOriginKind::None; - return DisallowedOriginKind::PackageImport; - } - - if (importSource->accessLevel < AccessLevel::Package) - return DisallowedOriginKind::InternalOrLessImport; - } + if (importSource.has_value() && + importSource->accessLevel < AccessLevel::Public) + return DisallowedOriginKind::NonPublicImport; return DisallowedOriginKind::None; } @@ -2352,19 +2336,13 @@ class DeclAvailabilityChecker : public DeclVisitor { } void checkConstrainedExtensionRequirements(ExtensionDecl *ED, - bool hasExportedPublicMembers, - bool hasExportedPackageMembers, - bool hasPackageInheritance) { + bool hasExportedMembers) { if (!ED->getTrailingWhereClause()) return; - ExportabilityReason reason = ExportabilityReason::ExtensionWithConditionalConformances; - if (hasExportedPublicMembers) - reason = ExportabilityReason::ExtensionWithPublicMembers; - else if (hasExportedPackageMembers) - reason = ExportabilityReason::ExtensionWithPackageMembers; - else if (hasPackageInheritance) - reason = ExportabilityReason::ExtensionWithPackageConditionalConformances; + ExportabilityReason reason = + hasExportedMembers ? ExportabilityReason::ExtensionWithPublicMembers + : ExportabilityReason::ExtensionWithConditionalConformances; forAllRequirementTypes(ED, [&](Type type, TypeRepr *typeRepr) { checkType(type, typeRepr, ED, reason); @@ -2391,61 +2369,23 @@ class DeclAvailabilityChecker : public DeclVisitor { // 2) If the extension contains exported members, the as-written // extended type should be exportable. - bool hasExportedPublicMembers = llvm::any_of(ED->getMembers(), - [](const Decl *member) -> bool { - auto *valueMember = dyn_cast(member); - if (!valueMember) - return false; - return isExported(valueMember) && - !valueMember->getFormalAccessScope(nullptr, true).isPackage(); - - }); - - // Keep track of package (exported) members separately from public - // members for diags purposes. - bool hasExportedPackageMembers = llvm::any_of(ED->getMembers(), + bool hasExportedMembers = llvm::any_of(ED->getMembers(), [](const Decl *member) -> bool { auto *valueMember = dyn_cast(member); if (!valueMember) return false; - return isExported(valueMember) && - valueMember->getFormalAccessScope(nullptr, true).isPackage(); - }); - - bool hasExportedMembers = hasExportedPublicMembers || hasExportedPackageMembers; - - // Keep track of inheritance with package access level for diags purposes. - bool hasPackageInheritance = llvm::any_of(ED->getInherited().getEntries(), - [](const InheritedEntry entry) -> bool { - if (!entry.wasValidated()) - return false; - auto enType = entry.getType(); - if (enType) { - if (const auto *ProtoD = dyn_cast_or_null(enType->getAnyNominal())) { - if (ProtoD && isExported(ProtoD) && - ProtoD->getFormalAccessScope(nullptr, true).isPackage()) - return true; - } - } - return false; + return isExported(valueMember); }); Where = wasWhere.withExported(hasExportedMembers); - - ExportabilityReason reason = ExportabilityReason::ExtensionWithPublicMembers; - if (!hasExportedPublicMembers && hasExportedPackageMembers) - reason = ExportabilityReason::ExtensionWithPackageMembers; - - checkType(ED->getExtendedType(), ED->getExtendedTypeRepr(), - ED, reason); + checkType(ED->getExtendedType(), ED->getExtendedTypeRepr(), ED, + ExportabilityReason::ExtensionWithPublicMembers); // 3) If the extension contains exported members or defines conformances, // the 'where' clause must only name exported types. Where = wasWhere.withExported(hasExportedMembers || !ED->getInherited().empty()); - checkConstrainedExtensionRequirements(ED, hasExportedPublicMembers, - hasExportedPackageMembers, - hasPackageInheritance); + checkConstrainedExtensionRequirements(ED, hasExportedMembers); if (!hasExportedMembers && !ED->getInherited().empty()) { @@ -2457,11 +2397,10 @@ class DeclAvailabilityChecker : public DeclVisitor { ImportAccessLevel import = extendedType->getImportAccessFrom(DC); if (import.has_value()) { auto SF = DC->getParentSourceFile(); - if (SF) { - if (SF->isMaxAccessLevelUsingImportInternal(import.value())) - SF->registerAccessLevelUsingImport(import.value(), - AccessLevel::Public); - } + if (SF) + SF->registerAccessLevelUsingImport(import.value(), + AccessLevel::Public); + auto &ctx = DC->getASTContext(); if (ctx.LangOpts.EnableModuleApiImportRemarks) { ModuleDecl *importedVia = import->module.importedModule, @@ -2611,6 +2550,49 @@ void swift::diagnoseUnnecessaryPublicImports(SourceFile &SF) { } } +/// Register the type extended by \p ED as being used in a package decl if +/// any member is a package decl. This patches a hole in the warnings on +/// superfluously public imports which usually relies on exportability checking +/// that is not currently executed for package decls. +void registerPackageAccessForPackageExtendedType(ExtensionDecl *ED) { + auto extendedType = ED->getExtendedNominal(); + if (!extendedType) + return; + + bool hasPackageMembers = llvm::any_of(ED->getMembers(), + [](const Decl *member) -> bool { + auto *VD = dyn_cast(member); + if (!VD) + return false; + + AccessScope accessScope = + VD->getFormalAccessScope(nullptr, + /*treatUsableFromInlineAsPublic*/true); + return accessScope.isPackage(); + }); + if (!hasPackageMembers) + return; + + DeclContext *DC = ED->getDeclContext(); + ImportAccessLevel import = extendedType->getImportAccessFrom(DC); + if (import.has_value()) { + auto SF = DC->getParentSourceFile(); + if (SF) + SF->registerAccessLevelUsingImport(import.value(), + AccessLevel::Package); + + auto &ctx = DC->getASTContext(); + if (ctx.LangOpts.EnableModuleApiImportRemarks) { + ModuleDecl *importedVia = import->module.importedModule, + *sourceModule = ED->getModuleContext(); + ED->diagnose(diag::module_api_import, + ED, importedVia, sourceModule, + importedVia == sourceModule, + /*isImplicit*/false); + } + } +} + void swift::checkAccessControl(Decl *D) { if (isa(D) || isa(D)) { bool allowInlineable = @@ -2619,6 +2601,7 @@ void swift::checkAccessControl(Decl *D) { UsableFromInlineChecker().visit(D); } else if (auto *ED = dyn_cast(D)) { checkExtensionGenericParamAccess(ED); + registerPackageAccessForPackageExtendedType(ED); } if (isa(D)) diff --git a/lib/Sema/TypeCheckAccess.h b/lib/Sema/TypeCheckAccess.h index b448da2fac608..6291c1de9d419 100644 --- a/lib/Sema/TypeCheckAccess.h +++ b/lib/Sema/TypeCheckAccess.h @@ -47,8 +47,7 @@ enum class DisallowedOriginKind : uint8_t { SPIOnly, MissingImport, FragileCxxAPI, - InternalOrLessImport, - PackageImport, + NonPublicImport, None }; diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 9f9c5b8391bfd..9ccb09655a4ec 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -44,12 +44,10 @@ using namespace swift; ExportContext::ExportContext( DeclContext *DC, AvailabilityContext runningOSVersion, - FragileFunctionKind kind, bool spi, bool isPackage, - bool exported, bool implicit, bool deprecated, - std::optional unavailablePlatformKind) + FragileFunctionKind kind, bool spi, bool exported, bool implicit, + bool deprecated, std::optional unavailablePlatformKind) : DC(DC), RunningOSVersion(runningOSVersion), FragileKind(kind) { SPI = spi; - IsPackage = isPackage; Exported = exported; Implicit = implicit; Deprecated = deprecated; @@ -74,7 +72,7 @@ bool swift::isExported(const ValueDecl *VD) { AccessScope accessScope = VD->getFormalAccessScope(nullptr, /*treatUsableFromInlineAsPublic*/true); - if (accessScope.isPublicOrPackage()) + if (accessScope.isPublic()) return true; // Is this a stored property in a @frozen struct or class? @@ -85,13 +83,13 @@ bool swift::isExported(const ValueDecl *VD) { return false; } -static bool hasConformancesToPublicOrPackageProtocols(const ExtensionDecl *ED) { +static bool hasConformancesToPublicProtocols(const ExtensionDecl *ED) { auto protocols = ED->getLocalProtocols(ConformanceLookupKind::OnlyExplicit); for (const ProtocolDecl *PD : protocols) { AccessScope scope = PD->getFormalAccessScope(/*useDC*/ nullptr, /*treatUsableFromInlineAsPublic*/ true); - if (scope.isPublicOrPackage()) + if (scope.isPublic()) return true; } @@ -113,7 +111,7 @@ bool swift::isExported(const ExtensionDecl *ED) { // If the extension declares a conformance to a public protocol then the // extension is exported. - if (hasConformancesToPublicOrPackageProtocols(ED)) + if (hasConformancesToPublicProtocols(ED)) return true; return false; @@ -186,20 +184,13 @@ static void forEachOuterDecl(DeclContext *DC, Fn fn) { } static void -computeExportContextBits(ASTContext &Ctx, Decl *D, - bool *spi, bool *isPackage, - bool *implicit, bool *deprecated, +computeExportContextBits(ASTContext &Ctx, Decl *D, bool *spi, bool *implicit, + bool *deprecated, std::optional *unavailablePlatformKind) { if (D->isSPI() || D->isAvailableAsSPI()) *spi = true; - if (auto VD = dyn_cast(D)) { - *isPackage = VD->getFormalAccessScope(nullptr, true).isPackage(); - } else if (auto ED = dyn_cast(D)) { - *isPackage = ED->getDefaultAccessLevel() == AccessLevel::Package; - } - // Defer bodies are desugared to an implicit closure expression. We need to // dilute the meaning of "implicit" to make sure we're still checking // availability inside of defer statements. @@ -217,8 +208,8 @@ computeExportContextBits(ASTContext &Ctx, Decl *D, if (auto *PBD = dyn_cast(D)) { for (unsigned i = 0, e = PBD->getNumPatternEntries(); i < e; ++i) { if (auto *VD = PBD->getAnchoringVarDecl(i)) - computeExportContextBits(Ctx, VD, spi, isPackage, implicit, - deprecated, unavailablePlatformKind); + computeExportContextBits(Ctx, VD, spi, implicit, deprecated, + unavailablePlatformKind); } } } @@ -233,25 +224,23 @@ ExportContext ExportContext::forDeclSignature(Decl *D) { ? AvailabilityContext::alwaysAvailable() : TypeChecker::overApproximateAvailabilityAtLocation(D->getLoc(), DC)); bool spi = Ctx.LangOpts.LibraryLevel == LibraryLevel::SPI; - bool isPackage = false; bool implicit = false; bool deprecated = false; std::optional unavailablePlatformKind; - computeExportContextBits(Ctx, D, &spi, &isPackage, &implicit, - &deprecated, &unavailablePlatformKind); - + computeExportContextBits(Ctx, D, &spi, &implicit, &deprecated, + &unavailablePlatformKind); forEachOuterDecl(D->getDeclContext(), [&](Decl *D) { computeExportContextBits(Ctx, D, - &spi, &isPackage, &implicit, - &deprecated, &unavailablePlatformKind); + &spi, &implicit, &deprecated, + &unavailablePlatformKind); }); bool exported = ::isExported(D); return ExportContext(DC, runningOSVersion, fragileKind, - spi, isPackage, exported, implicit, - deprecated, unavailablePlatformKind); + spi, exported, implicit, deprecated, + unavailablePlatformKind); } ExportContext ExportContext::forFunctionBody(DeclContext *DC, SourceLoc loc) { @@ -266,20 +255,19 @@ ExportContext ExportContext::forFunctionBody(DeclContext *DC, SourceLoc loc) { bool spi = Ctx.LangOpts.LibraryLevel == LibraryLevel::SPI; bool implicit = false; bool deprecated = false; - bool isPackage = false; std::optional unavailablePlatformKind; forEachOuterDecl(DC, [&](Decl *D) { computeExportContextBits(Ctx, D, - &spi, &isPackage, &implicit, - &deprecated, &unavailablePlatformKind); + &spi, &implicit, &deprecated, + &unavailablePlatformKind); }); bool exported = false; return ExportContext(DC, runningOSVersion, fragileKind, - spi, isPackage, exported, implicit, - deprecated, unavailablePlatformKind); + spi, exported, implicit, deprecated, + unavailablePlatformKind); } ExportContext ExportContext::forConformance(DeclContext *DC, @@ -288,7 +276,7 @@ ExportContext ExportContext::forConformance(DeclContext *DC, auto where = forDeclSignature(DC->getInnermostDeclarationDeclContext()); where.Exported &= proto->getFormalAccessScope( - DC, /*usableFromInlineAsPublic*/true).isPublicOrPackage(); + DC, /*usableFromInlineAsPublic*/true).isPublic(); return where; } @@ -4487,7 +4475,7 @@ void swift::checkExplicitAvailability(Decl *decl) { return false; }); - auto hasProtocols = hasConformancesToPublicOrPackageProtocols(extension); + auto hasProtocols = hasConformancesToPublicProtocols(extension); if (!hasMembers && !hasProtocols) return; diff --git a/lib/Sema/TypeCheckAvailability.h b/lib/Sema/TypeCheckAvailability.h index 6a527918c0231..c4e6fddfd57d2 100644 --- a/lib/Sema/TypeCheckAvailability.h +++ b/lib/Sema/TypeCheckAvailability.h @@ -72,11 +72,7 @@ enum class ExportabilityReason : unsigned { PropertyWrapper, ResultBuilder, ExtensionWithPublicMembers, - ExtensionWithConditionalConformances, - // Exported members of extension can be `package`. - ExtensionWithPackageMembers, - // Exported inheritance type can be `package`. - ExtensionWithPackageConditionalConformances + ExtensionWithConditionalConformances }; /// A description of the restrictions on what declarations can be referenced @@ -84,12 +80,9 @@ enum class ExportabilityReason : unsigned { /// /// We say a declaration is "exported" if all of the following holds: /// -/// - the declaration is `public` or `@usableFromInline` +/// - the declaration is `public` or `@usableFromInline` /// - the declaration is not `@_spi` /// - the declaration was not imported from an `@_implementationOnly` import -/// - the declaration is `package`; while treated as exported, the -/// scope is limited compared to `public` or `@usableFromInline`; -/// the `IsPackage` bit is set to track the scope. /// /// The "signature" of a declaration is the set of all types written in the /// declaration (such as function parameter and return types), but not @@ -112,7 +105,6 @@ class ExportContext { AvailabilityContext RunningOSVersion; FragileFunctionKind FragileKind; unsigned SPI : 1; - unsigned IsPackage : 1; unsigned Exported : 1; unsigned Deprecated : 1; unsigned Implicit : 1; @@ -121,7 +113,7 @@ class ExportContext { unsigned Reason : 3; ExportContext(DeclContext *DC, AvailabilityContext runningOSVersion, - FragileFunctionKind kind, bool spi, bool isPackage, bool exported, + FragileFunctionKind kind, bool spi, bool exported, bool implicit, bool deprecated, std::optional unavailablePlatformKind); @@ -176,9 +168,6 @@ class ExportContext { /// If true, the context is SPI and can reference SPI declarations. bool isSPI() const { return SPI; } - /// If true, the context has a package access scope. - bool isPackage() const { return IsPackage; } - /// If true, the context is exported and cannot reference SPI declarations /// or declarations from `@_implementationOnly` imports. bool isExported() const { return Exported; } diff --git a/test/Sema/access-level-import-classic-exportability.swift b/test/Sema/access-level-import-classic-exportability.swift index 47857813a423c..b08b900cb0e03 100644 --- a/test/Sema/access-level-import-classic-exportability.swift +++ b/test/Sema/access-level-import-classic-exportability.swift @@ -52,9 +52,9 @@ public struct PrivateImportType { //--- Client.swift public import PublicLib package import PackageLib // expected-note 2 {{struct 'PackageImportType' imported as 'package' from 'PackageLib' here}} -internal import InternalLib // expected-note 4 {{struct 'InternalImportType' imported as 'internal' from 'InternalLib' here}} -fileprivate import FileprivateLib // expected-note 4 {{struct 'FileprivateImportType' imported as 'fileprivate' from 'FileprivateLib' here}} -private import PrivateLib // expected-note 4 {{struct 'PrivateImportType' imported as 'private' from 'PrivateLib' here}} +internal import InternalLib // expected-note 2 {{struct 'InternalImportType' imported as 'internal' from 'InternalLib' here}} +fileprivate import FileprivateLib // expected-note 2 {{struct 'FileprivateImportType' imported as 'fileprivate' from 'FileprivateLib' here}} +private import PrivateLib // expected-note 2 {{struct 'PrivateImportType' imported as 'private' from 'PrivateLib' here}} public protocol PublicConstrainedExtensionProto {} extension Array: PublicConstrainedExtensionProto where Element == PublicImportType {} @@ -87,8 +87,8 @@ extension PublicImportType { } public protocol PackageConstrainedExtensionProto {} -extension Array: PackageConstrainedExtensionProto where Element == PackageImportType {} // expected-error {{cannot use struct 'PackageImportType' in an extension with conditional conformances; 'PackageLib' was imported as package}} -extension PackageImportType { // expected-error {{cannot use struct 'PackageImportType' in an extension with public or '@usableFromInline' members; 'PackageLib' was imported as package}} +extension Array: PackageConstrainedExtensionProto where Element == PackageImportType {} // expected-error {{cannot use struct 'PackageImportType' in an extension with conditional conformances; 'PackageLib' was not imported publicly}} +extension PackageImportType { // expected-error {{cannot use struct 'PackageImportType' in an extension with public or '@usableFromInline' members; 'PackageLib' was not imported publicly}} public func publicMethod() {} } @@ -123,8 +123,8 @@ extension InternalImportType { // expected-error {{cannot use struct 'InternalIm } package protocol InternalConstrainedExtensionProtoInPackage {} -extension Array: InternalConstrainedExtensionProtoInPackage where Element == InternalImportType {} // expected-error {{cannot use struct 'InternalImportType' in an extension with conditional conformances; 'InternalLib' was not imported publicly or as package}} -extension InternalImportType { // expected-error {{cannot use struct 'InternalImportType' in an extension with public, package, or '@usableFromInline' members; 'InternalLib' was not imported publicly or as package}} +extension Array: InternalConstrainedExtensionProtoInPackage where Element == InternalImportType {} +extension InternalImportType { package func packageMethod() {} } @@ -153,8 +153,8 @@ extension FileprivateImportType { // expected-error {{cannot use struct 'Filepri } package protocol FileprivateConstrainedExtensionProtoInPackage {} -extension Array: FileprivateConstrainedExtensionProtoInPackage where Element == FileprivateImportType {} // expected-error {{cannot use struct 'FileprivateImportType' in an extension with conditional conformances; 'FileprivateLib' was not imported publicly or as package}} -extension FileprivateImportType { // expected-error {{cannot use struct 'FileprivateImportType' in an extension with public, package, or '@usableFromInline' members; 'FileprivateLib' was not imported publicly or as package}} +extension Array: FileprivateConstrainedExtensionProtoInPackage where Element == FileprivateImportType {} +extension FileprivateImportType { package func packageMethod() {} } @@ -183,8 +183,8 @@ extension PrivateImportType { // expected-error {{cannot use struct 'PrivateImpo } package protocol PrivateConstrainedExtensionProtoInPackage {} -extension Array: PrivateConstrainedExtensionProtoInPackage where Element == PrivateImportType {} // expected-error {{cannot use struct 'PrivateImportType' in an extension with conditional conformances; 'PrivateLib' was not imported publicly or as package}} -extension PrivateImportType { // expected-error {{cannot use struct 'PrivateImportType' in an extension with public, package, or '@usableFromInline' members; 'PrivateLib' was not imported publicly or as package}} +extension Array: PrivateConstrainedExtensionProtoInPackage where Element == PrivateImportType {} +extension PrivateImportType { package func packageMethod() {} } diff --git a/test/Sema/access-level-import-conformances.swift b/test/Sema/access-level-import-conformances.swift index b2d974885d534..59026f41608db 100644 --- a/test/Sema/access-level-import-conformances.swift +++ b/test/Sema/access-level-import-conformances.swift @@ -2,82 +2,29 @@ // RUN: split-file --leading-lines %s %t /// Build the libraries. -// RUN: %target-swift-frontend -emit-module %t/ConformanceBaseTypes.swift -o %t -package-name pkg -// RUN: %target-swift-frontend -emit-module %t/ConformanceDefinition1.swift -o %t -I %t -package-name pkg -// RUN: %target-swift-frontend -emit-module %t/ConformanceDefinition2.swift -o %t -I %t -package-name pkg +// RUN: %target-swift-frontend -emit-module %t/ConformanceBaseTypes.swift -o %t +// RUN: %target-swift-frontend -emit-module %t/ConformanceDefinition.swift -o %t -I %t /// Check diagnostics. -// RUN: %target-swift-frontend -typecheck -verify %t/ClientA.swift -I %t -package-name pkg -// RUN: %target-swift-frontend -typecheck -verify %t/ClientB.swift -I %t -package-name pkg +// RUN: %target-swift-frontend -typecheck -verify %t/Client.swift -I %t //--- ConformanceBaseTypes.swift public protocol Proto {} public struct ConformingType { - public init () {} + public init () {} } -package protocol PkgProto {} // expected-note 2 {{protocol 'PkgProto' is not '@usableFromInline' or public}} -package struct PkgConformingType { // expected-note 4 {{struct 'PkgConformingType' is not '@usableFromInline' or public}} - package init () {} // expected-note 4 {{initializer 'init()' is not '@usableFromInline' or public}} -} - -//--- ConformanceDefinition1.swift +//--- ConformanceDefinition.swift import ConformanceBaseTypes extension ConformingType : Proto {} -//--- ConformanceDefinition2.swift -import ConformanceBaseTypes -extension PkgConformingType : PkgProto {} - -//--- ClientA.swift +//--- Client.swift public import ConformanceBaseTypes -internal import ConformanceDefinition1 // expected-note 2 {{extension of struct 'ConformingType' imported as 'internal' from 'ConformanceDefinition1' here}} -internal import ConformanceDefinition2 // expected-note 3 {{extension of struct 'PkgConformingType' imported as 'internal' from 'ConformanceDefinition2' here}} +internal import ConformanceDefinition // expected-note 2 {{extension of struct 'ConformingType' imported as 'internal' from 'ConformanceDefinition' here}} -public func useInAPI(a: any Proto = ConformingType()) { // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition1' was not imported publicly}} -} -public func useInAPI(b: any PkgProto = PkgConformingType()) { - // expected-error@-1 {{cannot use conformance of 'PkgConformingType' to 'PkgProto' here; 'ConformanceDefinition2' was not imported publicly}} - // expected-error@-2 {{function cannot be declared public because its parameter uses a package type}} - // expected-error@-3 {{struct 'PkgConformingType' is package and cannot be referenced from a default argument value}} - // expected-error@-4 {{initializer 'init()' is package and cannot be referenced from a default argument value}} -} -package func useInPkgAPI(a: any PkgProto = PkgConformingType()) { - // expected-error@-1 {{cannot use conformance of 'PkgConformingType' to 'PkgProto' here; 'ConformanceDefinition2' was not imported publicly}} +public func useInAPI(a: any Proto = ConformingType()) { // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition' was not imported publicly}} } @inlinable public func inlinableFunc() { - let _: any Proto = ConformingType() // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition1' was not imported publicly}} - - let _: any PkgProto = PkgConformingType() - // expected-error@-1 {{cannot use conformance of 'PkgConformingType' to 'PkgProto' here; 'ConformanceDefinition2' was not imported publicly}} - // expected-error@-2 {{protocol 'PkgProto' is package and cannot be referenced from an '@inlinable' function}} - // expected-error@-3 {{struct 'PkgConformingType' is package and cannot be referenced from an '@inlinable' function}} - // expected-error@-4 {{initializer 'init()' is package and cannot be referenced from an '@inlinable' function}} -} - -//--- ClientB.swift -public import ConformanceBaseTypes -package import ConformanceDefinition1 // expected-note 2 {{extension of struct 'ConformingType' imported as 'package' from 'ConformanceDefinition1' here}} -package import ConformanceDefinition2 // expected-note 2 {{extension of struct 'PkgConformingType' imported as 'package' from 'ConformanceDefinition2' here}} - -public func useInAPI(a: any Proto = ConformingType()) { // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition1' was imported as package}} -} -public func useInAPI(b: any PkgProto = PkgConformingType()) { - // expected-error@-1 {{cannot use conformance of 'PkgConformingType' to 'PkgProto' here; 'ConformanceDefinition2' was imported as package}} - // expected-error@-2 {{function cannot be declared public because its parameter uses a package type}} - // expected-error@-3 {{struct 'PkgConformingType' is package and cannot be referenced from a default argument value}} - // expected-error@-4 {{initializer 'init()' is package and cannot be referenced from a default argument value}} -} -package func useInPkgAPI(a: any PkgProto = PkgConformingType()) { // no-error -} - -@inlinable public func inlinableFunc() { - let _: any Proto = ConformingType() // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition1' was imported as package}} - - let _: any PkgProto = PkgConformingType() - // expected-error@-1 {{cannot use conformance of 'PkgConformingType' to 'PkgProto' here; 'ConformanceDefinition2' was imported as package}} - // expected-error@-2 {{protocol 'PkgProto' is package and cannot be referenced from an '@inlinable' function}} - // expected-error@-3 {{struct 'PkgConformingType' is package and cannot be referenced from an '@inlinable' function}} - // expected-error@-4 {{initializer 'init()' is package and cannot be referenced from an '@inlinable' function}} + let _: any Proto = ConformingType() // expected-error {{cannot use conformance of 'ConformingType' to 'Proto' here; 'ConformanceDefinition' was not imported publicly}} } diff --git a/test/Sema/access-level-import-inlinable.swift b/test/Sema/access-level-import-inlinable.swift index 22d7ddfa22c05..5ce02e71e90ac 100644 --- a/test/Sema/access-level-import-inlinable.swift +++ b/test/Sema/access-level-import-inlinable.swift @@ -43,20 +43,6 @@ public struct PackageImportType { public init() {} } -public protocol PackageImportProto { - associatedtype T -} - -public func PackageFunc() {} - -@propertyWrapper -public struct PackageImportWrapper { - public var wrappedValue: T - public init(wrappedValue: T) { - self.wrappedValue = wrappedValue - } -} - //--- InternalLib.swift public protocol InternalImportProto { associatedtype T @@ -90,12 +76,7 @@ public struct PrivateImportType { public import PublicLib package import PackageLib -// expected-note@-1 9 {{struct 'PackageImportType' imported as 'package' from 'PackageLib' here}} -// expected-note@-2 2 {{global function 'PackageFunc()' imported as 'package' from 'PackageLib' here}} -// expected-note@-3 2 {{protocol 'PackageImportProto' imported as 'package' from 'PackageLib' here}} -// expected-note@-4 2 {{initializer 'init()' imported as 'package' from 'PackageLib' here}} -// expected-note@-5 2 {{generic struct 'PackageImportWrapper' imported as 'package' from 'PackageLib' here}} -// expected-note@-6 2 {{initializer 'init(wrappedValue:)' imported as 'package' from 'PackageLib' here}} +// expected-note@-1 4 {{struct 'PackageImportType' imported as 'package' from 'PackageLib' here}} internal import InternalLib // expected-note@-1 9 {{struct 'InternalImportType' imported as 'internal' from 'InternalLib' here}} @@ -109,29 +90,24 @@ fileprivate import FileprivateLib // expected-note@-3 2 {{protocol 'FileprivateImportProto' imported as 'fileprivate' from 'FileprivateLib' here}} private import PrivateLib -// expected-note@-1 12 {{struct 'PrivateImportType' imported as 'private' from 'PrivateLib' here}} -// expected-note@-2 2 {{initializer 'init()' imported as 'private' from 'PrivateLib' here}} +// expected-note@-1 10 {{struct 'PrivateImportType' imported as 'private' from 'PrivateLib' here}} + // expected-note@-2 2 {{initializer 'init()' imported as 'private' from 'PrivateLib' here}} public struct GenericType {} @inlinable public func inlinable() { PublicFunc() - PackageFunc() // expected-error {{global function 'PackageFunc()' is package and cannot be referenced from an '@inlinable' function}} InternalFunc() // expected-error {{global function 'InternalFunc()' is internal and cannot be referenced from an '@inlinable' function}} let _: PublicImportType - let _: PackageImportType // expected-error {{struct 'PackageImportType' is package and cannot be referenced from an '@inlinable' function}} let _: InternalImportType // expected-error {{struct 'InternalImportType' is internal and cannot be referenced from an '@inlinable' function}} let _ = PublicImportType() - let _ = PackageImportType() // expected-error {{struct 'PackageImportType' is package and cannot be referenced from an '@inlinable' function}} - // expected-error @-1 {{initializer 'init()' is package and cannot be referenced from an '@inlinable' function}} let _ = PrivateImportType() // expected-error {{struct 'PrivateImportType' is private and cannot be referenced from an '@inlinable' function}} // expected-error @-1 {{initializer 'init()' is private and cannot be referenced from an '@inlinable' function}} let _: any PublicImportProto - let _: any PackageImportProto // expected-error {{protocol 'PackageImportProto' is package and cannot be referenced from an '@inlinable' function}} let _: any InternalImportProto // expected-error {{protocol 'InternalImportProto' is internal and cannot be referenced from an '@inlinable' function}} let _: any FileprivateImportProto & InternalImportProto // expected-error {{protocol 'FileprivateImportProto' is fileprivate and cannot be referenced from an '@inlinable' function}} @@ -150,10 +126,6 @@ public struct GenericType {} @PublicImportWrapper var wrappedPublic: PublicImportType - @PackageImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is package and cannot be referenced from an '@inlinable' function}} - // expected-error @-1 {{generic struct 'PackageImportWrapper' is package and cannot be referenced from an '@inlinable' function}} - var wrappedPackage: PublicImportType - @FileprivateImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is fileprivate and cannot be referenced from an '@inlinable' function}} // expected-error @-1 {{generic struct 'FileprivateImportWrapper' is fileprivate and cannot be referenced from an '@inlinable' function}} var wrappedFileprivate: PublicImportType @@ -166,21 +138,16 @@ public struct GenericType {} @_alwaysEmitIntoClient public func alwaysEmitIntoClient() { PublicFunc() - PackageFunc() // expected-error {{global function 'PackageFunc()' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} InternalFunc() // expected-error {{global function 'InternalFunc()' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _: PublicImportType - let _: PackageImportType // expected-error {{struct 'PackageImportType' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _: InternalImportType // expected-error {{struct 'InternalImportType' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _ = PublicImportType() - let _ = PackageImportType() // expected-error {{struct 'PackageImportType' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} - // expected-error @-1 {{initializer 'init()' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _ = PrivateImportType() // expected-error {{struct 'PrivateImportType' is private and cannot be referenced from an '@_alwaysEmitIntoClient' function}} // expected-error @-1 {{initializer 'init()' is private and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _: any PublicImportProto - let _: any PackageImportProto // expected-error {{protocol 'PackageImportProto' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _: any InternalImportProto // expected-error {{protocol 'InternalImportProto' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}} let _: any FileprivateImportProto & InternalImportProto // expected-error {{protocol 'FileprivateImportProto' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}} @@ -199,10 +166,6 @@ public struct GenericType {} @PublicImportWrapper var wrappedPublic: PublicImportType - @PackageImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} - // expected-error @-1 {{generic struct 'PackageImportWrapper' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}} - var wrappedPackage: PublicImportType - @FileprivateImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}} // expected-error @-1 {{generic struct 'FileprivateImportWrapper' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}} var wrappedFileprivate: PublicImportType @@ -217,23 +180,12 @@ public struct GenericType {} // expected-note @-1 {{struct 'PrivateImportType' is imported by this file as 'private' from 'PrivateLib'}} } -@frozen package struct PkgBadFields1 { - private var field: PrivateImportType // expected-error {{type referenced from a stored property in a '@frozen package' struct must be '@usableFromInline', public, or package}} - // expected-note @-1 {{struct 'PrivateImportType' is imported by this file as 'private' from 'PrivateLib'}} -} - @_fixed_layout public struct FixedBadFields1 { // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} private var field: PrivateImportType // expected-error {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}} // expected-note @-1 {{struct 'PrivateImportType' is imported by this file as 'private' from 'PrivateLib'}} } -@_fixed_layout package struct PkgFixedBadFields1 { - // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} - private var field: PrivateImportType // expected-error {{type referenced from a stored property in a '@frozen package' struct must be '@usableFromInline', public, or package}} - // expected-note @-1 {{struct 'PrivateImportType' is imported by this file as 'private' from 'PrivateLib'}} -} - @frozen public struct BadFields2 { private var field: PrivateImportType? // expected-error {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}} // expected-note @-1 {{struct 'PrivateImportType' is imported by this file as 'private' from 'PrivateLib'}} @@ -297,17 +249,6 @@ public struct GenericType {} } } -// expected-error@+1 {{the result of a '@usableFromInline' function must be '@usableFromInline' or public}} -@usableFromInline func notReallyUsableFromInlinePkg() -> PackageImportType? { return nil } -// expected-note @-1 {{struct 'PackageImportType' is imported by this file as 'package' from 'PackageLib'}} -@frozen public struct BadFieldsPkg7 { - private var field = notReallyUsableFromInlinePkg() // expected-error {{type referenced from a stored property with inferred type 'PackageImportType?' in a '@frozen' struct must be '@usableFromInline' or public}} -} -@_fixed_layout public struct FrozenBadFieldsPkg7 { - // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} - private var field = notReallyUsableFromInlinePkg() // expected-error {{type referenced from a stored property with inferred type 'PackageImportType?' in a '@frozen' struct must be '@usableFromInline' or public}} -} - // expected-error@+1 {{the result of a '@usableFromInline' function must be '@usableFromInline' or public}} @usableFromInline func notReallyUsableFromInline() -> InternalImportType? { return nil } // expected-note @-1 {{struct 'InternalImportType' is imported by this file as 'internal' from 'InternalLib'}} @@ -320,36 +261,13 @@ public struct GenericType {} private var field = notReallyUsableFromInline() // expected-error {{type referenced from a stored property with inferred type 'InternalImportType?' in a '@frozen' struct must be '@usableFromInline' or public}} } -@frozen package struct PkgBadFields7 { - private var field = notReallyUsableFromInline() // expected-error {{type referenced from a stored property with inferred type 'InternalImportType?' in a '@frozen package' struct must be '@usableFromInline', public, or package}} -} -@_fixed_layout package struct PkgFrozenBadFields7 { - // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} - private var field = notReallyUsableFromInline() // expected-error {{type referenced from a stored property with inferred type 'InternalImportType?' in a '@frozen package' struct must be '@usableFromInline', public, or package}} -} - @frozen public struct OKFields { - public var field: PublicImportType internal static var staticProp: InternalImportType? private var computed: PrivateImportType? { return nil } } @_fixed_layout public struct FixedOKFields { // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} - public var field: PublicImportType - internal static var staticProp: InternalImportType? - private var computed: PrivateImportType? { return nil } -} - -@frozen package struct PkgOKFields { - package var field: PackageImportType - internal static var staticProp: InternalImportType? - private var computed: PrivateImportType? { return nil } -} - -@_fixed_layout package struct PkgFixedOKFields { - // expected-warning@-1 {{'@frozen' attribute is now used for fixed-layout structs}} - package var field: PackageImportType internal static var staticProp: InternalImportType? private var computed: PrivateImportType? { return nil } } diff --git a/test/Sema/access-level-import-package-exportability.swift b/test/Sema/access-level-import-package-exportability.swift deleted file mode 100644 index 48d5e6a4b10cd..0000000000000 --- a/test/Sema/access-level-import-package-exportability.swift +++ /dev/null @@ -1,108 +0,0 @@ -// RUN: %empty-directory(%t) -// RUN: split-file %s %t - -// RUN: %target-swift-frontend -emit-module %t/Lib.swift \ -// RUN: -module-name Lib -swift-version 6 -I %t \ -// RUN: -package-name mypkg \ -// RUN: -enable-library-evolution \ -// RUN: -emit-module -emit-module-path %t/Lib.swiftmodule - -// RUN: %target-swift-frontend -typecheck %t/ClientA.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify -// RUN: %target-swift-frontend -typecheck %t/ClientB.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify -// RUN: %target-swift-frontend -typecheck %t/ClientC.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify -// RUN: %target-swift-frontend -typecheck %t/ClientD.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify -// RUN: %target-swift-frontend -typecheck %t/ClientE.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify -// RUN: %target-swift-frontend -typecheck %t/ClientF.swift -I %t -swift-version 6 -package-name mypkg -enable-library-evolution -verify - -//--- ClientA.swift - -@_implementationOnly import Lib // expected-warning {{'@_implementationOnly' is deprecated, use 'internal import' instead}} - -public func f() -> PubProto? { // expected-error {{cannot use protocol 'PubProto' here; 'Lib' has been imported as implementation-only}} - return nil -} -package func g() -> PkgProto? { // expected-error {{cannot use protocol 'PkgProto' here; 'Lib' has been imported as implementation-only}} - return nil -} - -//--- ClientB.swift -package import Lib // no-warning - -extension PkgStruct { - package static var v: Self { - fatalError() - } -} - -//--- ClientC.swift -package import Lib // no-warning - -extension PkgStruct { - package func f() {} -} - -//--- ClientD.swift -package import Lib // no-warning - -package extension PubStruct { - func f() {} -} - -//--- ClientE.swift -package import Lib - -package enum FeatureFlag: PubProto { // no-warning - case myFeatureFlag - - package var domain: StaticString { "MyDomain" } - package var feature: StaticString { "MyFeature" } - - package var someVar: String { "" } -} - -package struct MyStruct: PubProto { // no-warning - package var someVar: String { "" } -} - -//--- ClientF.swift -package struct PkgStruct {} -public protocol PubProto { - associatedtype CodeUnit -} - -extension PkgStruct { - @frozen - package enum ASCII {} -} - -extension PkgStruct.ASCII: PubProto { - package typealias CodeUnit = UInt8 -} - -//--- Lib.swift - -// expected-note@+1 1{{type declared here}} -public protocol PubProto { - var someVar: String { get } -} - -// expected-note@+1 1{{type declared here}} -package protocol PkgProto { - var someVar: String { get } -} - -public struct PubStruct { - public init() {} -} - -package struct PkgStruct { - package init() {} -} - -public class PubKlass { - public init() {} -} - -package class PkgKlass { - package init() {} -} diff --git a/test/Sema/access-level-import-typealias.swift b/test/Sema/access-level-import-typealias.swift index ec7e72eb441ce..95f30887c737d 100644 --- a/test/Sema/access-level-import-typealias.swift +++ b/test/Sema/access-level-import-typealias.swift @@ -13,22 +13,6 @@ // RUN: -swift-version 5 -enable-library-evolution \ // RUN: -enable-upcoming-feature InternalImportsByDefault -// RUN: %target-swift-frontend -emit-module %t/Original.swift -o %t \ -// RUN: -swift-version 6 -enable-library-evolution -package-name pkg - -// RUN: %target-swift-frontend -emit-module %t/AliasesPkg.swift -o %t \ -// RUN: -swift-version 6 -enable-library-evolution -I %t -package-name pkg - -// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesPkg1.swift -I %t \ -// RUN: -swift-version 5 -enable-library-evolution -package-name pkg -// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesPkg1.swift -I %t \ -// RUN: -swift-version 6 -enable-library-evolution -package-name pkg - -// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesPkg2.swift -I %t \ -// RUN: -swift-version 5 -enable-library-evolution -package-name pkg -// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesPkg2.swift -I %t \ -// RUN: -swift-version 6 -enable-library-evolution -package-name pkg - //--- Original.swift open class Clazz {} @@ -48,46 +32,3 @@ public class InheritsFromClazzAlias: ClazzAlias {} _ = ClazzAlias.self } - -//--- AliasesPkg.swift -public import Original // expected-warning {{public import of 'Original' was not used in public declarations or inlinable code}} -package typealias PkgClazzAlias = Clazz // expected-note 2 {{type alias 'PkgClazzAlias' is not '@usableFromInline' or public}} - -//--- UsesAliasesPkg1.swift -public import AliasesPkg // expected-warning {{public import of 'AliasesPkg' was not used in public declarations or inlinable code}} -internal import Original // expected-note 1 {{class 'Clazz' imported as 'internal' from 'Original' here}} - -// expected-error@+1 {{'PkgClazzAlias' aliases 'Original.Clazz' and cannot be used here because 'Original' was not imported publicly}} -package class InheritsFromPkgClazzAlias: PkgClazzAlias {} - -@inlinable public func inlinableFunc() { - // expected-error@+1 {{type alias 'PkgClazzAlias' is package and cannot be referenced from an '@inlinable' function}} - _ = PkgClazzAlias.self -} - -@inlinable package func inlinableFuncPkg() { - // expected-error@+1 {{type alias 'PkgClazzAlias' is package and cannot be referenced from an '@inlinable' function}} - _ = PkgClazzAlias.self -} - - -//--- UsesAliasesPkg2.swift -public import AliasesPkg // expected-warning {{public import of 'AliasesPkg' was not used in public declarations or inlinable code}} -package import Original - -package class InheritsFromPkgClazzAlias: PkgClazzAlias {} // no-error - -package func usePkgClazzAlias() { - _ = PkgClazzAlias.self // no-error -} - -@inlinable public func inlinableFunc() { - // expected-error@+1 {{type alias 'PkgClazzAlias' is package and cannot be referenced from an '@inlinable' function}} - _ = PkgClazzAlias.self -} - -@inlinable package func inlinableFuncPkg() { - // expected-error@+1 {{type alias 'PkgClazzAlias' is package and cannot be referenced from an '@inlinable' function}} - _ = PkgClazzAlias.self -} - diff --git a/test/Sema/superfluously-public-imports.swift b/test/Sema/superfluously-public-imports.swift index e65eef4d93fc4..b6e7f137c475d 100644 --- a/test/Sema/superfluously-public-imports.swift +++ b/test/Sema/superfluously-public-imports.swift @@ -235,9 +235,7 @@ internal func internalFunc(a: NotAnAPIType = notAnAPIFunc()) {} func implicitlyInternalFunc(a: NotAnAPIType = notAnAPIFunc()) {} // For package decls we only remark on types used in signatures, not for inlinable code. -package func packageFunc(a: PackageType = packageFunc()) {} -// expected-remark@-1 {{struct 'PackageType' is imported via 'ImportUsedInPackage'}} -// expected-remark@-2 {{global function 'packageFunc()' is imported via 'ImportUsedInPackage'}} +package func packageFunc(a: PackageType = packageFunc()) {} // expected-remark {{struct 'PackageType' is imported via 'ImportUsedInPackage'}} @_spi(X) public func spiFunc(a: ToUseFromSPI) {} // expected-remark {{struct 'ToUseFromSPI' is imported via 'SPIOnlyUsedInSPI'}} @@ -249,7 +247,7 @@ public protocol Countable { extension Extended: Countable { // expected-remark {{struct 'Extended' is imported via 'RetroactiveConformance'}} } -extension ExtendedPackageType { // expected-remark 2 {{struct 'ExtendedPackageType' is imported via 'ExtendedPackageTypeImport'}} +extension ExtendedPackageType { // expected-remark {{struct 'ExtendedPackageType' is imported via 'ExtendedPackageTypeImport'}} package func useExtendedPackageType() { } } diff --git a/test/attr/attr_fixed_layout_property_wrapper.swift b/test/attr/attr_fixed_layout_property_wrapper.swift index f3cf1ae60bfce..643e207837e4e 100644 --- a/test/attr/attr_fixed_layout_property_wrapper.swift +++ b/test/attr/attr_fixed_layout_property_wrapper.swift @@ -1,9 +1,8 @@ // RUN: %target-typecheck-verify-swift -swift-version 5 -package-name myPkg -private class PrivateType {} -// expected-note@-1 2 {{class 'PrivateType' is not '@usableFromInline' or public}} -// expected-note@-2 2 {{initializer 'init()' is not '@usableFromInline' or public}} -// expected-note@-3 2 {{type declared here}} +private class PrivateType {} // expected-note {{class 'PrivateType' is not '@usableFromInline' or public}} +// expected-note@-1 {{initializer 'init()' is not '@usableFromInline' or public}} +// expected-note@-2 {{type declared here}} package class PackageType { // expected-note@-1 {{class 'PackageType' is not '@usableFromInline' or public}} @@ -45,20 +44,3 @@ public struct Wrapper { @Wrapper private var z1: PackageTypeForInline @Wrapper private var z2 = PackageTypeForInline() } - - -@frozen package struct FrozenPackageStruct { - @Wrapper private var p1: PrivateType - // expected-error@-1 {{type referenced from a stored property in a '@frozen package' struct must be '@usableFromInline', public, or package}} - - @Wrapper private var p2 = PrivateType() - // expected-error@-1 {{class 'PrivateType' is private and cannot be referenced from a property initializer in a '@frozen' type}} - // expected-error@-2 {{initializer 'init()' is private and cannot be referenced from a property initializer in a '@frozen' type}} - // expected-error@-3 {{type referenced from a stored property with inferred type 'PrivateType' in a '@frozen package' struct must be '@usableFromInline', public, or package}} - - // no-errors below - @Wrapper private var q1: PackageType - @Wrapper private var q2 = PackageType() - @Wrapper private var r1: PackageTypeForInline - @Wrapper private var r2 = PackageTypeForInline() -} From 89b6f91a9fc28002220a8dddfd03e6aaffea550d Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Tue, 11 Jun 2024 09:56:24 -0700 Subject: [PATCH 049/165] IRGen: Use static alloca for builtin stackAlloc when possible rdar://129599643 --- lib/IRGen/GenOpaque.cpp | 9 +++++++- lib/IRGen/IRGenSIL.cpp | 13 ++++++++++++ test/IRGen/temporary_allocation/async.swift | 2 +- test/IRGen/temporary_allocation/codegen.swift | 21 +++++++++++-------- .../codegen_very_large_allocation.swift | 2 +- 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/lib/IRGen/GenOpaque.cpp b/lib/IRGen/GenOpaque.cpp index 51cdc11bf7ec1..8c24577a74e99 100644 --- a/lib/IRGen/GenOpaque.cpp +++ b/lib/IRGen/GenOpaque.cpp @@ -656,7 +656,14 @@ void IRGenFunction::emitDeallocateDynamicAlloca(StackAddress address, // NOTE: llvm does not support dynamic allocas in coroutines. auto allocToken = address.getExtraInfo(); - assert(allocToken && "dynamic alloca in coroutine without alloc token?"); + if (!allocToken) { +#ifndef NDEBUG + auto *alloca = cast(address.getAddress().getAddress()); + assert(isa(alloca->getArraySize()) && + "Dynamic alloca without a token?!"); +#endif + return; + } Builder.CreateIntrinsicCall(llvm::Intrinsic::coro_alloca_free, allocToken); return; } diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index d5808be6d7de6..e7fbd3fddf637 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -3559,6 +3559,11 @@ static llvm::Value *getStackAllocationSize(IRGenSILFunction &IGF, result = IGF.Builder.CreateMul(capacity, stride); } + if (auto constResult = dyn_cast(result)) { + if (!constResult->getUniqueInteger().isZero()) + return constResult; + } + // If the caller requests a zero-byte allocation, allocate one byte instead // to ensure that the resulting pointer is valid and unique on the stack. return IGF.Builder.CreateIntrinsicCall(llvm::Intrinsic::umax, @@ -3601,6 +3606,14 @@ static void emitBuiltinStackAlloc(IRGenSILFunction &IGF, IGF, i->getOperand(0), i->getOperand(1), loc); auto align = getStackAllocationAlignment(IGF, i->getOperand(2), loc); + // Emit a static alloca if the size is constant. + if (auto *constSize = dyn_cast(size)) { + auto stackAddress = IGF.createAlloca(IGF.IGM.Int8Ty, constSize, align, + "temp_alloc"); + IGF.setLoweredStackAddress(i, {stackAddress}); + return; + } + auto stackAddress = IGF.emitDynamicAlloca(IGF.IGM.Int8Ty, size, align, false, "temp_alloc"); IGF.setLoweredStackAddress(i, stackAddress); diff --git a/test/IRGen/temporary_allocation/async.swift b/test/IRGen/temporary_allocation/async.swift index d9453ff195236..be60d72733d43 100644 --- a/test/IRGen/temporary_allocation/async.swift +++ b/test/IRGen/temporary_allocation/async.swift @@ -9,5 +9,5 @@ func f() async { blackHole(buffer.baseAddress) } } -// CHECK: alloca [123 x i8], align 1 + // CHECK-NOT: swift_task_alloc diff --git a/test/IRGen/temporary_allocation/codegen.swift b/test/IRGen/temporary_allocation/codegen.swift index 815ff089bcee2..ba2c430279a08 100644 --- a/test/IRGen/temporary_allocation/codegen.swift +++ b/test/IRGen/temporary_allocation/codegen.swift @@ -10,10 +10,20 @@ do { blackHole(ptr) ptr.deallocate() } -// CHECK: ptrtoint ptr {{.*}} to [[WORD:i[0-9]+]] // MARK: Trivial Cases +// CHECK: [[ONE_BYTE_PTR_RAW:%temp_alloc[0-9]*]] = alloca i8, align 1 +// CHECK: [[FIVE_BYTE_PTR_RAW:%temp_alloc[0-9]*]] = alloca [5 x i8], align 1 +// CHECK: [[ONE_KB_PTR_RAW:%temp_alloc[0-9]*]] = alloca [1024 x i8], align 8 +// CHECK: [[ONE_KB_RAND_PTR_RAW:%temp_alloc[0-9]*]] = alloca [1024 x i8], align 16 +// CHECK: [[INT_PTR_RAW:%temp_alloc[0-9]*]] = alloca [16 x i8], align 4 +// CHECK: [[INT_PTR_RAW2:%temp_alloc[0-9]*]] = alloca [16 x i8], align 4 +// CHECK: [[VOID_PTR_RAW:%temp_alloc[0-9]*]] = alloca [2 x i8], align 1 + +// CHECK: ptrtoint ptr {{.*}} to [[WORD:i[0-9]+]] + + withUnsafeTemporaryAllocation(byteCount: 0, alignment: 1) { buffer in blackHole(buffer.baseAddress) } @@ -24,21 +34,18 @@ withUnsafeTemporaryAllocation(byteCount: 0, alignment: 1) { buffer in withUnsafeTemporaryAllocation(byteCount: 1, alignment: 1) { buffer in blackHole(buffer.baseAddress) } -// CHECK: [[ONE_BYTE_PTR_RAW:%temp_alloc[0-9]*]] = alloca i8, align 1 // CHECK: [[ONE_BYTE_PTR:%[0-9]+]] = ptrtoint ptr [[ONE_BYTE_PTR_RAW]] to [[WORD]] // CHECK: call swiftcc void @blackHole([[WORD]] [[ONE_BYTE_PTR]]) withUnsafeTemporaryAllocation(byteCount: 5, alignment: 1) { buffer in blackHole(buffer.baseAddress) } -// CHECK: [[FIVE_BYTE_PTR_RAW:%temp_alloc[0-9]*]] = alloca [5 x i8], align 1 // CHECK: [[FIVE_BYTE_PTR:%[0-9]+]] = ptrtoint ptr [[FIVE_BYTE_PTR_RAW]] to [[WORD]] // CHECK: call swiftcc void @blackHole([[WORD]] [[FIVE_BYTE_PTR]]) withUnsafeTemporaryAllocation(byteCount: 1024, alignment: 8) { buffer in blackHole(buffer.baseAddress) } -// CHECK: [[ONE_KB_PTR_RAW:%temp_alloc[0-9]*]] = alloca [1024 x i8], align 8 // CHECK: [[ONE_KB_PTR:%[0-9]+]] = ptrtoint ptr [[ONE_KB_PTR_RAW]] to [[WORD]] // CHECK: call swiftcc void @blackHole([[WORD]] [[ONE_KB_PTR]]) @@ -47,7 +54,6 @@ withUnsafeTemporaryAllocation(byteCount: 1024, alignment: 8) { buffer in withUnsafeTemporaryAllocation(byteCount: 1024, alignment: Int.random(in: 0 ..< 16)) { buffer in blackHole(buffer.baseAddress) } -// CHECK: [[ONE_KB_RAND_PTR_RAW:%temp_alloc[0-9]*]] = alloca [1024 x i8], align 16 // CHECK: [[ONE_KB_RAND_PTR:%[0-9]+]] = ptrtoint ptr [[ONE_KB_RAND_PTR_RAW]] to [[WORD]] // CHECK: call swiftcc void @blackHole([[WORD]] [[ONE_KB_RAND_PTR]]) @@ -56,21 +62,18 @@ withUnsafeTemporaryAllocation(byteCount: 1024, alignment: Int.random(in: 0 ..< 1 withUnsafeTemporaryAllocation(of: Int32.self, capacity: 4) { buffer in blackHole(buffer.baseAddress) } -// CHECK: [[INT_PTR_RAW:%temp_alloc[0-9]*]] = alloca [16 x i8], align 4 // CHECK: [[INT_PTR:%[0-9]+]] = ptrtoint ptr [[INT_PTR_RAW]] to [[WORD]] // CHECK: call swiftcc void @blackHole([[WORD]] [[INT_PTR]]) _withUnprotectedUnsafeTemporaryAllocation(of: Int32.self, capacity: 4) { buffer in blackHole(buffer.baseAddress) } -// CHECK: [[INT_PTR_RAW:%temp_alloc[0-9]*]] = alloca [16 x i8], align 4 -// CHECK: [[INT_PTR:%[0-9]+]] = ptrtoint ptr [[INT_PTR_RAW]] to [[WORD]] +// CHECK: [[INT_PTR:%[0-9]+]] = ptrtoint ptr [[INT_PTR_RAW2]] to [[WORD]] // CHECK: call swiftcc void @blackHole([[WORD]] [[INT_PTR]]) withUnsafeTemporaryAllocation(of: Void.self, capacity: 2) { buffer in blackHole(buffer.baseAddress) } -// CHECK: [[VOID_PTR_RAW:%temp_alloc[0-9]*]] = alloca [2 x i8], align 1 // CHECK: [[VOID_PTR:%[0-9]+]] = ptrtoint ptr [[VOID_PTR_RAW]] to [[WORD]] // CHECK: call swiftcc void @blackHole([[WORD]] [[VOID_PTR]]) diff --git a/test/IRGen/temporary_allocation/codegen_very_large_allocation.swift b/test/IRGen/temporary_allocation/codegen_very_large_allocation.swift index 335355724ecce..0773089e36cf7 100644 --- a/test/IRGen/temporary_allocation/codegen_very_large_allocation.swift +++ b/test/IRGen/temporary_allocation/codegen_very_large_allocation.swift @@ -24,7 +24,7 @@ withUnsafeTemporaryAllocation(byteCount: 0x0FFF_FFFF, alignment: 1) { buffer in // CHECK-LARGE-HEAP-ALLOC-NEXT: {{(tail )?}}call void @swift_slowDealloc(ptr [[HEAP_PTR_RAW]], [[WORD]] -1, [[WORD]] -1) // CHECK-LARGE-STACK-ALLOC: [[STACK_PTR_RAW:%temp_alloc[0-9]*]] = alloca [268435455 x i8], align 1 -// CHECK-LARGE-STACK-ALLOC-NEXT: [[STACK_PTR:%[0-9]+]] = ptrtoint ptr [[STACK_PTR_RAW]] to [[WORD]] +// CHECK-LARGE-STACK-ALLOC: [[STACK_PTR:%[0-9]+]] = ptrtoint ptr [[STACK_PTR_RAW]] to [[WORD]] // CHECK-LARGE-STACK-ALLOC-NEXT: call swiftcc void @blackHole([[WORD]] [[STACK_PTR]]) // CHECK-LARGE-ALLOC-DAG: [[IS_SAFE:%[0-9]+]] = {{(tail )?}}call {{(zeroext )?}}i1 @swift_stdlib_isStackAllocationSafe([[WORD]] 268435455, [[WORD]] 1) From 71ec06e65665526ddbe474507b27d4e8613ac837 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 11 Jun 2024 13:01:52 -0700 Subject: [PATCH 050/165] Cache visible Clang modules for interface printing in 'ModuleDecl' Instead of caching the collection of visible Clang modules in the 'TypePrinter', compute and cache them in the 'ModuleDecl'. When printing a textual interface, the compiler will instantiate many new instances of 'TypePrinter', which means caching them there is not useful. --- include/swift/AST/Module.h | 14 ++++++++++ lib/AST/ASTPrinter.cpp | 57 +------------------------------------- lib/AST/Module.cpp | 48 ++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 56 deletions(-) diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index de5819d870918..42f4a27b669a3 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -39,6 +39,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" #include +#include #include namespace clang { @@ -537,6 +538,11 @@ class ModuleDecl std::optional> declaringModuleAndBystander; + /// A cache of this module's visible Clang modules + /// parameterized by the Swift interface print mode. + using VisibleClangModuleSet = llvm::DenseMap; + std::unordered_map CachedVisibleClangModuleSet; + /// If this module is an underscored cross import overlay, gets the underlying /// module that declared it (which may itself be a cross-import overlay), /// along with the name of the required bystander module. Used by tooling to @@ -578,6 +584,14 @@ class ModuleDecl bool getRequiredBystandersIfCrossImportOverlay( ModuleDecl *declaring, SmallVectorImpl &bystanderNames); + /// Computes all Clang modules that are visible from this moule. + /// This includes any modules that are imported transitively through public + /// (`@_exported`) imports. + /// + /// The computed map associates each visible Clang module with the + /// corresponding Swift module. + const VisibleClangModuleSet & + getVisibleClangModules(PrintOptions::InterfaceMode contentMode); /// Walks and loads the declared, underscored cross-import overlays of this /// module and its underlying clang module, transitively, to find all cross diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 75fe2995540e5..073e8d272aa7e 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -5724,8 +5724,6 @@ class TypePrinter : public TypeVisitor { ASTPrinter &Printer; const PrintOptions &Options; - std::optional> - VisibleClangModules; void printGenericArgs(ArrayRef flatArgs) { Printer << "<"; @@ -5799,56 +5797,6 @@ class TypePrinter : public TypeVisitor { return T->hasSimpleTypeRepr(); } - /// Computes the map that is cached by `getVisibleClangModules()`. - /// Do not call directly. - llvm::DenseMap - computeVisibleClangModules() { - assert(Options.CurrentModule && - "CurrentModule needs to be set to determine imported Clang modules"); - - llvm::DenseMap Result; - - // For the current module, consider both private and public imports. - ModuleDecl::ImportFilter Filter = ModuleDecl::ImportFilterKind::Exported; - Filter |= ModuleDecl::ImportFilterKind::Default; - - // For private or package swiftinterfaces, also look through @_spiOnly imports. - if (!Options.printPublicInterface()) - Filter |= ModuleDecl::ImportFilterKind::SPIOnly; - // Consider package import for package interface - if (Options.printPackageInterface()) - Filter |= ModuleDecl::ImportFilterKind::PackageOnly; - - SmallVector Imports; - Options.CurrentModule->getImportedModules(Imports, Filter); - - SmallVector ModulesToProcess; - for (const auto &Import : Imports) { - ModulesToProcess.push_back(Import.importedModule); - } - - SmallPtrSet Processed; - while (!ModulesToProcess.empty()) { - ModuleDecl *Mod = ModulesToProcess.back(); - ModulesToProcess.pop_back(); - - if (!Processed.insert(Mod).second) - continue; - - if (const clang::Module *ClangModule = Mod->findUnderlyingClangModule()) - Result[ClangModule] = Mod; - - // For transitive imports, consider only public imports. - Imports.clear(); - Mod->getImportedModules(Imports, ModuleDecl::ImportFilterKind::Exported); - for (const auto &Import : Imports) { - ModulesToProcess.push_back(Import.importedModule); - } - } - - return Result; - } - /// Returns all Clang modules that are visible from `Options.CurrentModule`. /// This includes any modules that are imported transitively through public /// (`@_exported`) imports. @@ -5857,10 +5805,7 @@ class TypePrinter : public TypeVisitor { /// corresponding Swift module. const llvm::DenseMap & getVisibleClangModules() { - if (!VisibleClangModules) { - VisibleClangModules = computeVisibleClangModules(); - } - return *VisibleClangModules; + return Options.CurrentModule->getVisibleClangModules(Options.InterfaceContentKind); } template diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 24deaf7fb1101..0388e514dd572 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -1719,6 +1719,54 @@ void ModuleDecl::getMissingImportedModules( FORWARD(getMissingImportedModules, (imports)); } +const llvm::DenseMap & +ModuleDecl::getVisibleClangModules(PrintOptions::InterfaceMode contentMode) { + if (CachedVisibleClangModuleSet.find(contentMode) != CachedVisibleClangModuleSet.end()) + return CachedVisibleClangModuleSet[contentMode]; + else + CachedVisibleClangModuleSet.emplace(contentMode, VisibleClangModuleSet{}); + VisibleClangModuleSet &result = CachedVisibleClangModuleSet[contentMode]; + + // For the current module, consider both private and public imports. + ModuleDecl::ImportFilter Filter = ModuleDecl::ImportFilterKind::Exported; + Filter |= ModuleDecl::ImportFilterKind::Default; + + // For private or package swiftinterfaces, also look through @_spiOnly imports. + if (contentMode != PrintOptions::InterfaceMode::Public) + Filter |= ModuleDecl::ImportFilterKind::SPIOnly; + // Consider package import for package interface + if (contentMode == PrintOptions::InterfaceMode::Package) + Filter |= ModuleDecl::ImportFilterKind::PackageOnly; + + SmallVector Imports; + getImportedModules(Imports, Filter); + + SmallVector ModulesToProcess; + for (const auto &Import : Imports) + ModulesToProcess.push_back(Import.importedModule); + + SmallPtrSet Processed; + while (!ModulesToProcess.empty()) { + ModuleDecl *Mod = ModulesToProcess.back(); + ModulesToProcess.pop_back(); + + if (!Processed.insert(Mod).second) + continue; + + if (const clang::Module *ClangModule = Mod->findUnderlyingClangModule()) + result[ClangModule] = Mod; + + // For transitive imports, consider only public imports. + Imports.clear(); + Mod->getImportedModules(Imports, ModuleDecl::ImportFilterKind::Exported); + for (const auto &Import : Imports) { + ModulesToProcess.push_back(Import.importedModule); + } + } + + return result; +} + void SourceFile::getImportedModules(SmallVectorImpl &modules, ModuleDecl::ImportFilter filter) const { From d98cb9e2b31928ee22d205ae0a59b796d8ca01e6 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 11 Jun 2024 12:42:41 +0100 Subject: [PATCH 051/165] [Mangler] Mangle function type for invalid enum element Previously we would mangle a single ErrorType as the type for the element, but that would fail to demangle since we expect a function type. Use the same logic as AbstractFunctionDecl, mangling a function type of ErrorType. While here, also handle SubscriptDecls and check for error types rather than `isInvalid()`. rdar://129065620 --- lib/AST/ASTMangler.cpp | 9 ++--- ...um_case_with_invalid_associated_type.swift | 7 ++++ test/Index/rdar129065620.swift | 12 +++++++ ...ndex_effective_access_level.swift.response | 36 +++++++++---------- 4 files changed, 42 insertions(+), 22 deletions(-) create mode 100644 test/Index/enum_case_with_invalid_associated_type.swift create mode 100644 test/Index/rdar129065620.swift diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index b3b456a888f07..090a521a5c8b4 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -3842,8 +3842,11 @@ CanType ASTMangler::getDeclTypeForMangling( parentGenericSig = GenericSignature(); auto &C = decl->getASTContext(); - if (decl->isInvalid()) { - if (isa(decl)) { + + auto ty = decl->getInterfaceType()->getReferenceStorageReferent(); + if (ty->hasError()) { + if (isa(decl) || isa(decl) || + isa(decl)) { // FIXME: Verify ExtInfo state is correct, not working by accident. CanFunctionType::ExtInfo info; return CanFunctionType::get({AnyFunctionType::Param(C.TheErrorType)}, @@ -3852,8 +3855,6 @@ CanType ASTMangler::getDeclTypeForMangling( return C.TheErrorType; } - Type ty = decl->getInterfaceType()->getReferenceStorageReferent(); - // If this declaration predates concurrency, adjust its type to not // contain type features that were not available pre-concurrency. This // cannot alter the ABI in any way. diff --git a/test/Index/enum_case_with_invalid_associated_type.swift b/test/Index/enum_case_with_invalid_associated_type.swift new file mode 100644 index 0000000000000..c7921e1fd4598 --- /dev/null +++ b/test/Index/enum_case_with_invalid_associated_type.swift @@ -0,0 +1,7 @@ +enum MyEnum { +// RUN: %target-swift-ide-test -print-indexed-symbols -source-filename %s | %FileCheck %s + case test(artifactID: String, hostTriple: Triple) +// CHECK: enumerator/Swift | test(artifactID:hostTriple:) +// CHECK: param/Swift | artifactID +// CHECK: param/Swift | hostTriple +} diff --git a/test/Index/rdar129065620.swift b/test/Index/rdar129065620.swift new file mode 100644 index 0000000000000..d3504b9feb592 --- /dev/null +++ b/test/Index/rdar129065620.swift @@ -0,0 +1,12 @@ +// RUN: %empty-directory(%t) +// RUN: not %target-swift-frontend -typecheck %s -index-store-path %t + +// rdar://129065620 - Make sure we don't crash when verifying the mangling. +enum Foo { + case bar(id: UInt32) + case bar(id: UInt32) +} + +struct S { + subscript(x: Invalid) -> Invalid {} +} diff --git a/test/SourceKit/Indexing/index_effective_access_level.swift.response b/test/SourceKit/Indexing/index_effective_access_level.swift.response index af824d5ff6344..69cf39a48c6b9 100644 --- a/test/SourceKit/Indexing/index_effective_access_level.swift.response +++ b/test/SourceKit/Indexing/index_effective_access_level.swift.response @@ -1302,14 +1302,14 @@ { key.kind: source.lang.swift.decl.function.subscript, key.name: "subscript(_:)", - key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVXeip", + key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVyXeXecip", key.line: 93, key.column: 5, key.entities: [ { key.kind: source.lang.swift.decl.function.accessor.getter, key.name: "getter:subscript(_:)", - key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVXeig", + key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVyXeXecig", key.line: 93, key.column: 46 }, @@ -1333,14 +1333,14 @@ { key.kind: source.lang.swift.decl.function.subscript, key.name: "subscript(_:)", - key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVXeip", + key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVyXeXecip", key.line: 94, key.column: 17, key.entities: [ { key.kind: source.lang.swift.decl.function.accessor.getter, key.name: "getter:subscript(_:)", - key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVXeig", + key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVyXeXecig", key.line: 94, key.column: 61 }, @@ -1369,14 +1369,14 @@ { key.kind: source.lang.swift.decl.function.subscript, key.name: "subscript(_:)", - key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVXeip", + key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVyXeXecip", key.line: 95, key.column: 13, key.entities: [ { key.kind: source.lang.swift.decl.function.accessor.getter, key.name: "getter:subscript(_:)", - key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVXeig", + key.usr: "s:28index_effective_access_level18ScopeReducerStruct33_2295DDF1454D6A6D9229E8222CD85214LLVyXeXecig", key.line: 95, key.column: 53 }, @@ -2077,14 +2077,14 @@ { key.kind: source.lang.swift.decl.function.subscript, key.name: "subscript(_:)", - key.usr: "s:28index_effective_access_level17ScopeKeeperStructVXeip", + key.usr: "s:28index_effective_access_level17ScopeKeeperStructVyXeXecip", key.line: 121, key.column: 5, key.entities: [ { key.kind: source.lang.swift.decl.function.accessor.getter, key.name: "getter:subscript(_:)", - key.usr: "s:28index_effective_access_level17ScopeKeeperStructVXeig", + key.usr: "s:28index_effective_access_level17ScopeKeeperStructVyXeXecig", key.line: 121, key.column: 46 }, @@ -2108,14 +2108,14 @@ { key.kind: source.lang.swift.decl.function.subscript, key.name: "subscript(_:)", - key.usr: "s:28index_effective_access_level17ScopeKeeperStructVXe33_2295DDF1454D6A6D9229E8222CD85214Llip", + key.usr: "s:28index_effective_access_level17ScopeKeeperStructVyXeXec33_2295DDF1454D6A6D9229E8222CD85214Llip", key.line: 122, key.column: 17, key.entities: [ { key.kind: source.lang.swift.decl.function.accessor.getter, key.name: "getter:subscript(_:)", - key.usr: "s:28index_effective_access_level17ScopeKeeperStructVXe33_2295DDF1454D6A6D9229E8222CD85214Llig", + key.usr: "s:28index_effective_access_level17ScopeKeeperStructVyXeXec33_2295DDF1454D6A6D9229E8222CD85214Llig", key.line: 122, key.column: 61 }, @@ -2144,14 +2144,14 @@ { key.kind: source.lang.swift.decl.function.subscript, key.name: "subscript(_:)", - key.usr: "s:28index_effective_access_level17ScopeKeeperStructVXe33_2295DDF1454D6A6D9229E8222CD85214Llip", + key.usr: "s:28index_effective_access_level17ScopeKeeperStructVyXeXec33_2295DDF1454D6A6D9229E8222CD85214Llip", key.line: 123, key.column: 13, key.entities: [ { key.kind: source.lang.swift.decl.function.accessor.getter, key.name: "getter:subscript(_:)", - key.usr: "s:28index_effective_access_level17ScopeKeeperStructVXe33_2295DDF1454D6A6D9229E8222CD85214Llig", + key.usr: "s:28index_effective_access_level17ScopeKeeperStructVyXeXec33_2295DDF1454D6A6D9229E8222CD85214Llig", key.line: 123, key.column: 53 }, @@ -2852,14 +2852,14 @@ { key.kind: source.lang.swift.decl.function.subscript, key.name: "subscript(_:)", - key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVXeip", + key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVyXeXecip", key.line: 149, key.column: 5, key.entities: [ { key.kind: source.lang.swift.decl.function.accessor.getter, key.name: "getter:subscript(_:)", - key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVXeig", + key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVyXeXecig", key.line: 149, key.column: 46 }, @@ -2883,14 +2883,14 @@ { key.kind: source.lang.swift.decl.function.subscript, key.name: "subscript(_:)", - key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVXe33_2295DDF1454D6A6D9229E8222CD85214Llip", + key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVyXeXec33_2295DDF1454D6A6D9229E8222CD85214Llip", key.line: 150, key.column: 17, key.entities: [ { key.kind: source.lang.swift.decl.function.accessor.getter, key.name: "getter:subscript(_:)", - key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVXe33_2295DDF1454D6A6D9229E8222CD85214Llig", + key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVyXeXec33_2295DDF1454D6A6D9229E8222CD85214Llig", key.line: 150, key.column: 61 }, @@ -2919,14 +2919,14 @@ { key.kind: source.lang.swift.decl.function.subscript, key.name: "subscript(_:)", - key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVXe33_2295DDF1454D6A6D9229E8222CD85214Llip", + key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVyXeXec33_2295DDF1454D6A6D9229E8222CD85214Llip", key.line: 151, key.column: 13, key.entities: [ { key.kind: source.lang.swift.decl.function.accessor.getter, key.name: "getter:subscript(_:)", - key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVXe33_2295DDF1454D6A6D9229E8222CD85214Llig", + key.usr: "s:28index_effective_access_level25PartialScopeReducerStructVyXeXec33_2295DDF1454D6A6D9229E8222CD85214Llig", key.line: 151, key.column: 53 }, From 34d9b6cb6b6b63e5be603a38ecbb1d0d5005ddc7 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Tue, 11 Jun 2024 14:03:45 -0700 Subject: [PATCH 052/165] Revert "Sema: Report references to missing imports from package extensions" This reverts commit 12f7abcef69bbf7d0f18c438e6266f31ebaaa068. --- include/swift/AST/DiagnosticsSema.def | 2 -- test/Sema/missing-import-typealias.swift | 22 ++++------------------ 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index c9f84a778fefe..0117897c2c694 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -3662,8 +3662,6 @@ ERROR(typealias_desugars_to_type_from_hidden_module,none, "as property wrapper here|" "as result builder here|" "in an extension with public or '@usableFromInline' members|" - "in an extension with conditional conformances|" - "in an extension with public, package, or '@usableFromInline' members|" "in an extension with conditional conformances}3 " "because %select{%4 has been imported as implementation-only|" "it is an SPI imported from %4|" diff --git a/test/Sema/missing-import-typealias.swift b/test/Sema/missing-import-typealias.swift index 71862195a55ae..d67f01b1a935b 100644 --- a/test/Sema/missing-import-typealias.swift +++ b/test/Sema/missing-import-typealias.swift @@ -7,23 +7,22 @@ // RUN: %target-swift-emit-module-interface(%t/Aliases.swiftinterface) %t/Aliases.swift -I %t // RUN: %target-swift-typecheck-module-from-interface(%t/Aliases.swiftinterface) -I %t -// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesNoImport.swift -enable-library-evolution -I %t -package-name pkg +// RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesNoImport.swift -enable-library-evolution -I %t // RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesImplementationOnlyImport.swift -enable-library-evolution -I %t // RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesSPIOnlyImport.swift -enable-library-evolution -I %t -experimental-spi-only-imports // RUN: %target-swift-frontend -typecheck -verify %t/UsesAliasesWithImport.swift -enable-library-evolution -I %t /// With library evolution disabled UsesAliasesNoImport.swift should compile without diagnostics. -// RUN: %target-swift-frontend -typecheck %t/UsesAliasesNoImport.swift -I %t -package-name pkg | %FileCheck %t/UsesAliasesNoImport.swift --check-prefix=CHECK-NON-RESILIENT --allow-empty +// RUN: %target-swift-frontend -typecheck %t/UsesAliasesNoImport.swift -I %t | %FileCheck %t/UsesAliasesNoImport.swift --check-prefix=CHECK-NON-RESILIENT --allow-empty /// The swiftinterface is broken by the missing import without the workaround. -// RUN: %target-swift-emit-module-interface(%t/UsesAliasesNoImport.swiftinterface) %t/UsesAliasesNoImport.swift -I %t -package-name pkg \ +// RUN: %target-swift-emit-module-interface(%t/UsesAliasesNoImport.swiftinterface) %t/UsesAliasesNoImport.swift -I %t \ // RUN: -disable-print-missing-imports-in-module-interface // RUN: not %target-swift-typecheck-module-from-interface(%t/UsesAliasesNoImport.swiftinterface) -I %t /// The swiftinterface parses fine with the workaround adding the missing imports. -// RUN: %target-swift-emit-module-interface(%t/UsesAliasesNoImportFixed.swiftinterface) %t/UsesAliasesNoImport.swift -I %t -package-name pkg -emit-package-module-interface-path %t/UsesAliasesNoImportFixed.package.swiftinterface +// RUN: %target-swift-emit-module-interface(%t/UsesAliasesNoImportFixed.swiftinterface) %t/UsesAliasesNoImport.swift -I %t // RUN: %target-swift-typecheck-module-from-interface(%t/UsesAliasesNoImportFixed.swiftinterface) -I %t -// RUN: %target-swift-typecheck-module-from-interface(%t/UsesAliasesNoImportFixed.package.swiftinterface) -I %t -module-name UsesAliasesNoImportFixed /// The module with an implementation-only import is not affected by the workaround and remains broken. // RUN: %target-swift-emit-module-interface(%t/UsesAliasesImplementationOnlyImport.swiftinterface) %t/UsesAliasesImplementationOnlyImport.swift -I %t \ @@ -71,10 +70,6 @@ import Aliases // expected-note@+1 {{The missing import of module 'Original' will be added implicitly}} public class InheritsFromClazzAlias: ClazzAlias {} -// expected-warning@+2 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used here because 'Original' was not imported by this file; this is an error in the Swift 6 language mode}} -// expected-note@+1 {{The missing import of module 'Original' will be added implicitly}} -package class InheritsFromClazzAliasPackage: ClazzAlias {} - @inlinable public func inlinableFunc() { // expected-warning@+2 {{'StructAlias' aliases 'Original.Struct' and cannot be used in an '@inlinable' function because 'Original' was not imported by this file; this is an error in the Swift 6 language mode}} // expected-note@+1 {{The missing import of module 'Original' will be added implicitly}} @@ -85,10 +80,6 @@ package class InheritsFromClazzAliasPackage: ClazzAlias {} // expected-note@+1 {{The missing import of module 'Original' will be added implicitly}} public func takesGeneric(_ t: T) {} -// expected-warning@+2 {{'ProtoAlias' aliases 'Original.Proto' and cannot be used here because 'Original' was not imported by this file; this is an error in the Swift 6 language mode}} -// expected-note@+1 {{The missing import of module 'Original' will be added implicitly}} -package func takesGenericPackage(_ t: T) {} - public struct HasMembers { // expected-warning@+2 {{'WrapperAlias' aliases 'Original.Wrapper' and cannot be used as property wrapper here because 'Original' was not imported by this file; this is an error in the Swift 6 language mode}} // expected-note@+1 {{The missing import of module 'Original' will be added implicitly}} @@ -101,11 +92,6 @@ extension StructAlias { public func someFunc() {} } -// expected-warning@+2 {{'StructAlias' aliases 'Original.Struct' and cannot be used in an extension with public, package, or '@usableFromInline' members because 'Original' was not imported by this file; this is an error in the Swift 6 language mode}} -// expected-note@+1 {{The missing import of module 'Original' will be added implicitly}} -extension StructAlias { - package func someFuncPackage() {} -} //--- UsesAliasesImplementationOnlyImport.swift From 1a06ddc3ba91928ff0286838a4435ed7850f1b31 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 11 Jun 2024 12:36:37 -0700 Subject: [PATCH 053/165] Bump the DWARF version number to 5 on Darwin. The default debug info format for newer versions of Darwin is DWARF 5. https://developer.apple.com/documentation/xcode-release-notes/xcode-16-release-notes rdar://110925733 --- lib/Driver/DarwinToolChains.cpp | 29 +++++++++++++++++++++++------ test/Driver/options.swift | 12 ++++++++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/lib/Driver/DarwinToolChains.cpp b/lib/Driver/DarwinToolChains.cpp index 04670c6a5e3ae..5532de9c9e188 100644 --- a/lib/Driver/DarwinToolChains.cpp +++ b/lib/Driver/DarwinToolChains.cpp @@ -659,23 +659,40 @@ toolchains::Darwin::addDeploymentTargetArgs(ArgStringList &Arguments, static unsigned getDWARFVersionForTriple(const llvm::Triple &triple) { llvm::VersionTuple osVersion; const DarwinPlatformKind kind = getDarwinPlatformKind(triple); + // Default to DWARF 2 on OS X 10.10 / iOS 8 and lower. + // Default to DWARF 4 on OS X 10.11 - macOS 14 / iOS - iOS 17. switch (kind) { case DarwinPlatformKind::MacOS: triple.getMacOSXVersion(osVersion); if (osVersion < llvm::VersionTuple(10, 11)) return 2; - return 4; + if (osVersion < llvm::VersionTuple(15)) + return 4; + return 5; case DarwinPlatformKind::IPhoneOSSimulator: case DarwinPlatformKind::IPhoneOS: case DarwinPlatformKind::TvOS: case DarwinPlatformKind::TvOSSimulator: osVersion = triple.getiOSVersion(); - if (osVersion < llvm::VersionTuple(9)) - return 2; - return 4; - default: - return 4; + if (osVersion < llvm::VersionTuple(9)) + return 2; + if (osVersion < llvm::VersionTuple(18)) + return 4; + return 5; + case DarwinPlatformKind::WatchOS: + case DarwinPlatformKind::WatchOSSimulator: + osVersion = triple.getWatchOSVersion(); + if (osVersion < llvm::VersionTuple(11)) + return 4; + return 5; + case DarwinPlatformKind::VisionOS: + case DarwinPlatformKind::VisionOSSimulator: + osVersion = triple.getOSVersion(); + if (osVersion < llvm::VersionTuple(2)) + return 4; + return 5; } + llvm_unreachable("unsupported platform kind"); } void toolchains::Darwin::addCommonFrontendArgs( diff --git a/test/Driver/options.swift b/test/Driver/options.swift index d001acde914ac..39aa6b3f40f90 100644 --- a/test/Driver/options.swift +++ b/test/Driver/options.swift @@ -109,6 +109,7 @@ // MISSING_OPTION_G_ERROR: error: option '-debug-info-format={{.*}}' is missing a required argument (-g) // RUN: %swift_driver -### -g -dwarf-version=3 %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_3 %s +// DWARF_VERSION_5: -dwarf-version=5 // DWARF_VERSION_4: -dwarf-version=4 // DWARF_VERSION_3: -dwarf-version=3 // DWARF_VERSION_2: -dwarf-version=2 @@ -135,6 +136,17 @@ // RUN: %swift_driver -### -g -target arm64_32-apple-watchos10.0 %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_4 %s // RUN: %swiftc_driver -### -g -target arm64_32-apple-watchos10.0 %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_4 %s +// RUN: %swift_driver -### -g -target x86_64-apple-macosx15 %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_5 %s +// RUN: %swiftc_driver -### -g -target x86_64-apple-macosx15 %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_5 %s +// RUN: %swift_driver -### -g -target arm64-apple-ios18.0 %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_5 %s +// RUN: %swiftc_driver -### -g -target arm64-apple-ios18.0 %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_5 %s +// RUN: %swift_driver -### -g -target arm64-apple-ios18.0-macabi %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_5 %s +// RUN: %swiftc_driver -### -g -target arm64-apple-ios18.0-macabi %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_5 %s +// RUN: %swift_driver -### -g -target arm64-apple-tvos18 %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_5 %s +// RUN: %swiftc_driver -### -g -target arm64-apple-tvos18 %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_5 %s +// RUN: %swift_driver -### -g -target arm64_32-apple-watchos11 %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_5 %s +// RUN: %swiftc_driver -### -g -target arm64_32-apple-watchos11 %s 2>&1 | %FileCheck -check-prefix DWARF_VERSION_5 %s + // RUN: not %swift_driver -gline-tables-only -debug-info-format=codeview %s 2>&1 | %FileCheck -check-prefix BAD_DEBUG_LEVEL_ERROR %s // RUN: not %swift_driver -gdwarf-types -debug-info-format=codeview %s 2>&1 | %FileCheck -check-prefix BAD_DEBUG_LEVEL_ERROR %s // RUN: not %swiftc_driver -gline-tables-only -debug-info-format=codeview %s 2>&1 | %FileCheck -check-prefix BAD_DEBUG_LEVEL_ERROR %s From 2d70de8a7f058d703e1c37b08dd4453289c4c226 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 14:14:02 -0700 Subject: [PATCH 054/165] [IRGen] Assert on retaining noncopyable. --- lib/IRGen/IRGenSIL.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index d5808be6d7de6..82c13597ef4ad 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -5109,6 +5109,7 @@ void IRGenSILFunction::visitCondBranchInst(swift::CondBranchInst *i) { } void IRGenSILFunction::visitRetainValueInst(swift::RetainValueInst *i) { + assert(!i->getOperand()->getType().isMoveOnly()); Explosion in = getLoweredExplosion(i->getOperand()); Explosion out; cast(getTypeInfo(i->getOperand()->getType())) @@ -5119,6 +5120,7 @@ void IRGenSILFunction::visitRetainValueInst(swift::RetainValueInst *i) { void IRGenSILFunction::visitRetainValueAddrInst(swift::RetainValueAddrInst *i) { SILValue operandValue = i->getOperand(); + assert(!operandValue->getType().isMoveOnly()); Address addr = getLoweredAddress(operandValue); SILType addrTy = operandValue->getType(); SILType objectT = addrTy.getObjectType(); From 38db63c05e134d33e558cf2067b22ffc8e1c99dd Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 14:14:59 -0700 Subject: [PATCH 055/165] [NFC] ClosureSpecializer: Use llvm::enumerate. Rather than manually tracking the index. --- lib/SILOptimizer/IPO/ClosureSpecializer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index d3d2e0f5110ab..2c09bd7f9d870 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -680,9 +680,11 @@ static bool isSupportedClosure(const SILInstruction *Closure) { // This is a temporary limitation. auto ClosureCallee = FRI->getReferencedFunction(); auto ClosureCalleeConv = ClosureCallee->getConventions(); - unsigned ClosureArgIdx = + unsigned ClosureArgIdxBase = ClosureCalleeConv.getNumSILArguments() - PAI->getNumArguments(); - for (auto Arg : PAI->getArguments()) { + for (auto pair : llvm::enumerate(PAI->getArguments())) { + auto Arg = pair.value(); + auto ClosureArgIdx = pair.index() + ClosureArgIdxBase; SILType ArgTy = Arg->getType(); // If our argument is an object, continue... if (ArgTy.isObject()) { From 55eb29ad3a1acff8e852ef01238ef0e8c1a2b06c Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 14:16:20 -0700 Subject: [PATCH 056/165] [Gardening] Detypo'd. --- lib/SILOptimizer/IPO/ClosureSpecializer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index 2c09bd7f9d870..d37f18050f414 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -1396,7 +1396,7 @@ bool SILClosureSpecializerTransform::gatherCallSites( // foo({ c() }) // } // - // A limit of 2 is good enough and will not be exceed in "regular" + // A limit of 2 is good enough and will not be exceeded in "regular" // optimization scenarios. if (getSpecializationLevel(getClosureCallee(ClosureInst)) > SpecializationLevelLimit) { From ac5ae3cc2a71f9f8059a4bd86a32e2eceb50c1a3 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 14:16:41 -0700 Subject: [PATCH 057/165] [ClosureSpecializer] Bail on noncopyable argument. The optimization currently always creates a retain of the argument. This isn't legal for noncopyable values. rdar://129622373 --- lib/SILOptimizer/IPO/ClosureSpecializer.cpp | 16 +++++++---- test/SILOptimizer/closure_specialize.sil | 32 +++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index d37f18050f414..175b18d5db47e 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -675,9 +675,7 @@ static bool isSupportedClosure(const SILInstruction *Closure) { return false; if (auto *PAI = dyn_cast(Closure)) { - // Bail if any of the arguments are passed by address and - // are not @inout. - // This is a temporary limitation. + // Check whether each argument is supported. auto ClosureCallee = FRI->getReferencedFunction(); auto ClosureCalleeConv = ClosureCallee->getConventions(); unsigned ClosureArgIdxBase = @@ -685,14 +683,22 @@ static bool isSupportedClosure(const SILInstruction *Closure) { for (auto pair : llvm::enumerate(PAI->getArguments())) { auto Arg = pair.value(); auto ClosureArgIdx = pair.index() + ClosureArgIdxBase; + auto ArgConvention = + ClosureCalleeConv.getSILArgumentConvention(ClosureArgIdx); + SILType ArgTy = Arg->getType(); + // Specializing (currently) always produces a retain in the caller. + // That's not allowed for values of move-only type. + if (ArgTy.isMoveOnly()) { + return false; + } + + // Only @inout/@inout_aliasable addresses are (currently) supported. // If our argument is an object, continue... if (ArgTy.isObject()) { ++ClosureArgIdx; continue; } - auto ArgConvention = - ClosureCalleeConv.getSILArgumentConvention(ClosureArgIdx); if (ArgConvention != SILArgumentConvention::Indirect_Inout && ArgConvention != SILArgumentConvention::Indirect_InoutAliasable) return false; diff --git a/test/SILOptimizer/closure_specialize.sil b/test/SILOptimizer/closure_specialize.sil index b9c1d26e75104..fee8348f653fe 100644 --- a/test/SILOptimizer/closure_specialize.sil +++ b/test/SILOptimizer/closure_specialize.sil @@ -938,3 +938,35 @@ bb0(%0 : $Int): %empty = tuple () return %empty : $() } + +struct NC : ~Copyable { + deinit {} +} + +sil hidden [noinline] @noncopyable_arg_closure : $@convention(thin) (@guaranteed NC) -> () { +bb0(%0 : $NC): + %retval = tuple () + return %retval : $() +} + +sil hidden [noinline] @use_noncopyable_arg_closure : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> () { +bb0(%0 : $@noescape @callee_guaranteed () -> ()): + %2 = apply %0() : $@noescape @callee_guaranteed () -> () + %3 = tuple () + return %3 : $() +} + +// Ensure that a retain_value of a noncopyable value isn't created. +// CHECK-LABEL: sil @dont_specialize_noncopyable_arg_closure : {{.*}} { +// CHECK-NOT: retain_value {{%.*}} : $NC +// CHECK-LABEL: } // end sil function 'dont_specialize_noncopyable_arg_closure' +sil @dont_specialize_noncopyable_arg_closure : $@convention(thin) (@guaranteed NC) -> () { +bb0(%nc : $NC): + %closure_fn = function_ref @noncopyable_arg_closure : $@convention(thin) (@guaranteed NC) -> () + %closure = partial_apply [callee_guaranteed] [on_stack] %closure_fn(%nc) : $@convention(thin) (@guaranteed NC) -> () + %use = function_ref @use_noncopyable_arg_closure : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> () + apply %use(%closure) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> () + dealloc_stack %closure : $@noescape @callee_guaranteed () -> () + %11 = tuple () + return %11 : $() +} From d895c34c70297a9a468fd8720a0f8332036f4c3d Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 14:42:37 -0700 Subject: [PATCH 058/165] [Test] Add regression test. --- .../SILOptimizer/issue-71495.swift | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 validation-test/SILOptimizer/issue-71495.swift diff --git a/validation-test/SILOptimizer/issue-71495.swift b/validation-test/SILOptimizer/issue-71495.swift new file mode 100644 index 0000000000000..9b74e326ceb64 --- /dev/null +++ b/validation-test/SILOptimizer/issue-71495.swift @@ -0,0 +1,48 @@ +// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all) +// RUN: %target-run-simple-swift(-O -Xfrontend -sil-verify-all) + +// REQUIRES: executable_test + +/// A unique value represented by a heap memory location. +struct Handle: ~Copyable { + var address: UnsafeMutableRawPointer + + init() { + self.address = .allocate(byteCount: 2, alignment: 2) + } + + consuming func done() { + let address = self.address + discard self + address.deallocate() + print("deallocated handle via done()") + } + + deinit { + address.deallocate() + print("deallocated handle via deinit") + } +} + +func description(of pointer: UnsafeRawPointer) -> String { + let address = UInt(bitPattern: pointer) + return "0x" + String(address, radix: 16) +} + +func borrowHandleAndCrashNoMore(_ handle: borrowing Handle) -> String { + var string = "" + return string.withUTF8 { _ in + description(of: handle.address) + } +} + +let handleDescription: String + +do { + let handle = Handle() + handleDescription = borrowHandleAndCrashNoMore(handle) + handle.done() +} + +// CHECK: result: 0x +print("result: \(handleDescription)") From 414295df9613f0e43a46b4e6cdd88a4499be09df Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 11 Jun 2024 15:44:59 -0700 Subject: [PATCH 059/165] [AST] `@preconcurrency` conformance applies to implied conformances as well A `@preconcurrency` conformance to an inherited protocol should imply `@preconcurrency` on its parents as well. For example: ```swift protocol Parent { func a() } protocol Child: Parent { func b() } @MainActor class Test: @preconcurrency Child { func a() { } func b() { } } ``` `Test` conformance to `Parent` implied by its conformance to `Child` should carry `@preconcurrency` and inject dynamic actor isolation checks to witness of `a()`. Resolves: https://github.com/apple/swift/issues/74294 Resolves: rdar://129599097 --- include/swift/AST/ProtocolConformance.h | 7 ++- .../preconcurrency_conformances.swift | 16 +++++ .../preconcurrency_conformances.swift | 47 +++++++++++++++ ...cy_conformances_with_disabled_checks.swift | 41 +++++++++++++ test/SILGen/preconcurrency_conformances.swift | 59 +++++++++++++++++++ 5 files changed, 169 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h index 4437bd1bb7514..e415b08ead62d 100644 --- a/include/swift/AST/ProtocolConformance.h +++ b/include/swift/AST/ProtocolConformance.h @@ -681,7 +681,12 @@ class NormalProtocolConformance : public RootProtocolConformance, assert(sourceKind != ConformanceEntryKind::PreMacroExpansion && "cannot create conformance pre-macro-expansion"); Bits.NormalProtocolConformance.SourceKind = unsigned(sourceKind); - ImplyingConformance = implyingConformance; + if (auto implying = implyingConformance) { + ImplyingConformance = implying; + PreconcurrencyLoc = implying->getPreconcurrencyLoc(); + Bits.NormalProtocolConformance.IsPreconcurrency = + implying->isPreconcurrency(); + } } /// Determine whether this conformance is lazily loaded. diff --git a/test/Concurrency/preconcurrency_conformances.swift b/test/Concurrency/preconcurrency_conformances.swift index 42a953fc8e8ff..a1c31e192eb11 100644 --- a/test/Concurrency/preconcurrency_conformances.swift +++ b/test/Concurrency/preconcurrency_conformances.swift @@ -182,3 +182,19 @@ do { func test() {} } } + +// https://github.com/apple/swift/issues/74294 +protocol Parent { + func a() +} + +protocol Child: Parent { + func b() +} + +do { + actor Test: @preconcurrency Child { + func a() {} // Ok + func b() {} // Ok + } +} diff --git a/test/Interpreter/preconcurrency_conformances.swift b/test/Interpreter/preconcurrency_conformances.swift index c45872a98a14d..774504ed43fe0 100644 --- a/test/Interpreter/preconcurrency_conformances.swift +++ b/test/Interpreter/preconcurrency_conformances.swift @@ -34,6 +34,16 @@ // RUN: not --crash env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=legacy SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/crash4.out 2>&1 | %FileCheck %t/src/Crash4.swift --check-prefix=LEGACY_CHECK // RUN: not --crash env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=swift6 SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/crash4.out 2>&1 | %FileCheck %t/src/Crash4.swift --check-prefix=SWIFT6_CHECK --dump-input=always +// RUN: %target-build-swift -Xfrontend -enable-upcoming-feature -Xfrontend DynamicActorIsolation -I %t -L %t -l Types %t/src/Crash5.swift -o %t/crash5.out +// RUN: %target-codesign %t/crash5.out +// RUN: not --crash env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=legacy SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/crash5.out 2>&1 | %FileCheck %t/src/Crash5.swift --check-prefix=LEGACY_CHECK +// RUN: not --crash env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=swift6 SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/crash5.out 2>&1 | %FileCheck %t/src/Crash5.swift --check-prefix=SWIFT6_CHECK --dump-input=always + +// RUN: %target-build-swift -Xfrontend -enable-upcoming-feature -Xfrontend DynamicActorIsolation -I %t -L %t -l Types %t/src/Crash6.swift -o %t/crash6.out +// RUN: %target-codesign %t/crash6.out +// RUN: not --crash env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=legacy SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/crash6.out 2>&1 | %FileCheck %t/src/Crash6.swift --check-prefix=LEGACY_CHECK +// RUN: not --crash env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=swift6 SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/crash6.out 2>&1 | %FileCheck %t/src/Crash6.swift --check-prefix=SWIFT6_CHECK --dump-input=always + // REQUIRES: asserts // REQUIRES: concurrency // REQUIRES: concurrency_runtime @@ -51,6 +61,10 @@ public protocol P { func test() -> Int } +public protocol Q : P { + func childTest() +} + //--- Types.swift import Interface @@ -87,6 +101,21 @@ extension ActorTest : @preconcurrency P { public func test() -> Int { x } } +@MainActor +public struct TestWithParent : @preconcurrency Q { + public var prop: [String] = [] + + public init() {} + + public func test() -> Int { 42 } + public func childTest() {} +} + +public func runChildTest(_ type: T.Type) async { + let v = type.init() + return v.childTest() +} + //--- Crash1.swift import Types print(await runTest(Test.self)) @@ -122,3 +151,21 @@ print("OK") // SWIFT6_CHECK: Incorrect actor executor assumption // SWIFT6_CHECK-NOT: OK + +//--- Crash5.swift +import Types +print(await runTest(TestWithParent.self)) +print("OK") +// LEGACY_CHECK: data race detected: @MainActor function at Types/Types.swift:40 was not called on the main thread + +// Crash without good message, since via 'dispatch_assert_queue' +// SWIFT6_CHECK-NOT: OK + +//--- Crash6.swift +import Types +print(await runChildTest(TestWithParent.self)) +print("OK") +// LEGACY_CHECK: data race detected: @MainActor function at Types/Types.swift:40 was not called on the main thread + +// Crash without good message, since via 'dispatch_assert_queue' +// SWIFT6_CHECK-NOT: OK diff --git a/test/Interpreter/preconcurrency_conformances_with_disabled_checks.swift b/test/Interpreter/preconcurrency_conformances_with_disabled_checks.swift index c681e65748627..eb70d7cae4227 100644 --- a/test/Interpreter/preconcurrency_conformances_with_disabled_checks.swift +++ b/test/Interpreter/preconcurrency_conformances_with_disabled_checks.swift @@ -39,6 +39,18 @@ // RUN: env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=legacy SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/test4.out 2>&1 | %FileCheck %t/src/Test4.swift // RUN: env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=swift6 SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/test4.out 2>&1 | %FileCheck %t/src/Test4.swift +// RUN: %target-build-swift -I %t -L %t -l Types %t/src/Test5.swift -o %t/test5.out +// RUN: %target-codesign %t/test5.out +// RUN: env SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/test5.out 2>&1 | %FileCheck %t/src/Test5.swift +// RUN: env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=legacy SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/test5.out 2>&1 | %FileCheck %t/src/Test5.swift +// RUN: env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=swift6 SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/test5.out 2>&1 | %FileCheck %t/src/Test5.swift + +// RUN: %target-build-swift -I %t -L %t -l Types %t/src/Test6.swift -o %t/test6.out +// RUN: %target-codesign %t/test6.out +// RUN: env SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/test6.out 2>&1 | %FileCheck %t/src/Test6.swift +// RUN: env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=legacy SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/test6.out 2>&1 | %FileCheck %t/src/Test6.swift +// RUN: env SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE=swift6 SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2 %target-run %t/test6.out 2>&1 | %FileCheck %t/src/Test6.swift + // REQUIRES: asserts // REQUIRES: concurrency // REQUIRES: concurrency_runtime @@ -56,6 +68,10 @@ public protocol P { func test() -> Int } +public protocol Q : P { + func childTest() +} + //--- Types.swift import Interface @@ -92,6 +108,21 @@ extension ActorTest : @preconcurrency P { public func test() -> Int { x } } +@MainActor +public struct TestWithParent : @preconcurrency Q { + public var prop: [String] = [] + + public init() {} + + public func test() -> Int { 42 } + public func childTest() {} +} + +public func runChildTest(_ type: T.Type) async { + let v = type.init() + return v.childTest() +} + //--- Test1.swift import Types print(await runTest(Test.self)) @@ -111,3 +142,13 @@ print(await runTest(ActorTest.self)) import Types print(await runAccessors(ActorTest.self)) // CHECK-NOT: Incorrect actor executor assumption + +//--- Test5.swift +import Types +print(await runTest(TestWithParent.self)) +// CHECK-NOT: Incorrect actor executor assumption + +//--- Test6.swift +import Types +print(await runChildTest(TestWithParent.self)) +// CHECK-NOT: Incorrect actor executor assumption diff --git a/test/SILGen/preconcurrency_conformances.swift b/test/SILGen/preconcurrency_conformances.swift index e1c47378ca6aa..11041b5aa28d9 100644 --- a/test/SILGen/preconcurrency_conformances.swift +++ b/test/SILGen/preconcurrency_conformances.swift @@ -276,6 +276,39 @@ extension MyActor : @preconcurrency Q { // CHECK: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF // CHECK-NEXT: {{.*}} = apply [[CHECK_EXEC_REF]]({{.*}}, [[EXEC]]) +// https://github.com/apple/swift/issues/74294 +protocol Parent { + func a() +} + +protocol Child : Parent { + func b() +} + +@MainActor +struct PreconcurrencyAppliesToParentToo : @preconcurrency Child { + func a() { + } + + func b() { + } +} + +// protocol witness for Child.b() in conformance PreconcurrencyAppliesToParentToo +// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances32PreconcurrencyAppliesToParentTooVAA5ChildA2aDP1byyFTW : $@convention(witness_method: Child) (@in_guaranteed PreconcurrencyAppliesToParentToo) -> () +// CHECK: [[MAIN_ACTOR:%.*]] = begin_borrow {{.*}} : $MainActor +// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MAIN_ACTOR]] : $MainActor +// CHECK: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF +// CHECK-NEXT: {{.*}} = apply [[CHECK_EXEC_REF]]({{.*}}, [[EXEC]]) + + +// protocol witness for Parent.a() in conformance PreconcurrencyAppliesToParentToo +// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances32PreconcurrencyAppliesToParentTooVAA0F0A2aDP1ayyFTW : $@convention(witness_method: Parent) (@in_guaranteed PreconcurrencyAppliesToParentToo) -> () +// CHECK: [[MAIN_ACTOR:%.*]] = begin_borrow {{.*}} : $MainActor +// CHECK-NEXT: [[EXEC:%.*]] = extract_executor [[MAIN_ACTOR]] : $MainActor +// CHECK: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF +// CHECK-NEXT: {{.*}} = apply [[CHECK_EXEC_REF]]({{.*}}, [[EXEC]]) + //--- checks_disabled.swift protocol P { associatedtype T @@ -439,3 +472,29 @@ extension MyActor : @preconcurrency Q { // protocol witness for static Q.data.modify in conformance MyActor // CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances7MyActorCAA1QA2aDP4dataSaySiGSgvMZTW : $@yield_once @convention(witness_method: Q) @substituted <τ_0_0> (@thick τ_0_0.Type) -> @yields @inout Optional> for // CHECK-NOT: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF + +// https://github.com/apple/swift/issues/74294 +protocol Parent { + func a() +} + +protocol Child : Parent { + func b() +} + +@MainActor +struct PreconcurrencyAppliesToParentToo : @preconcurrency Child { + func a() { + } + + func b() { + } +} + +// protocol witness for Child.b() in conformance PreconcurrencyAppliesToParentToo +// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances32PreconcurrencyAppliesToParentTooVAA5ChildA2aDP1byyFTW : $@convention(witness_method: Child) (@in_guaranteed PreconcurrencyAppliesToParentToo) -> () +// CHECK-NOT: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF + +// protocol witness for Parent.a() in conformance PreconcurrencyAppliesToParentToo +// CHECK-LABEL: sil private [transparent] [thunk] [ossa] @$s27preconcurrency_conformances32PreconcurrencyAppliesToParentTooVAA0F0A2aDP1ayyFTW : $@convention(witness_method: Parent) (@in_guaranteed PreconcurrencyAppliesToParentToo) -> () +// CHECK-NOT: [[CHECK_EXEC_REF:%.*]] = function_ref @$ss22_checkExpectedExecutor14_filenameStart01_D6Length01_D7IsASCII5_line9_executoryBp_BwBi1_BwBetF From b5b637c72ec430607d7c2c0bd795e748fef4c7eb Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 16:00:08 -0700 Subject: [PATCH 060/165] [NFC] SIL: Renamed helper. removing...To -> removing...From --- include/swift/SIL/SILInstruction.h | 2 +- include/swift/SIL/SILType.h | 2 +- include/swift/SIL/SILValue.h | 2 +- lib/SIL/IR/SILType.cpp | 2 +- lib/SIL/Verifier/SILVerifier.cpp | 8 +++++--- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 4d382b579de2d..634749b427fc8 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -9160,7 +9160,7 @@ class MoveOnlyWrapperToCopyableBoxInst ValueOwnershipKind forwardingOwnershipKind) : UnaryInstructionBase( DebugLoc, operand, - operand->getType().removingMoveOnlyWrapperToBoxedType( + operand->getType().removingMoveOnlyWrapperFromBoxedType( operand->getFunction()), forwardingOwnershipKind) { assert( diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index a9f730b2bd3b3..20e4728d6cf8c 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -868,7 +868,7 @@ class SILType { /// /// DISCUSSION: This is separate from removingMoveOnlyWrapper since this API /// requires a SILFunction * and is specialized. - SILType removingMoveOnlyWrapperToBoxedType(const SILFunction *fn); + SILType removingMoveOnlyWrapperFromBoxedType(const SILFunction *fn); /// Returns a SILType with any archetypes mapped out of context. SILType mapTypeOutOfContext() const; diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h index 20dc42c382149..17acce67fd7e5 100644 --- a/include/swift/SIL/SILValue.h +++ b/include/swift/SIL/SILValue.h @@ -605,7 +605,7 @@ class ValueBase : public SILNode, public SILAllocated { Type = Type.removingMoveOnlyWrapper(); } else { assert(Type.isBoxedMoveOnlyWrappedType(fn)); - Type = Type.removingMoveOnlyWrapperToBoxedType(fn); + Type = Type.removingMoveOnlyWrapperFromBoxedType(fn); } return true; } diff --git a/lib/SIL/IR/SILType.cpp b/lib/SIL/IR/SILType.cpp index d223556c64b4a..c59783b591a24 100644 --- a/lib/SIL/IR/SILType.cpp +++ b/lib/SIL/IR/SILType.cpp @@ -1266,7 +1266,7 @@ SILType SILType::addingMoveOnlyWrapperToBoxedType(const SILFunction *fn) { return SILType::getPrimitiveObjectType(newBoxType); } -SILType SILType::removingMoveOnlyWrapperToBoxedType(const SILFunction *fn) { +SILType SILType::removingMoveOnlyWrapperFromBoxedType(const SILFunction *fn) { auto boxTy = castTo(); auto *oldLayout = boxTy->getLayout(); auto oldField = oldLayout->getFields()[0]; diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index cee5db011b5ef..9438d829549d6 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -6548,9 +6548,11 @@ class SILVerifier : public SILVerifierBase { "Operand value should be an object"); require(cvt->getOperand()->getType().isBoxedMoveOnlyWrappedType(cvt->getFunction()), "Operand should be move only wrapped"); - require(cvt->getType() == - cvt->getOperand()->getType().removingMoveOnlyWrapperToBoxedType(cvt->getFunction()), - "Result and operand must have the same type, today."); + require( + cvt->getType() == + cvt->getOperand()->getType().removingMoveOnlyWrapperFromBoxedType( + cvt->getFunction()), + "Result and operand must have the same type, today."); } void checkCopyableToMoveOnlyWrapperValueInst( From 78c18374c3d0c98dda615f108eaf588420f27f64 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 16:14:49 -0700 Subject: [PATCH 061/165] [NFC] SIL: Extracted has "any" move-only wrapping. This predicate is used in several places. --- include/swift/SIL/SILType.h | 5 +++++ include/swift/SIL/SILValue.h | 2 +- .../Mandatory/MoveOnlyWrappedTypeEliminator.cpp | 6 ++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index 20e4728d6cf8c..2d7fa6bb334cb 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -870,6 +870,11 @@ class SILType { /// requires a SILFunction * and is specialized. SILType removingMoveOnlyWrapperFromBoxedType(const SILFunction *fn); + /// Whether there's a direct wrapper or a wrapper inside a box. + bool hasAnyMoveOnlyWrapping(const SILFunction *fn) { + return isMoveOnlyWrapped() || isBoxedMoveOnlyWrappedType(fn); + } + /// Returns a SILType with any archetypes mapped out of context. SILType mapTypeOutOfContext() const; diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h index 17acce67fd7e5..df8f3522ebe37 100644 --- a/include/swift/SIL/SILValue.h +++ b/include/swift/SIL/SILValue.h @@ -599,7 +599,7 @@ class ValueBase : public SILNode, public SILAllocated { /// NOTE: Please do not use this directly! It is only meant to be used by the /// optimizer pass: SILMoveOnlyWrappedTypeEliminator. bool unsafelyEliminateMoveOnlyWrapper(const SILFunction *fn) { - if (!Type.isMoveOnlyWrapped() && !Type.isBoxedMoveOnlyWrappedType(fn)) + if (!Type.hasAnyMoveOnlyWrapping(fn)) return false; if (Type.isMoveOnlyWrapped()) { Type = Type.removingMoveOnlyWrapper(); diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp index 028985252090d..33a90f0e05c8a 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp @@ -300,8 +300,7 @@ bool SILMoveOnlyWrappedTypeEliminator::process() { for (auto &bb : *fn) { for (auto *arg : bb.getArguments()) { - if (!arg->getType().isMoveOnlyWrapped() && - !arg->getType().isBoxedMoveOnlyWrappedType(fn)) + if (!arg->getType().hasAnyMoveOnlyWrapping(fn)) continue; // If we are looking at trivial only, skip non-trivial function args. @@ -322,8 +321,7 @@ bool SILMoveOnlyWrappedTypeEliminator::process() { for (auto &ii : bb) { for (SILValue v : ii.getResults()) { - if (!v->getType().isMoveOnlyWrapped() && - !v->getType().isBoxedMoveOnlyWrappedType(fn)) + if (!v->getType().hasAnyMoveOnlyWrapping(fn)) continue; if (trivialOnly && From f39b70a86d237c3cbe0f0f662784bf11dc106568 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 16:15:33 -0700 Subject: [PATCH 062/165] [NFC] SIL: Extracted remove "any" m-o wrapping. --- include/swift/SIL/SILType.h | 3 +++ include/swift/SIL/SILValue.h | 7 +------ lib/SIL/IR/SILType.cpp | 11 +++++++++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index 2d7fa6bb334cb..930e40fe710c5 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -875,6 +875,9 @@ class SILType { return isMoveOnlyWrapped() || isBoxedMoveOnlyWrappedType(fn); } + /// Removes a direct wrapper from a type or a wrapper from a type in a box. + SILType removingAnyMoveOnlyWrapping(const SILFunction *fn); + /// Returns a SILType with any archetypes mapped out of context. SILType mapTypeOutOfContext() const; diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h index df8f3522ebe37..5dbb3c30e86f0 100644 --- a/include/swift/SIL/SILValue.h +++ b/include/swift/SIL/SILValue.h @@ -601,12 +601,7 @@ class ValueBase : public SILNode, public SILAllocated { bool unsafelyEliminateMoveOnlyWrapper(const SILFunction *fn) { if (!Type.hasAnyMoveOnlyWrapping(fn)) return false; - if (Type.isMoveOnlyWrapped()) { - Type = Type.removingMoveOnlyWrapper(); - } else { - assert(Type.isBoxedMoveOnlyWrappedType(fn)); - Type = Type.removingMoveOnlyWrapperFromBoxedType(fn); - } + Type = Type.removingAnyMoveOnlyWrapping(fn); return true; } diff --git a/lib/SIL/IR/SILType.cpp b/lib/SIL/IR/SILType.cpp index c59783b591a24..233a6930d5b6c 100644 --- a/lib/SIL/IR/SILType.cpp +++ b/lib/SIL/IR/SILType.cpp @@ -1284,6 +1284,17 @@ SILType SILType::removingMoveOnlyWrapperFromBoxedType(const SILFunction *fn) { return SILType::getPrimitiveObjectType(newBoxType); } +SILType SILType::removingAnyMoveOnlyWrapping(const SILFunction *fn) { + if (!isMoveOnlyWrapped() && !isBoxedMoveOnlyWrappedType(fn)) + return *this; + + if (isMoveOnlyWrapped()) + return removingMoveOnlyWrapper(); + + assert(isBoxedMoveOnlyWrappedType(fn)); + return removingMoveOnlyWrapperFromBoxedType(fn); +} + bool SILType::isSendable(SILFunction *fn) const { return getASTType()->isSendableType(); } From fed3cb84c6077bead8a3e9ff38c08d95f91cfcd3 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 08:17:00 -0700 Subject: [PATCH 063/165] [NFC] SIL: Expose undef values. --- include/swift/SIL/SILFunction.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index 155505220c783..76d7cc8344f7d 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -28,6 +28,8 @@ #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILLinkage.h" #include "swift/SIL/SILPrintContext.h" +#include "swift/SIL/SILUndef.h" +#include "llvm/ADT/MapVector.h" namespace swift { @@ -337,12 +339,8 @@ class SILFunction PerformanceConstraints perfConstraints = PerformanceConstraints::None; - /// This is the set of undef values we've created, for uniquing purposes. - /// - /// We use a SmallDenseMap since in most functions, we will have only one type - /// of undef if we have any at all. In that case, by staying small we avoid - /// needing a heap allocation. - llvm::SmallDenseMap undefValues; + /// The undefs of each type in the function. + llvm::SmallMapVector undefValues; /// This is the number of uses of this SILFunction inside the SIL. /// It does not include references from debug scopes. @@ -1637,6 +1635,10 @@ class SILFunction decl->getLifetimeAnnotation()); } + ArrayRef> getUndefValues() { + return {undefValues.begin(), undefValues.end()}; + } + /// verify - Run the SIL verifier to make sure that the SILFunction follows /// invariants. void verify(CalleeCache *calleeCache = nullptr, From a69a1a291acbc19d5b72ee4ba3415a264063e5b3 Mon Sep 17 00:00:00 2001 From: Karoy Lorentey Date: Tue, 11 Jun 2024 16:54:59 -0700 Subject: [PATCH 064/165] [update-checkout] Also update swift-collections on release/6.0 --- utils/update_checkout/update-checkout-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 10071956788aa..c93a9e6efc36e 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -178,7 +178,7 @@ "swiftpm": "release/6.0", "swift-argument-parser": "1.2.3", "swift-atomics": "1.2.0", - "swift-collections": "1.0.5", + "swift-collections": "1.1.1", "swift-crypto": "3.0.0", "swift-certificates": "1.0.1", "swift-asn1": "1.0.0", From 8883e88f5409473a8582f4f017512b2302a88922 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 07:56:52 -0700 Subject: [PATCH 065/165] [NFC] MOWTE: Deduplicated code. Replaced copy-pasted code with a twice-invoked closure. In preparation to add a third invocation. --- .../MoveOnlyWrappedTypeEliminator.cpp | 58 +++++++++++-------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp index 33a90f0e05c8a..60e95d160d848 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp @@ -298,45 +298,55 @@ bool SILMoveOnlyWrappedTypeEliminator::process() { llvm::SmallSetVector touchedArgs; llvm::SmallSetVector touchedInsts; + // For each value whose type is move-only wrapped: + // - rewrite the value's type + // - record its users for later visitation + auto visitValue = [&touchedInsts, fn = fn, + trivialOnly = trivialOnly](SILValue value) -> bool { + if (!value->getType().hasAnyMoveOnlyWrapping(fn)) + return false; + + // If we are looking at trivial only, skip non-trivial function args. + if (trivialOnly && !isMoveOnlyWrappedTrivial(value)) + return false; + + for (auto *use : value->getNonTypeDependentUses()) + touchedInsts.insert(use->getUser()); + + value->unsafelyEliminateMoveOnlyWrapper(fn); + + return true; + }; + for (auto &bb : *fn) { for (auto *arg : bb.getArguments()) { - if (!arg->getType().hasAnyMoveOnlyWrapping(fn)) + bool relevant = visitValue(arg); + if (!relevant) continue; - // If we are looking at trivial only, skip non-trivial function args. - if (trivialOnly && - !arg->getType().removingMoveOnlyWrapper().isTrivial(*fn)) - continue; - - arg->unsafelyEliminateMoveOnlyWrapper(fn); - // If our new type is trivial, convert the arguments ownership to // None. Otherwise, preserve the ownership kind of the argument. if (arg->getType().isTrivial(*fn)) arg->setOwnershipKind(OwnershipKind::None); touchedArgs.insert(arg); - for (auto *use : arg->getNonTypeDependentUses()) - touchedInsts.insert(use->getUser()); + + madeChange = true; } for (auto &ii : bb) { - for (SILValue v : ii.getResults()) { - if (!v->getType().hasAnyMoveOnlyWrapping(fn)) - continue; - - if (trivialOnly && - !isMoveOnlyWrappedTrivial(v)) + bool touched = false; + for (SILValue value : ii.getResults()) { + bool relevant = visitValue(value); + if (!relevant) continue; - v->unsafelyEliminateMoveOnlyWrapper(fn); - touchedInsts.insert(&ii); - - // Add all users as well. This ensures we visit things like - // destroy_value and end_borrow. - for (auto *use : v->getNonTypeDependentUses()) - touchedInsts.insert(use->getUser()); - madeChange = true; + touched = true; } + if (!touched) + continue; + touchedInsts.insert(&ii); + + madeChange = true; } } From d0341ddc7d7945c4e6acb1d325fd422aa6397175 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 11:14:11 -0700 Subject: [PATCH 066/165] [NFC] MOWTE: Deleted dead array. The modified arguments were recorded but never used. --- .../Mandatory/MoveOnlyWrappedTypeEliminator.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp index 60e95d160d848..1c3f420131b7f 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp @@ -51,12 +51,6 @@ namespace { struct SILMoveOnlyWrappedTypeEliminatorVisitor : SILInstructionVisitor { - const llvm::SmallSetVector &touchedArgs; - - SILMoveOnlyWrappedTypeEliminatorVisitor( - const llvm::SmallSetVector &touchedArgs) - : touchedArgs(touchedArgs) {} - bool visitSILInstruction(SILInstruction *inst) { llvm::errs() << "Unhandled SIL Instruction: " << *inst; llvm_unreachable("error"); @@ -295,7 +289,6 @@ static bool isMoveOnlyWrappedTrivial(SILValue value) { bool SILMoveOnlyWrappedTypeEliminator::process() { bool madeChange = true; - llvm::SmallSetVector touchedArgs; llvm::SmallSetVector touchedInsts; // For each value whose type is move-only wrapped: @@ -328,7 +321,6 @@ bool SILMoveOnlyWrappedTypeEliminator::process() { // None. Otherwise, preserve the ownership kind of the argument. if (arg->getType().isTrivial(*fn)) arg->setOwnershipKind(OwnershipKind::None); - touchedArgs.insert(arg); madeChange = true; } @@ -350,7 +342,7 @@ bool SILMoveOnlyWrappedTypeEliminator::process() { } } - SILMoveOnlyWrappedTypeEliminatorVisitor visitor(touchedArgs); + SILMoveOnlyWrappedTypeEliminatorVisitor visitor; while (!touchedInsts.empty()) { visitor.visit(touchedInsts.pop_back_val()); } From 69fa1ae2d2465e259146760374b84e490bf970e6 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 07:57:45 -0700 Subject: [PATCH 067/165] [MOWTE] Start madeChange at false. --- lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp index 1c3f420131b7f..90132711e6bb9 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp @@ -287,7 +287,7 @@ static bool isMoveOnlyWrappedTrivial(SILValue value) { } bool SILMoveOnlyWrappedTypeEliminator::process() { - bool madeChange = true; + bool madeChange = false; llvm::SmallSetVector touchedInsts; From 5d63fcfef600055d8813debc6c9ca589ee43f163 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 08:18:20 -0700 Subject: [PATCH 068/165] [MOWTE] Visit undef values. Such values' types may also also be move-only wrapped. --- .../Mandatory/MoveOnlyWrappedTypeEliminator.cpp | 16 +++++++++++++++- test/SILOptimizer/moveonly_type_eliminator.sil | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp index 90132711e6bb9..851635fd599b8 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp @@ -306,7 +306,11 @@ bool SILMoveOnlyWrappedTypeEliminator::process() { for (auto *use : value->getNonTypeDependentUses()) touchedInsts.insert(use->getUser()); - value->unsafelyEliminateMoveOnlyWrapper(fn); + if (isa(value)) + value->replaceAllUsesWith( + SILUndef::get(fn, value->getType().removingAnyMoveOnlyWrapping(fn))); + else + value->unsafelyEliminateMoveOnlyWrapper(fn); return true; }; @@ -341,6 +345,16 @@ bool SILMoveOnlyWrappedTypeEliminator::process() { madeChange = true; } } + // SILFunction::undefValues may grow during the loop. + SmallVector, 4> originalUndefs( + fn->getUndefValues()); + for (auto pair : originalUndefs) { + bool relevant = visitValue(pair.second); + if (!relevant) + continue; + + madeChange = true; + } SILMoveOnlyWrappedTypeEliminatorVisitor visitor; while (!touchedInsts.empty()) { diff --git a/test/SILOptimizer/moveonly_type_eliminator.sil b/test/SILOptimizer/moveonly_type_eliminator.sil index e27dad92be2f0..59a18a9bcba26 100644 --- a/test/SILOptimizer/moveonly_type_eliminator.sil +++ b/test/SILOptimizer/moveonly_type_eliminator.sil @@ -562,3 +562,19 @@ bb3(%result : @owned $@moveOnly FakeOptional): %result2 = moveonlywrapper_to_copyable [owned] %result : $@moveOnly FakeOptional return %result2 : $FakeOptional } + +// CHECK-LABEL: sil [ossa] @debug_value_undef : {{.*}} { +// CHECK: debug_value [moveable_value_debuginfo] undef : $*Klass, var, name "s" +// CHECK-LABEL: } // end sil function 'debug_value_undef' +sil [ossa] @debug_value_undef : $@convention(thin) (@owned Klass) -> () { +bb0(%x : @owned $Klass): + %addr = alloc_stack $@moveOnly Klass + %unwrapped_addr = moveonlywrapper_to_copyable_addr %addr : $*@moveOnly Klass + store %x to [init] %unwrapped_addr : $*Klass + debug_value %addr : $*@moveOnly Klass, var, name "s", argno 1, expr op_deref + destroy_addr %addr : $*@moveOnly Klass + debug_value undef : $*@moveOnly Klass, var, name "s", argno 1, expr op_deref + dealloc_stack %addr : $*@moveOnly Klass + %retval = tuple () + return %retval : $() +} From 562e724bbdbe7310831308bc40131c9bd5da9c11 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 11 Jun 2024 17:41:26 -0700 Subject: [PATCH 069/165] [Test] Add regression test. For https://github.com/apple/swift/issues/72615 . --- .../SILOptimizer/issue-72615.swift | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 validation-test/SILOptimizer/issue-72615.swift diff --git a/validation-test/SILOptimizer/issue-72615.swift b/validation-test/SILOptimizer/issue-72615.swift new file mode 100644 index 0000000000000..74004d6b39c2b --- /dev/null +++ b/validation-test/SILOptimizer/issue-72615.swift @@ -0,0 +1,29 @@ +// RUN: %target-swift-frontend \ +// RUN: %s \ +// RUN: -emit-sil -verify \ +// RUN: -sil-verify-all + +func doStuffUniquely(with value: consuming [Int]) { + // If we received the last remaining reference to `value`, we'd like + // to be able to efficiently update it without incurring more copies. + var newValue = consume value + newValue.append(42) +} + +func test() { + var x: [Int] = [1,2,3] + + // x is appended to. After this point, we know that x is unique. We want to + // preserve that property. + x.append(5) + + // Pass the current value of x off to another function, that + doStuffUniquely(with: consume x) + + // Reset x to a new value. Since we don't use the old value anymore, + x = [] + doMoreStuff(with: &x) +} + +func doMoreStuff(with value: inout [Int]) { +} From 155773c38e02e71d446e434ff125f4e21cf7f742 Mon Sep 17 00:00:00 2001 From: Alex Hoppen Date: Sun, 9 Jun 2024 11:15:42 -0700 Subject: [PATCH 070/165] Fix renaming enum case parameters with unnamed associated arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We treated enum case parameters the same way as function parameters and weren’t considering that they can be unlabeled. That caused us to insert eg. `_ ` in front of the case’s type, producing `case myCase(_ String)`, which is invalid. When we are inside an enum case parameter and the parameter label is empty, treat it the same as a function call, which will leave the label untouched if it isn’t modified and insert a label including a colon if a new label is introduced. https://github.com/apple/sourcekit-lsp/issues/1228 --- include/swift/IDE/IDEBridging.h | 7 +++ include/swift/IDE/Utils.h | 37 +++++++++++---- .../NameMatcherBridging.swift | 2 + .../SyntacticRenameRangeDetails.cpp | 13 ++++++ ...d_rename_ranges_enum_case_with_label.swift | 46 +++++++++++++++++++ ...ename_ranges_enum_case_without_label.swift | 44 ++++++++++++++++++ ...thout_underscore_as_first_name_label.swift | 45 ++++++++++++++++++ .../Outputs/types/case-other.swift.expected | 2 +- 8 files changed, 186 insertions(+), 10 deletions(-) create mode 100644 test/SourceKit/Refactoring/find_rename_ranges_enum_case_with_label.swift create mode 100644 test/SourceKit/Refactoring/find_rename_ranges_enum_case_without_label.swift create mode 100644 test/SourceKit/Refactoring/find_rename_ranges_enum_case_without_underscore_as_first_name_label.swift diff --git a/include/swift/IDE/IDEBridging.h b/include/swift/IDE/IDEBridging.h index 379783f82ec82..dbbed37e48cbb 100644 --- a/include/swift/IDE/IDEBridging.h +++ b/include/swift/IDE/IDEBridging.h @@ -38,6 +38,13 @@ enum class LabelRangeType { /// `func foo([a b]: Int)` Param, + /// The parameter of an enum case declaration + /// + /// ### Examples + /// - `case myCase([a]: Int)` + /// - `case myCase([]Int)` + EnumCaseParam, + /// Parameters of a function that can't be collapsed if they are the same. /// /// This is the case for parameters of subscripts since subscripts have diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index 3ca9b5de3b796..eb697d0615e1e 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -465,15 +465,34 @@ enum class RegionType { }; enum class RefactoringRangeKind { - BaseName, // func [foo](a b: Int) - KeywordBaseName, // [init](a: Int) - ParameterName, // func foo(a[ b]: Int) - NoncollapsibleParameterName, // subscript(a[ a]: Int) - DeclArgumentLabel, // func foo([a] b: Int) - CallArgumentLabel, // foo([a]: 1) - CallArgumentColon, // foo(a[: ]1) - CallArgumentCombined, // foo([]1) could expand to foo([a: ]1) - SelectorArgumentLabel, // foo([a]:) + /// `func [foo](a b: Int)` + BaseName, + + /// `[init](a: Int)` + KeywordBaseName, + + /// `func foo(a[ b]: Int)` + ParameterName, + + /// `subscript(a[ a]: Int)` + NoncollapsibleParameterName, + + /// `func foo([a] b: Int)` + DeclArgumentLabel, + + /// `foo([a]: 1)` + CallArgumentLabel, + + /// `foo(a[: ]1)` + CallArgumentColon, + + /// `foo([]1) could expand to foo([a: ]1)` + /// Also used for enum case declarations without a label, eg. + /// `case foo([]String)` should expand to `case foo([a: ]String)`. + CallArgumentCombined, + + /// `foo([a]:)` + SelectorArgumentLabel, }; struct NoteRegion { diff --git a/lib/ASTGen/Sources/SwiftIDEUtilsBridging/NameMatcherBridging.swift b/lib/ASTGen/Sources/SwiftIDEUtilsBridging/NameMatcherBridging.swift index 2f81023a3a8e3..30d198f48ffc1 100644 --- a/lib/ASTGen/Sources/SwiftIDEUtilsBridging/NameMatcherBridging.swift +++ b/lib/ASTGen/Sources/SwiftIDEUtilsBridging/NameMatcherBridging.swift @@ -50,6 +50,7 @@ fileprivate extension IDEBridging.LabelRangeType { case .noArguments: self = .None case .call: self = .CallArg case .parameters: self = .Param + case .enumCaseParameters: self = .EnumCaseParam case .noncollapsibleParameters: self = .NoncollapsibleParam case .selector: self = .CompoundName #if RESILIENT_SWIFT_SYNTAX @@ -72,6 +73,7 @@ extension BridgedResolvedLoc { case .noArguments: arguments = [] case .call(let arguments2, _): arguments = arguments2 case .parameters(let arguments2): arguments = arguments2 + case .enumCaseParameters(let arguments2): arguments = arguments2 case .noncollapsibleParameters(let arguments2): arguments = arguments2 case .selector(let arguments2): arguments = arguments2 #if RESILIENT_SWIFT_SYNTAX diff --git a/lib/Refactoring/SyntacticRenameRangeDetails.cpp b/lib/Refactoring/SyntacticRenameRangeDetails.cpp index 1e36c85c6c646..b22820f789349 100644 --- a/lib/Refactoring/SyntacticRenameRangeDetails.cpp +++ b/lib/Refactoring/SyntacticRenameRangeDetails.cpp @@ -146,6 +146,18 @@ void RenameRangeDetailCollector::splitAndRenameLabel(CharSourceRange Range, return splitAndRenameCallArg(Range, NameIndex); case LabelRangeType::Param: return splitAndRenameParamLabel(Range, NameIndex, /*IsCollapsible=*/true); + case LabelRangeType::EnumCaseParam: + if (Range.getByteLength() == 0) { + // If the associated value currently doesn't have a label, emit a + // `CallArgumentCombined` range, which will cause a new label followed by + // `:` to be inserted in the same fashion that call arguments get inserted + // to calls + return addRenameRange(Range, RefactoringRangeKind::CallArgumentCombined, NameIndex); + } else { + // If the associated value has a label already, we are in the same case as + // function parameters. + return splitAndRenameParamLabel(Range, NameIndex, /*IsCollapsible=*/true); + } case LabelRangeType::NoncollapsibleParam: return splitAndRenameParamLabel(Range, NameIndex, /*IsCollapsible=*/false); @@ -248,6 +260,7 @@ bool RenameRangeDetailCollector::labelRangeMatches(CharSourceRange Range, LLVM_FALLTHROUGH; case LabelRangeType::CallArg: case LabelRangeType::Param: + case LabelRangeType::EnumCaseParam: case LabelRangeType::CompoundName: return ExistingLabel == (Expected.empty() ? "_" : Expected); case LabelRangeType::None: diff --git a/test/SourceKit/Refactoring/find_rename_ranges_enum_case_with_label.swift b/test/SourceKit/Refactoring/find_rename_ranges_enum_case_with_label.swift new file mode 100644 index 0000000000000..4657564a87733 --- /dev/null +++ b/test/SourceKit/Refactoring/find_rename_ranges_enum_case_with_label.swift @@ -0,0 +1,46 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: %sourcekitd-test -req=find-rename-ranges -rename-spec %t/rename-spec.json %t/input.swift | %FileCheck %s + +// CHECK: source.edit.kind.active: +// CHECK-NEXT: 2:8-2:14 source.refactoring.range.kind.basename +// CHECK-NEXT: 2:15-2:20 source.refactoring.range.kind.decl-argument-label arg-index=0 +// CHECK-NEXT: 2:20-2:20 source.refactoring.range.kind.parameter-and-whitespace arg-index=0 +// CHECK-NEXT: source.edit.kind.active: +// CHECK-NEXT: 6:14-6:20 source.refactoring.range.kind.basename +// CHECK-NEXT: 6:21-6:26 source.refactoring.range.kind.call-argument-label arg-index=0 +// CHECK-NEXT: 6:26-6:28 source.refactoring.range.kind.call-argument-colon arg-index=0 + +//--- input.swift +enum MyEnum { + case myCase(label: String) +} + +func test() { + _ = MyEnum.myCase(label: "abc") +} + +//--- rename-spec.json + +[ + { + "key.name": "myCase(label:)", + "key.locations": [ + { + "key.line": 2, + "key.column": 8, + "key.nametype": source.syntacticrename.definition + } + ] + }, + { + "key.name": "myCase(label:)", + "key.locations": [ + { + "key.line": 6, + "key.column": 14, + "key.nametype": source.syntacticrename.call + } + ] + } +] diff --git a/test/SourceKit/Refactoring/find_rename_ranges_enum_case_without_label.swift b/test/SourceKit/Refactoring/find_rename_ranges_enum_case_without_label.swift new file mode 100644 index 0000000000000..60bc091b856c8 --- /dev/null +++ b/test/SourceKit/Refactoring/find_rename_ranges_enum_case_without_label.swift @@ -0,0 +1,44 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: %sourcekitd-test -req=find-rename-ranges -rename-spec %t/rename-spec.json %t/input.swift | %FileCheck %s + +// CHECK: source.edit.kind.active: +// CHECK-NEXT: 2:8-2:14 source.refactoring.range.kind.basename +// CHECK-NEXT: 2:15-2:15 source.refactoring.range.kind.call-argument-combined arg-index=0 +// CHECK-NEXT: source.edit.kind.active: +// CHECK-NEXT: 6:14-6:20 source.refactoring.range.kind.basename +// CHECK-NEXT: 6:21-6:21 source.refactoring.range.kind.call-argument-combined arg-index=0 + +//--- input.swift +enum MyEnum { + case myCase(String) +} + +func test() { + _ = MyEnum.myCase("abc") +} + +//--- rename-spec.json + +[ + { + "key.name": "myCase(_:)", + "key.locations": [ + { + "key.line": 2, + "key.column": 8, + "key.nametype": source.syntacticrename.definition + } + ] + }, + { + "key.name": "myCase(_:)", + "key.locations": [ + { + "key.line": 6, + "key.column": 14, + "key.nametype": source.syntacticrename.call + } + ] + } +] diff --git a/test/SourceKit/Refactoring/find_rename_ranges_enum_case_without_underscore_as_first_name_label.swift b/test/SourceKit/Refactoring/find_rename_ranges_enum_case_without_underscore_as_first_name_label.swift new file mode 100644 index 0000000000000..8dbe54c425191 --- /dev/null +++ b/test/SourceKit/Refactoring/find_rename_ranges_enum_case_without_underscore_as_first_name_label.swift @@ -0,0 +1,45 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: %sourcekitd-test -req=find-rename-ranges -rename-spec %t/rename-spec.json %t/input.swift | %FileCheck %s + +// CHECK: source.edit.kind.active: +// CHECK-NEXT: 2:8-2:14 source.refactoring.range.kind.basename +// CHECK-NEXT: 2:15-2:16 source.refactoring.range.kind.decl-argument-label arg-index=0 +// CHECK-NEXT: 2:16-2:22 source.refactoring.range.kind.parameter-and-whitespace arg-index=0 +// CHECK-NEXT: source.edit.kind.active: +// CHECK-NEXT: 6:14-6:20 source.refactoring.range.kind.basename +// CHECK-NEXT: 6:21-6:21 source.refactoring.range.kind.call-argument-combined arg-index=0 + +//--- input.swift +enum MyEnum { + case myCase(_ label: String) +} + +func test() { + _ = MyEnum.myCase("abc") +} + +//--- rename-spec.json + +[ + { + "key.name": "myCase(:)", + "key.locations": [ + { + "key.line": 2, + "key.column": 8, + "key.nametype": source.syntacticrename.definition + } + ] + }, + { + "key.name": "myCase(:)", + "key.locations": [ + { + "key.line": 6, + "key.column": 14, + "key.nametype": source.syntacticrename.call + } + ] + } +] diff --git a/test/refactoring/SyntacticRename/Outputs/types/case-other.swift.expected b/test/refactoring/SyntacticRename/Outputs/types/case-other.swift.expected index 915828f17a671..2a1786116f14d 100644 --- a/test/refactoring/SyntacticRename/Outputs/types/case-other.swift.expected +++ b/test/refactoring/SyntacticRename/Outputs/types/case-other.swift.expected @@ -27,7 +27,7 @@ extension /*class-Animal:def*/Animal { enum /*enum-Barcode:def*/Barcode { case upc(Int, Int, Int, Int) case /*case-qrCode:def*/qrCode(code: String) - case /*case-other:def*/other(Int) + case /*case-other:def*/other(Int) case /*case-another:def*/another } var barCode: /*enum-Barcode*/Barcode = /*enum-Barcode*/Barcode.upc(1, 1, 1, 1) From fe66c47b8aa4c501c62ae3486d78f8d3631ee05e Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 12 Jun 2024 12:28:55 +0900 Subject: [PATCH 071/165] [docs] Provide more documentation on custom executors with global actors It could be confusing to adopters who were led to believe by the types that they should "just" implement the sharedUnownedExecutor property, but insead they have to implement the unownedExecutor on the specific actor type. Adding documentation clarify this as well as a simple test that exercises this explicitly; We seem to have much coverage of main actor, but not so much of custom executor global actors. --- stdlib/public/Concurrency/GlobalActor.swift | 37 ++++++- .../Runtime/custom_executors.swift | 2 + .../custom_executors_globalActor.swift | 101 ++++++++++++++++++ 3 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 test/Concurrency/Runtime/custom_executors_globalActor.swift diff --git a/stdlib/public/Concurrency/GlobalActor.swift b/stdlib/public/Concurrency/GlobalActor.swift index 72f0657a6de28..d866ec61aab45 100644 --- a/stdlib/public/Concurrency/GlobalActor.swift +++ b/stdlib/public/Concurrency/GlobalActor.swift @@ -22,6 +22,25 @@ import Swift /// such a declaration from another actor (or from nonisolated code), /// synchronization is performed through the shared actor instance to ensure /// mutually-exclusive access to the declaration. +/// +/// ## Custom Actor Executors +/// A global actor use a custom executor if it needs to customize its execution +/// semantics, for example, by making sure all of its invocations are run on a +/// specific thread or dispatch queue. +/// +/// This is done the same way as with normal non-global actors, by declaring a +/// ``Actor/unownedExecutor`` nonisolated property in the ``ActorType`` +/// underlying this global actor. +/// +/// It is *not* necessary to override the ``sharedUnownedExecutor`` static +/// property of the global actor, as its default implementation already +/// delegates to the ``shared.unownedExecutor``, which is the most reasonable +/// and correct implementation of this protocol requirement. +/// +/// You can find out more about custom executors, by referring to the +/// ``SerialExecutor`` protocol's documentation. +/// +/// - SeeAlso: ``SerialExecutor`` @available(SwiftStdlib 5.1, *) public protocol GlobalActor { /// The type of the shared actor instance that will be used to provide @@ -36,10 +55,22 @@ public protocol GlobalActor { /// instance. static var shared: ActorType { get } - /// The shared executor instance that will be used to provide - /// mutually-exclusive access for the global actor. + /// Shorthand for referring to the `shared.unownedExecutor` of this global actor. + /// + /// When declaring a global actor with a custom executor, prefer to implement + /// the underlying actor's ``Actor/unownedExecutor`` property, and leave this + /// `sharedUnownedExecutor` default implementation in-place as it will simply + /// delegate to the `shared.unownedExecutor`. + /// + /// The value of this property must be equivalent to `shared.unownedExecutor`, + /// as may be used by the Swift concurrency runtime or explicit user code. with + /// that assumption in mind. + /// + /// Returning different executors for different invocations of this computed + /// property is also illegal, as it could lead to inconsistent synchronization + /// of the underlying actor. /// - /// The value of this property must be equivalent to `shared.unownedExecutor`. + /// - SeeAlso: ``SerialExecutor`` static var sharedUnownedExecutor: UnownedSerialExecutor { get } } diff --git a/test/Concurrency/Runtime/custom_executors.swift b/test/Concurrency/Runtime/custom_executors.swift index 334f42267eb04..323e655e8676e 100644 --- a/test/Concurrency/Runtime/custom_executors.swift +++ b/test/Concurrency/Runtime/custom_executors.swift @@ -27,6 +27,8 @@ actor Custom { } func report() async { + simple.preconditionIsolated() // we're supposed to be on the same executor as 'simple' + print("custom.count == \(count)") count += 1 diff --git a/test/Concurrency/Runtime/custom_executors_globalActor.swift b/test/Concurrency/Runtime/custom_executors_globalActor.swift new file mode 100644 index 0000000000000..8342a70799c4e --- /dev/null +++ b/test/Concurrency/Runtime/custom_executors_globalActor.swift @@ -0,0 +1,101 @@ +// RUN: %target-run-simple-swift( %import-libdispatch -strict-concurrency=complete -parse-as-library) | %FileCheck %s + +// REQUIRES: concurrency +// REQUIRES: executable_test +// REQUIRES: libdispatch +// UNSUPPORTED: freestanding + +// UNSUPPORTED: back_deployment_runtime +// REQUIRES: concurrency_runtime + +import Dispatch + +let globalQueue = DispatchQueue(label: "SimpleQueue") + +@available(SwiftStdlib 6.0, *) +final class NaiveQueueExecutor: SerialExecutor { + public func enqueue(_ unowned: UnownedJob) { + globalQueue.sync { + unowned.runSynchronously(on: self.asUnownedSerialExecutor()) + } + } + + public func asUnownedSerialExecutor() -> UnownedSerialExecutor { + return UnownedSerialExecutor(ordinary: self) + } + + func checkIsolated() { + // ok + } +} + +@available(SwiftStdlib 6.0, *) +actor Simple { + var count = 0 + let exec = NaiveQueueExecutor() + + func report() { + print("simple.count == \(count)") + count += 1 + } + + nonisolated var unownedExecutor: UnownedSerialExecutor { + print("Simple.unownedExecutor") + return exec.asUnownedSerialExecutor() + } +} + +@globalActor +@available(SwiftStdlib 6.0, *) +actor MyGlobalActor { + static let simple = Simple() + static let shared = MyGlobalActor() + + static var sharedUnownedExecutor: UnownedSerialExecutor { + print("MyGlobalActor.sharedUnownedExecutor") + return simple.unownedExecutor + } + nonisolated var unownedExecutor: UnownedSerialExecutor { + print("MyGlobalActor.unownedExecutor") + return Self.simple.unownedExecutor + } +} + +@MyGlobalActor +@available(SwiftStdlib 6.0, *) +final class Custom { + var count = 0 + let simple = MyGlobalActor.simple + + nonisolated var unownedExecutor: UnownedSerialExecutor { + return simple.unownedExecutor + } + + func report() async { + simple.preconditionIsolated() + + print("custom.count == \(count)") + count += 1 + + await simple.report() + } +} + +@available(SwiftStdlib 6.0, *) +@main struct Main { + static func main() async { + print("begin") + let actor = Custom() + await actor.report() + print("end") + } +} + +// CHECK: begin +// CHECK-NEXT: MyGlobalActor.unownedExecutor +// CHECK-NEXT: Simple.unownedExecutor +// CHECK-NEXT: Simple.unownedExecutor +// CHECK-NEXT: custom.count == 0 +// CHECK-NEXT: Simple.unownedExecutor +// CHECK-NEXT: simple.count == 0 +// CHECK-NEXT: end From 4bae14a5c4c1d410673d1963464399126cc3a8b7 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Tue, 11 Jun 2024 18:21:15 +0900 Subject: [PATCH 072/165] [Distributed] Improve erroring out when distributed types not found also return early when type hasError --- lib/Sema/CodeSynthesisDistributedActor.cpp | 6 +++--- lib/Sema/DerivedConformanceDistributedActor.cpp | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/Sema/CodeSynthesisDistributedActor.cpp b/lib/Sema/CodeSynthesisDistributedActor.cpp index 07c7ebe9e6851..236328ae5d50a 100644 --- a/lib/Sema/CodeSynthesisDistributedActor.cpp +++ b/lib/Sema/CodeSynthesisDistributedActor.cpp @@ -81,15 +81,15 @@ static VarDecl* // what already has a witness. static VarDecl *addImplicitDistributedActorIDProperty( ClassDecl *nominal) { - if (!nominal) - return nullptr; - if (!nominal->isDistributedActor()) + if (!nominal || !nominal->isDistributedActor()) return nullptr; auto &C = nominal->getASTContext(); // ==== Synthesize and add 'id' property to the actor decl Type propertyType = getDistributedActorIDType(nominal); + if (!propertyType || propertyType->hasError()) + return nullptr; auto *propDecl = new (C) VarDecl(/*IsStatic*/false, VarDecl::Introducer::Let, diff --git a/lib/Sema/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformanceDistributedActor.cpp index 5b396655dee0a..e3a44b70d9221 100644 --- a/lib/Sema/DerivedConformanceDistributedActor.cpp +++ b/lib/Sema/DerivedConformanceDistributedActor.cpp @@ -474,6 +474,9 @@ static ValueDecl *deriveDistributedActor_actorSystem( auto classDecl = dyn_cast(derived.Nominal); assert(classDecl && derived.Nominal->isDistributedActor()); + if (!C.getLoadedModule(C.Id_Distributed)) + return nullptr; + // ``` // nonisolated let actorSystem: ActorSystem // ``` From f035590784023f16136abd7b593151b3f0375829 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 11 Jun 2024 22:14:59 -0700 Subject: [PATCH 073/165] [region-isolation] Dont crash when processing global actor isolated init accessors. This just means that I stopped treating it like an actor instance isolated thing. This was fun to track down since ActorIsolation has a union in it that was being misinterpreted, leading to memory corruption... my favorite! = ). rdar://129256560 --- lib/SILOptimizer/Utils/SILIsolationInfo.cpp | 23 +++++++++++++-------- test/Concurrency/transfernonsendable.swift | 13 ++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp index d64a150774aa6..a84dc8f97f303 100644 --- a/lib/SILOptimizer/Utils/SILIsolationInfo.cpp +++ b/lib/SILOptimizer/Utils/SILIsolationInfo.cpp @@ -813,26 +813,31 @@ SILIsolationInfo SILIsolationInfo::get(SILArgument *arg) { } } - // Otherwise, see if we have an allocator decl ref. If we do and we have an - // actor instance isolation, then we know that we are actively just calling - // the initializer. To just make region isolation work, treat this as - // disconnected so we can construct the actor value. Users cannot write - // allocator functions so we just need to worry about compiler generated - // code. In the case of a non-actor, we can only have an allocator that is - // global actor isolated, so we will never hit this code path. + // Otherwise, see if we need to handle this isolation computation specially + // due to information from the decl ref if we have one. if (auto declRef = fArg->getFunction()->getDeclRef()) { + // First check if we have an allocator decl ref. If we do and we have an + // actor instance isolation, then we know that we are actively just calling + // the initializer. To just make region isolation work, treat this as + // disconnected so we can construct the actor value. Users cannot write + // allocator functions so we just need to worry about compiler generated + // code. In the case of a non-actor, we can only have an allocator that is + // global actor isolated, so we will never hit this code path. if (declRef.kind == SILDeclRef::Kind::Allocator) { if (fArg->getFunction()->getActorIsolation().isActorInstanceIsolated()) { return SILIsolationInfo::getDisconnected(false /*nonisolated(unsafe)*/); } } + // Then see if we have an init accessor that is isolated to an actor + // instance, but for which we have not actually passed self. In such a case, + // we need to pass in a "fake" ActorInstance that users know is a sentinel + // for the self value. if (auto functionIsolation = fArg->getFunction()->getActorIsolation()) { - if (declRef.getDecl()) { + if (functionIsolation.isActorInstanceIsolated() && declRef.getDecl()) { if (auto *accessor = dyn_cast_or_null(declRef.getFuncDecl())) { if (accessor->isInitAccessor()) { - assert(functionIsolation.isActorInstanceIsolated()); return SILIsolationInfo::getActorInstanceIsolated( fArg, ActorInstance::getForActorAccessorInit(), functionIsolation.getActor()); diff --git a/test/Concurrency/transfernonsendable.swift b/test/Concurrency/transfernonsendable.swift index c8fb0bc6c73a1..946fd612458f0 100644 --- a/test/Concurrency/transfernonsendable.swift +++ b/test/Concurrency/transfernonsendable.swift @@ -1688,6 +1688,19 @@ func initAccessorTests() { get { fatalError() } set { fatalError() } } + + @MainActor + var third: NonSendableKlass + @MainActor + var fourth: NonSendableKlass? = nil { + @storageRestrictions(initializes: third) + init(initialValue) { + third = initialValue! + } + + get { fatalError() } + set { fatalError() } + } } } From 8b00478bc601a454c5abd1eb54d984b4fdddf8b1 Mon Sep 17 00:00:00 2001 From: Ellie Shin Date: Tue, 11 Jun 2024 23:59:03 -0700 Subject: [PATCH 074/165] [SwiftCompilerSources] Remove unnecessary default case from SerializedKind funcs --- SwiftCompilerSources/Sources/SIL/Function.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/SwiftCompilerSources/Sources/SIL/Function.swift b/SwiftCompilerSources/Sources/SIL/Function.swift index a66e487c7aa3e..7f37efb703ed3 100644 --- a/SwiftCompilerSources/Sources/SIL/Function.swift +++ b/SwiftCompilerSources/Sources/SIL/Function.swift @@ -147,7 +147,6 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash case .IsNotSerialized: return .notSerialized case .IsSerialized: return .serialized case .IsSerializedForPackage: return .serializedForPackage - default: fatalError() } } @@ -156,7 +155,6 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash case .notSerialized: return .IsNotSerialized case .serialized: return .IsSerialized case .serializedForPackage: return .IsSerializedForPackage - default: fatalError() } } From b5dc34984d35ef6a34e72912a2c41800e783077d Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 12 Jun 2024 15:06:26 +0900 Subject: [PATCH 075/165] [Distributed] Typed throws for whenLocal: func must be @_AEIC --- stdlib/public/Distributed/DistributedActor.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/public/Distributed/DistributedActor.swift b/stdlib/public/Distributed/DistributedActor.swift index d4529c04956c7..a2bc90e1bb3f7 100644 --- a/stdlib/public/Distributed/DistributedActor.swift +++ b/stdlib/public/Distributed/DistributedActor.swift @@ -362,6 +362,7 @@ extension DistributedActor { /// state. /// /// When the actor is remote, the closure won't be executed and this function will return nil. + @_alwaysEmitIntoClient public nonisolated func whenLocal( _ body: @Sendable (isolated Self) async throws(E) -> T ) async throws(E) -> T? { From 3b95855a28cbd9c940726b4a548050b1d16415f7 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 12 Jun 2024 16:10:53 +0900 Subject: [PATCH 076/165] [Distributed] Reword docs since we no longer have ad-hoc requirements --- .../Distributed/DistributedActorSystem.swift | 147 +++--------------- 1 file changed, 20 insertions(+), 127 deletions(-) diff --git a/stdlib/public/Distributed/DistributedActorSystem.swift b/stdlib/public/Distributed/DistributedActorSystem.swift index 43583a90c301b..72a30b7a51d4f 100644 --- a/stdlib/public/Distributed/DistributedActorSystem.swift +++ b/stdlib/public/Distributed/DistributedActorSystem.swift @@ -172,58 +172,6 @@ import _Concurrency /// `remoteCall(on:target:invocation:returning:throwing:)` (or `remoteCallVoid(on:target:invocation:throwing:)` for Void returning methods). /// /// Implementing the remote calls correctly and efficiently is the important task for a distributed actor system library. -/// Since those methods are not currently expressible as protocol requirements due to advanced use of generics -/// combined with associated types, they will not appear in the protocol's documentation as explicit requirements. -/// Instead, we present their signatures that a conforming type has to implement here: -/// -/// > Note: Although the `remoteCall` methods are not expressed as protocol requirements in source, -/// > the compiler will provide the same errors as-if it was declared explicitly in this protocol. -/// -/// ```swift -/// /// Invoked by the Swift runtime when making a remote call. -/// /// -/// /// The `arguments` are the arguments container that was previously created -/// /// by `makeInvocationEncoder` and has been populated with all arguments. -/// /// -/// /// This method should perform the actual remote function call, and await for its response. -/// /// -/// /// ## Errors -/// /// This method is allowed to throw because of underlying transport or serialization errors, -/// /// as well as by re-throwing the error received from the remote callee (if able to). -/// func remoteCall( -/// on actor: Act, -/// target: RemoteCallTarget, -/// invocation: inout InvocationEncoder, -/// throwing: Err.Type, -/// returning: Res.Type -/// ) async throws -> Res -/// where Act: DistributedActor, -/// Act.ID == ActorID, -/// Err: Error, -/// Res: SerializationRequirement -/// ``` -/// -/// ```swift -/// /// Invoked by the Swift runtime when making a `Void`-returning remote call. -/// /// -/// /// The `arguments` are the arguments container that was previously created -/// /// by `makeInvocationEncoder` and has been populated with all arguments. -/// /// -/// /// This method should perform the actual remote function call, and await for its response. -/// /// -/// /// ## Errors -/// /// This method is allowed to throw because of underlying transport or serialization errors, -/// /// as well as by re-throwing the error received from the remote callee (if able to). -/// func remoteCallVoid( -/// on actor: Act, -/// target: RemoteCallTarget, -/// invocation: inout InvocationEncoder, -/// throwing: Err.Type -/// ) async throws -> Res -/// where Act: DistributedActor, -/// Act.ID == ActorID, -/// Err: Error -/// ``` /// /// Implementations of remote calls generally will serialize `actor.id`, `target` and `invocation` /// into some form of wire envelope, and send it over the network (or process boundary) using some @@ -379,6 +327,10 @@ public protocol DistributedActorSystem: Sendable { /// /// This method should perform the actual remote function call, and await for its response. /// + /// ## Serialization Requirement + /// Implementations of this method must ensure that the `Argument` type parameter conforms + /// to the types' `SerializationRequirement`. + /// /// ## Errors /// This method is allowed to throw because of underlying transport or serialization errors, /// as well as by re-throwing the error received from the remote callee (if able to). @@ -713,32 +665,6 @@ func _executeDistributedTarget( /// Once encoded, the system should use some underlying transport mechanism to send the /// bytes serialized by the invocation to the remote peer. /// -/// ### Protocol requirements -/// Similar to the ``DistributedActorSystem`` and its `remoteCall` and `remoteCallVoid` protocol requirements, -/// the `DistributedTargetInvocationEncoder` contains a few methods which are not possible to express in source due to -/// advanced use of generics combined with associated types. Specifically, the `recordArgument` and `recordReturnType` -/// methods are not expressed in source as protocol requirements, but will be treated by the compiler as-if they were. -/// -/// > Note: Although the `recordArgument` method is not expressed as protocol requirement in source, -/// > the compiler will provide the same errors as-if it was declared explicitly in this protocol. -/// -/// In addition to the compiler offering compile errors if those witnesses are missing in an adopting type, -/// we present their signatures here for reference: -/// -/// ```swift -/// /// Record an argument of `Argument` type. -/// /// This will be invoked for every argument of the target, in declaration order. -/// mutating func recordArgument( -/// _ argument: DistributedTargetArgument -/// ) throws -/// -/// /// Ad-hoc requirement -/// /// -/// /// Record the return type of the distributed method. -/// /// This method will not be invoked if the target is returning `Void`. -/// mutating func recordReturnType(_ type: R.Type) throws -/// ``` -/// /// ## Decoding an invocation /// Since every actor system is going to deal with a concrete invocation type, they may /// implement decoding them whichever way is most optimal for the given system. @@ -762,6 +688,10 @@ public protocol DistributedTargetInvocationEncoder { /// Record an argument of `Argument` type. /// This will be invoked for every argument of the target, in declaration order. + /// + /// ### Serialization Requirement + /// Implementations of this method must ensure that the `Value` type parameter conforms + /// to the types' `SerializationRequirement`. @available(SwiftStdlib 6.0, *) mutating func recordArgument( _ argument: RemoteCallArgument @@ -775,6 +705,10 @@ public protocol DistributedTargetInvocationEncoder { /// Record the return type of the distributed method. /// This method will not be invoked if the target is returning `Void`. + /// + /// ### Serialization Requirement + /// Implementations of this method must ensure that the `R` type parameter conforms + /// to the types' `SerializationRequirement`. @available(SwiftStdlib 6.0, *) mutating func recordReturnType(_ type: R.Type) throws @@ -839,35 +773,6 @@ public struct RemoteCallArgument { /// Decoder that must be provided to `executeDistributedTarget` and is used /// by the Swift runtime to decode arguments of the invocation. /// -/// ### Protocol requirements -/// Similar to the ``DistributedTargetInvocationEncoder`` and its `recordArgument` and `recordReturnType` protocol requirements, -/// the `DistributedTargetInvocationDecoder` contains a method which is not possible to express in source due to -/// advanced use of generics combined with associated types. Specifically, the `decodeNextArgument` -/// method is not expressed in source as protocol requirement, but will be treated by the compiler as-if it was. -/// -/// > Note: Although the `decodeNextArgument` method is not expressed as protocol requirement in source, -/// > the compiler will provide the same errors as-if it was declared explicitly in this protocol. -/// -/// In addition to the compiler offering compile errors if this witness is missing in an adopting type, -/// we present its signature here for reference: -/// -/// ```swift -/// /// Ad-hoc protocol requirement -/// /// -/// /// Attempt to decode the next argument from the underlying buffers into pre-allocated storage -/// /// pointed at by 'pointer'. -/// /// -/// /// This method should throw if it has no more arguments available, if decoding the argument failed, -/// /// or, optionally, if the argument type we're trying to decode does not match the stored type. -/// /// -/// /// The result of the decoding operation must be stored into the provided 'pointer' rather than -/// /// returning a value. This pattern allows the runtime to use a heavily optimized, pre-allocated -/// /// buffer for all the arguments and their expected types. The 'pointer' passed here is a pointer -/// /// to a "slot" in that pre-allocated buffer. That buffer will then be passed to a thunk that -/// /// performs the actual distributed (local) instance method invocation. -/// mutating func decodeNextArgument() throws -> Argument -/// ``` -/// /// ### Decoding DistributedActor arguments using Codable /// When using an actor system where ``ActorID`` is ``Codable``, every distributed actor using that system /// is also implicitly ``Codable`` (see ``DistributedActorSystem``). Such distributed actors are encoded @@ -914,6 +819,10 @@ public protocol DistributedTargetInvocationDecoder { /// buffer for all the arguments and their expected types. The 'pointer' passed here is a pointer /// to a "slot" in that pre-allocated buffer. That buffer will then be passed to a thunk that /// performs the actual distributed (local) instance method invocation. + /// + /// ### Serialization Requirement + /// Implementations of this method must ensure that the `Argument` type parameter conforms + /// to the types' `SerializationRequirement`. @available(SwiftStdlib 6.0, *) mutating func decodeNextArgument() throws -> Argument @@ -936,26 +845,6 @@ public protocol DistributedTargetInvocationDecoder { /// ``executeDistributedTarget(on:target:invocationDecoder:handler:)`` while handling an incoming distributed call. /// /// The handler will then be invoked with the return value (or error) that the invoked target returned (or threw). -/// -/// ### Protocol requirements -/// Similar to the ``DistributedActorSystem`` and its `remoteCall` and `remoteCallVoid` protocol requirements, -/// the `DistributedTargetInvocationResultHandler` contains a method which is not possible to express in source due to -/// advanced use of generics combined with associated types. Specifically, the `onReturn` method is not expressed in -/// source as protocol requirement, but will be treated by the compiler as-if they were. -/// -/// > Note: Although the `onReturn` method is not expressed as protocol requirement in source, -/// > the compiler will provide the same errors as-if it was declared explicitly in this protocol. -/// -/// In addition to the compiler offering compile errors if this witnesses is missing in an adopting type, -/// we present its signature here for reference: -/// -/// ```swift -/// /// Ad-hoc protocol requirement -/// /// -/// /// Invoked when the distributed target execution returns successfully. -/// /// The `value` is the return value of the executed distributed invocation target. -/// func onReturn(value: Success) async throws -/// ``` @available(SwiftStdlib 5.7, *) public protocol DistributedTargetInvocationResultHandler { /// The serialization requirement that the value passed to `onReturn` is required to conform to. @@ -963,6 +852,10 @@ public protocol DistributedTargetInvocationResultHandler(value: Success) async throws From 8a88569c6be904362ec1ec6bafbf5b622646ead4 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 12 Jun 2024 16:24:36 +0900 Subject: [PATCH 077/165] [Distributed] remoteCallVoid is a new requirement in Swift 6.0 And it is handled compatibly because all existing implementations must have already implemented it before -- it was an ad-hoc requirement before Swift 6.0, and now it has become a real requirement - the same as all the other ad-hoc requirements relying on the Serialization Requirement --- stdlib/public/Distributed/DistributedActorSystem.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/public/Distributed/DistributedActorSystem.swift b/stdlib/public/Distributed/DistributedActorSystem.swift index 72a30b7a51d4f..c9ab2b2700a2d 100644 --- a/stdlib/public/Distributed/DistributedActorSystem.swift +++ b/stdlib/public/Distributed/DistributedActorSystem.swift @@ -357,6 +357,7 @@ public protocol DistributedActorSystem: Sendable { /// ## Errors /// This method is allowed to throw because of underlying transport or serialization errors, /// as well as by re-throwing the error received from the remote callee (if able to). + @available(SwiftStdlib 6.0, *) func remoteCallVoid( on actor: Act, target: RemoteCallTarget, From d80813ee3bad9fa3e1458cb62475911ab1666042 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Wed, 12 Jun 2024 12:55:34 +0200 Subject: [PATCH 078/165] SIL: update borrowed-from instructions when cloning a basic block Cloning blocks might split CFG edges which can "convert" terminator result arguments to phi-arguments. In this case a borrowed-from instruction must be inserted. Fixes a SIL verifier crash caused by SimplifyCFG's jump threading. rdar://129187525 --- include/swift/SIL/SILCloner.h | 12 +++- lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp | 62 ++++++++++--------- test/SILOptimizer/simplify_cfg_ossa.sil | 44 +++++++++++++ 3 files changed, 89 insertions(+), 29 deletions(-) diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 3338b82a322de..2107073c790ec 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -87,6 +87,10 @@ class SILCloner : protected SILInstructionVisitor { /// blocks. llvm::DenseMap BBMap; + /// Blocks, where edge-spitting may have "converted" terminator result + /// arguments to phi-arguments. + llvm::SmallVector blocksWithNewPhiArgs; + private: /// MARK: Private state hidden from CRTP extensions. @@ -872,9 +876,15 @@ void SILCloner::visitBlocksDepthFirst(SILBasicBlock *startBB) { && isa(BB->getTerminator())) { continue; } + TermInst *term = BB->getTerminator(); + + // After edge-spitting, terminator result arguments become phi arguments. + if (!isa(term)) + blocksWithNewPhiArgs.push_back(BB->getSuccessors()[succIdx]); + // This predecessor has multiple successors, so cloning it without // cloning its successors would create a critical edge. - splitEdge(BB->getTerminator(), succIdx, DomTree); + splitEdge(term, succIdx, DomTree); assert(!BBMap.count(BB->getSuccessors()[succIdx])); } // Map the successor to a new BB. Layout the cloned blocks in the order diff --git a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp index 142d6c7263f7b..a5fbe48dcc3f9 100644 --- a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp +++ b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp @@ -125,41 +125,47 @@ void BasicBlockCloner::updateSSAAfterCloning() { break; } } - if (!needsSSAUpdate) - return; - - SILSSAUpdater ssaUpdater(&updateSSAPhis); - for (auto availValPair : availVals) { - auto inst = availValPair.first; - if (inst->use_empty()) - continue; + if (needsSSAUpdate) { + SILSSAUpdater ssaUpdater(&updateSSAPhis); + for (auto availValPair : availVals) { + auto inst = availValPair.first; + if (inst->use_empty()) + continue; - SILValue newResult(availValPair.second); + SILValue newResult(availValPair.second); - SmallVector useList; - // Collect the uses of the value. - for (auto *use : inst->getUses()) - useList.push_back(UseWrapper(use)); + SmallVector useList; + // Collect the uses of the value. + for (auto *use : inst->getUses()) + useList.push_back(UseWrapper(use)); - ssaUpdater.initialize(inst->getFunction(), inst->getType(), - inst->getOwnershipKind()); - ssaUpdater.addAvailableValue(origBB, inst); - ssaUpdater.addAvailableValue(getNewBB(), newResult); + ssaUpdater.initialize(inst->getFunction(), inst->getType(), + inst->getOwnershipKind()); + ssaUpdater.addAvailableValue(origBB, inst); + ssaUpdater.addAvailableValue(getNewBB(), newResult); - if (useList.empty()) - continue; + if (useList.empty()) + continue; - // Update all the uses. - for (auto useWrapper : useList) { - Operand *use = useWrapper; // unwrap - SILInstruction *user = use->getUser(); - assert(user && "Missing user"); + // Update all the uses. + for (auto useWrapper : useList) { + Operand *use = useWrapper; // unwrap + SILInstruction *user = use->getUser(); + assert(user && "Missing user"); - // Ignore uses in the same basic block. - if (user->getParent() == origBB) - continue; + // Ignore uses in the same basic block. + if (user->getParent() == origBB) + continue; - ssaUpdater.rewriteUse(*use); + ssaUpdater.rewriteUse(*use); + } + } + } + for (SILBasicBlock *b : blocksWithNewPhiArgs) { + for (SILArgument *arg : b->getArguments()) { + if (arg->getOwnershipKind() == OwnershipKind::Guaranteed) { + updateSSAPhis.push_back(cast(arg)); + } } } updateBorrowedFromPhis(pm, updateSSAPhis); diff --git a/test/SILOptimizer/simplify_cfg_ossa.sil b/test/SILOptimizer/simplify_cfg_ossa.sil index 06a1759e8c1a9..4c9cec76579e5 100644 --- a/test/SILOptimizer/simplify_cfg_ossa.sil +++ b/test/SILOptimizer/simplify_cfg_ossa.sil @@ -25,6 +25,7 @@ class Klass { var a: Int deinit init() + func foo() -> Int? } class B {} @@ -38,6 +39,10 @@ struct KlassWrapper { var k: Klass } +struct OptionalKlassWrapper { + @_hasStorage var k: Optional +} + internal enum CompareResult { case equal case less @@ -1843,3 +1848,42 @@ bb10(%7 : $()): bb11: unreachable } + +// CHECK-LABEL: sil [ossa] @jump_threading_creates_phi : +// CHECK: = borrowed %{{[0-9]+}} : $Klass from (%1 : $OptionalKlassWrapper) +// CHECK: } // end sil function 'jump_threading_creates_phi' +sil [ossa] @jump_threading_creates_phi: $@convention(thin) (Optional, @guaranteed OptionalKlassWrapper) -> () { +bb0(%0 : $Optional, %1 : @guaranteed $OptionalKlassWrapper): + %2 = alloc_stack [lexical] $Optional + store %0 to [trivial] %2 : $*Optional + switch_enum_addr %2 : $*Optional, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2 + +bb1: + %5 = unchecked_take_enum_data_addr %2 : $*Optional, #Optional.some!enumelt + %6 = load [trivial] %5 : $*A + br bb3(%6 : $A) + +bb2: + %8 = enum $A, #A.B!enumelt + br bb3(%8 : $A) + +bb3(%10 : $A): + dealloc_stack %2 : $*Optional + %12 = enum $Optional, #Optional.some!enumelt, %10 : $A + %13 = struct_extract %1 : $OptionalKlassWrapper, #OptionalKlassWrapper.k + switch_enum %13 : $Optional, case #Optional.some!enumelt: bb4, case #Optional.none!enumelt: bb5 + +bb4(%15 : @guaranteed $Klass): + %16 = class_method %15 : $Klass, #Klass.foo : (Klass) -> () -> Int?, $@convention(method) (@guaranteed Klass) -> Optional + %17 = apply %16(%15) : $@convention(method) (@guaranteed Klass) -> Optional + br bb6(%17 : $Optional) + +bb5: + %19 = enum $Optional, #Optional.none!enumelt + br bb6(%19 : $Optional) + +bb6(%21 : $Optional): + %22 = tuple () + return %22 : $() +} + From 3dd4198adc003451694c11265e12374afeb98a76 Mon Sep 17 00:00:00 2001 From: Jeremy Schonfeld <1004103+jmschonfeld@users.noreply.github.com> Date: Wed, 12 Jun 2024 08:28:39 -0700 Subject: [PATCH 079/165] [Windows] Prepare for swift-foundation in the toolchain (#74127) * [Windows] Prepare for swift-foundation in the toolchain * Update SwiftSyntax directory --- utils/build.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/utils/build.ps1 b/utils/build.ps1 index 06046abb1b6ff..4d3ba1a3a7e97 100644 --- a/utils/build.ps1 +++ b/utils/build.ps1 @@ -1629,6 +1629,7 @@ function Build-Dispatch([Platform]$Platform, $Arch, [switch]$Test = $false) { function Build-Foundation([Platform]$Platform, $Arch, [switch]$Test = $false) { $DispatchBinaryCache = Get-TargetProjectBinaryCache $Arch Dispatch + $SwiftSyntaxDir = Get-HostProjectCMakeModules Compilers $FoundationBinaryCache = Get-TargetProjectBinaryCache $Arch Foundation $ShortArch = $Arch.LLVMName @@ -1695,6 +1696,10 @@ function Build-Foundation([Platform]$Platform, $Arch, [switch]$Test = $false) { }; ZLIB_INCLUDE_DIR = "$LibraryRoot\zlib-1.3.1\usr\include"; dispatch_DIR = "$DispatchBinaryCache\cmake\modules"; + SwiftSyntax_DIR = "$SwiftSyntaxDir"; + _SwiftFoundation_SourceDIR = "$SourceCache\swift-foundation"; + _SwiftFoundationICU_SourceDIR = "$SourceCache\swift-foundation-icu"; + _SwiftCollections_SourceDIR = "$SourceCache\swift-collections" } + $TestingDefines) } } From ae1f8042c0458c18b562f66ac947357e35fe3a78 Mon Sep 17 00:00:00 2001 From: Gabor Horvath Date: Wed, 12 Jun 2024 12:15:08 +0100 Subject: [PATCH 080/165] [cxx-interop] Fix extra indirection when exporting CFData arguments/return values The clang nodes associated with Swift's Core Foundation types can already be represented by a pointer. The interop code does not need to add an extra layer of indirection in those cases. rdar://119840281 --- include/swift/ClangImporter/ClangImporter.h | 6 ++++++ lib/ClangImporter/CFTypeInfo.h | 7 ------- lib/PrintAsClang/PrintClangFunction.cpp | 10 ++++++++-- .../stdlib/core-foundation-types-in-cxx.swift | 14 ++++++++++++++ 4 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 test/Interop/SwiftToCxx/stdlib/core-foundation-types-in-cxx.swift diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 83f68ed05c1f7..3472cb4eff63b 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -678,6 +678,12 @@ getCxxReferencePointeeTypeOrNone(const clang::Type *type); /// Returns true if the given type is a C++ `const` reference type. bool isCxxConstReferenceType(const clang::Type *type); +/// Determine whether this typedef is a CF type. +bool isCFTypeDecl(const clang::TypedefNameDecl *Decl); + +/// Determine the imported CF type for the given typedef-name, or the empty +/// string if this is not an imported CF type name. +llvm::StringRef getCFTypeName(const clang::TypedefNameDecl *decl); } // namespace importer struct ClangInvocationFileMapping { diff --git a/lib/ClangImporter/CFTypeInfo.h b/lib/ClangImporter/CFTypeInfo.h index 3597e60f05ef7..e62576f5d71f0 100644 --- a/lib/ClangImporter/CFTypeInfo.h +++ b/lib/ClangImporter/CFTypeInfo.h @@ -107,13 +107,6 @@ class CFPointeeInfo { return Decl.get(); } }; - -/// Determine whether this typedef is a CF type. -bool isCFTypeDecl(const clang::TypedefNameDecl *Decl); - -/// Determine the imported CF type for the given typedef-name, or the empty -/// string if this is not an imported CF type name. -llvm::StringRef getCFTypeName(const clang::TypedefNameDecl *decl); } } diff --git a/lib/PrintAsClang/PrintClangFunction.cpp b/lib/PrintAsClang/PrintClangFunction.cpp index a85ce54802d99..662d46a9c60a3 100644 --- a/lib/PrintAsClang/PrintClangFunction.cpp +++ b/lib/PrintAsClang/PrintClangFunction.cpp @@ -31,6 +31,7 @@ #include "swift/IRGen/IRABIDetailsProvider.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "llvm/ADT/STLExtras.h" @@ -273,8 +274,13 @@ class CFunctionSignatureTypePrinter bool isInOutParam) { auto *cd = CT->getDecl(); if (cd->hasClangNode()) { - ClangSyntaxPrinter(os).printClangTypeReference(cd->getClangDecl()); - os << " *" + const auto *clangDecl = cd->getClangDecl(); + ClangSyntaxPrinter(os).printClangTypeReference(clangDecl); + bool alreadyPointer = false; + if (const auto *typedefDecl = dyn_cast(clangDecl)) + if (importer::isCFTypeDecl(typedefDecl)) + alreadyPointer = true; + os << (alreadyPointer ? " " : " *") << (!optionalKind || *optionalKind == OTK_None ? "_Nonnull" : "_Nullable"); if (isInOutParam) { diff --git a/test/Interop/SwiftToCxx/stdlib/core-foundation-types-in-cxx.swift b/test/Interop/SwiftToCxx/stdlib/core-foundation-types-in-cxx.swift new file mode 100644 index 0000000000000..7c45fbddfeb64 --- /dev/null +++ b/test/Interop/SwiftToCxx/stdlib/core-foundation-types-in-cxx.swift @@ -0,0 +1,14 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend -typecheck %s -typecheck -module-name UseCoreFoundation -enable-experimental-cxx-interop -clang-header-expose-decls=all-public -emit-clang-header-path %t/UseCoreFoundation.h +// RUN: %FileCheck %s < %t/UseCoreFoundation.h + +// REQUIRES: objc_interop + +import CoreFoundation + +public func foobar(_ a: CFData) -> Bool { + true +} + +// CHECK: SWIFT_EXTERN bool $s17UseCoreFoundation6foobarySbSo9CFDataRefaF(CFDataRef _Nonnull a) SWIFT_NOEXCEPT SWIFT_CALL; // foobar(_:) From c270597fd07a19e4a7a898acbe6c6ad92491314f Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 12 Jun 2024 11:27:14 -0400 Subject: [PATCH 081/165] SIL: Fix false positive in FlowIsolation with DynamicSelfType usage If an instruction references the DynamicSelfType by calling a static member with `Self.foo()`, we consider this a type-dependent use of `self`. This means that at runtime we may need to load the isa pointer, but we don't need to touch any other protected state from the instance. Therefore, we can skip type-dependent uses in the analysis to avoid false positives in this case. An existing test case already exercised the overly-conservative behavior, so I just updated it to not expect an error. Fixes rdar://129676769. --- lib/SILOptimizer/Mandatory/FlowIsolation.cpp | 6 ++++++ test/Concurrency/flow_isolation.swift | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/SILOptimizer/Mandatory/FlowIsolation.cpp b/lib/SILOptimizer/Mandatory/FlowIsolation.cpp index b845386a2fdbd..03cb2abe313ab 100644 --- a/lib/SILOptimizer/Mandatory/FlowIsolation.cpp +++ b/lib/SILOptimizer/Mandatory/FlowIsolation.cpp @@ -582,6 +582,12 @@ void AnalysisInfo::analyze(const SILArgument *selfParam) { worklist.pushUsesOfValueIfNotVisited(selfParam); while (Operand *operand = worklist.pop()) { + // A type-dependent use of `self` is an instruction that contains the + // DynamicSelfType. These instructions do not access any protected + // state. + if (operand->isTypeDependent()) + continue; + SILInstruction *user = operand->getUser(); // First, check if this is an apply that involves `self` diff --git a/test/Concurrency/flow_isolation.swift b/test/Concurrency/flow_isolation.swift index b9bfde51d6134..a0b39ff37fa5c 100644 --- a/test/Concurrency/flow_isolation.swift +++ b/test/Concurrency/flow_isolation.swift @@ -684,8 +684,7 @@ actor OhBrother { static var DefaultResult: Int { 10 } init() { - // expected-note@+2 {{after this closure involving 'self', only non-isolated properties of 'self' can be accessed from this init}} - // expected-warning@+1 {{cannot access property 'giver' here in non-isolated initializer; this is an error in the Swift 6 language mode}} + // this is OK: we're using DynamicSelfType but that doesn't access protected state. self.giver = { (x: OhBrother) -> Int in Self.DefaultResult } } From c9e2e8e66c82c8790784f1b12f4be521468190b3 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Wed, 12 Jun 2024 09:06:05 -0700 Subject: [PATCH 082/165] [Test] Add regression test. For https://github.com/apple/swift/issues/73525 . --- .../noimplicitcopy_existentials.swift | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 test/SILOptimizer/noimplicitcopy_existentials.swift diff --git a/test/SILOptimizer/noimplicitcopy_existentials.swift b/test/SILOptimizer/noimplicitcopy_existentials.swift new file mode 100644 index 0000000000000..ee912af2999ab --- /dev/null +++ b/test/SILOptimizer/noimplicitcopy_existentials.swift @@ -0,0 +1,26 @@ +// RUN: %target-swift-frontend \ +// RUN: -emit-sil -verify \ +// RUN: %s \ +// RUN: -sil-verify-all + +//////////////////////////////////////////////////////////////////////////////// +// https://github.com/apple/swift/issues/73525 {{ +//////////////////////////////////////////////////////////////////////////////// +protocol K { + var a: Int { get } +} + +protocol B { + init(k: any K) +} + +struct A: B { + let a: Int + + init(k: borrowing K) { + self.a = k.a + } +} +//////////////////////////////////////////////////////////////////////////////// +// https://github.com/apple/swift/issues/73525 }} +//////////////////////////////////////////////////////////////////////////////// From 2039b8d25418c4a81358115690a7a3eace9ee118 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Mon, 10 Jun 2024 21:04:40 -0700 Subject: [PATCH 083/165] [cxx-interop] import static operator call from C++23 as member callAsFunction functions in Swift to preserve source compatibility --- lib/ClangImporter/ImportDecl.cpp | 12 +++++++ lib/ClangImporter/SwiftDeclSynthesizer.cpp | 34 +++++++++++++++++-- lib/ClangImporter/SwiftDeclSynthesizer.h | 3 ++ .../Cxx/class/Inputs/protocol-conformance.h | 4 +++ .../protocol-conformance-typechecker.swift | 6 ++++ .../Cxx/operators/Inputs/member-inline.h | 15 ++++++++ .../member-inline-module-interface.swift | 13 +++++++ .../Interop/Cxx/operators/member-inline.swift | 20 +++++++++++ 8 files changed, 105 insertions(+), 2 deletions(-) diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 0fa135546da11..3e1827dcbd2ca 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -3734,6 +3734,18 @@ namespace { } Decl *VisitCXXMethodDecl(const clang::CXXMethodDecl *decl) { + // The static `operator ()` introduced in C++ 23 is still callable as an + // instance operator in C++, and we want to preserve the ability to call + // it as an instance method in Swift as well for source compatibility. + // Therefore, we synthesize a C++ instance member that invokes the + // operator and import it instead. + if (decl->getOverloadedOperator() == + clang::OverloadedOperatorKind::OO_Call && + decl->isStatic()) { + auto result = synthesizer.makeInstanceToStaticOperatorCallMethod(decl); + if (result) + return result; + } auto method = VisitFunctionDecl(decl); // Do not expose constructors of abstract C++ classes. diff --git a/lib/ClangImporter/SwiftDeclSynthesizer.cpp b/lib/ClangImporter/SwiftDeclSynthesizer.cpp index 3bd00a0dddbb8..b8d6614bd11c9 100644 --- a/lib/ClangImporter/SwiftDeclSynthesizer.cpp +++ b/lib/ClangImporter/SwiftDeclSynthesizer.cpp @@ -2021,9 +2021,12 @@ clang::CXXMethodDecl *SwiftDeclSynthesizer::synthesizeCXXForwardingMethod( auto &clangCtx = ImporterImpl.getClangASTContext(); auto &clangSema = ImporterImpl.getClangSema(); + assert(!method->isStatic() || + method->getNameInfo().getName().getCXXOverloadedOperator() == + clang::OO_Call); // When emitting symbolic decls, the method might not have a concrete // record type as this type. - if (ImporterImpl.importSymbolicCXXDecls && + if (ImporterImpl.importSymbolicCXXDecls && !method->isStatic() && !method->getThisType()->getPointeeCXXRecordDecl()) return nullptr; @@ -2051,6 +2054,11 @@ clang::CXXMethodDecl *SwiftDeclSynthesizer::synthesizeCXXForwardingMethod( (forwardingMethodKind == ForwardingMethodKind::Virtual ? "__synthesizedVirtualCall_operatorStar" : "__synthesizedBaseCall_operatorStar"))); + } else if (name.getCXXOverloadedOperator() == clang::OO_Call) { + assert(forwardingMethodKind != ForwardingMethodKind::Virtual); + name = clang::DeclarationName( + &ImporterImpl.getClangPreprocessor().getIdentifierTable().get( + "__synthesizedBaseCall_operatorCall")); } auto methodType = method->getType(); // Check if we need to drop the reference from the return type @@ -2093,7 +2101,8 @@ clang::CXXMethodDecl *SwiftDeclSynthesizer::synthesizeCXXForwardingMethod( clangCtx, const_cast(derivedClass), method->getSourceRange().getBegin(), clang::DeclarationNameInfo(name, clang::SourceLocation()), methodType, - method->getTypeSourceInfo(), method->getStorageClass(), + method->getTypeSourceInfo(), + method->isStatic() ? clang::SC_None : method->getStorageClass(), method->UsesFPIntrin(), /*isInline=*/true, method->getConstexprKind(), method->getSourceRange().getEnd()); newMethod->setImplicit(); @@ -2264,6 +2273,27 @@ FuncDecl *SwiftDeclSynthesizer::makeVirtualMethod( return result; } +// MARK: C++ operators + +FuncDecl *SwiftDeclSynthesizer::makeInstanceToStaticOperatorCallMethod( + const clang::CXXMethodDecl *clangMethodDecl) { + auto clangDC = clangMethodDecl->getParent(); + auto &ctx = ImporterImpl.SwiftContext; + + assert(clangMethodDecl->isStatic() && "Expected a static operator"); + + auto newMethod = synthesizeCXXForwardingMethod( + clangDC, clangDC, clangMethodDecl, ForwardingMethodKind::Base, + ReferenceReturnTypeBehaviorForBaseMethodSynthesis::KeepReference, + /*forceConstQualifier*/ true); + newMethod->addAttr(clang::SwiftNameAttr::CreateImplicit( + clangMethodDecl->getASTContext(), "callAsFunction")); + + auto result = dyn_cast_or_null( + ctx.getClangModuleLoader()->importDeclDirectly(newMethod)); + return result; +} + // MARK: C++ properties static std::pair diff --git a/lib/ClangImporter/SwiftDeclSynthesizer.h b/lib/ClangImporter/SwiftDeclSynthesizer.h index ae54c8406ee53..e7ab62a46e7ab 100644 --- a/lib/ClangImporter/SwiftDeclSynthesizer.h +++ b/lib/ClangImporter/SwiftDeclSynthesizer.h @@ -319,6 +319,9 @@ class SwiftDeclSynthesizer { /// method that dispatches the call dynamically. FuncDecl *makeVirtualMethod(const clang::CXXMethodDecl *clangMethodDecl); + FuncDecl *makeInstanceToStaticOperatorCallMethod( + const clang::CXXMethodDecl *clangMethodDecl); + VarDecl *makeComputedPropertyFromCXXMethods(FuncDecl *getter, FuncDecl *setter); diff --git a/test/Interop/Cxx/class/Inputs/protocol-conformance.h b/test/Interop/Cxx/class/Inputs/protocol-conformance.h index aa504d1d9e36f..bc95f2a058bf8 100644 --- a/test/Interop/Cxx/class/Inputs/protocol-conformance.h +++ b/test/Interop/Cxx/class/Inputs/protocol-conformance.h @@ -72,4 +72,8 @@ struct HasVirtualMethod { virtual int return42() { return 42; } }; +struct HasStaticOperatorCall { + static int operator()(int x) { return x * 2; } +}; + #endif // TEST_INTEROP_CXX_CLASS_INPUTS_PROTOCOL_CONFORMANCE_H diff --git a/test/Interop/Cxx/class/protocol-conformance-typechecker.swift b/test/Interop/Cxx/class/protocol-conformance-typechecker.swift index 4b9754b6be0c6..3fb6c0bab719b 100644 --- a/test/Interop/Cxx/class/protocol-conformance-typechecker.swift +++ b/test/Interop/Cxx/class/protocol-conformance-typechecker.swift @@ -49,3 +49,9 @@ protocol HasOperatorPlusEqualProtocol { } extension HasOperatorPlusEqualInt : HasOperatorPlusEqualProtocol {} + +protocol HasOperatorCall { + func callAsFunction(_ x: Int32) -> Int32 +} + +extension HasStaticOperatorCall : HasOperatorCall {} \ No newline at end of file diff --git a/test/Interop/Cxx/operators/Inputs/member-inline.h b/test/Interop/Cxx/operators/Inputs/member-inline.h index c168de6a5bd89..b7f949ac089c8 100644 --- a/test/Interop/Cxx/operators/Inputs/member-inline.h +++ b/test/Interop/Cxx/operators/Inputs/member-inline.h @@ -477,4 +477,19 @@ struct HasOperatorCallWithDefaultArg { int operator()(int x = 0) const { return value + x; } }; +class HasStaticOperatorCallBase { +public: + static int operator()(int x) { return x + 42; } +}; + +class HasStaticOperatorCallDerived : public HasStaticOperatorCallBase {}; + +class HasStaticOperatorCallWithConstOperator { +public: + inline int operator()(int x, int y) const { return x + y; } + static int operator()(int x) { + return x - 1; + } +}; + #endif diff --git a/test/Interop/Cxx/operators/member-inline-module-interface.swift b/test/Interop/Cxx/operators/member-inline-module-interface.swift index e9a40f365a691..d5d454def2ffc 100644 --- a/test/Interop/Cxx/operators/member-inline-module-interface.swift +++ b/test/Interop/Cxx/operators/member-inline-module-interface.swift @@ -294,3 +294,16 @@ // CHECK: struct HasOperatorCallWithDefaultArg { // CHECK: func callAsFunction(_ x: Int32 = cxxDefaultArg) -> Int32 // CHECK: } + +// CHECK: struct HasStaticOperatorCallBase { +// CHECK: func callAsFunction(_ x: Int32) -> Int32 +// CHECK: } + +// CHECK: struct HasStaticOperatorCallDerived { +// CHECK: func callAsFunction(_ x: Int32) -> Int32 +// CHECK: } + +// CHECK: struct HasStaticOperatorCallWithConstOperator { +// CHECK: func callAsFunction(_ x: Int32, _ y: Int32) -> Int32 +// CHECK: func callAsFunction(_ x: Int32) -> Int32 +// CHECK: } diff --git a/test/Interop/Cxx/operators/member-inline.swift b/test/Interop/Cxx/operators/member-inline.swift index 8354e7cc04035..73540783ee53a 100644 --- a/test/Interop/Cxx/operators/member-inline.swift +++ b/test/Interop/Cxx/operators/member-inline.swift @@ -437,4 +437,24 @@ OperatorsTestSuite.test("HasOperatorCallWithDefaultArg.call") { expectEqual(444, res) } +OperatorsTestSuite.test("HasStaticOperatorCallBase.call") { + let h = HasStaticOperatorCallBase() + let res = h(1) + expectEqual(43, res) +} + +OperatorsTestSuite.test("HasStaticOperatorCallDerived.call") { + let h = HasStaticOperatorCallDerived() + let res = h(0) + expectEqual(42, res) +} + +OperatorsTestSuite.test("HasStaticOperatorCallWithConstOperator.call") { + let h = HasStaticOperatorCallWithConstOperator() + let res = h(10) + expectEqual(9, res) + let res2 = h(3, 5) + expectEqual(8, res2) +} + runAllTests() From 13ecb51612b20545c9fa874a2bed5c145d7c5784 Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Wed, 12 Jun 2024 14:51:35 +0200 Subject: [PATCH 084/165] embedded: add swift_dynamicCastClass runtime function To enable dynamic class casts rdar://129672994 --- stdlib/public/core/EmbeddedRuntime.swift | 14 +++++++++++++ test/embedded/classes.swift | 26 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/stdlib/public/core/EmbeddedRuntime.swift b/stdlib/public/core/EmbeddedRuntime.swift index d8d3819e21ea5..7ad57e4846809 100644 --- a/stdlib/public/core/EmbeddedRuntime.swift +++ b/stdlib/public/core/EmbeddedRuntime.swift @@ -187,6 +187,20 @@ func isValidPointerForNativeRetain(object: Builtin.RawPointer) -> Bool { public func swift_setDeallocating(object: Builtin.RawPointer) { } +@_cdecl("swift_dynamicCastClass") +public func swift_dynamicCastClass(object: UnsafeMutableRawPointer, targetMetadata: UnsafeRawPointer) -> UnsafeMutableRawPointer? { + let sourceObj = object.assumingMemoryBound(to: HeapObject.self) + var type = _swift_embedded_get_heap_object_metadata_pointer(sourceObj).assumingMemoryBound(to: ClassMetadata.self) + let targetType = targetMetadata.assumingMemoryBound(to: ClassMetadata.self) + while type != targetType { + guard let superType = type.pointee.superclassMetadata else { + return nil + } + type = UnsafeMutablePointer(superType) + } + return object +} + @_cdecl("swift_isUniquelyReferenced_native") public func swift_isUniquelyReferenced_native(object: Builtin.RawPointer) -> Bool { if !isValidPointerForNativeRetain(object: object) { return false } diff --git a/test/embedded/classes.swift b/test/embedded/classes.swift index 74d94899751d4..4c88dc37e4f66 100644 --- a/test/embedded/classes.swift +++ b/test/embedded/classes.swift @@ -15,9 +15,15 @@ class MyClass { } class MySubClass: MyClass { + var x = 27 + override init() { print("MySubClass.init") } deinit { print("MySubClass.deinit") } override func foo() { print("MySubClass.foo") } + + func printX() { + print(x) + } } class MySubSubClass: MySubClass { @@ -26,6 +32,17 @@ class MySubSubClass: MySubClass { override func foo() { print("MySubSubClass.foo") } } +class OtherSubClass: MyClass {} + +func testCasting(_ title: StaticString, _ c: MyClass) { + print(title, terminator: "") + if let s = c as? MySubClass { + s.printX() + } else { + print("-") + } +} + @main struct Main { static var o: (MyClass?, MyClass?, MyClass?) = (nil, nil, nil) @@ -69,5 +86,14 @@ struct Main { // CHECK: MySubClass.deinit // CHECK: MyClass.deinit print("") + + // CHECK: base: - + testCasting("base: ", MyClass()) + // CHECK: sub: 27 + testCasting("sub: ", MySubClass()) + // CHECK: subsub: 27 + testCasting("subsub: ", MySubSubClass()) + // CHECK: other: - + testCasting("other: ", OtherSubClass()) } } From 98b74d801021ac158c1161778ec356930438e343 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Wed, 12 Jun 2024 10:03:24 -0700 Subject: [PATCH 085/165] [android] do not import stdatomic from android's libc++ android's libc++ uses an older module map that requires C++23 for stdatomic, and thus it fails to compile with anything else --- stdlib/public/Platform/SwiftAndroidNDK.h | 7 +++++ stdlib/public/Platform/SwiftBionic.h | 7 +++++ .../Cxx/stdlib/android-and-std-module.swift | 29 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 test/Interop/Cxx/stdlib/android-and-std-module.swift diff --git a/stdlib/public/Platform/SwiftAndroidNDK.h b/stdlib/public/Platform/SwiftAndroidNDK.h index 791ac40ec4336..4d294ef96ad51 100644 --- a/stdlib/public/Platform/SwiftAndroidNDK.h +++ b/stdlib/public/Platform/SwiftAndroidNDK.h @@ -24,7 +24,14 @@ #include #include #include +#ifdef __cplusplus +// The Android r26 NDK contains an old libc++ modulemap that requires C++23 +// for 'stdatomic', which can't be imported unless we're using C++23. Thus, +// import stdatomic from the NDK directly, bypassing the stdatomic from the libc++. +#pragma clang module import _stdatomic +#else #include +#endif #include #include #include diff --git a/stdlib/public/Platform/SwiftBionic.h b/stdlib/public/Platform/SwiftBionic.h index b3e173030f18b..af4652d5ca7e6 100644 --- a/stdlib/public/Platform/SwiftBionic.h +++ b/stdlib/public/Platform/SwiftBionic.h @@ -24,7 +24,14 @@ #include #include #include +#ifdef __cplusplus +// The Android r26 NDK contains an old libc++ modulemap that requires C++23 +// for 'stdatomic', which can't be imported unless we're using C++23. Thus, +// import stdatomic from the NDK directly, bypassing the stdatomic from the libc++. +#pragma clang module import _stdatomic +#else #include +#endif #include #include #include diff --git a/test/Interop/Cxx/stdlib/android-and-std-module.swift b/test/Interop/Cxx/stdlib/android-and-std-module.swift new file mode 100644 index 0000000000000..cff4db5e70ae8 --- /dev/null +++ b/test/Interop/Cxx/stdlib/android-and-std-module.swift @@ -0,0 +1,29 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend %s -c -cxx-interoperability-mode=default -Xcc -std=c++14 -Xcc -fmodules-cache-path=%t +// RUN: %target-swift-frontend %s -c -cxx-interoperability-mode=default -Xcc -std=c++17 -Xcc -fmodules-cache-path=%t +// RUN: %target-swift-frontend %s -c -cxx-interoperability-mode=default -Xcc -std=c++20 -Xcc -fmodules-cache-path=%t + +// RUN: find %t | %FileCheck %s + +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend %s -c -cxx-interoperability-mode=default -Xcc -std=c++17 -Xcc -fmodules-cache-path=%t -DADD_CXXSTDLIB +// RUN: %target-swift-frontend %s -c -cxx-interoperability-mode=default -Xcc -std=c++20 -Xcc -fmodules-cache-path=%t -DADD_CXXSTDLIB + +// REQUIRES: OS=linux-android + +import Android +import Bionic + +#if ADD_CXXSTDLIB +import CxxStdlib +#endif + +func test() { +#if ADD_CXXSTDLIB + let _ = std.string() +#endif +} + +// CHECK-DAG: Android{{.*}}.pcm +// CHECK-DAG: std{{.*}}.pcm From f53be7187486feeff8398ee9569df72077d1e7db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Tue, 11 Jun 2024 16:32:45 -0700 Subject: [PATCH 086/165] ModuleInterface: Print imports shadowed by a cross-import overlay In some cases this import may be superfluous as it's also `@_exported` imported by the overlay. However, when the overlay is hidden and the import not printed, the import can go entierly missing. --- lib/Frontend/ModuleInterfaceSupport.cpp | 3 +- test/CrossImport/module-interface.swift | 3 +- .../with-implementation-only.swift | 71 +++++++++++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 test/CrossImport/with-implementation-only.swift diff --git a/lib/Frontend/ModuleInterfaceSupport.cpp b/lib/Frontend/ModuleInterfaceSupport.cpp index 491baa89e671e..83db1e19b75ed 100644 --- a/lib/Frontend/ModuleInterfaceSupport.cpp +++ b/lib/Frontend/ModuleInterfaceSupport.cpp @@ -240,7 +240,8 @@ static void printImports(raw_ostream &out, // it's not obvious what higher-level optimization would be factored out here. ModuleDecl::ImportFilter allImportFilter = { ModuleDecl::ImportFilterKind::Exported, - ModuleDecl::ImportFilterKind::Default}; + ModuleDecl::ImportFilterKind::Default, + ModuleDecl::ImportFilterKind::ShadowedByCrossImportOverlay}; // With -experimental-spi-imports: // When printing the private or package swiftinterface file, print implementation-only diff --git a/test/CrossImport/module-interface.swift b/test/CrossImport/module-interface.swift index 991e1e52f3c69..2b0d52b70125f 100644 --- a/test/CrossImport/module-interface.swift +++ b/test/CrossImport/module-interface.swift @@ -10,7 +10,6 @@ // RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary // RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary // RUN: %FileCheck %s < %t.swiftinterface -// RUN: %FileCheck -check-prefix NEGATIVE %s < %t.swiftinterface // // Should fail with -disable-cross-import-overlays @@ -38,9 +37,9 @@ public func shadow(_: DeclaringLibrary.ShadowTy, _: ShadowTy) {} // CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary // CHECK-DAG: import Swift +// CHECK-DAG: import DeclaringLibrary // CHECK-DAG: import BystandingLibrary // CHECK-DAG: import _OverlayLibrary -// NEGATIVE-NOT: import DeclaringLibrary // CHECK-DAG: public func fn(_: DeclaringLibrary.DeclaringLibraryTy, _: BystandingLibrary.BystandingLibraryTy, _: _OverlayLibrary.OverlayLibraryTy) // CHECK-DAG: public func alias(_: _OverlayLibrary.OverlayLibraryTy) diff --git a/test/CrossImport/with-implementation-only.swift b/test/CrossImport/with-implementation-only.swift new file mode 100644 index 0000000000000..a78c9d540bedd --- /dev/null +++ b/test/CrossImport/with-implementation-only.swift @@ -0,0 +1,71 @@ +/// Check cross-import overlays with @_implementationOnly imports. + +// RUN: %empty-directory(%t) +// RUN: cp -r %S/Inputs/lib-templates/* %t/ +// RUN: split-file --leading-lines %s %t + +//--- BothPublic.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/BothPublic.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/BothPublic.swift < %t.swiftinterface + +import DeclaringLibrary +import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// CHECK-DAG: import DeclaringLibrary +// CHECK-DAG: import BystandingLibrary +// CHECK-DAG: import _OverlayLibrary + + +//--- BothHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/BothHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/BothHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefix NEGATIVE %t/BothHidden.swift < %t.swiftinterface + +@_implementationOnly import DeclaringLibrary +@_implementationOnly import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// NEGATIVE-NOT: import DeclaringLibrary +// NEGATIVE-NOT: import BystandingLibrary +// NEGATIVE-NOT: import _OverlayLibrary + + +//--- FirstHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/FirstHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/FirstHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefix NEGATIVE %t/FirstHidden.swift < %t.swiftinterface + +@_implementationOnly import DeclaringLibrary +import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// CHECK-DAG: import BystandingLibrary +// NEGATIVE-NOT: import DeclaringLibrary +// NEGATIVE-NOT: import _OverlayLibrary + + +//--- SecondHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/SecondHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/SecondHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefix NEGATIVE %t/SecondHidden.swift < %t.swiftinterface + +import DeclaringLibrary +@_implementationOnly import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// CHECK-DAG: import DeclaringLibrary +// NEGATIVE-NOT: import BystandingLibrary +// NEGATIVE-NOT: import _OverlayLibrary From bba8b921ab9e907bd89d967cc89306d1ceb5beda Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 12 Jun 2024 09:46:35 -0700 Subject: [PATCH 087/165] Finalize Swift debug info before running Clang codegen, because it may delete the llvm module. rdar://128309024 --- lib/IRGen/IRGenModule.cpp | 8 ++++--- test/DebugInfo/BridgingHeaderPCH.swift | 4 +--- test/DebugInfo/ClangModuleBreadcrumbs.swift | 24 ++++++--------------- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 0d9b66255f1ea..689443d879a36 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -1963,12 +1963,14 @@ bool IRGenModule::finalize() { } emitLazyPrivateDefinitions(); - // Finalize clang IR-generation. - finalizeClangCodeGen(); - + // Finalize Swift debug info before running Clang codegen, because it may + // delete the llvm module. if (DebugInfo) DebugInfo->finalize(); + // Finalize clang IR-generation. + finalizeClangCodeGen(); + // If that failed, report failure up and skip the final clean-up. if (!ClangCodeGen->GetModule()) return false; diff --git a/test/DebugInfo/BridgingHeaderPCH.swift b/test/DebugInfo/BridgingHeaderPCH.swift index 966e8baf997f4..b7a6996658eba 100644 --- a/test/DebugInfo/BridgingHeaderPCH.swift +++ b/test/DebugInfo/BridgingHeaderPCH.swift @@ -5,8 +5,6 @@ // CHECK: !DICompileUnit(language: DW_LANG_Swift // CHECK: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}}, -// CHECK: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}}, -// CHECK-SAME: splitDebugFilename: "{{.*}}.pch" -// CHECK-SAME: dwoId: +// CHECK: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}}{{.*}}splitDebugFilename: "{{.*}}.pch",{{.*}}dwoId: Foo() diff --git a/test/DebugInfo/ClangModuleBreadcrumbs.swift b/test/DebugInfo/ClangModuleBreadcrumbs.swift index 185e3be067272..56948b57c0ace 100644 --- a/test/DebugInfo/ClangModuleBreadcrumbs.swift +++ b/test/DebugInfo/ClangModuleBreadcrumbs.swift @@ -16,29 +16,17 @@ import OtherClangModule.SubModule let _ = someFunc(0) // Check for Clang module breadcrumbs. -// CHECK: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}},{{.*}} producer: "{{.*}}Swift -// CHECK-SAME: ClangModule -// CHECK-SAME: dwoId: +// CHECK: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}},{{.*}} producer: "{{.*}}Swift{{.*}}ClangModule{{.*}}dwoId: -// CHECK: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}}, {{.*}} producer: "{{.*}}Swift -// CHECK-SAME: OtherClangModule -// CHECK-SAME: dwoId: +// CHECK: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}}, {{.*}} producer: "{{.*}}Swift{{.*}}OtherClangModule{{.*}}dwoId: -// CHECK: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}},{{.*}} producer: "{{.*}}clang -// CHECK-SAME: ClangModule -// CHECK-SAME: dwoId: +// CHECK: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}},{{.*}} producer: "{{.*}}clang{{.*}}ClangModule{{.*}}dwoId: // NONE: DICompileUnit({{.*}} // NONE-NOT: DICompileUnit({{.*}}ClangModule -// REMAP: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}},{{.*}} producer: "{{.*}}Swift -// REMAP-SAME: PREFIX{{/|\\\\}}{{.*}}{{/|\\\\}}ClangModule -// REMAP-SAME: dwoId: +// REMAP: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}},{{.*}} producer: "{{.*}}Swift{{.*}}PREFIX{{/|\\\\}}{{.*}}{{/|\\\\}}ClangModule{{.*}}dwoId: -// REMAP: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}},{{.*}} producer: "{{.*}}Swift -// REMAP-SAME: PREFIX{{/|\\\\}}{{.*}}{{/|\\\\}}OtherClangModule -// REMAP-SAME: dwoId: +// REMAP: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}},{{.*}} producer: "{{.*}}Swift{{.*}}PREFIX{{/|\\\\}}{{.*}}{{/|\\\\}}OtherClangModule{{.*}}dwoId: -// REMAP: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}},{{.*}} producer: "{{.*}}clang -// REMAP-SAME: PREFIX{{/|\\\\}}{{.*}}{{/|\\\\}}ClangModule -// REMAP-SAME: dwoId: +// REMAP: !DICompileUnit(language: DW_LANG_{{ObjC|C99|C11}},{{.*}} producer: "{{.*}}clang{{.*}}PREFIX{{/|\\\\}}{{.*}}{{/|\\\\}}ClangModule{{.*}}dwoId: From 045c2145222ad13ad273df2b9289736d92892d54 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 12 Jun 2024 10:59:39 -0700 Subject: [PATCH 088/165] [docs] Add a little section about Disabling PCH Verification. --- docs/DebuggingTheCompiler.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/DebuggingTheCompiler.md b/docs/DebuggingTheCompiler.md index 5305c43199663..e919d4a9c3978 100644 --- a/docs/DebuggingTheCompiler.md +++ b/docs/DebuggingTheCompiler.md @@ -36,6 +36,7 @@ benefit of all Swift developers. - [Bisecting on SIL optimizer pass counts to identify optimizer bugs](#bisecting-on-sil-optimizer-pass-counts-to-identify-optimizer-bugs) - [Using git-bisect in the presence of branch forwarding/feature branches](#using-git-bisect-in-the-presence-of-branch-forwardingfeature-branches) - [Reducing SIL test cases using bug_reducer](#reducing-sil-test-cases-using-bug_reducer) + - [Disabling PCH Verification](#disabling-pch-verification) - [Debugging the Compiler Build](#debugging-the-compiler-build) - [Build Dry Run](#build-dry-run) - [Debugging the Compiler Driver](#debugging-the-compiler-driver-build) @@ -832,6 +833,19 @@ each time you change shas. To do this you can pass `--match-timestamp` to automatically checkout match the timestamp of the `apple/swift` repo across the other repos. +## Disabling PCH Verification + +Sometimes one needs to try to compile against PCH modules where the PCH version +verification checking is too strict. To work around this, one can disable the +checking by passing in to swift: + +```sh +-Xcc -Xclang -Xcc -fno-validate-pch +``` + +NOTE: If there are actual differences in between the on disk PCH format and the +format expected by the compiler crashes and undefined behavior may result. + # Debugging the Compiler Build ## Build Dry Run From 17b8e86a6da8e85f1e122560cdf48b513d243bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Tue, 11 Jun 2024 16:36:48 -0700 Subject: [PATCH 089/165] Sema: Support newer import restrictions with cross-import overlays Add support for access-level on imports and `@_spiOnly imports` to cross import overlays. The overlay inherits the most restrictive import access-level of the declaring module and the bystander module. rdar://129606112 --- lib/Sema/ImportResolution.cpp | 7 ++ lib/Sema/TypeCheckAccess.cpp | 13 +-- .../access-level-imports-errors.swift | 68 +++++++++++++++ .../with-access-level-import.swift | 71 +++++++++++++++ test/CrossImport/with-spi-only-import.swift | 86 +++++++++++++++++++ 5 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 test/CrossImport/access-level-imports-errors.swift create mode 100644 test/CrossImport/with-access-level-import.swift create mode 100644 test/CrossImport/with-spi-only-import.swift diff --git a/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index 8ffd8dadd5649..9fd2d67bc7134 100644 --- a/lib/Sema/ImportResolution.cpp +++ b/lib/Sema/ImportResolution.cpp @@ -1354,6 +1354,13 @@ UnboundImport::UnboundImport( if (declaringOptions.contains(ImportFlags::ImplementationOnly) || bystandingOptions.contains(ImportFlags::ImplementationOnly)) import.options |= ImportFlags::ImplementationOnly; + if (declaringOptions.contains(ImportFlags::SPIOnly) || + bystandingOptions.contains(ImportFlags::SPIOnly)) + import.options |= ImportFlags::SPIOnly; + + // Pick the most restrictive access level. + import.accessLevel = std::min(declaringImport.accessLevel, + bystandingImport.accessLevel); // If either have a `@_documentation(visibility: )` attribute, the // cross-import has the more restrictive of the two. diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 91361a33c6b61..7b704495a0516 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -404,12 +404,13 @@ static void noteLimitingImport(const Decl *userDecl, limitImport->accessLevel, limitImport->module.importedModule); - ctx.Diags.diagnose(limitImport->importLoc, - diag::decl_import_via_here, - VD, - limitImport->accessLevel, - limitImport->module.importedModule); - } else { + if (limitImport->importLoc.isValid()) + ctx.Diags.diagnose(limitImport->importLoc, + diag::decl_import_via_here, + VD, + limitImport->accessLevel, + limitImport->module.importedModule); + } else if (limitImport->importLoc.isValid()) { ctx.Diags.diagnose(limitImport->importLoc, diag::module_imported_here, limitImport->module.importedModule, limitImport->accessLevel); diff --git a/test/CrossImport/access-level-imports-errors.swift b/test/CrossImport/access-level-imports-errors.swift new file mode 100644 index 0000000000000..55918c222cf62 --- /dev/null +++ b/test/CrossImport/access-level-imports-errors.swift @@ -0,0 +1,68 @@ +/// Check semantic verification cross-import overlays with non-public imports. + +// RUN: %empty-directory(%t) +// RUN: cp -r %S/Inputs/lib-templates/* %t/ +// RUN: split-file --leading-lines %s %t + +//--- BothPublic.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/BothPublic.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary + +public import DeclaringLibrary +public import BystandingLibrary + +public func fn(_: OverlayLibraryTy) {} + + +//--- BothHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/BothHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary -verify + +internal import DeclaringLibrary +internal import BystandingLibrary + +public func fn(_: OverlayLibraryTy) {} +// expected-error @-1 {{function cannot be declared public because its parameter uses an internal type}} +// expected-note @-2 {{struct 'OverlayLibraryTy' is imported by this file as 'internal' from '_OverlayLibrary'}} + + +//--- FirstHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/FirstHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary -verify + +internal import DeclaringLibrary +public import BystandingLibrary // expected-warning {{public import of 'BystandingLibrary' was not used in public declarations or inlinable code}} + +public func fn(_: OverlayLibraryTy) {} +// expected-error @-1 {{function cannot be declared public because its parameter uses an internal type}} +// expected-note @-2 {{struct 'OverlayLibraryTy' is imported by this file as 'internal' from '_OverlayLibrary'}} + + +//--- SecondHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/SecondHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary -verify + +public import DeclaringLibrary // expected-warning {{public import of 'DeclaringLibrary' was not used in public declarations or inlinable code}} +internal import BystandingLibrary + +public func fn(_: OverlayLibraryTy) {} +// expected-error @-1 {{function cannot be declared public because its parameter uses an internal type}} +// expected-note @-2 {{struct 'OverlayLibraryTy' is imported by this file as 'internal' from '_OverlayLibrary'}} + + +//--- PrivateVsInternal.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/PrivateVsInternal.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary -verify + +private import DeclaringLibrary +internal import BystandingLibrary + +internal func fn(_: OverlayLibraryTy) {} +// expected-error @-1 {{function cannot be declared internal because its parameter uses a private type}} +// expected-note @-2 {{struct 'OverlayLibraryTy' is imported by this file as 'private' from '_OverlayLibrary'}} + + +//--- InternalVsPrivate.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/InternalVsPrivate.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary -verify + +internal import DeclaringLibrary +private import BystandingLibrary + +internal func fn(_: OverlayLibraryTy) {} +// expected-error @-1 {{function cannot be declared internal because its parameter uses a private type}} +// expected-note @-2 {{struct 'OverlayLibraryTy' is imported by this file as 'private' from '_OverlayLibrary'}} diff --git a/test/CrossImport/with-access-level-import.swift b/test/CrossImport/with-access-level-import.swift new file mode 100644 index 0000000000000..00cbf6123ae74 --- /dev/null +++ b/test/CrossImport/with-access-level-import.swift @@ -0,0 +1,71 @@ +/// Check cross-import overlays with non-public imports. + +// RUN: %empty-directory(%t) +// RUN: cp -r %S/Inputs/lib-templates/* %t/ +// RUN: split-file --leading-lines %s %t + +//--- BothPublic.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/BothPublic.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/BothPublic.swift < %t.swiftinterface + +public import DeclaringLibrary +public import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// CHECK-DAG: import DeclaringLibrary +// CHECK-DAG: import BystandingLibrary +// CHECK-DAG: import _OverlayLibrary + + +//--- BothHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/BothHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/BothHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefix NEGATIVE %t/BothHidden.swift < %t.swiftinterface + +internal import DeclaringLibrary +internal import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// NEGATIVE-NOT: import DeclaringLibrary +// NEGATIVE-NOT: import BystandingLibrary +// NEGATIVE-NOT: import _OverlayLibrary + + +//--- FirstHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/FirstHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/FirstHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefix NEGATIVE %t/FirstHidden.swift < %t.swiftinterface + +internal import DeclaringLibrary +public import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// CHECK-DAG: import BystandingLibrary +// NEGATIVE-NOT: import DeclaringLibrary +// NEGATIVE-NOT: import _OverlayLibrary + + +//--- SecondHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/SecondHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/SecondHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefix NEGATIVE %t/SecondHidden.swift < %t.swiftinterface + +public import DeclaringLibrary +internal import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// CHECK-DAG: import DeclaringLibrary +// NEGATIVE-NOT: import BystandingLibrary +// NEGATIVE-NOT: import _OverlayLibrary diff --git a/test/CrossImport/with-spi-only-import.swift b/test/CrossImport/with-spi-only-import.swift new file mode 100644 index 0000000000000..9ac2cb341deec --- /dev/null +++ b/test/CrossImport/with-spi-only-import.swift @@ -0,0 +1,86 @@ +/// Check cross-import overlays with @_spiOnly imports. + +// RUN: %empty-directory(%t) +// RUN: cp -r %S/Inputs/lib-templates/* %t/ +// RUN: split-file --leading-lines %s %t + +//--- BothPublic.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/BothPublic.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary -emit-private-module-interface-path %t.private.swiftinterface -swift-version 6 +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.private.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/BothPublic.swift < %t.swiftinterface +// RUN: %FileCheck %t/BothPublic.swift < %t.private.swiftinterface + +import DeclaringLibrary +import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// CHECK-DAG: import DeclaringLibrary +// CHECK-DAG: import BystandingLibrary +// CHECK-DAG: import _OverlayLibrary + + +//--- BothHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/BothHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary -emit-private-module-interface-path %t.private.swiftinterface -swift-version 6 +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.private.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/BothHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefix NEGATIVE %t/BothHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefixes CHECK,PRIVATE %t/BothHidden.swift < %t.private.swiftinterface + +@_spiOnly import DeclaringLibrary +@_spiOnly import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// NEGATIVE-NOT: import DeclaringLibrary +// NEGATIVE-NOT: import BystandingLibrary +// NEGATIVE-NOT: import _OverlayLibrary +// PRIVATE-DAG: import DeclaringLibrary +// PRIVATE-DAG: import BystandingLibrary +// PRIVATE-DAG: import _OverlayLibrary + + +//--- FirstHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/FirstHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary -emit-private-module-interface-path %t.private.swiftinterface -swift-version 6 +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.private.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/FirstHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefix NEGATIVE %t/FirstHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefixes CHECK,PRIVATE %t/FirstHidden.swift < %t.private.swiftinterface + +@_spiOnly import DeclaringLibrary +import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// CHECK-DAG: import BystandingLibrary +// NEGATIVE-NOT: import DeclaringLibrary +// NEGATIVE-NOT: import _OverlayLibrary +// PRIVATE-DAG: import DeclaringLibrary +// PRIVATE-DAG: import _OverlayLibrary + + +//--- SecondHidden.swift +// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %t/SecondHidden.swift -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary -emit-private-module-interface-path %t.private.swiftinterface -swift-version 6 +// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %target-swift-typecheck-module-from-interface(%t.private.swiftinterface) -enable-cross-import-overlays -I %t/lib/swift -module-name ClientLibrary +// RUN: %FileCheck %t/SecondHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefix NEGATIVE %t/SecondHidden.swift < %t.swiftinterface +// RUN: %FileCheck -check-prefixes CHECK,PRIVATE %t/SecondHidden.swift < %t.private.swiftinterface + +import DeclaringLibrary +@_spiOnly import BystandingLibrary + +// CHECK: // swift-interface-format-version +// CHECK: // swift-module-flags: {{.*}} -module-name ClientLibrary +// CHECK-DAG: import Swift +// CHECK-DAG: import DeclaringLibrary +// NEGATIVE-NOT: import BystandingLibrary +// NEGATIVE-NOT: import _OverlayLibrary +// PRIVATE-DAG: import BystandingLibrary +// PRIVATE-DAG: import _OverlayLibrary From e871cea02534cc3bd2d045431299dfa3430dd7dc Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Wed, 12 Jun 2024 11:26:02 -0700 Subject: [PATCH 090/165] [embedded] Respect float arg lowering convention under -mfloat-abi=hard --- lib/IRGen/GenCall.cpp | 8 ++++--- test/embedded/float-abi-hard.swift | 35 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 test/embedded/float-abi-hard.swift diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index e2a9f164e3373..a56861f397a0e 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -4299,11 +4299,12 @@ static void emitDirectForeignParameter(IRGenFunction &IGF, Explosion &in, // The ABI IR types for the entrypoint might differ from the // Swift IR types for the body of the function. + bool IsDirectFlattened = AI.isDirect() && AI.getCanBeFlattened(); + llvm::Type *coercionTy = AI.getCoerceToType(); ArrayRef expandedTys; - if (AI.isDirect() && AI.getCanBeFlattened() && - isa(coercionTy)) { + if (IsDirectFlattened && isa(coercionTy)) { const auto *ST = cast(coercionTy); expandedTys = llvm::ArrayRef(ST->element_begin(), ST->getNumElements()); } else if (coercionTy == paramTI.getStorageType()) { @@ -4344,7 +4345,8 @@ static void emitDirectForeignParameter(IRGenFunction &IGF, Explosion &in, Address coercedAddr = IGF.Builder.CreateElementBitCast(temporary, coercionTy); // Break down a struct expansion if necessary. - if (auto expansionTy = dyn_cast(coercionTy)) { + if (IsDirectFlattened && isa(coercionTy)) { + auto expansionTy = cast(coercionTy); auto layout = IGF.IGM.DataLayout.getStructLayout(expansionTy); for (unsigned i = 0, e = expansionTy->getNumElements(); i != e; ++i) { auto fieldOffset = Size(layout->getElementOffset(i)); diff --git a/test/embedded/float-abi-hard.swift b/test/embedded/float-abi-hard.swift new file mode 100644 index 0000000000000..b3a955a104450 --- /dev/null +++ b/test/embedded/float-abi-hard.swift @@ -0,0 +1,35 @@ +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s + +// RUN: %target-swift-emit-ir %t/Main.swift -import-bridging-header %t/BridgingHeader.h -parse-as-library -enable-experimental-feature Embedded -wmo \ +// RUN: -target armv7em-none-none-eabi -Xcc -mthumb -Xcc -mcpu=cortex-m7 -Xcc -mfloat-abi=hard -Xcc -mfpu=fpv5-sp-d16 -Xcc -D__FPU_USED=1 -Xcc -falign-functions=16 + +// REQUIRES: swift_in_compiler +// REQUIRES: optimized_stdlib +// REQUIRES: OS=macosx || OS=linux-gnu +// REQUIRES: CODEGENERATOR=ARM + +// BEGIN BridgingHeader.h + +typedef struct +{ + float x; + float y; + float width; + float height; +} Rect; + +typedef void FunctionType(Rect, Rect); +void (* _Nonnull callback)(FunctionType * _Nonnull func); +void c_function(Rect, Rect); + +// BEGIN Main.swift + +@main +struct Main { + static func main() { + callback({ a, b in + c_function(a, b) + }) + } +} From 09a1f0b0c1a3493023d017bd043e2bdbc78d98ff Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 12 Jun 2024 19:38:09 +0100 Subject: [PATCH 091/165] [CS] NFC: Factor out `includingParentApply` --- include/swift/Sema/ConstraintSystem.h | 4 ++++ lib/Sema/CSRanking.cpp | 15 +++------------ lib/Sema/ConstraintSystem.cpp | 10 ++++++++++ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 45dc07602c1ac..3db029eb5c3c3 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -2826,6 +2826,10 @@ class ConstraintSystem { /// Associate an argument list with a call at a given locator. void associateArgumentList(ConstraintLocator *locator, ArgumentList *args); + /// If the given node is a function expression with a parent ApplyExpr, + /// returns the apply, otherwise returns the node itself. + ASTNode includingParentApply(ASTNode node); + std::optional findSelectedOverloadFor(ConstraintLocator *locator) const { auto result = ResolvedOverloads.find(locator); diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index e62edf343e516..38fad7a2c9d96 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -1036,18 +1036,9 @@ SolutionCompareResult ConstraintSystem::compareSolutions( if (cs.isForCodeCompletion()) { // Don't rank based on overload choices of function calls that contain the // code completion token. - ASTNode anchor = simplifyLocatorToAnchor(overload.locator); - if (auto expr = getAsExpr(anchor)) { - // If the anchor is a called function, also don't rank overload choices - // if any of the arguments contain the code completion token. - if (auto apply = dyn_cast_or_null(cs.getParentExpr(expr))) { - if (apply->getFn() == expr) { - anchor = apply; - } - } - } - if (anchor && cs.containsIDEInspectionTarget(anchor)) { - continue; + if (auto anchor = simplifyLocatorToAnchor(overload.locator)) { + if (cs.containsIDEInspectionTarget(cs.includingParentApply(anchor))) + continue; } } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 3dce3ebf1b379..21460cc95df28 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -6658,6 +6658,16 @@ static bool shouldHaveDirectCalleeOverload(const CallExpr *callExpr) { } #endif +ASTNode ConstraintSystem::includingParentApply(ASTNode node) { + if (auto *expr = getAsExpr(node)) { + if (auto apply = getAsExpr(getParentExpr(expr))) { + if (apply->getFn() == expr) + return apply; + } + } + return node; +} + Type Solution::resolveInterfaceType(Type type) const { auto resolvedType = type.transform([&](Type type) -> Type { if (auto *tvt = type->getAs()) { From 7c7e914dfe2d8d0b2730eadf4a832ea93bf5bedb Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 12 Jun 2024 19:38:09 +0100 Subject: [PATCH 092/165] [Completion] Skip `tryOptimizeGenericDisjunction` if there's a completion child Attempting to favor a disjunction choice here can lead to unhelpful results if there's e.g a code completion token argument, since it acts as a placeholder. rdar://127844278 --- lib/Sema/CSSolver.cpp | 19 ++++++++++++--- test/IDE/complete_rdar127844278.swift | 35 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 test/IDE/complete_rdar127844278.swift diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 8b0be4fe8195c..df21d48cc2977 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -2064,9 +2064,20 @@ Constraint *ConstraintSystem::getUnboundBindOverloadDisjunction( // Performance hack: if there are two generic overloads, and one is // more specialized than the other, prefer the more-specialized one. -static Constraint *tryOptimizeGenericDisjunction( - DeclContext *dc, - ArrayRef constraints) { +static Constraint * +tryOptimizeGenericDisjunction(ConstraintSystem &cs, Constraint *disjunction, + ArrayRef constraints) { + auto *dc = cs.DC; + + // If we're solving for code completion, and have a child completion token, + // skip this optimization since the completion token being a placeholder can + // allow us to prefer an unhelpful disjunction choice. + if (cs.isForCodeCompletion()) { + auto anchor = disjunction->getLocator()->getAnchor(); + if (cs.containsIDEInspectionTarget(cs.includingParentApply(anchor))) + return nullptr; + } + llvm::SmallVector choices; for (auto *choice : constraints) { if (choices.size() > 2) @@ -2311,7 +2322,7 @@ void DisjunctionChoiceProducer::partitionDisjunction( SmallVectorImpl &PartitionBeginning) { // Apply a special-case rule for favoring one generic function over // another. - if (auto favored = tryOptimizeGenericDisjunction(CS.DC, Choices)) { + if (auto favored = tryOptimizeGenericDisjunction(CS, Disjunction, Choices)) { CS.favorConstraint(favored); } diff --git a/test/IDE/complete_rdar127844278.swift b/test/IDE/complete_rdar127844278.swift new file mode 100644 index 0000000000000..05740b2932452 --- /dev/null +++ b/test/IDE/complete_rdar127844278.swift @@ -0,0 +1,35 @@ +// RUN: %batch-code-completion + +// rdar://127844278 - Make sure we don't attempt to favor one buildExpression +// call over the other when there's a child code completion. + +protocol P {} +protocol Q: P {} + +struct S: P { + private init() {} +} + +extension S where T == () { + init(a: Void) {} +} +extension S: Q where T == String { + init(b: String) {} +} + +@resultBuilder struct Builder { + static func buildExpression(_ x: T) -> T { x } + static func buildExpression(_ x: T) -> T { x } + + static func buildBlock(_ x: T) -> some P { x } + static func buildBlock(_ x: T) -> some P { x } +} + +func foo(@Builder _: () -> T) where T: P {} +func foo(@Builder _: () -> T) where T: Q {} + +foo { + S(#^COMPLETE^#) +} +// COMPLETE-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#a: Void#}[')'][#S<()>#]; name=a: +// COMPLETE-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#b: String#}[')'][#S#]; name=b: From 29ee0ed56e6791cf78cdf84e9f54d8ed647173e2 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Wed, 12 Jun 2024 13:12:21 -0700 Subject: [PATCH 093/165] [Gardening] Clarified documentation. --- include/swift/SIL/MemAccessUtils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/swift/SIL/MemAccessUtils.h b/include/swift/SIL/MemAccessUtils.h index 5230960314e85..62564ae220b0c 100644 --- a/include/swift/SIL/MemAccessUtils.h +++ b/include/swift/SIL/MemAccessUtils.h @@ -887,10 +887,10 @@ namespace swift { /// For convenience, encapsulate and AccessStorage value along with its /// accessed base address. struct AccessStorageWithBase { - /// Identical to AccessStorage::compute but preserves the access base. + /// Identical to AccessStorage::computeInScope but walks through begin_access. static AccessStorageWithBase compute(SILValue sourceAddress); - /// Identical to AccessStorage::computeInScope but preserves the base. + /// Identical to AccessStorage::compute but stops at begin_access static AccessStorageWithBase computeInScope(SILValue sourceAddress); AccessStorage storage; From cc40e29f2c95817dc4361d80ec5ff978911912ea Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Wed, 12 Jun 2024 13:13:45 -0700 Subject: [PATCH 094/165] [ConsumeAddrChecker] Diagnose consumes of borrows. When checking a `mark_unresolved_move_addr` instruction, first check whether it is legal to consume the source. rdar://127518559&125817827 --- ...onsumeOperatorCopyableAddressesChecker.cpp | 86 +++++++++++++++++++ ...ator_kills_copyable_addressonly_lets.swift | 28 ++++-- 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp b/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp index 6e1834b476a8e..9bf2358b0039b 100644 --- a/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp +++ b/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp @@ -2080,12 +2080,98 @@ bool ConsumeOperatorCopyableAddressesChecker::performClosureDataflow( closureConsumes); } +struct MoveConstraint { + enum Value : uint8_t { + None, + RequiresReinit, + Illegal, + } value; + + operator Value() { return value; } + MoveConstraint(Value value) : value(value) {} + + static MoveConstraint forGuaranteed(bool guaranteed) { + return guaranteed ? Illegal : None; + } + + bool isIllegal() { return value == Illegal; } +}; + +static MoveConstraint getMoveConstraint(SILValue addr) { + assert(addr->getType().isAddress()); + auto access = AccessPathWithBase::computeInScope(addr); + auto base = access.getAccessBase(); + switch (access.accessPath.getStorage().getKind()) { + case AccessRepresentation::Kind::Box: + // Even if the box is guaranteed, it may be permitted to consume its + // storage. + return MoveConstraint::None; + case AccessRepresentation::Kind::Stack: { + // An alloc_stack is guaranteed if it's a "store_borrow destination". + auto *asi = cast(base.getBaseAddress()); + return MoveConstraint::forGuaranteed( + !asi->getUsersOfType().empty()); + } + case AccessRepresentation::Kind::Global: + // A global can be consumed if it's reinitialized. + return MoveConstraint::RequiresReinit; + case AccessRepresentation::Kind::Class: + // A class field can be consumed if it's reinitialized. + return MoveConstraint::RequiresReinit; + case AccessRepresentation::Kind::Tail: + // A class field can be consumed if it's reinitialized. + return MoveConstraint::RequiresReinit; + case AccessRepresentation::Kind::Argument: { + // An indirect argument is guaranteed if it's @in_guaranteed. + auto *arg = base.getArgument(); + return MoveConstraint::forGuaranteed( + arg->getArgumentConvention().isGuaranteedConvention()); + } + case AccessRepresentation::Kind::Yield: { + auto baseAddr = base.getBaseAddress(); + auto *bai = cast( + cast(baseAddr)->getParent()); + auto index = *bai->getIndexOfResult(baseAddr); + auto info = bai->getSubstCalleeConv().getYieldInfoForOperandIndex(index); + return MoveConstraint::forGuaranteed(!info.isConsumed()); + } + case AccessRepresentation::Kind::Nested: { + auto *bai = cast(base.getBaseAddress()); + if (bai->getAccessKind() == SILAccessKind::Init || + bai->getAccessKind() == SILAccessKind::Read) + return MoveConstraint::Illegal; + // Allow moves from both modify and deinit. + return MoveConstraint::None; + } + case AccessRepresentation::Kind::Unidentified: + // Conservatively reject for now. + return MoveConstraint::Illegal; + } +} + // Returns true if we emitted a diagnostic and handled the single block // case. Returns false if we visited all of the uses and seeded the UseState // struct with the information needed to perform our interprocedural dataflow. bool ConsumeOperatorCopyableAddressesChecker::performSingleBasicBlockAnalysis( SILValue address, DebugVarCarryingInst addressDebugInst, MarkUnresolvedMoveAddrInst *mvi) { + if (getMoveConstraint(mvi->getSrc()).isIllegal()) { + auto &astCtx = mvi->getFunction()->getASTContext(); + StringRef name = getDebugVarName(address); + diagnose(astCtx, getSourceLocFromValue(address), + diag::sil_movechecking_guaranteed_value_consumed, name); + diagnose(astCtx, mvi->getLoc().getSourceLoc(), + diag::sil_movechecking_consuming_use_here); + + // Replace the marker instruction with a copy_addr to avoid subsequent + // diagnostics. + SILBuilderWithScope builder(mvi); + builder.createCopyAddr(mvi->getLoc(), mvi->getSrc(), mvi->getDest(), + IsNotTake, IsInitialization); + mvi->eraseFromParent(); + + return true; + } // First scan downwards to make sure we are move out of this block. auto &useState = dataflowState.useState; auto &applySiteToPromotedArgIndices = diff --git a/test/SILOptimizer/consume_operator_kills_copyable_addressonly_lets.swift b/test/SILOptimizer/consume_operator_kills_copyable_addressonly_lets.swift index 5509810ed33f5..d1eee7c416328 100644 --- a/test/SILOptimizer/consume_operator_kills_copyable_addressonly_lets.swift +++ b/test/SILOptimizer/consume_operator_kills_copyable_addressonly_lets.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -verify %s -parse-stdlib -emit-sil -o /dev/null +// RUN: %target-swift-frontend -sil-verify-all -verify %s -parse-stdlib -emit-sil -o /dev/null import Swift @@ -146,8 +146,8 @@ public func conditionalBadConsumingUseLoop2(_ x: T) { // Parameters // This is ok, no uses after. -public func simpleMoveOfParameter(_ x: T) -> () { - let _ = consume x +public func simpleMoveOfParameter(_ x: T) -> () { // expected-error {{'x' is borrowed and cannot be consumed}} + let _ = consume x // expected-note {{consumed here}} } public func simpleMoveOfOwnedParameter(_ x: __owned T) -> () { @@ -214,12 +214,12 @@ func consumeOwned(_ k: __owned T) { _ = consume k } -func consumeShared(_ k: __shared T) { - _ = consume k +func consumeShared(_ k: __shared T) { // expected-error {{'k' is borrowed and cannot be consumed}} + _ = consume k // expected-note {{consumed here}} } -func consumeBare(_ k: T) { - _ = consume k +func consumeBare(_ k: T) { // expected-error {{'k' is borrowed and cannot be consumed}} + _ = consume k // expected-note {{consumed here}} } //////////////////////// @@ -384,6 +384,20 @@ public func castTestIfLet2(_ x : __owned EnumWithKlass) { // expected-error {{'x } } +enum rdar125817827 { + case a(A) + case b(B) +} + +extension rdar125817827 { + func foo() { // expected-error {{'self' is borrowed and cannot be consumed}} + switch consume self { // expected-note {{consumed here}} + case let .a(a): print(a) + case let .b(b): print(b) + } + } +} + ///////////////////////// // Partial Apply Tests // ///////////////////////// From b1c7999361ed1376b9ddae0da8ddb0ad78c38b23 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Wed, 12 Jun 2024 14:10:05 -0700 Subject: [PATCH 095/165] [Test] Add regression test. For https://github.com/apple/swift/issues/69252 . --- .../SILOptimizer/consume_checking.swift | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 validation-test/SILOptimizer/consume_checking.swift diff --git a/validation-test/SILOptimizer/consume_checking.swift b/validation-test/SILOptimizer/consume_checking.swift new file mode 100644 index 0000000000000..dcb5c4faceb07 --- /dev/null +++ b/validation-test/SILOptimizer/consume_checking.swift @@ -0,0 +1,42 @@ +// RUN: %target-swift-frontend \ +// RUN: -emit-sil -verify \ +// RUN: %s \ +// RUN: -sil-verify-all + +//////////////////////////////////////////////////////////////////////////////// +// https://github.com/apple/swift/issues/69252 {{ +//////////////////////////////////////////////////////////////////////////////// +public enum LineEnding: String { + /// The default unix `\n` character + case lineFeed = "\n" + /// MacOS line ending `\r` character + case carriageReturn = "\r" + /// Windows line ending sequence `\r\n` + case carriageReturnLineFeed = "\r\n" + + /// Initialize a line ending from a line string. + /// - Parameter line: The line to use + public init?(line: borrowing String) { + guard let lastChar = line.last, + let lineEnding = LineEnding(rawValue: String(lastChar)) else { return nil } + self = lineEnding + } + + + static func makeLineEnding(_ line: borrowing String) -> LineEnding? { + guard let lastChar = line.last, + let lineEnding = LineEnding(rawValue: String(lastChar)) else { return nil } + _ = lineEnding + return nil + } + + func makeLineEnding(_ line: borrowing String) -> LineEnding? { + guard let lastChar = line.last, + let lineEnding = LineEnding(rawValue: String(lastChar)) else { return nil } + _ = lineEnding + return nil + } +} +//////////////////////////////////////////////////////////////////////////////// +// https://github.com/apple/swift/issues/69252 }} +//////////////////////////////////////////////////////////////////////////////// From ec4a125f3e8b97ddeeb675d43f807aef2fcdf8d7 Mon Sep 17 00:00:00 2001 From: Kavon Farvardin Date: Thu, 6 Jun 2024 15:39:39 -0700 Subject: [PATCH 096/165] NCGenerics: ext's might not infer invertible req's If the extension adds conformance to an invertible protocol, it's confusing for people to also infer conditional requirements on the generic parameters for those invertible protocols. This came up in the review of SE-427. --- lib/AST/ASTPrinter.cpp | 28 ++++++++++++++-- .../RequirementMachineRequests.cpp | 1 - lib/Sema/TypeCheckGeneric.cpp | 32 ++++++++++++++++++- stdlib/public/core/Optional.swift | 2 +- stdlib/public/core/Result.swift | 2 +- ..._conditional_conformance_restriction.swift | 13 +++++--- test/Generics/inverse_generics.swift | 23 ++++++++++--- test/Generics/inverse_generics_stdlib.swift | 2 +- test/Inputs/Swiftskell.swift | 4 +-- .../moveonly_generics_casting.swift | 2 +- .../Inputs/NoncopyableGenerics_Misc.swift | 14 ++++---- .../invertible_constraints.swift | 4 +-- .../noncopyable_generics.swift | 18 +++++------ test/SILGen/mangling_inverse_generics.swift | 2 +- ...oveonly_empty_conditionally_copyable.swift | 2 +- test/SILGen/typelowering_inverses.swift | 16 +++++----- .../lifetime_dependence_optional.swift | 4 +-- test/Sema/conditionally_copyable.swift | 2 +- test/Serialization/Inputs/ncgenerics.swift | 2 +- test/Serialization/noncopyable_generics.swift | 2 +- 20 files changed, 123 insertions(+), 52 deletions(-) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 75fe2995540e5..580d0ba28ad11 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2915,6 +2915,18 @@ void PrintAST::printExtendedTypeName(TypeLoc ExtendedTypeLoc) { printTypeLoc(TypeLoc(ExtendedTypeLoc.getTypeRepr(), Ty)); } +/// If an extension adds a conformance for an invertible protocol, then we +/// should not print inverses for its generic signature, because no conditional +/// requirements are inferred by default for such an extension. +static bool isExtensionAddingInvertibleConformance(const ExtensionDecl *ext) { + auto conformances = ext->getLocalConformances(); + for (auto *conf : conformances) { + if (conf->getProtocol()->getInvertibleProtocolKind()) { + return true; + } + } + return false; +} void PrintAST::printSynthesizedExtension(Type ExtendedType, ExtensionDecl *ExtDecl) { @@ -3039,9 +3051,21 @@ void PrintAST::printExtension(ExtensionDecl *decl) { auto baseGenericSig = decl->getExtendedNominal()->getGenericSignature(); assert(baseGenericSig && "an extension can't be generic if the base type isn't"); + + auto genSigFlags = defaultGenericRequirementFlags() + | IncludeOuterInverses; + + // Disable printing inverses if the extension is adding a conformance + // for an invertible protocol itself, as we do not infer any requirements + // in such an extension. We need to print the whole signature: + // extension S: Copyable where T: Copyable + if (isExtensionAddingInvertibleConformance(decl)) { + genSigFlags &= ~PrintInverseRequirements; + genSigFlags &= ~IncludeOuterInverses; + } + printGenericSignature(genericSig, - defaultGenericRequirementFlags() - | IncludeOuterInverses, + genSigFlags, [baseGenericSig](const Requirement &req) -> bool { // Only include constraints that are not satisfied by the base type. return !baseGenericSig->isRequirementSatisfied(req); diff --git a/lib/AST/RequirementMachine/RequirementMachineRequests.cpp b/lib/AST/RequirementMachine/RequirementMachineRequests.cpp index 1b7b9eec45390..78922b3d4b11d 100644 --- a/lib/AST/RequirementMachine/RequirementMachineRequests.cpp +++ b/lib/AST/RequirementMachine/RequirementMachineRequests.cpp @@ -782,7 +782,6 @@ InferredGenericSignatureRequest::evaluate( unsigned numOuterParams = genericParams.size(); if (isExtension) { - assert(allowInverses); numOuterParams = 0; } diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 8340a855cdc9a..be330146cbda9 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -684,6 +684,7 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, SmallVector inferenceSources; SmallVector extraReqs; SourceLoc loc; + bool inferInvertibleReqs = true; if (auto VD = dyn_cast(GC->getAsDecl())) { loc = VD->getLoc(); @@ -781,6 +782,35 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, } else if (auto *ext = dyn_cast(GC)) { loc = ext->getLoc(); + // The inherited entries influence the generic signature of the extension, + // because if it introduces conformance to invertible protocol IP, we do not + // we do not infer any requirements that the generic parameters to conform + // to invertible protocols. This forces people to write out the conditions. + const unsigned numEntries = ext->getInherited().size(); + for (unsigned i = 0; i < numEntries; ++i) { + InheritedTypeRequest request{ext, i, TypeResolutionStage::Structural}; + auto result = evaluateOrDefault(ctx.evaluator, request, + InheritedTypeResult::forDefault()); + Type inheritedTy; + switch (result) { + case InheritedTypeResult::Inherited: + inheritedTy = result.getInheritedType(); + break; + case InheritedTypeResult::Suppressed: + case InheritedTypeResult::Default: + continue; + } + + if (inheritedTy) { + if (auto kp = inheritedTy->getKnownProtocol()) { + if (getInvertibleProtocolKind(*kp)) { + inferInvertibleReqs = false; + break; + } + } + } + } + collectAdditionalExtensionRequirements(ext->getExtendedType(), extraReqs); auto *extendedNominal = ext->getExtendedNominal(); @@ -800,7 +830,7 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, genericParams, WhereClauseOwner(GC), extraReqs, inferenceSources, loc, /*isExtension=*/isa(GC), - /*allowInverses=*/true}; + /*allowInverses=*/inferInvertibleReqs}; return evaluateOrDefault(ctx.evaluator, request, GenericSignatureWithError()).getPointer(); } diff --git a/stdlib/public/core/Optional.swift b/stdlib/public/core/Optional.swift index 2313ac7040fe6..b6ecca2fd1f66 100644 --- a/stdlib/public/core/Optional.swift +++ b/stdlib/public/core/Optional.swift @@ -132,7 +132,7 @@ public enum Optional: ~Copyable { case some(Wrapped) } -extension Optional: Copyable /* where Wrapped: Copyable */ {} +extension Optional: Copyable where Wrapped: Copyable {} extension Optional: Sendable where Wrapped: ~Copyable & Sendable { } diff --git a/stdlib/public/core/Result.swift b/stdlib/public/core/Result.swift index 0c1dd43eeae01..24dddadc22305 100644 --- a/stdlib/public/core/Result.swift +++ b/stdlib/public/core/Result.swift @@ -21,7 +21,7 @@ public enum Result { case failure(Failure) } -extension Result: Copyable /* where Success: Copyable */ {} +extension Result: Copyable where Success: Copyable {} extension Result: Sendable where Success: Sendable & ~Copyable {} diff --git a/test/Generics/inverse_conditional_conformance_restriction.swift b/test/Generics/inverse_conditional_conformance_restriction.swift index f1face72c74bb..f44b00a6a8746 100644 --- a/test/Generics/inverse_conditional_conformance_restriction.swift +++ b/test/Generics/inverse_conditional_conformance_restriction.swift @@ -7,12 +7,15 @@ protocol Q {} class DoggoClass {} struct Blah: ~Copyable, ~Escapable {} -extension Blah: Copyable {} // expected-error {{conditional conformance to suppressible protocol 'Copyable' cannot depend on 'T: Escapable'}} -extension Blah: Escapable {} // expected-error {{conditional conformance to suppressible protocol 'Escapable' cannot depend on 'T: Copyable'}} +extension Blah: Copyable where T: Copyable & Escapable {} +// expected-error@-1 {{conditional conformance to suppressible protocol 'Copyable' cannot depend on 'T: Escapable'}} -struct Yuck: ~Copyable, ~Escapable {} -extension Yuck: Copyable where T: ~Escapable {} -extension Yuck: Escapable where T: ~Copyable {} +extension Blah: Escapable where T: Copyable, T: Escapable {} +// expected-error@-1 {{conditional conformance to suppressible protocol 'Escapable' cannot depend on 'T: Copyable'}} + +struct Fixed: ~Copyable, ~Escapable {} +extension Fixed: Copyable where T: Copyable {} +extension Fixed: Escapable where T: Escapable {} struct TryConformance: ~Copyable {} extension TryConformance: Copyable diff --git a/test/Generics/inverse_generics.swift b/test/Generics/inverse_generics.swift index c58d065e067d8..b81dcdf093290 100644 --- a/test/Generics/inverse_generics.swift +++ b/test/Generics/inverse_generics.swift @@ -2,11 +2,26 @@ // RUN: -enable-experimental-feature NonescapableTypes \ // RUN: -enable-experimental-feature SuppressedAssociatedTypes +// expected-note@+1 {{'T' has '~Copyable' constraint preventing implicit 'Copyable' conformance}} +struct AttemptImplicitConditionalConformance: ~Copyable { + var t: T // expected-error {{stored property 't' of 'Copyable'-conforming generic struct 'AttemptImplicitConditionalConformance' has non-Copyable type 'T'}} +} +extension AttemptImplicitConditionalConformance: Copyable {} +// expected-error@-1 {{generic struct 'AttemptImplicitConditionalConformance' required to be 'Copyable' but is marked with '~Copyable'}} + +enum Hello: ~Escapable & ~Copyable {} +extension Hello: Escapable {} // expected-error {{generic enum 'Hello' required to be 'Escapable' but is marked with '~Escapable'}} +extension Hello: Copyable {} // expected-error {{generic enum 'Hello' required to be 'Copyable' but is marked with '~Copyable'}} + +enum HelloExplicitlyFixed: Escapable, Copyable {} +struct NoInverseBecauseNoDefault: ~Copyable {} +extension NoInverseBecauseNoDefault: Copyable where T: Copyable, T: ~Escapable {} +// expected-error@-1 {{cannot suppress '~Escapable' on generic parameter 'T' defined in outer scope}} // Check support for explicit conditional conformance public struct ExplicitCond: ~Copyable {} -extension ExplicitCond: Copyable {} +extension ExplicitCond: Copyable where T: Copyable {} // expected-note@-1 {{requirement from conditional conformance}} // expected-note@-2 {{requirement from conditional conformance of 'ExplicitCondAlias' (aka 'ExplicitCond') to 'Copyable'}} @@ -80,7 +95,7 @@ struct ConditionalContainment: ~Copyable { var y: NC // expected-error {{stored property 'y' of 'Copyable'-conforming generic struct 'ConditionalContainment' has non-Copyable type 'NC'}} } -extension ConditionalContainment: Copyable {} +extension ConditionalContainment: Copyable where T: Copyable {} func chk(_ T: RequireCopyable>) {} @@ -126,7 +141,7 @@ enum Maybe: ~Copyable { deinit {} // expected-error {{deinitializer cannot be declared in generic enum 'Maybe' that conforms to 'Copyable'}} } -extension Maybe: Copyable {} +extension Maybe: Copyable where Wrapped: Copyable {} // expected-note@+4{{requirement specified as 'NC' : 'Copyable'}} // expected-note@+3{{requirement from conditional conformance of 'Maybe' to 'Copyable'}} @@ -265,7 +280,7 @@ enum MaybeEscapes: ~Escapable { // expected-note {{generic enum ' case none } -extension MaybeEscapes: Escapable {} +extension MaybeEscapes: Escapable where T: Escapable {} struct Escapes { // expected-note {{consider adding '~Escapable' to struct 'Escapes'}} let t: MaybeEscapes // expected-error {{stored property 't' of 'Escapable'-conforming struct 'Escapes' has non-Escapable type 'MaybeEscapes'}} diff --git a/test/Generics/inverse_generics_stdlib.swift b/test/Generics/inverse_generics_stdlib.swift index 3eea8b8f7928c..200df47bd344a 100644 --- a/test/Generics/inverse_generics_stdlib.swift +++ b/test/Generics/inverse_generics_stdlib.swift @@ -21,7 +21,7 @@ public enum Optional: ~Copyable { case none } -extension Optional: Copyable {} +extension Optional: Copyable where T: Copyable {} public func wrapping(_ t: consuming T) -> T? { return .some(t) diff --git a/test/Inputs/Swiftskell.swift b/test/Inputs/Swiftskell.swift index 9e4b96bf3a8bc..981d130c2a019 100644 --- a/test/Inputs/Swiftskell.swift +++ b/test/Inputs/Swiftskell.swift @@ -36,7 +36,7 @@ public enum Either: ~Copyable { case failure(Failure) } -extension Either: Copyable {} +extension Either: Copyable where Success: Copyable {} extension Either where Failure == Swift.Error { public init(catching body: () throws -> Success) { @@ -77,7 +77,7 @@ public enum Maybe: ~Copyable { case just(Wrapped) case nothing } -extension Maybe: Copyable {} +extension Maybe: Copyable where Wrapped: Copyable {} extension Maybe: Show where Wrapped: Show & ~Copyable { public borrowing func show() -> String { diff --git a/test/Interpreter/moveonly_generics_casting.swift b/test/Interpreter/moveonly_generics_casting.swift index 1b838817a30a7..abff30496b199 100644 --- a/test/Interpreter/moveonly_generics_casting.swift +++ b/test/Interpreter/moveonly_generics_casting.swift @@ -136,7 +136,7 @@ enum Maybe: ~Copyable { case just(Wrapped) case nothing } -extension Maybe: Copyable {} +extension Maybe: Copyable where Wrapped: Copyable {} extension Maybe: CustomDebugStringConvertible { var debugDescription: String { "cast succeeded" diff --git a/test/ModuleInterface/Inputs/NoncopyableGenerics_Misc.swift b/test/ModuleInterface/Inputs/NoncopyableGenerics_Misc.swift index 4efd9e23b6508..9b2dffec8f25e 100644 --- a/test/ModuleInterface/Inputs/NoncopyableGenerics_Misc.swift +++ b/test/ModuleInterface/Inputs/NoncopyableGenerics_Misc.swift @@ -55,12 +55,12 @@ public struct _Toys { public struct ExplicitHello: ~Copyable { let thing: T } -extension ExplicitHello: Copyable {} +extension ExplicitHello: Copyable where T: Copyable {} public struct Hello: ~Copyable, ~Escapable where T: ~Escapable {} -extension Hello: Escapable where T: ~Copyable {} -extension Hello: Copyable where T: ~Escapable {} +extension Hello: Escapable where T: Escapable {} +extension Hello: Copyable where T: Copyable {} public protocol TestAssocTypes { associatedtype A: ~Copyable, _NoCopyP = Int @@ -94,11 +94,11 @@ public struct Outer: ~Copyable { public struct InnerVariation2: ~Copyable, ~Escapable {} } -extension Outer: Copyable {} -extension Outer.InnerStruct: Copyable {} +extension Outer: Copyable where A: Copyable {} +extension Outer.InnerStruct: Copyable where C: Copyable, A: Copyable {} -extension Outer.InnerVariation1: Copyable {} -extension Outer.InnerVariation2: Escapable where A: ~Copyable {} +extension Outer.InnerVariation1: Copyable where A: Copyable, D: Copyable & Escapable {} +extension Outer.InnerVariation2: Escapable where A: Escapable, D: Escapable {} extension Outer.InnerStruct { public func hello(_ t: T) {} diff --git a/test/ModuleInterface/invertible_constraints.swift b/test/ModuleInterface/invertible_constraints.swift index 890567057e32a..4ecd3ec136bcd 100644 --- a/test/ModuleInterface/invertible_constraints.swift +++ b/test/ModuleInterface/invertible_constraints.swift @@ -26,14 +26,14 @@ public protocol P: ~Copyable { public struct X: ~Copyable { } // CHECK: #if compiler(>=5.3) && $NoncopyableGenerics -// CHECK: extension Test.X : Swift.Copyable { +// CHECK: extension Test.X : Swift.Copyable where T : Swift.Copyable { // CHECK-NEXT: func f() // CHECK: } // CHECK: #else // CHECK: extension Test.X { // CHECK-NEXT: func f() // CHECK: } -extension X: Copyable { +extension X: Copyable where T: Copyable { public func f() { } } diff --git a/test/ModuleInterface/noncopyable_generics.swift b/test/ModuleInterface/noncopyable_generics.swift index d1806d76c2278..b96241d9fbef0 100644 --- a/test/ModuleInterface/noncopyable_generics.swift +++ b/test/ModuleInterface/noncopyable_generics.swift @@ -77,18 +77,18 @@ import NoncopyableGenerics_Misc // CHECK-MISC-NEXT: public struct ExplicitHello : ~Swift.Copyable where T : ~Copyable { // CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics -// CHECK-MISC-NEXT: extension {{.*}}.ExplicitHello : Swift.Copyable { +// CHECK-MISC-NEXT: extension {{.*}}.ExplicitHello : Swift.Copyable where T : Swift.Copyable { // CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics // CHECK-MISC-NEXT: public struct Hello : ~Swift.Copyable, ~Swift.Escapable where T : ~Copyable, T : ~Escapable { // CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics -// CHECK-MISC-NEXT: extension NoncopyableGenerics_Misc.Hello : Swift.Escapable where T : ~Copyable { +// CHECK-MISC-NEXT: extension NoncopyableGenerics_Misc.Hello : Swift.Escapable where T : Swift.Escapable { // CHECK-MISC-NEXT: } // CHECK-MISC: #endif // CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics -// CHECK-MISC-NEXT: extension NoncopyableGenerics_Misc.Hello : Swift.Copyable where T : ~Escapable { +// CHECK-MISC-NEXT: extension NoncopyableGenerics_Misc.Hello : Swift.Copyable where T : Swift.Copyable { // CHECK-MISC-NEXT: } // CHECK-MISC: #endif @@ -121,19 +121,19 @@ import NoncopyableGenerics_Misc // CHECK-MISC: public struct InnerVariation2 : ~Swift.Copyable, ~Swift.Escapable where D : ~Escapable // CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics -// CHECK-MISC-NEXT: extension {{.*}}.Outer : Swift.Copyable { +// CHECK-MISC-NEXT: extension {{.*}}.Outer : Swift.Copyable where A : Swift.Copyable { // CHECK-MISC: #endif // CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics -// CHECK-MISC-NEXT: extension {{.*}}.Outer.InnerStruct : Swift.Copyable { +// CHECK-MISC-NEXT: extension {{.*}}.Outer.InnerStruct : Swift.Copyable where A : Swift.Copyable, C : Swift.Copyable { // CHECK-MISC: #endif // CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics -// CHECK-MISC-NEXT: extension {{.*}}.Outer.InnerVariation1 : Swift.Copyable { +// CHECK-MISC-NEXT: extension {{.*}}.Outer.InnerVariation1 : Swift.Copyable where A : Swift.Copyable, D : Swift.Copyable { // CHECK-MISC: #endif // CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics -// CHECK-MISC-NEXT: extension {{.*}}.Outer.InnerVariation2 : Swift.Escapable where A : ~Copyable { +// CHECK-MISC-NEXT: extension {{.*}}.Outer.InnerVariation2 : Swift.Escapable where D : Swift.Escapable { // CHECK-MISC: #endif // CHECK-MISC: #if compiler(>=5.3) && $NoncopyableGenerics @@ -250,7 +250,7 @@ import Swiftskell // CHECK: #endif // CHECK: #if compiler(>=5.3) && $NoncopyableGenerics -// CHECK-NEXT: extension Swiftskell.Pair : Swift.Copyable { +// CHECK-NEXT: extension Swiftskell.Pair : Swift.Copyable where L : Swift.Copyable, R : Swift.Copyable { // CHECK: #endif // CHECK: #if compiler(>=5.3) && $NoncopyableGenerics @@ -258,7 +258,7 @@ import Swiftskell // CHECK: #endif // CHECK: #if compiler(>=5.3) && $NoncopyableGenerics -// CHECK-NEXT: extension Swiftskell.Maybe : Swift.Copyable { +// CHECK-NEXT: extension Swiftskell.Maybe : Swift.Copyable where Wrapped : Swift.Copyable { // CHECK: #endif // CHECK: #if compiler(>=5.3) && $NoncopyableGenerics diff --git a/test/SILGen/mangling_inverse_generics.swift b/test/SILGen/mangling_inverse_generics.swift index 1395654d30d16..3533902b0b687 100644 --- a/test/SILGen/mangling_inverse_generics.swift +++ b/test/SILGen/mangling_inverse_generics.swift @@ -145,7 +145,7 @@ public struct A: ~Copyable { // CHECK: sil hidden [ossa] @$s4test1AVAARi_zrlEACyxGycfC : $@convention(method) (@thin A.Type) -> @owned A { } -extension A: Copyable {} +extension A: Copyable where T: Copyable {} // extension A where T: ~Copyable { diff --git a/test/SILGen/moveonly_empty_conditionally_copyable.swift b/test/SILGen/moveonly_empty_conditionally_copyable.swift index 6715a13336f25..baabfca3a62b6 100644 --- a/test/SILGen/moveonly_empty_conditionally_copyable.swift +++ b/test/SILGen/moveonly_empty_conditionally_copyable.swift @@ -2,4 +2,4 @@ struct G: ~Copyable { } -extension G: Copyable {} +extension G: Copyable where T: Copyable {} diff --git a/test/SILGen/typelowering_inverses.swift b/test/SILGen/typelowering_inverses.swift index fc6a4b235d298..cf1b383e7c448 100644 --- a/test/SILGen/typelowering_inverses.swift +++ b/test/SILGen/typelowering_inverses.swift @@ -15,14 +15,14 @@ enum RudeEnum: Copyable { struct CondCopyableStruct: ~Copyable {} -extension CondCopyableStruct: Copyable {} +extension CondCopyableStruct: Copyable where T: Copyable {} enum CondCopyableEnum: ~Copyable { case some(T) case none } -extension CondCopyableEnum: Copyable {} +extension CondCopyableEnum: Copyable where T: Copyable {} protocol NoEscapeP: ~Escapable {} @@ -39,14 +39,14 @@ enum TooRudeEnum: Escapable { struct CondEscapableStruct: ~Escapable {} -extension CondEscapableStruct: Escapable {} +extension CondEscapableStruct: Escapable where T: Escapable {} enum CondEscapableEnum: ~Escapable { case some(T) case none } -extension CondEscapableEnum: Escapable {} +extension CondEscapableEnum: Escapable where T: Escapable {} // MARK: ensure certain conditionally Copyable types are treated as trivial (no ownership in func signature). @@ -142,18 +142,18 @@ struct MyStruct: ~Copyable & ~Escapable { var x: T } -extension MyStruct: Copyable where T: Copyable & ~Escapable {} +extension MyStruct: Copyable where T: Copyable {} -extension MyStruct: Escapable where T: Escapable & ~Copyable {} +extension MyStruct: Escapable where T: Escapable {} enum MyEnum: ~Copyable & ~Escapable { case x(T) case knoll } -extension MyEnum: Copyable where T: Copyable & ~Escapable {} +extension MyEnum: Copyable where T: Copyable {} -extension MyEnum: Escapable where T: Escapable & ~Copyable {} +extension MyEnum: Escapable where T: Escapable {} enum Trivial { case a, b, c diff --git a/test/SILOptimizer/lifetime_dependence_optional.swift b/test/SILOptimizer/lifetime_dependence_optional.swift index f0c7c5cc3ac8b..9b1761110a744 100644 --- a/test/SILOptimizer/lifetime_dependence_optional.swift +++ b/test/SILOptimizer/lifetime_dependence_optional.swift @@ -21,9 +21,9 @@ public enum Nillable: ~Copyable & ~Escapable { case some(Wrapped) } -extension Nillable: Copyable where Wrapped: ~Escapable /* & Copyable */ {} +extension Nillable: Copyable where Wrapped: Copyable {} -extension Nillable: Escapable where Wrapped: ~Copyable /* & Escapable */ {} +extension Nillable: Escapable where Wrapped: Escapable {} extension Nillable: Sendable where Wrapped: ~Copyable & ~Escapable & Sendable { } diff --git a/test/Sema/conditionally_copyable.swift b/test/Sema/conditionally_copyable.swift index 73ccd71c228a7..2e49e06243a13 100644 --- a/test/Sema/conditionally_copyable.swift +++ b/test/Sema/conditionally_copyable.swift @@ -2,7 +2,7 @@ struct G: ~Copyable {} -extension G: Copyable {} +extension G: Copyable where T: Copyable {} protocol Base {} protocol Derived: Base {} diff --git a/test/Serialization/Inputs/ncgenerics.swift b/test/Serialization/Inputs/ncgenerics.swift index 7ea772ebb9a90..c657e5ea8bf00 100644 --- a/test/Serialization/Inputs/ncgenerics.swift +++ b/test/Serialization/Inputs/ncgenerics.swift @@ -25,7 +25,7 @@ public enum Maybe: ~Copyable { case none } -extension Maybe: Copyable {} +extension Maybe: Copyable where Wrapped: Copyable {} public func ncIdentity(_ t: consuming T) -> T { return t } diff --git a/test/Serialization/noncopyable_generics.swift b/test/Serialization/noncopyable_generics.swift index 2e2271aa528d8..4b6cada929dad 100644 --- a/test/Serialization/noncopyable_generics.swift +++ b/test/Serialization/noncopyable_generics.swift @@ -18,7 +18,7 @@ // CHECK-PRINT-DAG: protocol Generator { // CHECK-PRINT-DAG: enum Maybe : ~Copyable where Wrapped : ~Copyable { -// CHECK-PRINT-DAG: extension Maybe : Copyable { +// CHECK-PRINT-DAG: extension Maybe : Copyable where Wrapped : Copyable { // CHECK-PRINT-DAG: func ncIdentity(_ t: consuming T) -> T where T : ~Copyable // CHECK-PRINT-DAG: protocol Either : ~Copyable { // CHECK-PRINT-DAG: associatedtype Left : ~Copyable From 2893e3dd8da5a654fc14ec2fb8d1604e8fd4ea2f Mon Sep 17 00:00:00 2001 From: Kavon Farvardin Date: Tue, 11 Jun 2024 15:12:33 -0700 Subject: [PATCH 097/165] Sema: reword inverse-on-extension message We should be saying "can't suppress Copyable" instead, since you can't "suppress" ~Copyable. --- include/swift/AST/DiagnosticsSema.def | 4 ++-- lib/Sema/TypeCheckDeclPrimary.cpp | 13 +++++++++---- test/Generics/inverse_generics.swift | 4 ++-- test/Parse/inverses.swift | 8 +++++++- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index d593348a68660..46af1565dd416 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7728,8 +7728,8 @@ ERROR(inverse_conflicts_explicit_composition, none, "composition cannot contain '~%0' when another member requires '%0'", (StringRef)) ERROR(inverse_extension, none, - "cannot suppress %0 in extension", - (Type)) + "cannot suppress '%0' in extension", + (StringRef)) ERROR(copyable_illegal_deinit, none, "deinitializer cannot be declared in %kind0 that conforms to 'Copyable'", (const ValueDecl *)) diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index a45b20741383f..83e28f32a6f0a 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -295,10 +295,15 @@ static void checkInheritanceClause( auto layout = inheritedTy->getExistentialLayout(); // An inverse on an extension is an error. - if (isa(decl)) - if (auto pct = inheritedTy->getAs()) - if (!pct->getInverses().empty()) - decl->diagnose(diag::inverse_extension, inheritedTy); + if (isa(decl)) { + auto canInheritedTy = inheritedTy->getCanonicalType(); + if (auto pct = canInheritedTy->getAs()) { + for (auto inverse : pct->getInverses()) { + decl->diagnose(diag::inverse_extension, + getProtocolName(getKnownProtocolKind(inverse))); + } + } + } // Subclass existentials are not allowed except on classes and // non-@objc protocols. diff --git a/test/Generics/inverse_generics.swift b/test/Generics/inverse_generics.swift index b81dcdf093290..e38b09a7b1263 100644 --- a/test/Generics/inverse_generics.swift +++ b/test/Generics/inverse_generics.swift @@ -188,11 +188,11 @@ class NiceTry: ~Copyable, Copyable {} // expected-error {{classes cannot be '~Co struct Extendo: ~Copyable {} -extension Extendo: Copyable, ~Copyable {} // expected-error {{cannot suppress '~Copyable' in extension}} +extension Extendo: Copyable, ~Copyable {} // expected-error {{cannot suppress 'Copyable' in extension}} // expected-error@-1 {{struct 'Extendo' required to be 'Copyable' but is marked with '~Copyable'}} enum EnumExtendo {} -extension EnumExtendo: ~Copyable {} // expected-error {{cannot suppress '~Copyable' in extension}} +extension EnumExtendo: ~Copyable {} // expected-error {{cannot suppress 'Copyable' in extension}} extension NeedsCopyable where Self: ~Copyable {} // expected-error@-1 {{'Self' required to be 'Copyable' but is marked with '~Copyable'}} diff --git a/test/Parse/inverses.swift b/test/Parse/inverses.swift index 3ddafa9340574..b9d367f16b953 100644 --- a/test/Parse/inverses.swift +++ b/test/Parse/inverses.swift @@ -52,7 +52,7 @@ protocol Rope: Hashable, ~Copyable { // expected-error {{'Self' requir associatedtype Element: ~Copyable } -extension S: ~Copyable {} // expected-error {{cannot suppress '~Copyable' in extension}} +extension S: ~Copyable {} // expected-error {{cannot suppress 'Copyable' in extension}} struct S: ~U, // expected-error {{type 'U' cannot be suppressed}} ~Copyable {} @@ -123,3 +123,9 @@ func typeInExpression() { func param3(_ t: borrowing any ~Copyable) {} func param4(_ t: any ~Copyable.Type) {} + +protocol P: ~Copyable {} +protocol Q: ~Copyable {} +protocol R: ~Copyable {} +struct Blooper: ~Copyable {} +extension Blooper: (Q & (R & (~Copyable & P))) {} // expected-error {{cannot suppress 'Copyable' in extension}} From a1e14ae0c78b36cd60f87517e362cd60529494fe Mon Sep 17 00:00:00 2001 From: Kavon Farvardin Date: Tue, 11 Jun 2024 21:44:02 -0700 Subject: [PATCH 098/165] Sema: ext's must add solo invertible conformances This helps prevent confusion after not inferring requirements if the extension adds a Copyable conformance. --- include/swift/AST/DiagnosticsSema.def | 3 ++ lib/AST/ASTPrinter.cpp | 1 + lib/Frontend/ModuleInterfaceSupport.cpp | 45 ++++++++++++------- lib/Sema/TypeCheckDeclPrimary.cpp | 24 ++++++++++ test/Parse/inverses.swift | 17 +++++++ .../ParseableInterface/rdar128577611.swift | 8 +++- 6 files changed, 82 insertions(+), 16 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 46af1565dd416..7166b975314d1 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7799,6 +7799,9 @@ ERROR(suppress_nonsuppressable_protocol,none, "conformance to %0 cannot be suppressed", (const ProtocolDecl *)) WARNING(suppress_already_suppressed_protocol,none, "already suppressed conformance to %0", (const ProtocolDecl *)) +ERROR(extension_conforms_to_invertible_and_others, none, + "conformance to '%0' must be declared in a separate extension", + (StringRef)) // -- older ones below -- ERROR(noncopyable_parameter_requires_ownership, none, diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 580d0ba28ad11..1ceb257e083da 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -2922,6 +2922,7 @@ static bool isExtensionAddingInvertibleConformance(const ExtensionDecl *ext) { auto conformances = ext->getLocalConformances(); for (auto *conf : conformances) { if (conf->getProtocol()->getInvertibleProtocolKind()) { + assert(conformances.size() == 1 && "expected solo conformance"); return true; } } diff --git a/lib/Frontend/ModuleInterfaceSupport.cpp b/lib/Frontend/ModuleInterfaceSupport.cpp index 491baa89e671e..d9114201d3b13 100644 --- a/lib/Frontend/ModuleInterfaceSupport.cpp +++ b/lib/Frontend/ModuleInterfaceSupport.cpp @@ -801,7 +801,7 @@ class InheritedProtocolCollector { } /// If there were any conditional conformances that couldn't be printed, - /// make a dummy extension that conforms to all of them, constrained by a + /// make dummy extension(s) that conforms to all of them, constrained by a /// fake protocol. bool printInaccessibleConformanceExtensionIfNeeded( raw_ostream &out, const PrintOptions &printOptions, @@ -810,20 +810,35 @@ class InheritedProtocolCollector { return false; assert(nominal->isGenericContext()); - if (!printOptions.printPublicInterface()) - out << "@_spi(" << DummyProtocolName << ")\n"; - out << "@available(*, unavailable)\nextension "; - nominal->getDeclaredType().print(out, printOptions); - out << " : "; - llvm::interleave( - ConditionalConformanceProtocols, - [&out, &printOptions](const ProtocolType *protoTy) { - protoTy->print(out, printOptions); - }, - [&out] { out << ", "; }); - out << " where " - << nominal->getGenericSignature().getGenericParams().front()->getName() - << " : " << DummyProtocolName << " {}\n"; + auto emitExtension = + [&](ArrayRef conformanceProtos) { + if (!printOptions.printPublicInterface()) + out << "@_spi(" << DummyProtocolName << ")\n"; + out << "@available(*, unavailable)\nextension "; + nominal->getDeclaredType().print(out, printOptions); + out << " : "; + llvm::interleave( + conformanceProtos, + [&out, &printOptions](const ProtocolType *protoTy) { + protoTy->print(out, printOptions); + }, + [&out] { out << ", "; }); + out << " where " + << nominal->getGenericSignature().getGenericParams()[0]->getName() + << " : " << DummyProtocolName << " {}\n"; + }; + + // We have to print conformances for invertible protocols in separate + // extensions, so do those first and save the rest for one extension. + SmallVector regulars; + for (auto *proto : ConditionalConformanceProtocols) { + if (proto->getDecl()->getInvertibleProtocolKind()) { + emitExtension(proto); + continue; + } + regulars.push_back(proto); + } + emitExtension(regulars); return true; } diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index 83e28f32a6f0a..a65e2c4b1484b 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -154,6 +154,28 @@ class CheckRepressions { } }; +/// If the extension adds a conformance to an invertible protocol, ensure that +/// it does not add a conformance to any other protocol. So these are illegal: +/// +/// extension S: Copyable & P {} +/// extension S: Q, Copyable {} +/// +/// This policy is in place because extensions adding a conformance to an +/// invertible protocol do _not_ add default requirements on generic parameters, +/// so it would be confusing to mix them together in the same extension. +static void checkExtensionAddsSoloInvertibleProtocol(const ExtensionDecl *ext) { + auto localConfs = ext->getLocalConformances(); + if (localConfs.size() <= 1) + return; + + for (auto *conf : localConfs) { + if (auto ip = conf->getProtocol()->getInvertibleProtocolKind()) { + ext->diagnose(diag::extension_conforms_to_invertible_and_others, + getInvertibleProtocolKindName(*ip)); + } + } +} + /// Check the inheritance clause of a type declaration or extension thereof. /// /// This routine performs detailed checking of the inheritance clause of the @@ -3979,6 +4001,8 @@ class DeclChecker : public DeclVisitor { diagnoseExtensionOfMarkerProtocol(ED); checkTupleExtension(ED); + + checkExtensionAddsSoloInvertibleProtocol(ED); } void visitTopLevelCodeDecl(TopLevelCodeDecl *TLCD) { diff --git a/test/Parse/inverses.swift b/test/Parse/inverses.swift index b9d367f16b953..587badfe3cbb0 100644 --- a/test/Parse/inverses.swift +++ b/test/Parse/inverses.swift @@ -129,3 +129,20 @@ protocol Q: ~Copyable {} protocol R: ~Copyable {} struct Blooper: ~Copyable {} extension Blooper: (Q & (R & (~Copyable & P))) {} // expected-error {{cannot suppress 'Copyable' in extension}} + +protocol Edible {} +protocol Portable {} +typealias Alias = Portable & Copyable + +struct Burrito: ~Copyable {} +extension Burrito: Alias {} // expected-error {{conformance to 'Copyable' must be declared in a separate extension}} +// expected-note@-1 {{'Burrito' declares conformance to protocol 'Copyable' here}} + +extension Burrito: Copyable & Edible & P {} // expected-error {{redundant conformance of 'Burrito' to protocol 'Copyable'}} + +struct Blah: ~Copyable {} +extension Blah: P, Q, Copyable, R {} // expected-error {{generic struct 'Blah' required to be 'Copyable' but is marked with '~Copyable'}} +// expected-error@-1 {{conformance to 'Copyable' must be declared in a separate extension}} + +enum Hello: ~Copyable {} +extension Hello: Copyable & Edible & P {} // expected-error {{conformance to 'Copyable' must be declared in a separate extension}} diff --git a/validation-test/ParseableInterface/rdar128577611.swift b/validation-test/ParseableInterface/rdar128577611.swift index 18ca4b791b179..a4086137ad521 100644 --- a/validation-test/ParseableInterface/rdar128577611.swift +++ b/validation-test/ParseableInterface/rdar128577611.swift @@ -7,4 +7,10 @@ struct InternalStruct {} extension [Int: InternalStruct]: Sendable {} // CHECK: @available(*, unavailable) -// CHECK: extension Swift.Dictionary : Swift.Copyable, Swift.Escapable, Swift.Sendable where Key : _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {} +// CHECK-NEXT: extension Swift.Dictionary : Swift.Copyable where Key : _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {} + +// CHECK: @available(*, unavailable) +// CHECK-NEXT: extension Swift.Dictionary : Swift.Escapable where Key : _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {} + +// CHECK: @available(*, unavailable) +// CHECK-NEXT: extension Swift.Dictionary : Swift.Sendable where Key : _ConstraintThatIsNotPartOfTheAPIOfThisLibrary {} From 67694c2ab0b6c19f37be42ff642cb69356848a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Thu, 30 May 2024 21:29:16 -0700 Subject: [PATCH 099/165] Sema: Report public conformances to non-publicly imported protocols Exportability checking for non-public imports relies on classic access-level checks for some of the work. However while conforming to a local internal protocol from a public type is allow we should disallow it for imported types, even when imported as internal. Track exportability issues on conformances to protocols separately from the general category. Use that information to improve the diagnostics and report these issues for access-level on imports. rdar://128420980 --- PrivateLib | Bin 0 -> 34023 bytes include/swift/AST/DiagnosticsSema.def | 9 ++- lib/Sema/ResilienceDiagnostics.cpp | 21 ++++-- lib/Sema/TypeCheckAccess.cpp | 4 +- lib/Sema/TypeCheckAvailability.h | 3 +- ...access-level-import-conforming-types.swift | 70 ++++++++++++++++++ test/Sema/access-level-import-typealias.swift | 3 +- .../implementation-only-import-in-decls.swift | 15 ++-- .../package-import-conforming-types.swift | 67 +++++++++++++++++ 9 files changed, 171 insertions(+), 21 deletions(-) create mode 100755 PrivateLib create mode 100644 test/Sema/access-level-import-conforming-types.swift create mode 100644 test/Sema/package-import-conforming-types.swift diff --git a/PrivateLib b/PrivateLib new file mode 100755 index 0000000000000000000000000000000000000000..9000ea30fd388cc9f034945c238822fd3a721a3e GIT binary patch literal 34023 zcmeI5U2IfE6vxkgR4UNckVYW_SxJLv6pEGzPwrBR5W1zbrIunc-R|CnmF_Ot-L@>@ zV+kQq2th!li4TH6R75Res^C`>6P^ePF%k_SF%rN;9{hMPM6Kt{&bE7RNlRjUG5<+V zXZ|yD&OP&+d-rYb{p$9uzb6y9h>M$T3ftilqFvuc$H7*7gJ@Xh?aE?7cb?8 z+uTqp-5ZN$7APx`No7aJTWI2y8Yj`Vc*VhVyl^s+9!b!dpWno5GJc}Hju^#qIKNDG zqm{Cv&Ugn*ynBpOK^Mm;ZV$(c#;mSLJmQSkXX4#woJ5bkUc*oFOONLFmWfwbqv)~Y zbtigbiHM3NqDjudncqnhuhHZudaQVI-`&)4mIPV?s&-{VbN=r0o130%T^zNCJH;fn zuu#gmuXm0&mFMc>&-)uSs!}T1`FvQ#;-PhxELACcys7Lj&qd+B6FuHK^UrDh@`e?4 zOO_X&v7BR_tfkyA8zR>zetv6+a(eG`L>)Z#q|qI$`&dg3dW}1X%DDYC*EtR_iQ9!e zk$bUV{M%xS&+@KHInVO3iT}LrbZTB#taDx@+ZACgNRpm*iUGd6X-?KG9s}aQYHQekY2HTz4UxjLDikk%#$b$TgA+ z=hK``XRP?##dA5YSSL^7B7T0hf*+O2uUC1`X>JgWs4i6pP#zRkS%)cyQan0(qmC9xVf$G5g>XBC?v@WF*dj~an z=$N>M$e*B~hkh3kq`C%b_tFbFzM`ipJ->S7EezE(QN`CQYm*i3&RA-_6^d9X+UJUg zVhK9vlI%S6@;3e}^~&1Lu+8K!)A_vzlK)lFo*dO1{fp5r8C}McW_ojU!01J+%lQ-E zeMYy7mXEgk4G(TsaG%eNFEF~wXn|D0FKLkXF7Pz!70v#o{=7aU+Pt+v#^2F8|Go#& zr`Wibb?M?0_%rcml*VC*$=f9}< z^{6#zU~_YHu%>e3wwb-NZ&jr)%s6!P+MKPQyu1D62W`o7KSc+c;kzVg_5Bvi#&oVXu literal 0 HcmV?d00001 diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index d593348a68660..add294831081e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -3648,7 +3648,8 @@ ERROR(decl_from_hidden_module,none, "cannot use %kind0 %select{here|as property wrapper here|" "as result builder here|" "in an extension with public or '@usableFromInline' members|" - "in an extension with conditional conformances}1; " + "in an extension with conditional conformances|" + "in a public or '@usableFromInline' conformance}1; " "%select{%2 has been imported as implementation-only|" "it is an SPI imported from %2|" "it is SPI|" @@ -3662,7 +3663,8 @@ ERROR(typealias_desugars_to_type_from_hidden_module,none, "as property wrapper here|" "as result builder here|" "in an extension with public or '@usableFromInline' members|" - "in an extension with conditional conformances}3 " + "in an extension with conditional conformance|" + "in a public or '@usableFromInline' conformance}3 " "because %select{%4 has been imported as implementation-only|" "it is an SPI imported from %4|" "<>|" @@ -3675,7 +3677,8 @@ ERROR(conformance_from_implementation_only_module,none, "cannot use conformance of %0 to %1 %select{here|as property wrapper here|" "as result builder here|" "in an extension with public or '@usableFromInline' members|" - "in an extension with conditional conformances}2; " + "in an extension with conditional conformances|" + "<>}2; " "%select{%3 has been imported as implementation-only|" "the conformance is declared as SPI in %3|" "the conformance is declared as SPI|" diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp index d3915ad77a3bf..0f855431a0e78 100644 --- a/lib/Sema/ResilienceDiagnostics.cpp +++ b/lib/Sema/ResilienceDiagnostics.cpp @@ -248,11 +248,22 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D, } // Access levels from imports are reported with the others access levels. - // Except for extensions, we report them here. - if (originKind == DisallowedOriginKind::NonPublicImport && - reason != ExportabilityReason::ExtensionWithPublicMembers && - reason != ExportabilityReason::ExtensionWithConditionalConformances) - return false; + // Except for extensions and protocol conformances, we report them here. + if (originKind == DisallowedOriginKind::NonPublicImport) { + bool reportHere = [&] { + switch (*reason) { + case ExportabilityReason::ExtensionWithPublicMembers: + case ExportabilityReason::ExtensionWithConditionalConformances: + return true; + case ExportabilityReason::Inheritance: + return isa(D); + default: + return false; + } + }(); + if (!reportHere) + return false; + } if (ctx.LangOpts.EnableModuleApiImportRemarks && import.has_value() && where.isExported() && diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index db37064b5feec..1595933be479b 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -2259,7 +2259,7 @@ class DeclAvailabilityChecker : public DeclVisitor { for (TypeLoc inherited : nominal->getInherited().getEntries()) { checkType(inherited.getType(), inherited.getTypeRepr(), nominal, - ExportabilityReason::General, flags); + ExportabilityReason::Inheritance, flags); } } @@ -2361,7 +2361,7 @@ class DeclAvailabilityChecker : public DeclVisitor { // must be exported. for (TypeLoc inherited : ED->getInherited().getEntries()) { checkType(inherited.getType(), inherited.getTypeRepr(), ED, - ExportabilityReason::General, + ExportabilityReason::Inheritance, DeclAvailabilityFlag::AllowPotentiallyUnavailableProtocol); } diff --git a/lib/Sema/TypeCheckAvailability.h b/lib/Sema/TypeCheckAvailability.h index c4e6fddfd57d2..a8badf06c1246 100644 --- a/lib/Sema/TypeCheckAvailability.h +++ b/lib/Sema/TypeCheckAvailability.h @@ -72,7 +72,8 @@ enum class ExportabilityReason : unsigned { PropertyWrapper, ResultBuilder, ExtensionWithPublicMembers, - ExtensionWithConditionalConformances + ExtensionWithConditionalConformances, + Inheritance }; /// A description of the restrictions on what declarations can be referenced diff --git a/test/Sema/access-level-import-conforming-types.swift b/test/Sema/access-level-import-conforming-types.swift new file mode 100644 index 0000000000000..89de2c49ac6be --- /dev/null +++ b/test/Sema/access-level-import-conforming-types.swift @@ -0,0 +1,70 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend -emit-module -o %t/NormalLibrary.swiftmodule \ +// RUN: %S/Inputs/implementation-only-import-in-decls-public-helper.swift \ +// RUN: -enable-library-evolution -swift-version 5 + +// RUN: %target-swift-frontend -emit-module -o %t/BADLibrary.swiftmodule \ +// RUN: %S/Inputs/implementation-only-import-in-decls-helper.swift -I %t \ +// RUN: -enable-library-evolution -swift-version 5 + +// RUN: %target-typecheck-verify-swift -I %t \ +// RUN: -swift-version 5 -package-name pkg -enable-library-evolution +// RUN: %target-typecheck-verify-swift -I %t \ +// RUN: -swift-version 5 -package-name pkg + +internal import BADLibrary // expected-note 14 {{protocol 'BadProto' imported as 'internal' from 'BADLibrary' here}} +// expected-note @-1 2 {{struct 'IntLike' imported as 'internal' from 'BADLibrary' here}} +// expected-note @-2 2 {{class 'BadClass' imported as 'internal' from 'BADLibrary' here}} + +public protocol LocalProto {} + +public struct TestConformance: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} +public struct TestConformanceComposition: LocalProto & BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +@usableFromInline struct TestConformanceUFI: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +public class TestConformanceClass: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} +public enum TestConformanceEnum: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +public struct TestExtensionStruct {} +extension TestExtensionStruct: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +package struct TestConformancePackage: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} +package struct TestConformanceCompositionPackage: LocalProto & BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +@usableFromInline struct TestConformanceUFIPackage: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +package class TestConformanceClassPackage: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} +package enum TestConformanceEnumPackage: BADLibrary.BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +package struct TestExtensionStructPackage {} +extension TestExtensionStructPackage: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +/// Other inheritance types are covered by the classic access-level check. + +public class TestSubclass: BadClass { // expected-error {{class cannot be declared public because its superclass is internal}} +// expected-note @-1 {{class 'BadClass' is imported by this file as 'internal' from 'BADLibrary'}} +} + +public enum TestRawType: IntLike { // expected-error {{enum cannot be declared public because its raw type uses an internal type}} +// expected-note @-1 {{struct 'IntLike' is imported by this file as 'internal' from 'BADLibrary'}} + case x = 1 +} + +public protocol TestRefinedProto: BadProto { // expected-error {{public protocol cannot refine an internal protocol}} +// expected-note @-1 {{protocol 'BadProto' is imported by this file as 'internal' from 'BADLibrary'}} +} + +package class TestSubclassPackage: BadClass { // expected-error {{class cannot be declared package because its superclass is internal}} +// expected-note @-1 {{class 'BadClass' is imported by this file as 'internal' from 'BADLibrary'}} +} + +package enum TestRawTypePackage: IntLike { // expected-error {{enum cannot be declared package because its raw type uses an internal type}} +// expected-note @-1 {{struct 'IntLike' is imported by this file as 'internal' from 'BADLibrary'}} + case x = 1 +} + +package protocol TestRefinedProtoPackage: BadProto { // expected-error {{package protocol cannot refine an internal protocol}} +// expected-note @-1 {{protocol 'BadProto' is imported by this file as 'internal' from 'BADLibrary'}} +} diff --git a/test/Sema/access-level-import-typealias.swift b/test/Sema/access-level-import-typealias.swift index 95f30887c737d..950ec4b9aac46 100644 --- a/test/Sema/access-level-import-typealias.swift +++ b/test/Sema/access-level-import-typealias.swift @@ -24,11 +24,10 @@ public typealias ClazzAlias = Clazz public import Aliases internal import Original // expected-note 2 {{class 'Clazz' imported as 'internal' from 'Original' here}} -// expected-error@+1 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used here because 'Original' was not imported publicly}} +// expected-error@+1 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used for a conformance on a public, package or '@usableFromInline' type because 'Original' was not imported publicly}} public class InheritsFromClazzAlias: ClazzAlias {} @inlinable public func inlinableFunc() { // expected-error@+1 {{'ClazzAlias' aliases 'Original.Clazz' and cannot be used in an '@inlinable' function because 'Original' was not imported publicly}} _ = ClazzAlias.self } - diff --git a/test/Sema/implementation-only-import-in-decls.swift b/test/Sema/implementation-only-import-in-decls.swift index c452a6c3b56fd..07f20d4c3d9f2 100644 --- a/test/Sema/implementation-only-import-in-decls.swift +++ b/test/Sema/implementation-only-import-in-decls.swift @@ -11,15 +11,14 @@ import NormalLibrary @_implementationOnly import BADLibrary // expected-warning @-1 {{'@_implementationOnly' is deprecated, use 'internal import' instead}} -public struct TestConformance: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}} +public struct TestConformance: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}} -@usableFromInline struct TestConformanceUFI: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}} +@usableFromInline struct TestConformanceUFI: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}} struct TestConformanceOkay: BadProto {} // ok -public class TestConformanceClass: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}} -public enum TestConformanceEnum: BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}} - +public class TestConformanceClass: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}} +public enum TestConformanceEnum: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}} public struct TestGenericParams {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}} @@ -75,11 +74,11 @@ public protocol TestAssocTypeWhereClause { associatedtype Assoc: Collection where Assoc.Element: BadProto // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}} } -public enum TestRawType: IntLike { // expected-error {{cannot use struct 'IntLike' here; 'BADLibrary' has been imported as implementation-only}} +public enum TestRawType: IntLike { // expected-error {{cannot use struct 'IntLike' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}} case x = 1 } -public class TestSubclass: BadClass { // expected-error {{cannot use class 'BadClass' here; 'BADLibrary' has been imported as implementation-only}} +public class TestSubclass: BadClass { // expected-error {{cannot use class 'BadClass' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}} } public typealias TestUnderlying = BadStruct // expected-error {{cannot use struct 'BadStruct' here; 'BADLibrary' has been imported as implementation-only}} @@ -121,7 +120,7 @@ extension Array where Element == BadStruct { subscript(okay _: Int) -> Int { 0 } // okay } -extension Int: @retroactive BadProto {} // expected-error {{cannot use protocol 'BadProto' here; 'BADLibrary' has been imported as implementation-only}} +extension Int: @retroactive BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' has been imported as implementation-only}} struct TestExtensionConformanceOkay {} extension TestExtensionConformanceOkay: BadProto {} // okay diff --git a/test/Sema/package-import-conforming-types.swift b/test/Sema/package-import-conforming-types.swift new file mode 100644 index 0000000000000..bb2fc7b88687c --- /dev/null +++ b/test/Sema/package-import-conforming-types.swift @@ -0,0 +1,67 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend -emit-module -o %t/NormalLibrary.swiftmodule \ +// RUN: %S/Inputs/implementation-only-import-in-decls-public-helper.swift \ +// RUN: -enable-library-evolution -swift-version 5 + +// RUN: %target-swift-frontend -emit-module -o %t/BADLibrary.swiftmodule \ +// RUN: %S/Inputs/implementation-only-import-in-decls-helper.swift -I %t \ +// RUN: -enable-library-evolution -swift-version 5 + +// RUN: %target-typecheck-verify-swift -I %t \ +// RUN: -swift-version 5 -package-name pkg -enable-library-evolution +// RUN: %target-typecheck-verify-swift -I %t \ +// RUN: -swift-version 5 -package-name pkg + +package import BADLibrary // expected-note 9 {{protocol 'BadProto' imported as 'package' from 'BADLibrary' here}} +// expected-note @-1 {{struct 'IntLike' imported as 'package' from 'BADLibrary' here}} +// expected-note @-2 {{class 'BadClass' imported as 'package' from 'BADLibrary' here}} + +public protocol LocalProto {} + +public struct TestConformance: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} +public struct TestConformanceComposition: LocalProto & BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +@usableFromInline struct TestConformanceUFI: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +public class TestConformanceClass: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} +public enum TestConformanceEnum: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +public struct TestExtensionStruct {} +extension TestExtensionStruct: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +package struct TestConformancePackage: BadProto {} +package struct TestConformanceCompositionPackage: LocalProto & BadProto {} + +@usableFromInline struct TestConformanceUFIPackage: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +package class TestConformanceClassPackage: BadProto {} +package enum TestConformanceEnumPackage: BADLibrary.BadProto {} + +package struct TestExtensionStructPackage {} +extension TestExtensionStructPackage: BadProto {} // expected-error {{cannot use protocol 'BadProto' in a public or '@usableFromInline' conformance; 'BADLibrary' was not imported publicly}} + +/// Other inheritance types are covered by the classic access-level check. + +public class TestSubclass: BadClass { // expected-error {{class cannot be declared public because its superclass is package}} +// expected-note @-1 {{class 'BadClass' is imported by this file as 'package' from 'BADLibrary'}} +} + +public enum TestRawType: IntLike { // expected-error {{enum cannot be declared public because its raw type uses a package type}} +// expected-note @-1 {{struct 'IntLike' is imported by this file as 'package' from 'BADLibrary'}} + case x = 1 +} + +public protocol TestRefinedProto: BadProto { // expected-error {{public protocol cannot refine a package protocol}} +// expected-note @-1 {{protocol 'BadProto' is imported by this file as 'package' from 'BADLibrary'}} +} + +package class TestSubclassPackage: BadClass { +} + +package enum TestRawTypePackage: IntLike { + case x = 1 +} + +package protocol TestRefinedProtoPackage: BadProto { +} From c65264738b3be53b68268ffe4d4f330441306a49 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 12 Jun 2024 14:54:09 -0700 Subject: [PATCH 100/165] Treat references to enum cases with associated values as `@Sendable` functions When `InferSendableFromCaptures`, make sure to treat references to enum cases that have associated values as `@Sendable` functions. --- lib/Sema/ConstraintSystem.cpp | 10 +++++++++- test/Concurrency/sendable_methods.swift | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 3dce3ebf1b379..d2ed898bb46c7 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -1747,8 +1747,16 @@ FunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency( }); if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) { + DeclContext *DC = nullptr; if (auto *FD = dyn_cast(decl)) { - auto *DC = FD->getDeclContext(); + DC = FD->getDeclContext(); + } else if (auto EED = dyn_cast(decl)) { + if (EED->hasAssociatedValues()) { + DC = EED->getDeclContext(); + } + } + + if (DC) { // All global functions should be @Sendable if (DC->isModuleScopeContext()) { if (!adjustedTy->getExtInfo().isSendable()) { diff --git a/test/Concurrency/sendable_methods.swift b/test/Concurrency/sendable_methods.swift index d141121737673..88e204504f584 100644 --- a/test/Concurrency/sendable_methods.swift +++ b/test/Concurrency/sendable_methods.swift @@ -42,6 +42,7 @@ struct InferredSendableS: P { enum InferredSendableE: P { case a, b + case c(Int) func f() { } } @@ -60,6 +61,13 @@ struct GenericS : P { func g() async { } } +enum GenericE { + case a + case b(T) +} + +extension GenericE: Sendable where T: Sendable { } + class NonSendable { func f() {} } @@ -265,3 +273,9 @@ do { true ? nil : c // Ok } } + +func acceptSendableFunc(_: @Sendable (T) -> U) { } + +acceptSendableFunc(InferredSendableE.c) +acceptSendableFunc(GenericE.b) +acceptSendableFunc(GenericE.b) From bd472b12be5bd807b4ad0eb932b1b97f42d52102 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 4 Jun 2024 11:53:03 -0700 Subject: [PATCH 101/165] [region-isolation] Make store_borrow a store operation that does not require. TLDR: The reason why I am doing this is it ensures that temporary store_borrow that we create when materializing a value before were treated as uses. So we would error on this: ```swift @MainActor func transferToMain(_ t: T) async {} func test() async { let x = NonSendableKlass() await transferToMain(x) await transferToMain(x) } ``` ---- store_borrow is an instruction intended to be used to initialize temporary alloc_stack with borrows. Since it is a temporary, we do not want to error on the temporaries initialization... instead, we want to error on the use of the temporary parameter. This is achieved by making it so that store_borrow still performs an assign/merge, but does not require that src/dest be alive. So the regions still merge (yielding diagnostics for later uses). It also required me to make it so that PartitionOp::{Assign,Merge} do not require by default. Instead, we want the individual operations to always emit a PartitionOp::Require explicitly (which they already did). One thing to be aware of is that when it comes to diagnostics, we already know how to find a temporaries original value and how to handle that. So this is the last part of making store_borrow behave nicely. rdar://129237675 --- .../swift/SILOptimizer/Utils/PartitionUtils.h | 22 ------ lib/SILOptimizer/Analysis/RegionAnalysis.cpp | 69 ++++++++++++++++--- test/Concurrency/transfernonsendable.swift | 12 +++- .../transfernonsendable_asynclet.swift | 39 ++++++++--- 4 files changed, 103 insertions(+), 39 deletions(-) diff --git a/include/swift/SILOptimizer/Utils/PartitionUtils.h b/include/swift/SILOptimizer/Utils/PartitionUtils.h index 99ee99860416d..e1e2a1aed57ea 100644 --- a/include/swift/SILOptimizer/Utils/PartitionUtils.h +++ b/include/swift/SILOptimizer/Utils/PartitionUtils.h @@ -1025,14 +1025,6 @@ struct PartitionOpEvaluator { "Assign PartitionOp should be passed 2 arguments"); assert(p.isTrackingElement(op.getOpArgs()[1]) && "Assign PartitionOp's source argument should be already tracked"); - // If we are using a region that was transferred as our assignment source - // value... emit an error. - if (auto *transferredOperandSet = p.getTransferred(op.getOpArgs()[1])) { - for (auto transferredOperand : transferredOperandSet->data()) { - handleLocalUseAfterTransferHelper(op, op.getOpArgs()[1], - transferredOperand); - } - } p.assignElement(op.getOpArgs()[0], op.getOpArgs()[1]); return; case PartitionOpKind::AssignFresh: @@ -1122,20 +1114,6 @@ struct PartitionOpEvaluator { p.isTrackingElement(op.getOpArgs()[1]) && "Merge PartitionOp's arguments should already be tracked"); - // if attempting to merge a transferred region, handle the failure - if (auto *transferredOperandSet = p.getTransferred(op.getOpArgs()[0])) { - for (auto transferredOperand : transferredOperandSet->data()) { - handleLocalUseAfterTransferHelper(op, op.getOpArgs()[0], - transferredOperand); - } - } - if (auto *transferredOperandSet = p.getTransferred(op.getOpArgs()[1])) { - for (auto transferredOperand : transferredOperandSet->data()) { - handleLocalUseAfterTransferHelper(op, op.getOpArgs()[1], - transferredOperand); - } - } - p.merge(op.getOpArgs()[0], op.getOpArgs()[1]); return; case PartitionOpKind::Require: diff --git a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp index aa2234aa9efcc..7a69f93d143dd 100644 --- a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp @@ -1584,7 +1584,8 @@ class PartitionOpTranslator { void translateSILMultiAssign(const TargetRange &resultValues, const SourceRange &sourceValues, - SILIsolationInfo resultIsolationInfoOverride = {}) { + SILIsolationInfo resultIsolationInfoOverride = {}, + bool requireSrcValues = true) { SmallVector assignOperands; SmallVector assignResults; @@ -1631,9 +1632,17 @@ class PartitionOpTranslator { } } - // Require all srcs. - for (auto src : assignOperands) - builder.addRequire(src); + // Require all srcs if we are supposed to. (By default we do). + // + // DISCUSSION: The reason that this may be useful is for special + // instructions like store_borrow. On the one hand, we want store_borrow to + // act like a store in the sense that we want to combine the regions of its + // src and dest... but at the same time, we do not want to treat the store + // itself as a use of its parent value. We want that to be any subsequent + // uses of the store_borrow. + if (requireSrcValues) + for (auto src : assignOperands) + builder.addRequire(src); // Merge all srcs. for (unsigned i = 1; i < assignOperands.size(); i++) { @@ -2082,12 +2091,17 @@ class PartitionOpTranslator { } template - void translateSILMerge(SILValue dest, Collection collection) { + void translateSILMerge(SILValue dest, Collection collection, + bool requireOperands = true) { auto trackableDest = tryToTrackValue(dest); if (!trackableDest) return; for (SILValue elt : collection) { if (auto trackableSrc = tryToTrackValue(elt)) { + if (requireOperands) { + builder.addRequire(trackableSrc->getRepresentative().getValue()); + builder.addRequire(trackableDest->getRepresentative().getValue()); + } builder.addMerge(trackableDest->getRepresentative().getValue(), trackableSrc->getRepresentative().getValue()); } @@ -2095,8 +2109,10 @@ class PartitionOpTranslator { } template <> - void translateSILMerge(SILValue dest, SILValue src) { - return translateSILMerge(dest, TinyPtrVector(src)); + void translateSILMerge(SILValue dest, SILValue src, + bool requireOperands) { + return translateSILMerge(dest, TinyPtrVector(src), + requireOperands); } void translateSILAssignmentToTransferringParameter(TrackableValue destRoot, @@ -2572,7 +2588,6 @@ CONSTANT_TRANSLATION(InitExistentialValueInst, LookThrough) CONSTANT_TRANSLATION(CopyAddrInst, Store) CONSTANT_TRANSLATION(ExplicitCopyAddrInst, Store) CONSTANT_TRANSLATION(StoreInst, Store) -CONSTANT_TRANSLATION(StoreBorrowInst, Store) CONSTANT_TRANSLATION(StoreWeakInst, Store) CONSTANT_TRANSLATION(MarkUnresolvedMoveAddrInst, Store) CONSTANT_TRANSLATION(UncheckedRefCastAddrInst, Store) @@ -2803,6 +2818,44 @@ LOOKTHROUGH_IF_NONSENDABLE_RESULT_AND_OPERAND(UncheckedTakeEnumDataAddrInst) // Custom Handling // +TranslationSemantics +PartitionOpTranslator::visitStoreBorrowInst(StoreBorrowInst *sbi) { + // A store_borrow is an interesting instruction since we are essentially + // temporarily binding an object value to an address... so really any uses of + // the address, we want to consider to be uses of the parent object. So we + // basically put source/dest into the same region, but do not consider the + // store_borrow itself to be a require use. This prevents the store_borrow + // from causing incorrect diagnostics. + SILValue destValue = sbi->getDest(); + SILValue srcValue = sbi->getSrc(); + + auto nonSendableDest = tryToTrackValue(destValue); + if (!nonSendableDest) + return TranslationSemantics::Ignored; + + // In the following situations, we can perform an assign: + // + // 1. A store to unaliased storage. + // 2. A store that is to an entire value. + // + // DISCUSSION: If we have case 2, we need to merge the regions since we + // are not overwriting the entire region of the value. This does mean that + // we artificially include the previous region that was stored + // specifically in this projection... but that is better than + // miscompiling. For memory like this, we probably need to track it on a + // per field basis to allow for us to assign. + if (nonSendableDest.value().isNoAlias() && + !isProjectedFromAggregate(destValue)) { + translateSILMultiAssign(sbi->getResults(), sbi->getOperandValues(), + SILIsolationInfo(), false /*require src*/); + } else { + // Stores to possibly aliased storage must be treated as merges. + translateSILMerge(destValue, srcValue, false /*require src*/); + } + + return TranslationSemantics::Special; +} + TranslationSemantics PartitionOpTranslator::visitAllocStackInst(AllocStackInst *asi) { // Before we do anything, see if asi is Sendable or if it is non-Sendable, diff --git a/test/Concurrency/transfernonsendable.swift b/test/Concurrency/transfernonsendable.swift index c8fb0bc6c73a1..83947080750a7 100644 --- a/test/Concurrency/transfernonsendable.swift +++ b/test/Concurrency/transfernonsendable.swift @@ -15,7 +15,7 @@ //////////////////////// /// Classes are always non-sendable, so this is non-sendable -class NonSendableKlass { // expected-complete-note 51{{}} +class NonSendableKlass { // expected-complete-note 53{{}} // expected-typechecker-only-note @-1 3{{}} // expected-tns-note @-2 {{}} var field: NonSendableKlass? = nil @@ -1723,3 +1723,13 @@ func sendableGlobalActorIsolated() { } print(x) // expected-tns-note {{access can happen concurrently}} } + +// We do not get an error here since we are transferring x both times to a main +// actor isolated thing function. We used to emit an error when using region +// isolation since we would trip on the store_borrow we used to materialize the +// value. +func testIndirectParameterSameIsolationNoError() async { + let x = NonSendableKlass() + await transferToMain(x) // expected-complete-warning {{passing argument of non-sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}} + await transferToMain(x) // expected-complete-warning {{passing argument of non-sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}} +} diff --git a/test/Concurrency/transfernonsendable_asynclet.swift b/test/Concurrency/transfernonsendable_asynclet.swift index 462dbff8113d1..d41bed7366251 100644 --- a/test/Concurrency/transfernonsendable_asynclet.swift +++ b/test/Concurrency/transfernonsendable_asynclet.swift @@ -9,7 +9,7 @@ //////////////////////// /// Classes are always non-sendable, so this is non-sendable -class NonSendableKlass { // expected-complete-note 96{{}} +class NonSendableKlass { // expected-complete-note 99{{}} // expected-tns-note @-1 {{}} var field: NonSendableKlass? = nil var field2: NonSendableKlass? = nil @@ -34,6 +34,13 @@ final actor FinalActor { func useKlass(_ x: NonSendableKlass) {} } +actor CustomActorInstance {} + +@globalActor +struct CustomActor { + static let shared = CustomActorInstance() +} + func useInOut(_ x: inout T) {} @discardableResult func useValue(_ x: T) -> T { x } @@ -42,6 +49,7 @@ func useValueWrapInOptional(_ x: T) -> T? { x } @MainActor func returnValueFromMain() async -> T { fatalError() } @MainActor func transferToMain(_ t: T) async {} @MainActor func transferToMainInt(_ t: T) async -> Int { 5 } +@CustomActor func transferToCustomInt(_ t: T) async -> Int { 5 } @MainActor func transferToMainIntOpt(_ t: T) async -> Int? { 5 } func transferToNonIsolated(_ t: T) async {} @@ -306,18 +314,33 @@ func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr3() async { let _ = await y } -// Make sure that we emit an error for transferToMainInt in the async val -// function itself. +// Make sure that we do not emit an error for transferToMainInt in the async val +// function itself since we are sending the value to the same main actor +// isolated use and transferring it into one async let variable. func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr4() async { let x = NonSendableKlass() - async let y = useValue(transferToMainInt(x) + transferToMainInt(x)) // expected-tns-warning {{sending 'x' risks causing data races}} - // expected-tns-note @-1 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} - // expected-tns-note @-2:67 {{access can happen concurrently}} + async let y = useValue(transferToMainInt(x) + transferToMainInt(x)) + // expected-complete-warning @-1 {{capture of 'x' with non-sendable type 'NonSendableKlass' in 'async let' binding}} + // expected-complete-warning @-2 {{passing argument of non-sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}} + // expected-complete-warning @-3 {{passing argument of non-sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}} - // expected-complete-warning @-4 {{capture of 'x' with non-sendable type 'NonSendableKlass' in 'async let' binding}} - // expected-complete-warning @-5 {{passing argument of non-sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}} + let _ = await y +} + +// Make sure that we do emit an error since we are sending the value to two +// different isolation domains in the async let. +func asyncLet_Let_ActorIsolated_CallBuriedInOtherExpr5() async { + let x = NonSendableKlass() + + async let y = useValue(transferToMainInt(x) + transferToCustomInt(x)) + // expected-tns-warning @-1 {{sending 'x' risks causing data races}} + // expected-tns-note @-2 {{sending 'x' to main actor-isolated global function 'transferToMainInt' risks causing data races between main actor-isolated and local nonisolated uses}} + // expected-tns-note @-3:49 {{access can happen concurrently}} + + // expected-complete-warning @-5 {{capture of 'x' with non-sendable type 'NonSendableKlass' in 'async let' binding}} // expected-complete-warning @-6 {{passing argument of non-sendable type 'NonSendableKlass' into main actor-isolated context may introduce data races}} + // expected-complete-warning @-7 {{passing argument of non-sendable type 'NonSendableKlass' into global actor 'CustomActor'-isolated context may introduce data races}} let _ = await y } From f9b3a625c1eff6eddf35a0b93f6cd2abbd10770b Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Wed, 12 Jun 2024 15:15:15 -0700 Subject: [PATCH 102/165] [Test] Narrow the 'ScanDependencies/module_deps_link_libs.swift' tests to avoid checking target-dependent libraries --- test/ScanDependencies/module_deps_link_libs.swift | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/test/ScanDependencies/module_deps_link_libs.swift b/test/ScanDependencies/module_deps_link_libs.swift index 6b27388bc54cd..2792e9dbd3a22 100644 --- a/test/ScanDependencies/module_deps_link_libs.swift +++ b/test/ScanDependencies/module_deps_link_libs.swift @@ -17,18 +17,6 @@ import SubE // CHECK-NEXT: "isFramework": false, // CHECK-NEXT: "shouldForceLoad": false -// CHECK-DAG: "linkName": "swiftCompatibilityConcurrency", -// CHECK-NEXT: "isFramework": false, -// CHECK-NEXT: "shouldForceLoad": true - -// CHECK-DAG: "linkName": "swiftCompatibility56", -// CHECK-NEXT: "isFramework": false, -// CHECK-NEXT: "shouldForceLoad": true - -// CHECK-DAG: "linkName": "swiftCompatibilityPacks", -// CHECK-NEXT: "isFramework": false, -// CHECK-NEXT: "shouldForceLoad": false - // CHECK-DAG: "linkName": "swiftyLibE", // CHECK-NEXT: "isFramework": false, // CHECK-NEXT: "shouldForceLoad": true From c5a77fcce54395785e8784de97701cea571f0261 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 12 Jun 2024 15:52:03 -0700 Subject: [PATCH 103/165] Add a proper `TaskGroup.Iterator.next(isolation:)` Implement this function to pass the isolation through to the task group's `next(isolation:)`. Fixes rdar://129690995. --- stdlib/public/Concurrency/TaskGroup.swift | 25 +++++++++++++++++++- test/Concurrency/async_sequence_macosx.swift | 14 +++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/stdlib/public/Concurrency/TaskGroup.swift b/stdlib/public/Concurrency/TaskGroup.swift index 9566a60f41588..3376e7389fdd7 100644 --- a/stdlib/public/Concurrency/TaskGroup.swift +++ b/stdlib/public/Concurrency/TaskGroup.swift @@ -1211,6 +1211,29 @@ extension TaskGroup: AsyncSequence { return element } + /// Advances to and returns the result of the next child task. + /// + /// The elements returned from this method + /// appear in the order that the tasks *completed*, + /// not in the order that those tasks were added to the task group. + /// After this method returns `nil`, + /// this iterator is guaranteed to never produce more values. + /// + /// For more information about the iteration order and semantics, + /// see `TaskGroup.next()`. + /// + /// - Returns: The value returned by the next child task that completes, + /// or `nil` if there are no remaining child tasks, + @available(SwiftStdlib 6.0, *) + public mutating func next(isolation actor: isolated (any Actor)?) async -> Element? { + guard !finished else { return nil } + guard let element = await group.next(isolation: actor) else { + finished = true + return nil + } + return element + } + public mutating func cancel() { finished = true group.cancelAll() @@ -1324,7 +1347,7 @@ extension ThrowingTaskGroup: AsyncSequence { public mutating func next(isolation actor: isolated (any Actor)?) async throws(Failure) -> Element? { guard !finished else { return nil } do { - guard let element = try await group.next() else { + guard let element = try await group.next(isolation: actor) else { finished = true return nil } diff --git a/test/Concurrency/async_sequence_macosx.swift b/test/Concurrency/async_sequence_macosx.swift index 261f1a125e69b..c2f24ada80b0a 100644 --- a/test/Concurrency/async_sequence_macosx.swift +++ b/test/Concurrency/async_sequence_macosx.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -target %target-cpu-apple-macos14.0 %s -emit-sil -o /dev/null -verify +// RUN: %target-swift-frontend -target %target-cpu-apple-macos14.0 %s -emit-sil -o /dev/null -verify -swift-version 6 // REQUIRES: concurrency, OS=macosx @@ -15,4 +15,14 @@ func f(s: S) async throws { } } - +// Make sure we don't complain about crossing a concurrency boundary here. +@MainActor +class Store { + private func intercept(_ action: Action) async { + await withTaskGroup(of: Optional.self) { group in + for await case let nextAction? in group { + _ = nextAction + } + } + } +} From 1c9b1780f6000ba050b1e7b5e937e7530b988727 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 4 Jun 2024 14:38:47 -0700 Subject: [PATCH 104/165] [sending] Do not let protocol function reqs with a sending result be witnessed by a function without a sending result. This is important since the witness is not promising to return a disconnected value and the caller of the requirement is going to accept that. rdar://127675288 --- lib/Sema/TypeCheckProtocol.cpp | 13 +++++ ...ransfernonsendable_functionsubtyping.swift | 57 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 test/Concurrency/transfernonsendable_functionsubtyping.swift diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index d66b35c1b6881..332520673a8c5 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -743,6 +743,13 @@ RequirementMatch swift::matchWitness( reqTypeIsIUO != witnessTypeIsIUO) return RequirementMatch(witness, MatchKind::TypeConflict, witnessType); + // If our requirement says that it has a sending result, then our witness + // must also have a sending result since otherwise, in generic contexts, + // we would be returning non-disconnected values as disconnected. + if (reqFnType->hasExtInfo() && reqFnType->hasSendingResult() && + (!witnessFnType->hasExtInfo() || !witnessFnType->hasSendingResult())) + return RequirementMatch(witness, MatchKind::TypeConflict, witnessType); + if (auto result = matchTypes(std::get<0>(types), std::get<1>(types))) { return std::move(result.value()); } @@ -775,6 +782,12 @@ RequirementMatch swift::matchWitness( if (reqParams[i].isInOut() != witnessParams[i].isInOut()) return RequirementMatch(witness, MatchKind::TypeConflict, witnessType); + // If we have a requirement without sending and our witness expects a + // sending parameter, error. + if (!reqParams[i].getParameterFlags().isSending() && + witnessParams[i].getParameterFlags().isSending()) + return RequirementMatch(witness, MatchKind::TypeConflict, witnessType); + auto reqParamDecl = reqParamList->get(i); auto witnessParamDecl = witnessParamList->get(i); diff --git a/test/Concurrency/transfernonsendable_functionsubtyping.swift b/test/Concurrency/transfernonsendable_functionsubtyping.swift new file mode 100644 index 0000000000000..7f3cd4e3577f9 --- /dev/null +++ b/test/Concurrency/transfernonsendable_functionsubtyping.swift @@ -0,0 +1,57 @@ +// RUN: %target-swift-frontend -swift-version 6 -verify -c %s + +// READ THIS! This file only contains tests that validate that the relevant +// function subtyping rules for sending work. Please do not put other tests in +// the file! + +// REQUIRES: concurrency +// REQUIRES: asserts + +//////////////////////// +// MARK: Declarations // +//////////////////////// + +class NonSendableKlass {} + +protocol ProtocolWithSendingReqs { + func sendingResult() -> sending NonSendableKlass // expected-note {{}} + func nonSendingParam(_ x: NonSendableKlass) // expected-note {{}} +} + +protocol ProtocolWithMixedReqs { + func nonSendingParamAndSendingResult(_ x: NonSendableKlass) -> sending NonSendableKlass // expected-note 4{{}} +} + +///////////////// +// MARK: Tests // +///////////////// + +struct MatchSuccess : ProtocolWithSendingReqs, ProtocolWithMixedReqs { + func sendingResult() -> sending NonSendableKlass { fatalError() } + func nonSendingParam(_ x: NonSendableKlass) -> () { fatalError() } + func nonSendingParamAndSendingResult(_ x: NonSendableKlass) -> sending NonSendableKlass { fatalError() } +} + +struct FailToMatch : ProtocolWithSendingReqs, ProtocolWithMixedReqs { // expected-error 2{{}} + func sendingResult() -> NonSendableKlass { fatalError() } + // expected-note @-1 {{candidate has non-matching type '() -> NonSendableKlass'}} + func nonSendingParam(_ x: sending NonSendableKlass) -> () { fatalError() } + // expected-note @-1 {{candidate has non-matching type '(sending NonSendableKlass) -> ()'}} + func nonSendingParamAndSendingResult(_ x: sending NonSendableKlass) -> NonSendableKlass { fatalError() } + // expected-note @-1 {{candidate has non-matching type '(sending NonSendableKlass) -> NonSendableKlass'}} +} + +struct FailToMatch2 : ProtocolWithMixedReqs { // expected-error {{}} + func nonSendingParamAndSendingResult(_ x: sending NonSendableKlass) -> NonSendableKlass { fatalError() } + // expected-note @-1 {{candidate has non-matching type '(sending NonSendableKlass) -> NonSendableKlass'}} +} + +struct FailToMatch3 : ProtocolWithMixedReqs { // expected-error {{}} + func nonSendingParamAndSendingResult(_ x: NonSendableKlass) -> NonSendableKlass { fatalError() } + // expected-note @-1 {{candidate has non-matching type '(NonSendableKlass) -> NonSendableKlass'}} +} + +struct FailToMatch4 : ProtocolWithMixedReqs { // expected-error {{}} + func nonSendingParamAndSendingResult(_ x: sending NonSendableKlass) -> sending NonSendableKlass { fatalError() } + // expected-note @-1 {{candidate has non-matching type '(sending NonSendableKlass) -> sending NonSendableKlass'}} +} From 3c166b5d96132085664340c823133281f6a62426 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Tue, 4 Jun 2024 15:45:01 -0700 Subject: [PATCH 105/165] [sending] Implement non-protocol function subtyping rules. rdar://127675288 --- lib/Sema/CSSimplify.cpp | 13 +++++ ...ransfernonsendable_functionsubtyping.swift | 54 +++++++++++++++++-- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 251f6e74818cb..b1de2e1c58dbb 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -3235,6 +3235,12 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, return getTypeMatchFailure(locator); } + // () -> sending T can be a subtype of () -> T... but not vis-a-versa. + if (func1->hasSendingResult() != func2->hasSendingResult() && + (!func1->hasSendingResult() || kind < ConstraintKind::Subtype)) { + return getTypeMatchFailure(locator); + } + if (!matchFunctionIsolations(func1, func2, kind, flags, locator)) return getTypeMatchFailure(locator); @@ -3665,6 +3671,13 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, return getTypeMatchFailure(argumentLocator); } + // Do not allow for functions that expect a sending parameter to match + // with a function that expects a non-sending parameter. + if (func1Param.getParameterFlags().isSending() && + !func2Param.getParameterFlags().isSending()) { + return getTypeMatchFailure(argumentLocator); + } + // FIXME: We should check value ownership too, but it's not completely // trivial because of inout-to-pointer conversions. diff --git a/test/Concurrency/transfernonsendable_functionsubtyping.swift b/test/Concurrency/transfernonsendable_functionsubtyping.swift index 7f3cd4e3577f9..b9257377c2135 100644 --- a/test/Concurrency/transfernonsendable_functionsubtyping.swift +++ b/test/Concurrency/transfernonsendable_functionsubtyping.swift @@ -22,9 +22,57 @@ protocol ProtocolWithMixedReqs { func nonSendingParamAndSendingResult(_ x: NonSendableKlass) -> sending NonSendableKlass // expected-note 4{{}} } -///////////////// -// MARK: Tests // -///////////////// +///////////////////////////////// +// MARK: Normal Function Tests // +///////////////////////////////// + +func functionWithSendingResult() -> sending NonSendableKlass { fatalError() } +func functionWithoutSendingResult() -> NonSendableKlass { fatalError() } +func functionWithSendingParameter(_ x: sending NonSendableKlass) { fatalError() } +func functionWithoutSendingParameter(_ x: NonSendableKlass) { fatalError() } + +func takeFnWithSendingResult(_ fn: () -> sending NonSendableKlass) {} +func takeFnWithoutSendingResult(_ fn: () -> NonSendableKlass) {} +func takeFnWithSendingParam(_ fn: (sending NonSendableKlass) -> ()) {} +func takeFnWithoutSendingParam(_ fn: (NonSendableKlass) -> ()) {} + +func testFunctionMatching() { + let _: (NonSendableKlass) -> () = functionWithSendingParameter + // expected-error @-1 {{cannot convert value of type '@Sendable (sending NonSendableKlass) -> ()' to specified type '(NonSendableKlass) -> ()'}} + let _: (sending NonSendableKlass) -> () = functionWithSendingParameter + + let _: (NonSendableKlass) -> () = functionWithoutSendingParameter + let _: (sending NonSendableKlass) -> () = functionWithoutSendingParameter + + takeFnWithSendingParam(functionWithSendingParameter) + takeFnWithoutSendingParam(functionWithSendingParameter) + // expected-error @-1 {{@Sendable (sending NonSendableKlass) -> ()' to expected argument type '(NonSendableKlass) -> ()}} + takeFnWithSendingParam(functionWithoutSendingParameter) + takeFnWithoutSendingParam(functionWithoutSendingParameter) +} + +func testReturnValueMatching() { + let _: () -> NonSendableKlass = functionWithSendingResult + let _: () -> sending NonSendableKlass = functionWithSendingResult + let _: () -> NonSendableKlass = functionWithoutSendingResult + let _: () -> sending NonSendableKlass = functionWithoutSendingResult + // expected-error @-1 {{cannot convert value of type '@Sendable () -> NonSendableKlass' to specified type '() -> sending NonSendableKlass'}} + + takeFnWithSendingResult(functionWithSendingResult) + takeFnWithSendingResult(functionWithoutSendingResult) + // expected-error @-1 {{cannot convert value of type '@Sendable () -> NonSendableKlass' to expected argument type '() -> sending NonSendableKlass'}} + let x: () -> NonSendableKlass = { fatalError() } + takeFnWithSendingResult(x) + // expected-error @-1 {{cannot convert value of type '() -> NonSendableKlass' to expected argument type '() -> sending NonSendableKlass'}} + + takeFnWithoutSendingResult(functionWithSendingResult) + takeFnWithoutSendingResult(functionWithoutSendingResult) + takeFnWithoutSendingResult(x) +} + +////////////////////////// +// MARK: Protocol Tests // +////////////////////////// struct MatchSuccess : ProtocolWithSendingReqs, ProtocolWithMixedReqs { func sendingResult() -> sending NonSendableKlass { fatalError() } From 83bcf23dcafd4bc18145590c7e7de47ef60500e3 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 5 Jun 2024 13:30:17 -0700 Subject: [PATCH 106/165] [sending] Check for a nullptr in AssociatedTypeInference when calling computeFailureTypeWitness. The problem happens when a type conforms to AsyncIterator.next when next in the protocol returns its value as sending, but the witness does not have sending. This results in the function subtyping rules rejecting the witness... but we still leave in the witness as a nullptr... so we need to handle it here. rdar://129300953 --- lib/Sema/AssociatedTypeInference.cpp | 4 +- ..._asynciteratornext_typechecker_error.swift | 77 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 test/Concurrency/sending_asynciteratornext_typechecker_error.swift diff --git a/lib/Sema/AssociatedTypeInference.cpp b/lib/Sema/AssociatedTypeInference.cpp index 3147c4aa99cbc..8b4433f6b82aa 100644 --- a/lib/Sema/AssociatedTypeInference.cpp +++ b/lib/Sema/AssociatedTypeInference.cpp @@ -2425,7 +2425,9 @@ AssociatedTypeInference::computeFailureTypeWitness( // it. for (const auto &witness : valueWitnesses) { if (isAsyncIteratorProtocolNext(witness.first)) { - if (auto witnessFunc = dyn_cast(witness.second)) { + // We use a dyn_cast_or_null since we can get a nullptr here if we fail to + // match a witness. In such a case, we should just fail here. + if (auto witnessFunc = dyn_cast_or_null(witness.second)) { auto thrownError = witnessFunc->getEffectiveThrownErrorType(); // If it doesn't throw, Failure == Never. diff --git a/test/Concurrency/sending_asynciteratornext_typechecker_error.swift b/test/Concurrency/sending_asynciteratornext_typechecker_error.swift new file mode 100644 index 0000000000000..e0054ba2b9c14 --- /dev/null +++ b/test/Concurrency/sending_asynciteratornext_typechecker_error.swift @@ -0,0 +1,77 @@ +// RUN: not %target-swift-frontend %s -c -swift-version 6 -module-name _Concurrency + +// READ THIS: This test is only supposed to be making sure that we do not crash +// when we fail to match a witness that doesn't match AsyncIteratorProtocol.next +// b/c of sending. It should fail... but not crash. + +@available(SwiftStdlib 5.1, *) +public protocol AsyncIteratorProtocol { + associatedtype Element + + /// The type of failure produced by iteration. + @available(SwiftStdlib 6.0, *) + associatedtype Failure: Error = any Error + + /// Asynchronously advances to the next element and returns it, or ends the + /// sequence if there is no next element. + /// + /// - Returns: The next element, if it exists, or `nil` to signal the end of + /// the sequence. + mutating func next() async throws -> sending Element? + + /// Asynchronously advances to the next element and returns it, or ends the + /// sequence if there is no next element. + /// + /// - Returns: The next element, if it exists, or `nil` to signal the end of + /// the sequence. + @available(SwiftStdlib 6.0, *) + mutating func next(isolation actor: isolated (any Actor)?) async throws(Failure) -> sending Element? +} + +@available(SwiftStdlib 5.1, *) +extension AsyncIteratorProtocol { + /// Default implementation of `next(isolation:)` in terms of `next()`, which + /// is required to maintain backward compatibility with existing async + /// iterators. + @available(SwiftStdlib 6.0, *) + @inlinable + public mutating func next(isolation actor: isolated (any Actor)?) async throws(Failure) -> sending Element? { + do { + return try await next() + } catch { + throw error as! Failure + } + } +} + +@available(SwiftStdlib 5.1, *) +extension AsyncIteratorProtocol { + /// Default implementation of `next()` in terms of `next(isolation:)`, which + /// is required to maintain backward compatibility with existing async + /// iterators. + @available(SwiftStdlib 6.0, *) + @inlinable + public mutating func next() async throws(Failure) -> sending Element? { +#if $OptionalIsolatedParameters + return try await next(isolation: nil) +#else + fatalError("unsupported compiler") +#endif + } +} + +public struct FakeMapSequence : AsyncIteratorProtocol { + typealias Element = T + + @available(SwiftStdlib 6.0, *) + @inlinable + public mutating func next(isolation actor: isolated (any Actor)?) async throws(Failure) -> Element? { + fatalError() + } + + @inlinable + public mutating func next() async throws -> Element? { + fatalError() + } +} + From ba6c8afd678150b947575832c6235feecbb12b92 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 6 Jun 2024 10:04:21 -0700 Subject: [PATCH 107/165] Simplify test to only use target-typecheck-verify-swift since we are testing typecheck errors. --- test/Concurrency/transfernonsendable_functionsubtyping.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Concurrency/transfernonsendable_functionsubtyping.swift b/test/Concurrency/transfernonsendable_functionsubtyping.swift index b9257377c2135..ecc8ddb64a965 100644 --- a/test/Concurrency/transfernonsendable_functionsubtyping.swift +++ b/test/Concurrency/transfernonsendable_functionsubtyping.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -swift-version 6 -verify -c %s +// RUN: %target-typecheck-verify-swift -swift-version 6 %s // READ THIS! This file only contains tests that validate that the relevant // function subtyping rules for sending work. Please do not put other tests in @@ -103,3 +103,4 @@ struct FailToMatch4 : ProtocolWithMixedReqs { // expected-error {{}} func nonSendingParamAndSendingResult(_ x: sending NonSendableKlass) -> sending NonSendableKlass { fatalError() } // expected-note @-1 {{candidate has non-matching type '(sending NonSendableKlass) -> sending NonSendableKlass'}} } + From 2ac874e8e308cbcd3d32e77d990cc273c1f36225 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 6 Jun 2024 10:04:33 -0700 Subject: [PATCH 108/165] [sending] Fix a few bugs around closure inference of sending parameters and results. I found this while writing tests for the earlier part of this work. Since this is also type checking work, I am just folding this work into that work. --- include/swift/AST/Types.h | 3 ++ lib/Parse/ParseType.cpp | 2 + lib/Sema/CSSimplify.cpp | 14 ++++-- .../sending_closure_inference.swift | 44 +++++++++++++++++++ 4 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 test/Concurrency/sending_closure_inference.swift diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index d3b3f91a4c62b..bbe4850f07e73 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -3237,6 +3237,9 @@ class AnyFunctionType : public TypeBase { /// Whether the parameter is 'isolated'. bool isIsolated() const { return Flags.isIsolated(); } + /// Whether or not the parameter is 'sending'. + bool isSending() const { return Flags.isSending(); } + /// Whether the parameter is 'isCompileTimeConst'. bool isCompileTimeConst() const { return Flags.isCompileTimeConst(); } diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 16af391fefa1d..6ce73e82115ef 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -1555,6 +1555,8 @@ bool Parser::canParseType() { consumeToken(); } else if (Tok.isContextualKeyword("each")) { consumeToken(); + } else if (Tok.isContextualKeyword("sending")) { + consumeToken(); } switch (Tok.getKind()) { diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index b1de2e1c58dbb..2faf95864ff80 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -11810,10 +11810,10 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar, if (contextualParam->isIsolated() && !flags.isIsolated() && paramDecl) isolatedParams.insert(paramDecl); - param = - param.withFlags(flags.withInOut(contextualParam->isInOut()) - .withVariadic(contextualParam->isVariadic()) - .withIsolated(contextualParam->isIsolated())); + param = param.withFlags(flags.withInOut(contextualParam->isInOut()) + .withVariadic(contextualParam->isVariadic()) + .withIsolated(contextualParam->isIsolated()) + .withSending(contextualParam->isSending())); } } @@ -11940,6 +11940,12 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar, closureExtInfo = closureExtInfo.withSendable(); } + // Propagate sending result from the contextual type to the closure. + if (auto contextualFnType = contextualType->getAs()) { + if (contextualFnType->hasExtInfo() && contextualFnType->hasSendingResult()) + closureExtInfo = closureExtInfo.withSendingResult(); + } + // Isolated parameters override any other kind of isolation we might infer. if (hasIsolatedParam) { closureExtInfo = closureExtInfo.withIsolation( diff --git a/test/Concurrency/sending_closure_inference.swift b/test/Concurrency/sending_closure_inference.swift new file mode 100644 index 0000000000000..66618c0727aa9 --- /dev/null +++ b/test/Concurrency/sending_closure_inference.swift @@ -0,0 +1,44 @@ +// RUN: %target-swift-frontend -swift-version 6 %s -emit-silgen | %FileCheck %s + +// READ THIS! This file only contains tests that validate that the relevant +// function subtyping rules for sending work. Please do not put other tests in +// the file! + +// REQUIRES: concurrency +// REQUIRES: asserts + +//////////////////////// +// MARK: Declarations // +//////////////////////// + +class NonSendableKlass {} + +///////////////// +// MARK: Tests // +///////////////// + +// CHECK: sil private [ossa] @$s25sending_closure_inference38testAnonymousParameterSendingInferenceyyFySSYucfU_ : $@convention(thin) (@sil_sending @guaranteed String) -> () { +func testAnonymousParameterSendingInference() { + let _: (sending String) -> () = { + print($0) + } +} + +// CHECK: sil private [ossa] @$s25sending_closure_inference38testNamedOnlyParameterSendingInferenceyyFySSYucfU_ : $@convention(thin) (@sil_sending @guaranteed String) -> () { +func testNamedOnlyParameterSendingInference() { + let _: (sending String) -> () = { x in + print(x) + } +} + +// CHECK: sil private [ossa] @$s25sending_closure_inference38testNamedTypeParameterSendingInferenceyyFySSnYucfU_ : $@convention(thin) (@sil_sending @owned String) -> () { +func testNamedTypeParameterSendingInference() { + let _: (sending String) -> () = { (x: sending String) in + print(x) + } +} + +// CHECK: sil private [ossa] @$s25sending_closure_inference26testSendingResultInferenceyyFSSyYTcfU_ : $@convention(thin) () -> @sil_sending @owned String { +func testSendingResultInference() { + let _: () -> sending String = { "" } +} From 4d99192e8d41c473bdc413127f34e7e375c87103 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 13 Jun 2024 08:13:36 +0900 Subject: [PATCH 109/165] Remove new whenLocal func from ABI test - it is always emit into client --- test/abi/macOS/arm64/distributed.swift | 6 ------ test/abi/macOS/x86_64/distributed.swift | 6 ------ 2 files changed, 12 deletions(-) diff --git a/test/abi/macOS/arm64/distributed.swift b/test/abi/macOS/arm64/distributed.swift index bf11ee0bdac88..35d02d2d5ad8e 100644 --- a/test/abi/macOS/arm64/distributed.swift +++ b/test/abi/macOS/arm64/distributed.swift @@ -102,11 +102,5 @@ Added: _$s11Distributed0A5ActorPAAE07asLocalB0ScA_pvpMV // property descriptor for (extension in Distributed):Distributed.DistributedActor.__actorUnownedExecutor : Swift.UnownedSerialExecutor Added: _$s11Distributed0A5ActorPAAE22__actorUnownedExecutorScevpMV -// (extension in Distributed):Distributed.DistributedActor.whenLocal(@Sendable (isolated A) async throws(B1) -> A1) async throws(B1) -> A1? -Added: _$s11Distributed0A5ActorPAAE9whenLocalyqd__Sgqd__xYiYaYbqd_0_YKXEYaqd_0_YKs8SendableRd__s5ErrorRd_0_r0_lF - -// async function pointer to (extension in Distributed):Distributed.DistributedActor.whenLocal(@Sendable (isolated A) async throws(B1) -> A1) async throws(B1) -> A1? -Added: _$s11Distributed0A5ActorPAAE9whenLocalyqd__Sgqd__xYiYaYbqd_0_YKXEYaqd_0_YKs8SendableRd__s5ErrorRd_0_r0_lFTu - // Distributed._distributedStubFatalError(function: Swift.String) -> Swift.Never Added: _$s11Distributed26_distributedStubFatalError8functions5NeverOSS_tF diff --git a/test/abi/macOS/x86_64/distributed.swift b/test/abi/macOS/x86_64/distributed.swift index 5b6071c90b132..82ed7c9d54400 100644 --- a/test/abi/macOS/x86_64/distributed.swift +++ b/test/abi/macOS/x86_64/distributed.swift @@ -102,11 +102,5 @@ Added: _$s11Distributed0A5ActorPAAE07asLocalB0ScA_pvpMV // property descriptor for (extension in Distributed):Distributed.DistributedActor.__actorUnownedExecutor : Swift.UnownedSerialExecutor Added: _$s11Distributed0A5ActorPAAE22__actorUnownedExecutorScevpMV -// (extension in Distributed):Distributed.DistributedActor.whenLocal(@Sendable (isolated A) async throws(B1) -> A1) async throws(B1) -> A1? -Added: _$s11Distributed0A5ActorPAAE9whenLocalyqd__Sgqd__xYiYaYbqd_0_YKXEYaqd_0_YKs8SendableRd__s5ErrorRd_0_r0_lF - -// async function pointer to (extension in Distributed):Distributed.DistributedActor.whenLocal(@Sendable (isolated A) async throws(B1) -> A1) async throws(B1) -> A1? -Added: _$s11Distributed0A5ActorPAAE9whenLocalyqd__Sgqd__xYiYaYbqd_0_YKXEYaqd_0_YKs8SendableRd__s5ErrorRd_0_r0_lFTu - // Distributed._distributedStubFatalError(function: Swift.String) -> Swift.Never Added: _$s11Distributed26_distributedStubFatalError8functions5NeverOSS_tF From 5a1c26856f3e90927a5c687e959972eb547abb84 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 12 Jun 2024 16:14:21 -0700 Subject: [PATCH 110/165] Add test for ThrowingTaskGroup version --- test/Concurrency/async_sequence_macosx.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/Concurrency/async_sequence_macosx.swift b/test/Concurrency/async_sequence_macosx.swift index c2f24ada80b0a..99b312dbff0c2 100644 --- a/test/Concurrency/async_sequence_macosx.swift +++ b/test/Concurrency/async_sequence_macosx.swift @@ -18,11 +18,18 @@ func f(s: S) async throws { // Make sure we don't complain about crossing a concurrency boundary here. @MainActor class Store { - private func intercept(_ action: Action) async { + private func intercept(_ action: Action) async throws { await withTaskGroup(of: Optional.self) { group in for await case let nextAction? in group { _ = nextAction } } + + try await withThrowingTaskGroup(of: Optional.self) { group in + for try await case let nextAction? in group { + _ = nextAction + } + } + } } From 81100ad660808856677166087117f17c031314af Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 12 Jun 2024 16:45:44 -0700 Subject: [PATCH 111/165] [sending] Fix type inference for sending results of closures. The previous commit fixed things like: ```swift let x: () -> sending String = { "" } ``` This commit fixes this test case: ```swift let x = { () -> sending String in "" } ``` --- lib/Sema/CSGen.cpp | 11 ++++++----- lib/Sema/TypeCheckType.cpp | 3 ++- lib/Sema/TypeCheckType.h | 2 +- test/Concurrency/sending_closure_inference.swift | 4 ++++ 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 20a1dd0565076..854bcd105ff0d 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1649,10 +1649,9 @@ namespace { } Type - resolveTypeReferenceInExpression(TypeRepr *repr, TypeResolverContext resCtx, + resolveTypeReferenceInExpression(TypeRepr *repr, + TypeResolutionOptions options, const ConstraintLocatorBuilder &locator) { - TypeResolutionOptions options(resCtx); - // Introduce type variables for unbound generics. const auto genericOpener = OpenUnboundGenericType(CS, locator); const auto placeholderHandler = HandlePlaceholderType(CS, locator); @@ -2541,9 +2540,11 @@ namespace { return declaredTy; } + auto options = + TypeResolutionOptions(TypeResolverContext::InExpression); + options.setContext(TypeResolverContext::ClosureExpr); const auto resolvedTy = resolveTypeReferenceInExpression( - closure->getExplicitResultTypeRepr(), - TypeResolverContext::InExpression, resultLocator); + closure->getExplicitResultTypeRepr(), options, resultLocator); if (resolvedTy) return resolvedTy; } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 45bc4fe02a972..d62dcb1b11e20 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -4971,7 +4971,8 @@ TypeResolver::resolveSendingTypeRepr(SendingTypeRepr *repr, return ErrorType::get(getASTContext()); } - if (!options.is(TypeResolverContext::FunctionResult) && + if (!options.is(TypeResolverContext::ClosureExpr) && + !options.is(TypeResolverContext::FunctionResult) && (!options.is(TypeResolverContext::FunctionInput) || options.hasBase(TypeResolverContext::EnumElementDecl))) { diagnoseInvalid(repr, repr->getSpecifierLoc(), diff --git a/lib/Sema/TypeCheckType.h b/lib/Sema/TypeCheckType.h index e3ac2bd5388b1..40415a0614b56 100644 --- a/lib/Sema/TypeCheckType.h +++ b/lib/Sema/TypeCheckType.h @@ -118,7 +118,7 @@ enum class TypeResolverContext : uint8_t { /// Whether we are checking the parameter list of a subscript. SubscriptDecl, - /// Whether we are checking the parameter list of a closure. + /// Whether we are checking the parameter list or result of a closure. ClosureExpr, /// Whether we are in the input type of a function, or under one level of diff --git a/test/Concurrency/sending_closure_inference.swift b/test/Concurrency/sending_closure_inference.swift index 66618c0727aa9..e8343ade2b8ff 100644 --- a/test/Concurrency/sending_closure_inference.swift +++ b/test/Concurrency/sending_closure_inference.swift @@ -42,3 +42,7 @@ func testNamedTypeParameterSendingInference() { func testSendingResultInference() { let _: () -> sending String = { "" } } + +func testSendingResultOnClosure() { + let _ = { (x: String) -> sending String in x } +} From 273549239baed22c300782b17337ca01a4ee0c6d Mon Sep 17 00:00:00 2001 From: Kavon Farvardin Date: Wed, 12 Jun 2024 17:19:58 -0700 Subject: [PATCH 112/165] AST: fix `isWrittenWithConstraints` Surprisingly, there are some situations where an extension can end up with _fewer_ constraints than the extended type. That was baked-in as an assertion in this new-ish method. I haven't figured out why that can happen in the reproducer only when using `-interpret` mode. It didn't trigger the assertion for me when compiling normally. The fix is simple: check all the requirements, rather than using a short-cut. resolves rdar://125659789 / https://github.com/apple/swift/issues/72719 --- lib/AST/Decl.cpp | 16 +++++++++++----- validation-test/execution/issue-72719.swift | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 validation-test/execution/issue-72719.swift diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index daf2b8c759f68..a847e54d14b6e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1809,14 +1809,20 @@ bool ExtensionDecl::isWrittenWithConstraints() const { typeSig->getRequirementsWithInverses(typeReqs, typeInverseReqs); // If the (non-inverse) requirements are different between the extension and - // the original type, it's written with constraints. Note that - // the extension can only add requirements, so we need only check the size - // (not the specific requirements). - if (extReqs.size() > typeReqs.size()) { + // the original type, it's written with constraints. + if (extReqs.size() != typeReqs.size()) { return true; } - assert(extReqs.size() == typeReqs.size()); + // In case of equal number of constraints, we have to check the specific + // requirements. Extensions can end up with fewer requirements than the type + // extended, due to a same-type requirement in the extension. + // + // This mirrors the 'same' check in `ASTMangler::gatherGenericSignatureParts` + for (size_t i = 0; i < extReqs.size(); i++) { + if (extReqs[i] != typeReqs[i]) + return true; + } // If the type has no inverse requirements, there are no extra constraints // to write. diff --git a/validation-test/execution/issue-72719.swift b/validation-test/execution/issue-72719.swift new file mode 100644 index 0000000000000..2f45c87be74e0 --- /dev/null +++ b/validation-test/execution/issue-72719.swift @@ -0,0 +1,17 @@ +// RUN: %target-swift-frontend -interpret %s +// REQUIRES: executable_test + +// This only reproduced if you provide the -interpret flag! +// https://github.com/apple/swift/issues/72719 + +protocol D {} +struct U: D, Equatable {} +class Q {} +class R {} +extension R where E == U { + struct S {} + static func a(_: T) -> R { + let x = Q>() + fatalError() + } +} From bb4c0d3d59aad54f1f475be1c78022b40aceffbf Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Wed, 12 Jun 2024 18:40:04 -0700 Subject: [PATCH 113/165] MoveOnlyAddressChecker: Turn assertion into early exit. This condition can occur in practice if, while doing the walk back to find the liveness reason for a consume-without-reinitialization of an `inout` binding through conditional control flow, we visit a block that reinitializes the binding before any branch that leaves the binding uninitialized. Fixes rdar://123604613. --- .../Mandatory/MoveOnlyAddressCheckerUtils.cpp | 10 +++---- ...moveonly_addresschecker_branch_order.swift | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 test/SILOptimizer/moveonly_addresschecker_branch_order.swift diff --git a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp index 98d58a7e4519b..046f9a392c13c 100644 --- a/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp +++ b/lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp @@ -2934,13 +2934,13 @@ bool GlobalLivenessChecker::testInstVectorLiveness( continue; case IsLive::LiveOut: { LLVM_DEBUG(llvm::dbgs() << " Live out block!\n"); - // If we see a live out block that is also a def block, we need to fa -#ifndef NDEBUG + // If we see a live out block that is also a def block, skip. SmallBitVector defBits(addressUseState.getNumSubelements()); liveness.isDefBlock(block, errorSpan, defBits); - assert((defBits & errorSpan).none() && - "If in def block... we are in liveness block"); -#endif + if (!(defBits & errorSpan).none()) { + LLVM_DEBUG(llvm::dbgs() << " Also a def block; skipping!\n"); + continue; + } [[clang::fallthrough]]; } case IsLive::LiveWithin: diff --git a/test/SILOptimizer/moveonly_addresschecker_branch_order.swift b/test/SILOptimizer/moveonly_addresschecker_branch_order.swift new file mode 100644 index 0000000000000..9ef305a81b2f8 --- /dev/null +++ b/test/SILOptimizer/moveonly_addresschecker_branch_order.swift @@ -0,0 +1,26 @@ +//RUN: %target-swift-frontend -emit-sil -verify %s + +@_silgen_name("cond") +func cond() -> Bool + +struct Foo: ~Copyable {} + +func consume(_: consuming Foo) {} + +func test1(_ x: inout Foo, _ y: consuming Foo) { // expected-error{{missing reinitialization}} + consume(x) // expected-note{{consumed here}} + if cond() { + return + } else { + x = y + } +} + +func test2(_ x: inout Foo, _ y: consuming Foo) { // expected-error{{missing reinitialization}} + consume(x) // expected-note{{consumed here}} + if cond() { + x = y + } else { + return + } +} From a451fe645ae207d95d1ee236d52557107e742045 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Wed, 12 Jun 2024 23:07:25 -0700 Subject: [PATCH 114/165] Fix a test --- test/DebugInfo/sending_params_and_results.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/DebugInfo/sending_params_and_results.swift b/test/DebugInfo/sending_params_and_results.swift index 84bb6d475628a..756c688c4a7c1 100644 --- a/test/DebugInfo/sending_params_and_results.swift +++ b/test/DebugInfo/sending_params_and_results.swift @@ -14,11 +14,11 @@ public struct SendableStruct: Sendable { // // @escaping @callee_guaranteed (@guaranteed sending Swift.Result) -> () // -// CHECK: !{{[0-9]+}} = !DICompositeType(tag: DW_TAG_structure_type, name: "$ss6ResultOy4test14SendableStructVs5Error_pGIeggT_D", flags: DIFlagFwdDecl, runtimeLang: DW_LANG_Swift) +// CHECK: !{{[0-9]+}} = !DICompositeType(tag: DW_TAG_structure_type, name: "$ss6ResultOy4test14SendableStructVs5Error_pGIeggT_D", func testReconstructingEscapingClosureWithSendingParam() async throws -> SendableStruct { func callSendableFunction(_ x: @Sendable () -> ()) {} - func helper(_ completion: @escaping (Result) -> Void) { + func helper(_ completion: @escaping (__shared sending Result) -> Void) { fatalError() } From 49e8a73027d707431dd00e0ea68b3b8017957c70 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 12 Jun 2024 23:55:51 -0700 Subject: [PATCH 115/165] Adjust Synchronization module dependencies for macCatalyst --- stdlib/public/Synchronization/CMakeLists.txt | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/stdlib/public/Synchronization/CMakeLists.txt b/stdlib/public/Synchronization/CMakeLists.txt index dead46e532bbc..88cc673522ad1 100644 --- a/stdlib/public/Synchronization/CMakeLists.txt +++ b/stdlib/public/Synchronization/CMakeLists.txt @@ -33,7 +33,13 @@ set(SWIFT_SYNCHRONIZATION_GYB_SOURCES Atomics/AtomicStorage.swift.gyb ) -# Darwin sources +# Darwin dependencies and sources + +set(SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES) + +if(SWIFT_BUILD_SDK_OVERLAY) + set(SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES Darwin) +endif() set(SWIFT_SYNCHRONIZATION_DARWIN_SOURCES Mutex/DarwinImpl.swift @@ -96,15 +102,17 @@ add_swift_target_library(swiftSynchronization ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES Mutex/MutexUnavailable.swift SWIFT_MODULE_DEPENDS_OSX - Darwin + ${SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES} SWIFT_MODULE_DEPENDS_IOS - Darwin + ${SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES} SWIFT_MODULE_DEPENDS_TVOS - Darwin + ${SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES} SWIFT_MODULE_DEPENDS_WATCHOS - Darwin + ${SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES} SWIFT_MODULE_DEPENDS_XROS - Darwin + ${SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES} + SWIFT_MODULE_DEPENDS_MACCATALYST + ${SWIFT_SYNCHRONIZATION_DARWIN_DEPENDENCIES} SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_ANDROID From 71eb55a8d2333b6c858673bcd0e55c3e4e9f77a5 Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 12 Jun 2024 22:32:54 -0400 Subject: [PATCH 116/165] Properly handle `@objc` thunks for generic classes and actors Fixes rdar://129187133 --- lib/SILGen/SILGenBridging.cpp | 19 +++++++++---- test/SILGen/objc_generic_class.swift | 40 ++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index f0f7ba95519a1..2654527ec85f7 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -1514,7 +1514,7 @@ SILFunction *SILGenFunction::emitNativeAsyncToForeignThunk(SILDeclRef thunk) { .withAsync() .withSendable() .build(); - auto closureTy = objcFnTy->getWithExtInfo(closureExtInfo); + auto closureTy = objcInfo.SILFnType->getWithExtInfo(closureExtInfo); SmallString<64> closureName(F.getName().begin(), F.getName().end()); // Trim off the thunk suffix and mangle this like a closure nested inside the @@ -1535,7 +1535,7 @@ SILFunction *SILGenFunction::emitNativeAsyncToForeignThunk(SILDeclRef thunk) { IsNotDistributed, IsNotRuntimeAccessible); auto closureRef = B.createFunctionRef(loc, closure); - + auto closureVal = B.createPartialApply(loc, closureRef, subs, closureArgs, ParameterConvention::Direct_Guaranteed); @@ -1575,15 +1575,17 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { } } + // Use the same generic environment as the native entry point. + // We need to set this before we can call things like + // F.getForwardingSubstitutionMap(). + F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(native)); + auto nativeInfo = getConstantInfo(getTypeExpansionContext(), native); auto subs = F.getForwardingSubstitutionMap(); auto substTy = nativeInfo.SILFnType->substGenericArgs( SGM.M, subs, getTypeExpansionContext()); SILFunctionConventions substConv(substTy, SGM.M); - // Use the same generic environment as the native entry point. - F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(native)); - auto loc = thunk.getAsRegularLocation(); loc.markAutoGenerated(); Scope scope(Cleanups, CleanupLocation(loc)); @@ -1848,6 +1850,13 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { // The immediate function result is an empty tuple. return SILUndef::get(&F, SGM.Types.getEmptyTupleType()); }; + + // If the function we're calling isn't actually polymorphic, drop the + // substitutions. This should only happen in concrete specializations. + if (subs && !nativeFn->getType().castTo()->isPolymorphic()) { + assert(subs.getGenericSignature()->areAllParamsConcrete()); + subs = SubstitutionMap(); + } if (!substTy->hasErrorResult()) { // Create the apply. diff --git a/test/SILGen/objc_generic_class.swift b/test/SILGen/objc_generic_class.swift index 2c9a00e7a0a90..9d0fcd10013e1 100644 --- a/test/SILGen/objc_generic_class.swift +++ b/test/SILGen/objc_generic_class.swift @@ -1,6 +1,7 @@ -// RUN: %target-swift-emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import %s | %FileCheck %s +// RUN: %target-swift-emit-silgen -sdk %S/Inputs -I %S/Inputs -enable-source-import %s -disable-availability-checking | %FileCheck %s // REQUIRES: objc_interop +// REQUIRES: concurrency import gizmo @@ -11,9 +12,23 @@ import gizmo // CHECK-NOT: sil hidden [ossa] @$sSo7GenericCfd // CHECK-NOT: sil hidden [ossa] @$sSo8NSObjectCfd -class Generic: NSObject { +class Generic: NSObject, ObjCProtocol { var x: Int = 10 + // CHECK-LABEL: sil private [thunk] [ossa] @$s18objc_generic_class7GenericC5evokeyyFTo : $@convention(objc_method) (Generic) -> () { + // CHECK: [[FN:%.*]] = function_ref @$s18objc_generic_class7GenericC5evokeyyF + // CHECK-NEXT: apply [[FN]] + func evoke() {} + + // CHECK-LABEL: sil private [thunk] [ossa] @$s18objc_generic_class7GenericC10evokeAsyncyyYaFTo : $@convention(objc_method) (@convention(block) () -> (), Generic) -> () { + // CHECK: [[FN:%.*]] = function_ref @$s18objc_generic_class7GenericC10evokeAsyncyyYaFyyYacfU_To + // CHECK-NEXT: partial_apply [callee_guaranteed] [[FN]] + + // CHECK-LABEL: sil shared [thunk] [ossa] @$s18objc_generic_class7GenericC10evokeAsyncyyYaFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) () -> (), Generic) -> () + // CHECK: [[FN:%.*]] = function_ref @$s18objc_generic_class7GenericC10evokeAsyncyyYaF : $@convention(method) @async <τ_0_0> (@guaranteed Generic<τ_0_0>) -> () + // CHECK-NEXT: apply [[FN]] + func evokeAsync() async {} + // CHECK-LABEL: sil hidden [ossa] @$s18objc_generic_class7GenericCfD : $@convention(method) (@owned Generic) -> () { // CHECK: bb0({{%.*}} : @owned $Generic): // CHECK: } // end sil function '$s18objc_generic_class7GenericCfD' @@ -33,6 +48,11 @@ class Generic: NSObject { // CHECK-NOT: sil hidden [ossa] @$s18objc_generic_class7GenericCfd // CHECK-NOT: sil hidden [ossa] @$sSo8NSObjectCfd +@objc protocol ObjCProtocol { + func evoke() + func evokeAsync() async +} + // CHECK-LABEL: sil hidden [ossa] @$s18objc_generic_class11SubGeneric1CfD : $@convention(method) (@owned SubGeneric1) -> () { // CHECK: bb0([[SELF:%.*]] : @owned $SubGeneric1): // CHECK: [[SUPER_DEALLOC:%.*]] = objc_super_method [[SELF]] : $SubGeneric1, #Generic.deinit!deallocator.foreign : (Generic) -> () -> (), $@convention(objc_method) <τ_0_0> (Generic<τ_0_0>) -> () @@ -51,3 +71,19 @@ public extension GenericStruct where T == String { @objc public func f() -> String { "hello" } } } + +// rdar://129187133 - handle generic @objc thunks properly +actor GenericActor : SendableObjCProtocol { + // CHECK-LABEL: sil private [thunk] [ossa] @$s18objc_generic_class12GenericActorC10evokeAsyncyyYaFTo : $@convention(objc_method) (@convention(block) () -> (), @sil_isolated GenericActor) -> () + // CHECK: [[FN:%.*]] = function_ref @$s18objc_generic_class12GenericActorC10evokeAsyncyyYaFyyYacfU_To : $@convention(thin) @Sendable @async <τ_0_0> (@convention(block) () -> (), @sil_isolated GenericActor<τ_0_0>) -> () + // CHECK-NEXT: partial_apply [callee_guaranteed] [[FN]] + func evokeAsync() async {} + + // CHECK-LABEL: sil shared [thunk] [ossa] @$s18objc_generic_class12GenericActorC10evokeAsyncyyYaFyyYacfU_To : $@convention(thin) @Sendable @async (@convention(block) () -> (), @sil_isolated GenericActor) -> () + // CHECK: [[FN:%.*]] = function_ref @$s18objc_generic_class12GenericActorC10evokeAsyncyyYaF : $@convention(method) @async <τ_0_0> (@sil_isolated @guaranteed GenericActor<τ_0_0>) -> () + // CHECK-NEXT: apply [[FN]] +} + +@objc protocol SendableObjCProtocol : Sendable { + func evokeAsync() async +} From dbdd9833923cbce1182696e483d1778cd1ec292c Mon Sep 17 00:00:00 2001 From: Gabor Horvath Date: Thu, 13 Jun 2024 12:25:59 +0100 Subject: [PATCH 117/165] [cxx-interop] Fix generated declaration order The generated thunks for functions can refer to some internal methods of their arguments. As a result, those generated thunks should always be after the definitions of the corresponding argument types. The printer ordered the declarations by name, and Swift had the convention starting types with upper case letters and functions with lower case letters. This naming convention together with the ordering resulted in the correct ordering in most of the cases. There were a couple of exceptions when people diverged from the naming conventions or wanted to export operators. This patch fixes this problem by always ordering type decls before function decls. rdar://129276354 --- lib/PrintAsClang/ModuleContentsWriter.cpp | 14 ++++++++++++-- .../SwiftToCxx/class/swift-class-in-cxx.swift | 8 ++++---- .../SwiftToCxx/functions/swift-operators.swift | 4 +--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/PrintAsClang/ModuleContentsWriter.cpp b/lib/PrintAsClang/ModuleContentsWriter.cpp index f554639b1f7a1..7b5ec02b35757 100644 --- a/lib/PrintAsClang/ModuleContentsWriter.cpp +++ b/lib/PrintAsClang/ModuleContentsWriter.cpp @@ -20,6 +20,7 @@ #include "PrintSwiftToClangCoreScaffold.h" #include "SwiftToClangInteropContext.h" +#include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Module.h" @@ -671,6 +672,15 @@ class ModuleWriter { llvm_unreachable("unknown top-level ObjC decl"); }; + // When we visit a function, we might also generate a thunk that calls into the + // implementation of structs/enums to get the opaque pointers. To avoid + // referencing these methods before we see the definition for the generated + // classes, we want to visit function definitions last. + if (isa(*rhs) && isa(*lhs)) + return Descending; + if (isa(*lhs) && isa(*rhs)) + return Ascending; + // Sort by names. int result = getSortName(*rhs).compare(getSortName(*lhs)); if (result != 0) @@ -700,9 +710,9 @@ class ModuleWriter { // even when the variable might not actually be emitted by the emitter. // In that case, order the function before the variable. if (isa(*rhs) && isa(*lhs)) - return 1; + return Descending; if (isa(*lhs) && isa(*rhs)) - return -1; + return Ascending; // Prefer value decls to extensions. assert(!(isa(*lhs) && isa(*rhs))); diff --git a/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift b/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift index 5b051632c5b27..2a774b7fc6c11 100644 --- a/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift +++ b/test/Interop/SwiftToCxx/class/swift-class-in-cxx.swift @@ -102,14 +102,14 @@ public final class ClassWithIntField { // CHECK-EMPTY: // CHECK-NEXT: namespace Class SWIFT_PRIVATE_ATTR SWIFT_SYMBOL_MODULE("Class") { -// CHECK: SWIFT_INLINE_THUNK ClassWithIntField passThroughClassWithIntField(const ClassWithIntField& x) noexcept SWIFT_SYMBOL("s:5Class011passThroughA12WithIntFieldyAA0adeF0CADF") SWIFT_WARN_UNUSED_RESULT { -// CHECK-NEXT: return _impl::_impl_ClassWithIntField::makeRetained(_impl::$s5Class011passThroughA12WithIntFieldyAA0adeF0CADF(::swift::_impl::_impl_RefCountedClass::getOpaquePointer(x))); -// CHECK-NEXT: } - public final class register { } // CHECK: class SWIFT_SYMBOL("s:5Class8registerC") register_ final : public swift::_impl::RefCountedClass { +// CHECK: SWIFT_INLINE_THUNK ClassWithIntField passThroughClassWithIntField(const ClassWithIntField& x) noexcept SWIFT_SYMBOL("s:5Class011passThroughA12WithIntFieldyAA0adeF0CADF") SWIFT_WARN_UNUSED_RESULT { +// CHECK-NEXT: return _impl::_impl_ClassWithIntField::makeRetained(_impl::$s5Class011passThroughA12WithIntFieldyAA0adeF0CADF(::swift::_impl::_impl_RefCountedClass::getOpaquePointer(x))); +// CHECK-NEXT: } + public func returnClassWithIntField() -> ClassWithIntField { return ClassWithIntField() } diff --git a/test/Interop/SwiftToCxx/functions/swift-operators.swift b/test/Interop/SwiftToCxx/functions/swift-operators.swift index 662b7f07875db..af9de28907042 100644 --- a/test/Interop/SwiftToCxx/functions/swift-operators.swift +++ b/test/Interop/SwiftToCxx/functions/swift-operators.swift @@ -2,9 +2,7 @@ // RUN: %target-swift-frontend %s -typecheck -module-name Operators -clang-header-expose-decls=all-public -emit-clang-header-path %t/operators.h // RUN: %FileCheck %s < %t/operators.h -// TODO: %check-interop-cxx-header-in-clang(%t/operators.h) -// unfortunately the header still triggers an error: -// error: no member named '_impl_IntBox' in namespace 'Operators::_impl' +// RUN: %check-interop-cxx-header-in-clang(%t/operators.h) // CHECK-LABEL: namespace Operators SWIFT_PRIVATE_ATTR SWIFT_SYMBOL_MODULE("Operators") { From c20ef6de2ac36f967deac6939bc57a7799328ac2 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Thu, 13 Jun 2024 09:34:43 -0700 Subject: [PATCH 118/165] Remove RemoteInspection code to fetch no-longer-used reflection metadata without relying on spare bit information in the reflection metadata (which was added in #40906). As a result, we can remove the code from #40906. This is the first step in such removal. It removes the RemoteMirror code for looking up such metadata. It leaves behind: * Sufficient stubs for LLDB to continue to build. Once LLDB is updated, these stubs can be removed as well. * The compiler code to emit such metadata. This allows new binaries to still reflect MPEs on older runtimes. This will need to be kept for a transitional period. --- .../swift/RemoteInspection/DescriptorFinder.h | 28 ++-- include/swift/RemoteInspection/Records.h | 105 ------------- .../RemoteInspection/ReflectionContext.h | 27 +--- .../llvm/BinaryFormat/Swift.def | 1 - .../swift/RemoteInspection/TypeRefBuilder.h | 38 +---- .../public/RemoteInspection/TypeLowering.cpp | 2 - .../RemoteInspection/TypeRefBuilder.cpp | 142 ------------------ .../SwiftRemoteMirror/SwiftRemoteMirror.cpp | 2 - .../SwiftShims/swift/shims/MetadataSections.h | 1 - stdlib/public/runtime/SwiftRT-COFF.cpp | 2 - stdlib/public/runtime/SwiftRT-ELF-WASM.cpp | 2 - 11 files changed, 25 insertions(+), 325 deletions(-) diff --git a/include/swift/RemoteInspection/DescriptorFinder.h b/include/swift/RemoteInspection/DescriptorFinder.h index 9335474be6fbb..96508c40304af 100644 --- a/include/swift/RemoteInspection/DescriptorFinder.h +++ b/include/swift/RemoteInspection/DescriptorFinder.h @@ -93,26 +93,31 @@ struct FieldDescriptorBase { getFieldRecords() = 0; }; +// There are no longer any clients of this interface, but we +// need to keep this stubbed out until all the +// implementors have been removed. In particular, LLDB +// still implements this interface. +// TODO: Delete this after Swift 6.0 ships struct MultiPayloadEnumDescriptorBase { - virtual ~MultiPayloadEnumDescriptorBase(){}; + virtual ~MultiPayloadEnumDescriptorBase(){ abort(); }; - virtual llvm::StringRef getMangledTypeName() = 0; - - virtual uint32_t getContentsSizeInWords() const = 0; + virtual llvm::StringRef getMangledTypeName() { abort(); }; - virtual size_t getSizeInBytes() const = 0; + virtual uint32_t getContentsSizeInWords() const { abort(); }; - virtual uint32_t getFlags() const = 0; + virtual size_t getSizeInBytes() const { abort(); }; - virtual bool usesPayloadSpareBits() const = 0; + virtual uint32_t getFlags() const { abort(); }; - virtual uint32_t getPayloadSpareBitMaskByteOffset() const = 0; + virtual bool usesPayloadSpareBits() const { abort(); }; - virtual uint32_t getPayloadSpareBitMaskByteCount() const = 0; + virtual uint32_t getPayloadSpareBitMaskByteOffset() const { abort(); }; - virtual const uint8_t *getPayloadSpareBits() const = 0; + virtual uint32_t getPayloadSpareBitMaskByteCount() const { abort(); }; + virtual const uint8_t *getPayloadSpareBits() const { abort(); }; }; + /// Interface for finding type descriptors. Implementors may provide descriptors /// that live inside or outside reflection metadata. struct DescriptorFinder { @@ -125,8 +130,9 @@ struct DescriptorFinder { virtual std::unique_ptr getFieldDescriptor(const TypeRef *TR) = 0; + // TODO: Delete this as soon as LLDB no longer attempts to override it virtual std::unique_ptr - getMultiPayloadEnumDescriptor(const TypeRef *TR) = 0; + getMultiPayloadEnumDescriptor(const TypeRef *TR) { abort(); }; }; } // namespace reflection diff --git a/include/swift/RemoteInspection/Records.h b/include/swift/RemoteInspection/Records.h index aa08ce3ef5b6d..1c0ceeb976257 100644 --- a/include/swift/RemoteInspection/Records.h +++ b/include/swift/RemoteInspection/Records.h @@ -378,111 +378,6 @@ class BuiltinTypeDescriptor { } }; -class MultiPayloadEnumDescriptor { -public: - const RelativeDirectPointer TypeName; - -private: - // This descriptor contains a series of 32-bit words - uint32_t contents[]; - - // Properties are stored in `contents` at particular indexes: - - // uint32_t SizeFlags; - // Upper 16 bits are the size of the contents (in 32-bit words): - // (This allows us to expand this structure in the future; - // new fields should have accessors that test whether the - // size is large enough and return "non-existent" if the - // descriptor isn't large enough to have that field.) - // Lower 16 bits are flag bits - - int getSizeFlagsIndex() const { return 0; } - - // uint32_t PayloadSpareBitMaskByteOffsetCount; - // Number of bytes in "payload spare bits", and - // offset of them within the payload area - // Only present if `usePayloadSpareBits()` - - int getPayloadSpareBitMaskByteCountIndex() const { - return getSizeFlagsIndex() + 1; - } - - // uint8_t *PayloadSpareBits; - // Variably-sized bitmask field (padded to a multiple of 4 bytes) - // Only present if `usePayloadSpareBits()` - - int getPayloadSpareBitsIndex() const { - int PayloadSpareBitMaskByteCountFieldSize = usesPayloadSpareBits() ? 1 : 0; - return getPayloadSpareBitMaskByteCountIndex() + PayloadSpareBitMaskByteCountFieldSize; - } - - // uint32_t foo; - // TODO: Some future field - // int getFooIndex() const { - // int PayloadSpareBitMaskFieldSize = (getPayloadSpareBitMaskByteCount() + 3) / 4; - // return getPayloadSpareBitsIndex() + PayloadSpareBitMaskFieldSize; - // } - - // uint32_t getFoo() const { - // if (getFooIndex() < getContentsSizeInWords()) { - // return contents[getFooIndex()]; - // } else { - // return 0; // Field isn't present - // } - // } - -public: - // - // Data derived from the above... - // - - uint32_t getContentsSizeInWords() const { - return contents[getSizeFlagsIndex()] >> 16; - } - - size_t getSizeInBytes() const { -// assert(getContentsSizeInWords() > 0 && "Malformed MPEnum reflection record"); - size_t sizeInBytes = sizeof(TypeName) + getContentsSizeInWords() * 4; - return sizeInBytes; - } - - uint32_t getFlags() const { - assert(getContentsSizeInWords() > 0 && "Malformed MPEnum reflection record"); - return contents[getSizeFlagsIndex()] & 0xffff; - } - - bool usesPayloadSpareBits() const { - return getFlags() & 1; - } - - uint32_t getPayloadSpareBitMaskByteOffset() const { - if (usesPayloadSpareBits()) { - return contents[getPayloadSpareBitMaskByteCountIndex()] >> 16; - } else { - return 0; - } - } - - uint32_t getPayloadSpareBitMaskByteCount() const { - if (usesPayloadSpareBits()) { - auto byteCount = contents[getPayloadSpareBitMaskByteCountIndex()] & 0xffff; - assert(getContentsSizeInWords() >= 2 + (byteCount + 3) / 4 - && "Malformed MPEnum reflection record: mask bigger than record"); - return byteCount; - } else { - return 0; - } - } - - const uint8_t *getPayloadSpareBits() const { - if (usesPayloadSpareBits()) { - return reinterpret_cast(&contents[getPayloadSpareBitsIndex()]); - } else { - return nullptr; - } - } -}; - class CaptureTypeRecord { public: const RelativeDirectPointer MangledTypeName; diff --git a/include/swift/RemoteInspection/ReflectionContext.h b/include/swift/RemoteInspection/ReflectionContext.h index e2384813ab4d7..8b0f109483251 100644 --- a/include/swift/RemoteInspection/ReflectionContext.h +++ b/include/swift/RemoteInspection/ReflectionContext.h @@ -335,8 +335,6 @@ class ReflectionContext ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr)); auto ConformMdSec = findMachOSectionByName( ObjectFileFormat.getSectionName(ReflectionSectionKind::conform)); - auto MPEnumMdSec = findMachOSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::mpenum)); if (FieldMdSec.first == nullptr && AssocTySec.first == nullptr && @@ -344,8 +342,7 @@ class ReflectionContext CaptureSec.first == nullptr && TypeRefMdSec.first == nullptr && ReflStrMdSec.first == nullptr && - ConformMdSec.first == nullptr && - MPEnumMdSec.first == nullptr) + ConformMdSec.first == nullptr) return {}; ReflectionInfo info = {{FieldMdSec.first, FieldMdSec.second}, @@ -355,7 +352,6 @@ class ReflectionContext {TypeRefMdSec.first, TypeRefMdSec.second}, {ReflStrMdSec.first, ReflStrMdSec.second}, {ConformMdSec.first, ConformMdSec.second}, - {MPEnumMdSec.first, MPEnumMdSec.second}, PotentialModuleNames}; auto InfoID = this->addReflectionInfo(info); @@ -470,8 +466,6 @@ class ReflectionContext ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr)); auto ConformMdSec = findCOFFSectionByName( ObjectFileFormat.getSectionName(ReflectionSectionKind::conform)); - auto MPEnumMdSec = findCOFFSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::mpenum)); if (FieldMdSec.first == nullptr && AssocTySec.first == nullptr && @@ -479,8 +473,7 @@ class ReflectionContext CaptureSec.first == nullptr && TypeRefMdSec.first == nullptr && ReflStrMdSec.first == nullptr && - ConformMdSec.first == nullptr && - MPEnumMdSec.first == nullptr) + ConformMdSec.first == nullptr) return {}; ReflectionInfo Info = {{FieldMdSec.first, FieldMdSec.second}, @@ -490,7 +483,6 @@ class ReflectionContext {TypeRefMdSec.first, TypeRefMdSec.second}, {ReflStrMdSec.first, ReflStrMdSec.second}, {ConformMdSec.first, ConformMdSec.second}, - {MPEnumMdSec.first, MPEnumMdSec.second}, PotentialModuleNames}; return this->addReflectionInfo(Info); } @@ -687,9 +679,6 @@ class ReflectionContext ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr), true); auto ConformMdSec = findELFSectionByName( ObjectFileFormat.getSectionName(ReflectionSectionKind::conform), true); - auto MPEnumMdSec = findELFSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::mpenum), true); - if (Error) return {}; @@ -699,7 +688,7 @@ class ReflectionContext // ELF executable. if (FieldMdSec.first || AssocTySec.first || BuiltinTySec.first || CaptureSec.first || TypeRefMdSec.first || ReflStrMdSec.first || - ConformMdSec.first || MPEnumMdSec.first) { + ConformMdSec.first) { ReflectionInfo info = {{FieldMdSec.first, FieldMdSec.second}, {AssocTySec.first, AssocTySec.second}, {BuiltinTySec.first, BuiltinTySec.second}, @@ -707,7 +696,6 @@ class ReflectionContext {TypeRefMdSec.first, TypeRefMdSec.second}, {ReflStrMdSec.first, ReflStrMdSec.second}, {ConformMdSec.first, ConformMdSec.second}, - {MPEnumMdSec.first, MPEnumMdSec.second}, PotentialModuleNames}; result = this->addReflectionInfo(info); } @@ -730,15 +718,13 @@ class ReflectionContext ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr), false); ConformMdSec = findELFSectionByName( ObjectFileFormat.getSectionName(ReflectionSectionKind::conform), false); - MPEnumMdSec = findELFSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::mpenum), false); if (Error) return {}; if (FieldMdSec.first || AssocTySec.first || BuiltinTySec.first || CaptureSec.first || TypeRefMdSec.first || ReflStrMdSec.first || - ConformMdSec.first || MPEnumMdSec.first) { + ConformMdSec.first) { ReflectionInfo info = {{FieldMdSec.first, FieldMdSec.second}, {AssocTySec.first, AssocTySec.second}, {BuiltinTySec.first, BuiltinTySec.second}, @@ -746,7 +732,6 @@ class ReflectionContext {TypeRefMdSec.first, TypeRefMdSec.second}, {ReflStrMdSec.first, ReflStrMdSec.second}, {ConformMdSec.first, ConformMdSec.second}, - {MPEnumMdSec.first, MPEnumMdSec.second}, PotentialModuleNames}; auto rid = this->addReflectionInfo(info); if (!result) @@ -861,7 +846,8 @@ class ReflectionContext ReflectionSectionKind::fieldmd, ReflectionSectionKind::assocty, ReflectionSectionKind::builtin, ReflectionSectionKind::capture, ReflectionSectionKind::typeref, ReflectionSectionKind::reflstr, - ReflectionSectionKind::conform, ReflectionSectionKind::mpenum}; + ReflectionSectionKind::conform + }; llvm::SmallVector, uint64_t>, 6> Pairs; for (auto Section : Sections) { @@ -887,7 +873,6 @@ class ReflectionContext {Pairs[4].first, Pairs[4].second}, {Pairs[5].first, Pairs[5].second}, {Pairs[6].first, Pairs[6].second}, - {Pairs[7].first, Pairs[7].second}, PotentialModuleNames}; return addReflectionInfo(Info); } diff --git a/include/swift/RemoteInspection/RuntimeHeaders/llvm/BinaryFormat/Swift.def b/include/swift/RemoteInspection/RuntimeHeaders/llvm/BinaryFormat/Swift.def index 05b60e40632cd..1ea0bc548b37e 100644 --- a/include/swift/RemoteInspection/RuntimeHeaders/llvm/BinaryFormat/Swift.def +++ b/include/swift/RemoteInspection/RuntimeHeaders/llvm/BinaryFormat/Swift.def @@ -30,4 +30,3 @@ HANDLE_SWIFT_SECTION(protocs, "__swift5_protos", "swift5_protocols", ".sw5prt$B") HANDLE_SWIFT_SECTION(acfuncs, "__swift5_acfuncs", "swift5_accessible_functions", ".sw5acfn$B") -HANDLE_SWIFT_SECTION(mpenum, "__swift5_mpenum", "swift5_mpenum", ".sw5mpen$B") diff --git a/include/swift/RemoteInspection/TypeRefBuilder.h b/include/swift/RemoteInspection/TypeRefBuilder.h index 0a98b782d05c2..b787b8522ded5 100644 --- a/include/swift/RemoteInspection/TypeRefBuilder.h +++ b/include/swift/RemoteInspection/TypeRefBuilder.h @@ -231,21 +231,6 @@ class CaptureDescriptorIterator }; using CaptureSection = ReflectionSection; -class MultiPayloadEnumDescriptorIterator - : public ReflectionSectionIteratorBase { -public: - MultiPayloadEnumDescriptorIterator(RemoteRef Cur, uint64_t Size) - : ReflectionSectionIteratorBase(Cur, Size, "MultiPayloadEnum") {} - - static uint64_t - getCurrentRecordSize(RemoteRef MPER) { - return MPER->getSizeInBytes(); - } -}; -using MultiPayloadEnumSection = - ReflectionSection; - using GenericSection = ReflectionSection; struct ReflectionInfo { @@ -256,7 +241,6 @@ struct ReflectionInfo { GenericSection TypeReference; GenericSection ReflectionString; GenericSection Conformance; - MultiPayloadEnumSection MultiPayloadEnum; llvm::SmallVector PotentialModuleNames; }; @@ -490,10 +474,6 @@ class TypeRefBuilder { /// Get the unsubstituted capture types for a closure context. ClosureContextInfo getClosureContextInfo(RemoteRef CD); - /// Get the multipayload enum projection information for a given TR - std::unique_ptr - getMultiPayloadEnumDescriptor(const TypeRef *TR) override; - const TypeRef *lookupTypeWitness(const std::string &MangledTypeName, const std::string &Member, StringRef Protocol); @@ -516,8 +496,6 @@ class TypeRefBuilder { /// Load unsubstituted field types for a nominal type. RemoteRef getFieldTypeInfo(const TypeRef *TR); - RemoteRef getMultiPayloadEnumInfo(const TypeRef *TR); - void populateFieldTypeInfoCacheWithReflectionAtIndex(size_t Index); std::optional> @@ -567,8 +545,7 @@ class TypeRefBuilder { public: /// - /// Dumping typerefs, field declarations, builtin types, captures, - /// multi-payload enums + /// Dumping typerefs, field declarations, builtin types, captures /// void dumpTypeRef(RemoteRef MangledName, std::ostream &stream, bool printTypeName = false); @@ -577,7 +554,6 @@ class TypeRefBuilder { void dumpFieldSection(std::ostream &stream); void dumpBuiltinTypeSection(std::ostream &stream); void dumpCaptureSection(std::ostream &stream); - void dumpMultiPayloadEnumSection(std::ostream &stream); template