diff --git a/SwiftCompilerSources/Sources/SIL/Function.swift b/SwiftCompilerSources/Sources/SIL/Function.swift
index a66e487c7aa3e..ae9f149d63a7d 100644
--- a/SwiftCompilerSources/Sources/SIL/Function.swift
+++ b/SwiftCompilerSources/Sources/SIL/Function.swift
@@ -147,7 +147,7 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
case .IsNotSerialized: return .notSerialized
case .IsSerialized: return .serialized
case .IsSerializedForPackage: return .serializedForPackage
- default: fatalError()
+ @unknown default: fatalError()
}
}
@@ -156,7 +156,6 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
case .notSerialized: return .IsNotSerialized
case .serialized: return .IsSerialized
case .serializedForPackage: return .IsSerializedForPackage
- default: fatalError()
}
}
diff --git a/benchmark/single-source/CharacterRecognizer.swift b/benchmark/single-source/CharacterRecognizer.swift
index 8662291cb9ec6..13017e2634f95 100644
--- a/benchmark/single-source/CharacterRecognizer.swift
+++ b/benchmark/single-source/CharacterRecognizer.swift
@@ -13,7 +13,7 @@
import TestsUtils
public var benchmarks: [BenchmarkInfo] {
- guard #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) else {
+ guard #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) else {
return []
}
return [
@@ -82,7 +82,7 @@ let _asciiString = #"""
"""#
let asciiString = String(repeating: _asciiString, count: 10)
-@available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
+@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
func run(string: String, n: Int) {
var state = Unicode._CharacterRecognizer()
var c = 0
diff --git a/benchmark/single-source/StringTests.swift b/benchmark/single-source/StringTests.swift
index 9fa313c73208f..bcc43a2633777 100644
--- a/benchmark/single-source/StringTests.swift
+++ b/benchmark/single-source/StringTests.swift
@@ -14,36 +14,43 @@ import TestsUtils
@_spi(_Unicode)
import Swift
-public let benchmarks = [
- BenchmarkInfo(
- name: "StringEqualPointerComparison",
- runFunction: run_StringEqualPointerComparison,
- tags: [.validation, .api, .String]),
- BenchmarkInfo(
- name: "StringHasPrefixAscii",
- runFunction: run_StringHasPrefixAscii,
- tags: [.validation, .api, .String],
- legacyFactor: 10),
- BenchmarkInfo(
- name: "StringHasPrefixUnicode",
- runFunction: run_StringHasPrefixUnicode,
- tags: [.validation, .api, .String],
- legacyFactor: 1000),
- BenchmarkInfo(
- name: "StringHasSuffixAscii",
- runFunction: run_StringHasSuffixAscii,
- tags: [.validation, .api, .String],
- legacyFactor: 10),
- BenchmarkInfo(
- name: "StringHasSuffixUnicode",
- runFunction: run_StringHasSuffixUnicode,
- tags: [.validation, .api, .String],
- legacyFactor: 1000),
- BenchmarkInfo(
- name: "StringIterateWords",
- runFunction: run_iterateWords,
- tags: [.validation, .String]),
-]
+public var benchmarks: [BenchmarkInfo] {
+ var result = [
+ BenchmarkInfo(
+ name: "StringEqualPointerComparison",
+ runFunction: run_StringEqualPointerComparison,
+ tags: [.validation, .api, .String]),
+ BenchmarkInfo(
+ name: "StringHasPrefixAscii",
+ runFunction: run_StringHasPrefixAscii,
+ tags: [.validation, .api, .String],
+ legacyFactor: 10),
+ BenchmarkInfo(
+ name: "StringHasPrefixUnicode",
+ runFunction: run_StringHasPrefixUnicode,
+ tags: [.validation, .api, .String],
+ legacyFactor: 1000),
+ BenchmarkInfo(
+ name: "StringHasSuffixAscii",
+ runFunction: run_StringHasSuffixAscii,
+ tags: [.validation, .api, .String],
+ legacyFactor: 10),
+ BenchmarkInfo(
+ name: "StringHasSuffixUnicode",
+ runFunction: run_StringHasSuffixUnicode,
+ tags: [.validation, .api, .String],
+ legacyFactor: 1000),
+ ]
+
+ if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) {
+ result.append(
+ BenchmarkInfo(
+ name: "StringIterateWords",
+ runFunction: run_iterateWords,
+ tags: [.validation, .String]))
+ }
+ return result
+}
// FIXME(string)
public func run_StringHasPrefixAscii(_ n: Int) {
@@ -1644,11 +1651,8 @@ architecture on Linux.
extension String {
@inline(never)
- @available(SwiftStdlib 5.9, *)
+ @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
var _words: [Substring] {
- guard #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *) else {
- fatalError("Can't run this benchmark")
- }
var result: [Substring] = []
var i = startIndex
@@ -1666,6 +1670,7 @@ extension String {
}
}
+@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
public func run_iterateWords(_ n: Int) {
for _ in 0 ..< n {
blackHole(swiftOrgHTML._words)
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
diff --git a/docs/EmbeddedSwift/ABI.md b/docs/EmbeddedSwift/ABI.md
new file mode 100644
index 0000000000000..d7046239ceef6
--- /dev/null
+++ b/docs/EmbeddedSwift/ABI.md
@@ -0,0 +1,37 @@
+# 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.
+
+## 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:
+
+- 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.
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..e7e12012cb52f 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)
+- (4) Post-processing the linked firmware into a flashable format (UF2, 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
@@ -41,7 +41,7 @@ $ swiftc -target -enable-experimental-feature Embedded -wmo \
### Building Swift firmware for an embedded target
-To build Swift firmware (for now ingnoring integration with SDKs, libraries and other pre-existing C code), we can use the `-target` argument to specify the CPU architecture. The target triple also decides whether the output object file will be an ELF file, or a Mach-O. For example:
+To build Swift firmware (for now ignoring integration with SDKs, libraries and other pre-existing C code), we can use the `-target` argument to specify the CPU architecture. The target triple also decides whether the output object file will be an ELF file, or a Mach-O. For example:
```bash
# To build an ARMv7 Mach-O object file:
@@ -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,58 @@ 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
+- 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)
+- 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 +185,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 stringification of arbitrary types (achieved 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 +210,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.
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
```
diff --git a/include/swift/ABI/Executor.h b/include/swift/ABI/Executor.h
index d7769211b0d43..95dc3c660ffa2 100644
--- a/include/swift/ABI/Executor.h
+++ b/include/swift/ABI/Executor.h
@@ -260,12 +260,6 @@ class TaskExecutorRef {
return reinterpret_cast(table);
}
-// /// Do we have to do any work to start running as the requested
-// /// executor?
-// bool mustSwitchToRun(TaskExecutorRef newExecutor) const {
-// return Identity != newExecutor.Identity;
-// }
-
/// Get the raw value of the Implementation field, for tracing.
uintptr_t getRawImplementation() const {
return Implementation & WitnessTableMask;
diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h
index edd1ccfd5f932..3fdc23fb5f2e9 100644
--- a/include/swift/ABI/MetadataValues.h
+++ b/include/swift/ABI/MetadataValues.h
@@ -2697,7 +2697,8 @@ enum class TaskOptionRecordKind : uint8_t {
/// Information about the result type of the task, used in embedded Swift.
ResultTypeInfo = 4,
/// Set the initial task executor preference of the task.
- InitialTaskExecutor = 5,
+ InitialTaskExecutorUnowned = 5,
+ InitialTaskExecutorOwned = 6,
/// Request a child task for swift_task_run_inline.
RunInline = UINT8_MAX,
};
diff --git a/include/swift/ABI/Task.h b/include/swift/ABI/Task.h
index 4ef2550b8ca3e..1cefd0f45077d 100644
--- a/include/swift/ABI/Task.h
+++ b/include/swift/ABI/Task.h
@@ -419,12 +419,16 @@ class AsyncTask : public Job {
/// Get the preferred task executor reference if there is one set for this
/// task.
- TaskExecutorRef getPreferredTaskExecutor();
+ TaskExecutorRef getPreferredTaskExecutor(bool assumeHasRecord = false);
/// WARNING: Only to be used during task creation, in other situations prefer
/// to use `swift_task_pushTaskExecutorPreference` and
/// `swift_task_popTaskExecutorPreference`.
- void pushInitialTaskExecutorPreference(TaskExecutorRef preferred);
+ ///
+ /// The `owned` parameter indicates if the executor is owned by the task,
+ /// and must be released when the task completes.
+ void pushInitialTaskExecutorPreference(
+ TaskExecutorRef preferred, bool owned);
/// WARNING: Only to be used during task completion (destroy).
///
diff --git a/include/swift/ABI/TaskOptions.h b/include/swift/ABI/TaskOptions.h
index 96cc3d88e6bc4..39775009bef4d 100644
--- a/include/swift/ABI/TaskOptions.h
+++ b/include/swift/ABI/TaskOptions.h
@@ -77,23 +77,58 @@ class TaskGroupTaskOptionRecord : public TaskOptionRecord {
/// Task option to specify on what executor the task should be executed.
///
-/// Not passing this option implies that an inferred (e.g. surrounding actor
-/// when we inherit execution context) or the default executor should be used.
+/// Not passing this option (or it's alternative "owned" version) implies that
+/// an inferred (e.g. surrounding actor when we inherit execution context)
+/// or the default executor should be used.
///
/// Lack of this option usually means that the global concurrent executor, or
/// the executor of the enclosing actor will be used.
-class InitialTaskExecutorPreferenceTaskOptionRecord : public TaskOptionRecord {
+class InitialTaskExecutorRefPreferenceTaskOptionRecord : public TaskOptionRecord {
const TaskExecutorRef Executor;
public:
- InitialTaskExecutorPreferenceTaskOptionRecord(TaskExecutorRef executor)
- : TaskOptionRecord(TaskOptionRecordKind::InitialTaskExecutor),
+ InitialTaskExecutorRefPreferenceTaskOptionRecord(TaskExecutorRef executor)
+ : TaskOptionRecord(TaskOptionRecordKind::InitialTaskExecutorUnowned),
Executor(executor) {}
TaskExecutorRef getExecutorRef() const { return Executor; }
static bool classof(const TaskOptionRecord *record) {
- return record->getKind() == TaskOptionRecordKind::InitialTaskExecutor;
+ return record->getKind() == TaskOptionRecordKind::InitialTaskExecutorUnowned;
+ }
+};
+
+/// This is quite similar to `InitialTaskExecutorRefPreferenceTaskOptionRecord`
+/// however it takes a "raw" TaskExecutor existential in the form of an Identity
+/// and WitnessTable - rather than the specific UnownedTaskExecutor which already
+/// may have specific "flags" set on it.
+///
+/// In order to use the executor in the runtime, we need to call into the type's
+/// `asUnownedTaskExecutor` which is done by
+/// `getExecutorRefFromUnownedTaskExecutor`.
+class InitialTaskExecutorOwnedPreferenceTaskOptionRecord
+ : public TaskOptionRecord {
+
+ // These look similar to TaskExecutorRef but are NOT the same!
+ // A TaskExecutorRef is obtained through calling user defined
+ // `asUnownedTaskExecutor` which is what we need to do on these to get a real executor ref.
+ HeapObject *Identity;
+ const TaskExecutorWitnessTable *WitnessTable;
+
+public:
+ InitialTaskExecutorOwnedPreferenceTaskOptionRecord(
+ HeapObject *executor, uintptr_t witnessTable)
+ : TaskOptionRecord(TaskOptionRecordKind::InitialTaskExecutorOwned),
+ Identity(executor) {
+ WitnessTable = reinterpret_cast(witnessTable);
+ }
+
+ /// Invokes Swift implemented `asUnownedTaskExecutor` in order to obtain an
+ /// `TaskExecutorRef` which is properly populated with any flags it might need.
+ TaskExecutorRef getExecutorRefFromUnownedTaskExecutor() const;
+
+ static bool classof(const TaskOptionRecord *record) {
+ return record->getKind() == TaskOptionRecordKind::InitialTaskExecutorOwned;
}
};
diff --git a/include/swift/ABI/TaskStatus.h b/include/swift/ABI/TaskStatus.h
index 88702002189cf..5c3a38932baba 100644
--- a/include/swift/ABI/TaskStatus.h
+++ b/include/swift/ABI/TaskStatus.h
@@ -20,6 +20,7 @@
#ifndef SWIFT_ABI_TASKSTATUS_H
#define SWIFT_ABI_TASKSTATUS_H
+#include "swift/Basic/OptionSet.h"
#include "swift/ABI/MetadataValues.h"
#include "swift/ABI/Task.h"
#include "swift/ABI/Executor.h"
@@ -285,15 +286,35 @@ class EscalationNotificationStatusRecord : public TaskStatusRecord {
/// innermost preference takes priority.
class TaskExecutorPreferenceStatusRecord : public TaskStatusRecord {
private:
+ enum class Flags : uint8_t {
+ /// The executor was retained during this task's creation,
+ /// and therefore must be released when this task completes.
+ ///
+ /// The only tasks which need to manually retain/release the task executor
+ /// are those which cannot structurally guarantee its lifetime. E.g. an async
+ /// let does not need to do so, because it structurally always will end
+ /// before/// we leave the scope in which it was defined -- and such scope
+ /// must have been keeping alive the executor.
+ HasRetainedExecutor = 1 << 0
+ };
+ OptionSet flags;
const TaskExecutorRef Preferred;
public:
- TaskExecutorPreferenceStatusRecord(TaskExecutorRef executor)
+ TaskExecutorPreferenceStatusRecord(TaskExecutorRef executor, bool retainedExecutor)
: TaskStatusRecord(TaskStatusRecordKind::TaskExecutorPreference),
- Preferred(executor) {}
+ Preferred(executor) {
+ if (retainedExecutor) {
+ flags = Flags::HasRetainedExecutor;
+ }
+ }
TaskExecutorRef getPreferredExecutor() { return Preferred; }
+ bool hasRetainedExecutor() const {
+ return flags.contains(Flags::HasRetainedExecutor);
+ }
+
static bool classof(const TaskStatusRecord *record) {
return record->getKind() == TaskStatusRecordKind::TaskExecutorPreference;
}
diff --git a/include/swift/AST/ASTSynthesis.h b/include/swift/AST/ASTSynthesis.h
index 6605cff3959cb..5ca157ff1de00 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) {
@@ -77,11 +78,17 @@ inline Type synthesizeType(SynthesisContext &SC,
return SC.Context.getProtocol(KnownProtocolKind::SerialExecutor)
->getDeclaredInterfaceType();
case _taskExecutor:
- return SC.Context.getProtocol(KnownProtocolKind::TaskExecutor)
- ->getDeclaredInterfaceType();
+ if (auto ty = SC.Context.getProtocol(KnownProtocolKind::TaskExecutor)) {
+ return ty->getDeclaredInterfaceType();
+ } else {
+ return nullptr;
+ }
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();
@@ -171,6 +178,28 @@ Type synthesizeType(SynthesisContext &SC,
return ExistentialType::get(synthesizeType(SC, M.Sub));
}
+/// A synthesizer which generates an existential type from a requirement type.
+template
+struct BincompatIfTypeAvailableTypeSynthesizer {
+ bool condition;
+ S Sub;
+ FallbackS FallbackSub;
+};
+template
+constexpr BincompatIfTypeAvailableTypeSynthesizer _bincompatType(
+ bool bincompatCondition, S sub, FallbackS fallbackSub) {
+ return {bincompatCondition, sub, {fallbackSub}};
+}
+template
+Type synthesizeType(SynthesisContext &SC,
+ const BincompatIfTypeAvailableTypeSynthesizer &M) {
+ if (M.condition) {
+ return synthesizeType(SC, M.Sub);
+ } else {
+ return synthesizeType(SC, M.FallbackSub);
+ }
+}
+
MetatypeRepresentation
inline synthesizeMetatypeRepresentation(RepresentationSynthesizer rep) {
switch (rep) {
@@ -328,6 +357,10 @@ constexpr SpecifiedParamSynthesizer _owned(G sub) {
return {ParamSpecifier::LegacyOwned, sub};
}
template
+constexpr SpecifiedParamSynthesizer _consuming(G sub) {
+ return {ParamSpecifier::Consuming, sub};
+}
+template
constexpr SpecifiedParamSynthesizer _inout(G sub) {
return {ParamSpecifier::InOut, sub};
}
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/Builtins.def b/include/swift/AST/Builtins.def
index 6d4a8de8651e9..e654093a59e68 100644
--- a/include/swift/AST/Builtins.def
+++ b/include/swift/AST/Builtins.def
@@ -899,6 +899,25 @@ 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) -> (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
+/// initialized at this point. 'actor' is always an alias for the 'self'
+/// 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/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 2cf21b7d82ddc..123f8362e1dfd 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 "
@@ -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,
@@ -3644,48 +3649,43 @@ ERROR(decl_from_hidden_module,none,
"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; "
+ "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|"
"%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|"
"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 "
+ "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|"
"<>|"
"%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|"
"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|"
"%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))
@@ -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", ())
@@ -5763,8 +5766,12 @@ ERROR(any_not_existential,none,
"'any' has no effect on %select{concrete type|type parameter}0 %1",
(bool, Type))
ERROR(incorrect_optional_any,none,
- "optional 'any' type must be written %0",
- (Type))
+ "using '!' is not allowed here; perhaps '?' was intended",
+ ())
+
+ERROR(incorrect_iuo_any,none,
+ "force unwrapped 'any' type must be written (%0)!",
+ (StringRef))
ERROR(existential_requires_any,none,
"use of %select{protocol |}2%0 as a type must be written %1",
(Type, Type, bool))
@@ -6920,8 +6927,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,
@@ -6939,8 +6945,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,
@@ -6954,8 +6959,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 "
@@ -7730,8 +7735,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 *))
@@ -7801,6 +7806,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,
@@ -7973,6 +7981,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
@@ -7991,6 +8001,19 @@ ERROR(sending_only_on_parameters_and_results, none,
"'sending' may only be used on parameters and results", ())
ERROR(sending_cannot_be_applied_to_tuple_elt, none,
"'sending' cannot be applied to tuple elements", ())
+ERROR(sending_function_wrong_sending,none,
+ "converting a value of type %0 to type %1 risks causing data races",
+ (Type, Type))
+NOTE(sending_function_param_with_sending_param_note, none,
+ "converting a function typed value with a sending parameter to one "
+ "without risks allowing actor-isolated values to escape their isolation "
+ "domain as an argument to an invocation of value",
+ ())
+NOTE(sending_function_result_with_sending_param_note, none,
+ "converting a function typed value without a sending result as one with "
+ "risks allowing actor-isolated values to escape their "
+ "isolation domain through a result of an invocation of value",
+ ())
#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
diff --git a/include/swift/AST/FeatureAvailability.def b/include/swift/AST/FeatureAvailability.def
index 4c9ccddb20105..b56e651f8abbe 100644
--- a/include/swift/AST/FeatureAvailability.def
+++ b/include/swift/AST/FeatureAvailability.def
@@ -64,12 +64,12 @@ FEATURE(ConcurrencyDiscardingTaskGroup, (5, 9))
FEATURE(ConcurrencyDistributedActorWithCustomExecutor, (5, 9))
FEATURE(SignedDescriptor, (5, 9))
-FEATURE(ObjCSymbolicReferences, (5, 11))
-FEATURE(TypedThrows, (5, 11))
-FEATURE(StaticReadOnlyArrays, (5, 11))
-FEATURE(SwiftExceptionPersonality, (5, 11))
+FEATURE(ObjCSymbolicReferences, (6, 0))
+FEATURE(TypedThrows, (6, 0))
+FEATURE(StaticReadOnlyArrays, (6, 0))
+FEATURE(SwiftExceptionPersonality, (6, 0))
// Metadata support for @isolated(any) function types
-FEATURE(IsolatedAny, (5, 11))
+FEATURE(IsolatedAny, (6, 0))
FEATURE(TaskExecutor, FUTURE)
FEATURE(Differentiation, FUTURE)
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/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/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/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/include/swift/AST/RuntimeVersions.def b/include/swift/AST/RuntimeVersions.def
index 2aa07fee075e3..37e8e59ffc61c 100644
--- a/include/swift/AST/RuntimeVersions.def
+++ b/include/swift/AST/RuntimeVersions.def
@@ -138,12 +138,24 @@ RUNTIME_VERSION(
PLATFORM(xrOS, (1, 0, 0))
)
+END_MAJOR_VERSION(5)
+
+MAJOR_VERSION(6)
+
RUNTIME_VERSION(
- (5, 11),
+ (6, 0),
+ PLATFORM(macOS, (15, 0, 0))
+ PLATFORM(iOS, (18, 0, 0))
+ PLATFORM(watchOS, (11, 0, 0))
+ PLATFORM(xrOS, (2, 0, 0))
+)
+
+RUNTIME_VERSION(
+ (6, 1),
FUTURE
)
-END_MAJOR_VERSION(5)
+END_MAJOR_VERSION(6)
// .......................................................................... //
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/include/swift/AST/Stmt.h b/include/swift/AST/Stmt.h
index 9f3fdb6b68400..0ed93d4078ad9 100644
--- a/include/swift/AST/Stmt.h
+++ b/include/swift/AST/Stmt.h
@@ -1305,7 +1305,9 @@ class CaseStmt final
SourceLoc getStartLoc() const {
if (UnknownAttrLoc.isValid())
return UnknownAttrLoc;
- return getLoc();
+ if (ItemIntroducerLoc.isValid())
+ return ItemIntroducerLoc;
+ return getBody()->getStartLoc();
}
SourceLoc getEndLoc() const { return getBody()->getEndLoc(); }
diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h
index 055003687c791..c67e60e475d1d 100644
--- a/include/swift/AST/Types.h
+++ b/include/swift/AST/Types.h
@@ -3232,6 +3232,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/include/swift/Basic/Features.def b/include/swift/Basic/Features.def
index 9535de9ab727d..60a51092bf8d5 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)
@@ -227,7 +227,7 @@ EXPERIMENTAL_FEATURE(FlowSensitiveConcurrencyCaptures, false)
EXPERIMENTAL_FEATURE(CodeItemMacros, false)
EXPERIMENTAL_FEATURE(PreambleMacros, false)
EXPERIMENTAL_FEATURE(TupleConformances, false)
-EXPERIMENTAL_FEATURE(FullTypedThrows, true)
+EXPERIMENTAL_FEATURE(FullTypedThrows, false)
// Whether to enable @_used and @_section attributes
EXPERIMENTAL_FEATURE(SymbolLinkageMarkers, true)
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/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def
index c16d5d583024b..ea69bf07aea4c 100644
--- a/include/swift/Demangling/DemangleNodes.def
+++ b/include/swift/Demangling/DemangleNodes.def
@@ -164,6 +164,7 @@ NODE(LazyProtocolWitnessTableAccessor)
NODE(LazyProtocolWitnessTableCacheVariable)
NODE(LocalDeclName)
NODE(Macro)
+NODE(MacroExpansionLoc)
NODE(MacroExpansionUniqueName)
CONTEXT_NODE(MaterializeForSet)
NODE(MemberAttachedMacroExpansion)
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/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/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;
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/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/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,
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index 4d382b579de2d..e36b07f375a57 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();
@@ -9160,7 +9162,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..f1af54aa97d91 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.
@@ -868,7 +871,15 @@ 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);
+
+ /// Whether there's a direct wrapper or a wrapper inside a box.
+ bool hasAnyMoveOnlyWrapping(const SILFunction *fn) {
+ 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 20dc42c382149..5dbb3c30e86f0 100644
--- a/include/swift/SIL/SILValue.h
+++ b/include/swift/SIL/SILValue.h
@@ -599,14 +599,9 @@ 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();
- } else {
- assert(Type.isBoxedMoveOnlyWrappedType(fn));
- Type = Type.removingMoveOnlyWrapperToBoxedType(fn);
- }
+ Type = Type.removingAnyMoveOnlyWrapping(fn);
return true;
}
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/include/swift/Sema/CSFix.h b/include/swift/Sema/CSFix.h
index bf418b6a2d21d..d38cfbb499482 100644
--- a/include/swift/Sema/CSFix.h
+++ b/include/swift/Sema/CSFix.h
@@ -471,6 +471,17 @@ enum class FixKind : uint8_t {
/// Ignore situations when key path subscript index gets passed an invalid
/// type as an argument (something that is not a key path).
IgnoreKeyPathSubscriptIndexMismatch,
+
+ /// Ignore the following situations:
+ ///
+ /// 1. Where we have a function that expects a function typed parameter
+ /// without a sendable parameter but is passed a function type with a sending
+ /// parameter.
+ ///
+ /// 2. Where we have a function that expects a function typed parameter with a
+ /// sending result, but is passed a function typeed parameter without a
+ /// sending result.
+ AllowSendingMismatch,
};
class ConstraintFix {
@@ -2619,6 +2630,49 @@ class TreatEphemeralAsNonEphemeral final : public AllowArgumentMismatch {
}
};
+/// Error if a user passes let f: (sending T) -> () as a (T) -> ().
+///
+/// This prevents data races since f assumes its parameter if the parameter is
+/// non-Sendable is safe to transfer onto other situations. The caller though
+/// that this is being sent to does not enforce that invariants within its body.
+class AllowSendingMismatch final : public ContextualMismatch {
+public:
+ enum class Kind {
+ Parameter,
+ Result,
+ };
+
+private:
+ Kind kind;
+
+ AllowSendingMismatch(ConstraintSystem &cs, Type argType, Type paramType,
+ ConstraintLocator *locator, Kind kind,
+ FixBehavior fixBehavior)
+ : ContextualMismatch(cs, FixKind::AllowSendingMismatch, argType,
+ paramType, locator, fixBehavior),
+ kind(kind) {}
+
+public:
+ std::string getName() const override {
+ return "treat a function argument with sending parameter as a function "
+ "argument without sending parameters";
+ }
+
+ bool diagnose(const Solution &solution, bool asNote = false) const override;
+
+ bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
+ return diagnose(*commonFixes.front().first);
+ }
+
+ static AllowSendingMismatch *create(ConstraintSystem &cs,
+ ConstraintLocator *locator, Type srcType,
+ Type dstType, Kind kind);
+
+ static bool classof(const ConstraintFix *fix) {
+ return fix->getKind() == FixKind::AllowSendingMismatch;
+ }
+};
+
class SpecifyBaseTypeForContextualMember final : public ConstraintFix {
DeclNameRef MemberName;
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/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/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp
index ae667d06a5e9c..d5e6754845ecc 100644
--- a/lib/AST/ASTDemangler.cpp
+++ b/lib/AST/ASTDemangler.cpp
@@ -755,36 +755,53 @@ Type ASTBuilder::createExistentialMetatypeType(
Type ASTBuilder::createConstrainedExistentialType(
Type base, ArrayRef constraints,
ArrayRef inverseRequirements) {
- // FIXME: Generalize to other kinds of bases.
- if (!base->getAs())
- return Type();
- auto baseTy = base->castTo();
- auto baseDecl = baseTy->getDecl();
- llvm::SmallDenseMap cmap;
- for (const auto &req : constraints) {
- switch (req.getKind()) {
- case RequirementKind::SameShape:
- llvm_unreachable("Same-shape requirement not supported here");
- case RequirementKind::Conformance:
- case RequirementKind::Superclass:
- case RequirementKind::Layout:
- continue;
+ Type constrainedBase;
+
+ if (auto baseTy = base->getAs()) {
+ auto baseDecl = baseTy->getDecl();
+ llvm::SmallDenseMap cmap;
+ for (const auto &req : constraints) {
+ switch (req.getKind()) {
+ case RequirementKind::SameShape:
+ llvm_unreachable("Same-shape requirement not supported here");
+ case RequirementKind::Conformance:
+ case RequirementKind::Superclass:
+ case RequirementKind::Layout:
+ continue;
- case RequirementKind::SameType:
- if (auto *DMT = req.getFirstType()->getAs())
- cmap[DMT->getName()] = req.getSecondType();
+ case RequirementKind::SameType:
+ if (auto *DMT = req.getFirstType()->getAs())
+ cmap[DMT->getName()] = req.getSecondType();
+ }
}
- }
- llvm::SmallVector args;
- for (auto *assocTy : baseDecl->getPrimaryAssociatedTypes()) {
- auto argTy = cmap.find(assocTy->getName());
- if (argTy == cmap.end()) {
- return Type();
+ llvm::SmallVector args;
+ for (auto *assocTy : baseDecl->getPrimaryAssociatedTypes()) {
+ auto argTy = cmap.find(assocTy->getName());
+ if (argTy == cmap.end()) {
+ return Type();
+ }
+ args.push_back(argTy->getSecond());
+ }
+
+ // We may not have any arguments because the constrained existential is a
+ // plain protocol with an inverse requirement.
+ if (args.empty()) {
+ constrainedBase =
+ ProtocolType::get(baseDecl, baseTy, base->getASTContext());
+ } else {
+ constrainedBase =
+ ParameterizedProtocolType::get(base->getASTContext(), baseTy, args);
}
- args.push_back(argTy->getSecond());
+ } else if (base->isAny()) {
+ // The only other case should be that we got an empty PCT, which is equal to
+ // the Any type. The other constraints should have been encoded in the
+ // existential's generic signature (and arrive as BuiltInverseRequirement).
+ constrainedBase = base;
+ } else {
+ return Type();
}
- Type constrainedBase =
- ParameterizedProtocolType::get(base->getASTContext(), baseTy, args);
+
+ assert(constrainedBase);
// Handle inverse requirements.
if (!inverseRequirements.empty()) {
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 7b22da4ec9a7f..17bdda599a2ec 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -482,21 +482,22 @@ namespace {
raw_ostream &OS;
unsigned Indent;
public:
+ bool ParseIfNeeded;
llvm::function_ref GetTypeOfExpr;
llvm::function_ref GetTypeOfTypeRepr;
llvm::function_ref
GetTypeOfKeyPathComponent;
char quote = '"';
- explicit PrintBase(raw_ostream &os, unsigned indent = 0,
- llvm::function_ref getTypeOfExpr = defaultGetTypeOfExpr,
- llvm::function_ref getTypeOfTypeRepr = nullptr,
- llvm::function_ref
- getTypeOfKeyPathComponent =
- defaultGetTypeOfKeyPathComponent)
- : OS(os), Indent(indent), GetTypeOfExpr(getTypeOfExpr),
- GetTypeOfTypeRepr(getTypeOfTypeRepr),
- GetTypeOfKeyPathComponent(getTypeOfKeyPathComponent) { }
+ explicit PrintBase(
+ raw_ostream &os, unsigned indent = 0, bool parseIfNeeded = false,
+ llvm::function_ref getTypeOfExpr = defaultGetTypeOfExpr,
+ llvm::function_ref getTypeOfTypeRepr = nullptr,
+ llvm::function_ref
+ getTypeOfKeyPathComponent = defaultGetTypeOfKeyPathComponent)
+ : OS(os), Indent(indent), ParseIfNeeded(parseIfNeeded),
+ GetTypeOfExpr(getTypeOfExpr), GetTypeOfTypeRepr(getTypeOfTypeRepr),
+ GetTypeOfKeyPathComponent(getTypeOfKeyPathComponent) {}
bool hasNonStandardOutput() {
return &OS != &llvm::errs() && &OS != &llvm::dbgs();
@@ -1301,7 +1302,9 @@ namespace {
break;
}
- for (Decl *D : IDC->getMembers()) {
+ auto members = ParseIfNeeded ? IDC->getMembers()
+ : IDC->getCurrentMembersWithoutLoading();
+ for (Decl *D : members) {
printRec(D);
}
printFoot();
@@ -1313,7 +1316,9 @@ namespace {
OS << SF.getFilename();
});
- if (auto items = SF.getCachedTopLevelItems()) {
+ auto items =
+ ParseIfNeeded ? SF.getTopLevelItems() : SF.getCachedTopLevelItems();
+ if (items) {
for (auto item : *items) {
if (item.isImplicit())
continue;
@@ -1556,7 +1561,7 @@ namespace {
});
}
- if (auto Body = D->getBody(/*canSynthesize=*/false)) {
+ if (auto Body = D->getBody(/*canSynthesize=*/ParseIfNeeded)) {
printRec(Body, &D->getASTContext());
}
}
@@ -1858,13 +1863,7 @@ void SourceFile::dump() const {
}
void SourceFile::dump(llvm::raw_ostream &OS, bool parseIfNeeded) const {
- // If we're allowed to parse the SourceFile, do so now. We need to force the
- // parsing request as by default the dumping logic tries not to kick any
- // requests.
- if (parseIfNeeded)
- (void)getTopLevelItems();
-
- PrintDecl(OS).visitSourceFile(*this);
+ PrintDecl(OS, /*indent*/ 0, parseIfNeeded).visitSourceFile(*this);
llvm::errs() << '\n';
}
@@ -1889,13 +1888,16 @@ class PrintStmt : public StmtVisitor,
using PrintBase::PrintBase;
const ASTContext *Ctx;
- PrintStmt(raw_ostream &os, const ASTContext *ctx, unsigned indent = 0,
- llvm::function_ref getTypeOfExpr = defaultGetTypeOfExpr,
- llvm::function_ref getTypeOfTypeRepr = nullptr,
- llvm::function_ref
- getTypeOfKeyPathComponent = defaultGetTypeOfKeyPathComponent)
- : PrintBase(os, indent, getTypeOfExpr, getTypeOfTypeRepr,
- getTypeOfKeyPathComponent), Ctx(ctx) { }
+ PrintStmt(
+ raw_ostream &os, const ASTContext *ctx, unsigned indent = 0,
+ bool parseIfNeeded = false,
+ llvm::function_ref getTypeOfExpr = defaultGetTypeOfExpr,
+ llvm::function_ref getTypeOfTypeRepr = nullptr,
+ llvm::function_ref
+ getTypeOfKeyPathComponent = defaultGetTypeOfKeyPathComponent)
+ : PrintBase(os, indent, parseIfNeeded, getTypeOfExpr, getTypeOfTypeRepr,
+ getTypeOfKeyPathComponent),
+ Ctx(ctx) {}
using PrintBase::printRec;
@@ -3259,8 +3261,8 @@ void Expr::dump(raw_ostream &OS, llvm::function_ref getTypeOfExpr,
llvm::function_ref
getTypeOfKeyPathComponent,
unsigned Indent) const {
- PrintExpr(OS, Indent, getTypeOfExpr, getTypeOfTypeRepr,
- getTypeOfKeyPathComponent)
+ PrintExpr(OS, Indent, /*parseIfNeeded*/ false, getTypeOfExpr,
+ getTypeOfTypeRepr, getTypeOfKeyPathComponent)
.visit(const_cast(this), "");
}
@@ -3564,8 +3566,9 @@ void PrintBase::printRec(Decl *D, StringRef label) {
printHead("", DeclColor, label);
printFoot();
} else {
- PrintDecl(OS, Indent, GetTypeOfExpr, GetTypeOfTypeRepr,
- GetTypeOfKeyPathComponent).visit(D, label);
+ PrintDecl(OS, Indent, ParseIfNeeded, GetTypeOfExpr, GetTypeOfTypeRepr,
+ GetTypeOfKeyPathComponent)
+ .visit(D, label);
}
}, label);
}
@@ -3575,8 +3578,9 @@ void PrintBase::printRec(Expr *E, StringRef label) {
printHead("", ExprColor, label);
printFoot();
} else {
- PrintExpr(OS, Indent, GetTypeOfExpr, GetTypeOfTypeRepr,
- GetTypeOfKeyPathComponent).visit(E, label);
+ PrintExpr(OS, Indent, ParseIfNeeded, GetTypeOfExpr, GetTypeOfTypeRepr,
+ GetTypeOfKeyPathComponent)
+ .visit(E, label);
}
}, label);
}
@@ -3586,8 +3590,9 @@ void PrintBase::printRec(Stmt *S, const ASTContext *Ctx, StringRef label) {
printHead("", ExprColor, label);
printFoot();
} else {
- PrintStmt(OS, Ctx, Indent, GetTypeOfExpr, GetTypeOfTypeRepr,
- GetTypeOfKeyPathComponent).visit(S, label);
+ PrintStmt(OS, Ctx, Indent, ParseIfNeeded, GetTypeOfExpr,
+ GetTypeOfTypeRepr, GetTypeOfKeyPathComponent)
+ .visit(S, label);
}
}, label);
}
@@ -3597,8 +3602,9 @@ void PrintBase::printRec(TypeRepr *T, StringRef label) {
printHead("", TypeReprColor, label);
printFoot();
} else {
- PrintTypeRepr(OS, Indent, GetTypeOfExpr, GetTypeOfTypeRepr,
- GetTypeOfKeyPathComponent).visit(T, label);
+ PrintTypeRepr(OS, Indent, ParseIfNeeded, GetTypeOfExpr, GetTypeOfTypeRepr,
+ GetTypeOfKeyPathComponent)
+ .visit(T, label);
}
}, label);
}
@@ -3608,9 +3614,9 @@ void PrintBase::printRec(const Pattern *P, StringRef label) {
printHead("", PatternColor, label);
printFoot();
} else {
- PrintPattern(OS, Indent, GetTypeOfExpr, GetTypeOfTypeRepr,
- GetTypeOfKeyPathComponent).visit(const_cast(P),
- label);
+ PrintPattern(OS, Indent, ParseIfNeeded, GetTypeOfExpr, GetTypeOfTypeRepr,
+ GetTypeOfKeyPathComponent)
+ .visit(const_cast(P), label);
}
}, label);
}
@@ -4536,8 +4542,9 @@ namespace {
printHead("", DeclColor, label);
printFoot();
} else {
- PrintType(OS, Indent, GetTypeOfExpr, GetTypeOfTypeRepr,
- GetTypeOfKeyPathComponent).visit(type, label);
+ PrintType(OS, Indent, ParseIfNeeded, GetTypeOfExpr, GetTypeOfTypeRepr,
+ GetTypeOfKeyPathComponent)
+ .visit(type, label);
}
}, label);
}
diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp
index b3b456a888f07..88146e8429c12 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.
@@ -4440,10 +4441,21 @@ void ASTMangler::appendMacroExpansionContext(
ASTContext &ctx = origDC->getASTContext();
SourceManager &sourceMgr = ctx.SourceMgr;
+ auto appendMacroExpansionLoc = [&]() {
+ appendIdentifier(origDC->getParentModule()->getName().str());
+
+ auto *SF = origDC->getParentSourceFile();
+ appendIdentifier(llvm::sys::path::filename(SF->getFilename()));
+
+ auto lineColumn = sourceMgr.getLineAndColumnInBuffer(loc);
+ appendOperator("fMX", Index(lineColumn.first), Index(lineColumn.second));
+ };
+
auto bufferID = sourceMgr.findBufferContainingLoc(loc);
auto generatedSourceInfo = sourceMgr.getGeneratedSourceInfo(bufferID);
- if (!generatedSourceInfo)
- return appendContext(origDC, nullBase, StringRef());
+ if (!generatedSourceInfo) {
+ return appendMacroExpansionLoc();
+ }
SourceLoc outerExpansionLoc;
DeclContext *outerExpansionDC;
@@ -4462,7 +4474,7 @@ void ASTMangler::appendMacroExpansionContext(
case GeneratedSourceInfo::PrettyPrinted:
case GeneratedSourceInfo::ReplacedFunctionBody:
case GeneratedSourceInfo::DefaultArgument:
- return appendContext(origDC, nullBase, StringRef());
+ return appendMacroExpansionLoc();
}
switch (generatedSourceInfo->kind) {
@@ -4519,7 +4531,7 @@ void ASTMangler::appendMacroExpansionContext(
// If we hit the point where the structure is represented as a DeclContext,
// we're done.
if (origDC->isChildContextOf(outerExpansionDC))
- return appendContext(origDC, nullBase, StringRef());
+ return appendMacroExpansionLoc();
// Append our own context and discriminator.
appendMacroExpansionContext(outerExpansionLoc, origDC);
diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp
index 75fe2995540e5..3e298e5b03f45 100644
--- a/lib/AST/ASTPrinter.cpp
+++ b/lib/AST/ASTPrinter.cpp
@@ -2915,6 +2915,19 @@ 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()) {
+ assert(conformances.size() == 1 && "expected solo conformance");
+ return true;
+ }
+ }
+ return false;
+}
void PrintAST::printSynthesizedExtension(Type ExtendedType,
ExtensionDecl *ExtDecl) {
@@ -3039,9 +3052,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);
@@ -5724,8 +5749,6 @@ class TypePrinter : public TypeVisitor {
ASTPrinter &Printer;
const PrintOptions &Options;
- std::optional>
- VisibleClangModules;
void printGenericArgs(ArrayRef flatArgs) {
Printer << "<";
@@ -5799,56 +5822,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 +5830,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/Builtins.cpp b/lib/AST/Builtins.cpp
index cffba1fb45d3a..43ff8ce5cb5ac 100644
--- a/lib/AST/Builtins.cpp
+++ b/lib/AST/Builtins.cpp
@@ -1526,6 +1526,9 @@ Type swift::getAsyncTaskAndContextType(ASTContext &ctx) {
}
static ValueDecl *getCreateTask(ASTContext &ctx, Identifier id) {
+ auto taskExecutorIsAvailable =
+ ctx.getProtocol(swift::KnownProtocolKind::TaskExecutor) != nullptr;
+
return getBuiltinFunction(
ctx, id, _thin, _generics(_unrestricted, _conformsToDefaults(0)),
_parameters(
@@ -1533,12 +1536,21 @@ static ValueDecl *getCreateTask(ASTContext &ctx, Identifier id) {
_label("initialSerialExecutor", _defaulted(_optional(_executor), _nil)),
_label("taskGroup", _defaulted(_optional(_rawPointer), _nil)),
_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)),
- _label("operation", _function(_async(_throws(_sendable(_thick))),
+ _label("initialTaskExecutorConsuming",
+ _defaulted(_consuming(_optional(_bincompatType(
+ /*if*/ taskExecutorIsAvailable,
+ _existential(_taskExecutor),
+ /*else*/ _executor))),
+ _nil)),
+ _label("operation", _function(_async(_throws(_sendable(_thick))),
_typeparam(0), _parameters()))),
_tuple(_nativeObject, _rawPointer));
}
static ValueDecl *getCreateDiscardingTask(ASTContext &ctx, Identifier id) {
+ auto taskExecutorIsAvailable =
+ ctx.getProtocol(swift::KnownProtocolKind::TaskExecutor) != nullptr;
+
return getBuiltinFunction(
ctx, id, _thin,
_parameters(
@@ -1546,11 +1558,18 @@ static ValueDecl *getCreateDiscardingTask(ASTContext &ctx, Identifier id) {
_label("initialSerialExecutor", _defaulted(_optional(_executor), _nil)),
_label("taskGroup", _defaulted(_optional(_rawPointer), _nil)),
_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)),
+ _label("initialTaskExecutorConsuming",
+ _defaulted(_consuming(_optional(_bincompatType(
+ /*if*/ taskExecutorIsAvailable,
+ _existential(_taskExecutor),
+ /*else*/ _executor))),
+ _nil)),
_label("operation", _function(_async(_throws(_sendable(_thick))),
_void, _parameters()))),
_tuple(_nativeObject, _rawPointer));
}
+// Legacy entry point, prefer `createAsyncTask`
static ValueDecl *getCreateAsyncTask(ASTContext &ctx, Identifier id,
bool inGroup, bool withTaskExecutor,
bool isDiscarding) {
@@ -1560,6 +1579,7 @@ static ValueDecl *getCreateAsyncTask(ASTContext &ctx, Identifier id,
if (inGroup) {
builder.addParameter(makeConcrete(ctx.TheRawPointerType)); // group
}
+
if (withTaskExecutor) {
builder.addParameter(makeConcrete(ctx.TheExecutorType)); // executor
}
@@ -2089,6 +2109,20 @@ static ValueDecl *getHopToActor(ASTContext &ctx, Identifier id) {
return builder.build(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),
+ isDistributed ? _distributedActor : _actor)),
+ _parameters(_typeparam(0)),
+ _optional(_existential(_actor)));
+}
+
static ValueDecl *getDistributedActorAsAnyActor(ASTContext &ctx, Identifier id) {
BuiltinFunctionBuilder builder(ctx);
auto *distributedActorProto = ctx.getProtocol(KnownProtocolKind::DistributedActor);
@@ -2976,7 +3010,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
case BuiltinValueKind::FixLifetime:
return getFixLifetimeOperation(Context, Id);
-
+
case BuiltinValueKind::CanBeObjCClass:
return getCanBeObjCClassOperation(Context, Id);
@@ -3191,6 +3225,12 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
case BuiltinValueKind::HopToActor:
return getHopToActor(Context, Id);
+ case BuiltinValueKind::FlowSensitiveSelfIsolation:
+ return getFlowSensitiveSelfIsolation(Context, Id, false);
+
+ case BuiltinValueKind::FlowSensitiveDistributedSelfIsolation:
+ return getFlowSensitiveSelfIsolation(Context, Id, true);
+
case BuiltinValueKind::AutoDiffCreateLinearMapContextWithType:
return getAutoDiffCreateLinearMapContext(Context, Id);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 4ecf953e9215d..56685fd1ee074 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1809,18 +1809,25 @@ 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.
if (typeInverseReqs.empty()) {
+ assert(extInverseReqs.empty() && "extension retroactively added inverse?");
return false;
}
@@ -2314,7 +2321,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())
@@ -3054,9 +3061,6 @@ bool AbstractStorageDecl::isResilient(ModuleDecl *M,
case ResilienceExpansion::Maximal:
if (M == getModuleContext())
return false;
- // Access non-resiliently if package optimization is enabled
- if (bypassResilienceInPackage(M))
- return false;
return isResilient();
}
llvm_unreachable("bad resilience expansion");
@@ -4680,10 +4684,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/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();
}
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/AST/Module.cpp b/lib/AST/Module.cpp
index 24deaf7fb1101..86ad07fcc1dfc 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 {
@@ -2620,9 +2668,11 @@ ImportDeclRequest::evaluate(Evaluator &evaluator, const SourceFile *sf,
auto &ctx = sf->getASTContext();
auto imports = sf->getImports();
+ auto mutModule = const_cast(module);
// Look to see if the owning module was directly imported.
for (const auto &import : imports) {
- if (import.module.importedModule == module)
+ if (import.module.importedModule
+ ->isSameModuleLookingThroughOverlays(mutModule))
return import;
}
@@ -2631,7 +2681,8 @@ ImportDeclRequest::evaluate(Evaluator &evaluator, const SourceFile *sf,
for (const auto &import : imports) {
auto &importSet = importCache.getImportSet(import.module.importedModule);
for (const auto &transitive : importSet.getTransitiveImports()) {
- if (transitive.importedModule == module) {
+ if (transitive.importedModule
+ ->isSameModuleLookingThroughOverlays(mutModule)) {
return import;
}
}
@@ -2650,12 +2701,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 {
@@ -2674,6 +2719,26 @@ void SourceFile::registerAccessLevelUsingImport(
ImportsUseAccessLevel[mod] = accessLevel;
else
ImportsUseAccessLevel[mod] = std::max(accessLevel, known->second);
+
+ // Also register modules triggering the import of cross-import overlays.
+ auto declaringMod = mod->getDeclaringModuleIfCrossImportOverlay();
+ if (!declaringMod)
+ return;
+
+ SmallVector bystanders;
+ auto bystandersValid =
+ mod->getRequiredBystandersIfCrossImportOverlay(declaringMod, bystanders);
+ if (!bystandersValid)
+ return;
+
+ for (auto &otherImport : *Imports) {
+ auto otherImportMod = otherImport.module.importedModule;
+ auto otherImportModName = otherImportMod->getName();
+ if (otherImportMod == declaringMod ||
+ llvm::find(bystanders, otherImportModName) != bystanders.end()) {
+ registerAccessLevelUsingImport(otherImport, accessLevel);
+ }
+ }
}
bool HasImportsMatchingFlagRequest::evaluate(Evaluator &evaluator,
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/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/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/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/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/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index f79f69853bb51..1290022c99d2e 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -4294,7 +4294,8 @@ static bool isMacroExpansionNodeKind(Node::Kind kind) {
kind == Node::Kind::MemberAttachedMacroExpansion ||
kind == Node::Kind::PeerAttachedMacroExpansion ||
kind == Node::Kind::ConformanceAttachedMacroExpansion ||
- kind == Node::Kind::ExtensionAttachedMacroExpansion;
+ kind == Node::Kind::ExtensionAttachedMacroExpansion ||
+ kind == Node::Kind::MacroExpansionLoc;
}
NodePointer Demangler::demangleMacroExpansion() {
@@ -4323,6 +4324,20 @@ NodePointer Demangler::demangleMacroExpansion() {
isFreestanding = false;
break;
+ case 'X': {
+ kind = Node::Kind::MacroExpansionLoc;
+
+ int line = demangleIndex();
+ int col = demangleIndex();
+
+ auto lineNode = createNode(Node::Kind::Index, line);
+ auto colNode = createNode(Node::Kind::Index, col);
+
+ NodePointer buffer = popNode(Node::Kind::Identifier);
+ NodePointer module = popNode(Node::Kind::Identifier);
+ return createWithChildren(kind, module, buffer, lineNode, colNode);
+ }
+
default:
return nullptr;
}
diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp
index 0094537d666fb..2dfa67193dc3d 100644
--- a/lib/Demangling/NodePrinter.cpp
+++ b/lib/Demangling/NodePrinter.cpp
@@ -457,6 +457,7 @@ class NodePrinter {
case Node::Kind::LazyProtocolWitnessTableCacheVariable:
case Node::Kind::LocalDeclName:
case Node::Kind::Macro:
+ case Node::Kind::MacroExpansionLoc:
case Node::Kind::MacroExpansionUniqueName:
case Node::Kind::MaterializeForSet:
case Node::Kind::MemberAttributeAttachedMacroExpansion:
@@ -1544,6 +1545,24 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth,
return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
/*hasName*/true, "freestanding macro expansion #",
(int)Node->getChild(2)->getIndex() + 1);
+ case Node::Kind::MacroExpansionLoc:
+ if (Node->getNumChildren() > 0) {
+ Printer << "module ";
+ print(Node->getChild(0), depth + 1);
+ }
+ if (Node->getNumChildren() > 1) {
+ Printer << " file ";
+ print(Node->getChild(1), depth + 1);
+ }
+ if (Node->getNumChildren() > 2) {
+ Printer << " line ";
+ print(Node->getChild(2), depth + 1);
+ }
+ if (Node->getNumChildren() > 3) {
+ Printer << " column ";
+ print(Node->getChild(3), depth + 1);
+ }
+ return nullptr;
case Node::Kind::MacroExpansionUniqueName:
return printEntity(Node, depth, asPrefixContext, TypePrinting::NoType,
/*hasName*/true, "unique name #",
diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp
index 46529b2389382..1c115e1400515 100644
--- a/lib/Demangling/OldRemangler.cpp
+++ b/lib/Demangling/OldRemangler.cpp
@@ -1115,6 +1115,11 @@ ManglingError Remangler::mangleMacroExpansionUniqueName(
return mangleChildNodes(node, depth + 1);
}
+ManglingError Remangler::mangleMacroExpansionLoc(
+ Node *node, unsigned depth) {
+ return MANGLING_ERROR(ManglingError::UnsupportedNodeKind, node);
+}
+
ManglingError Remangler::mangleAccessor(Node *storageNode,
StringRef accessorCode,
EntityContext &ctx, unsigned depth) {
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index a5ae66913c80a..3aa0009c8862e 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -3120,6 +3120,21 @@ ManglingError Remangler::mangle##Name##AttachedMacroExpansion( \
}
#include "swift/Basic/MacroRoles.def"
+ManglingError Remangler::mangleMacroExpansionLoc(
+ Node *node, unsigned depth) {
+ RETURN_IF_ERROR(mangleChildNode(node, 0, depth + 1));
+ RETURN_IF_ERROR(mangleChildNode(node, 1, depth + 1));
+
+ auto line = node->getChild(2)->getIndex();
+ auto col = node->getChild(3)->getIndex();
+
+ Buffer << "fMX";
+ mangleIndex(line);
+ mangleIndex(col);
+
+ return ManglingError::Success;
+}
+
ManglingError Remangler::mangleMacroExpansionUniqueName(
Node *node, unsigned depth) {
RETURN_IF_ERROR(mangleChildNode(node, 0, depth + 1));
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/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)) {
diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp
index a9e5c7b7c9ddc..80c0104086167 100644
--- a/lib/Frontend/Frontend.cpp
+++ b/lib/Frontend/Frontend.cpp
@@ -1650,11 +1650,6 @@ CompilerInstance::getSourceFileParsingOptions(bool forPrimary) const {
action != ActionType::ScanDependencies) {
opts |= ParsingFlags::DisablePoundIfEvaluation;
}
-
- // If we need to dump the parse tree, disable delayed bodies as we want to
- // show everything.
- if (action == ActionType::DumpParse)
- opts |= ParsingFlags::DisableDelayedBodies;
}
const auto &typeOpts = getASTContext().TypeCheckerOpts;
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/lib/Frontend/ModuleInterfaceSupport.cpp b/lib/Frontend/ModuleInterfaceSupport.cpp
index 491baa89e671e..586ed236757fa 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
@@ -801,7 +802,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 +811,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/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index ffb44e70c60d0..319e5073a3b6b 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -598,6 +598,8 @@ mapFrontendInvocationToAction(const CompilerInvocation &Invocation) {
return "backend";
else
return "compile";
+ case FrontendOptions::ActionType::EmitModuleOnly:
+ return "emit-module";
default:
return "compile";
}
@@ -634,7 +636,8 @@ static swift::file_types::ID computeFileTypeForPath(const StringRef Path) {
static DetailedTaskDescription
constructDetailedTaskDescription(const CompilerInvocation &Invocation,
ArrayRef PrimaryInputs,
- ArrayRef Args) {
+ ArrayRef Args,
+ bool isEmitModuleOnly = false) {
// Command line and arguments
std::string Executable = Invocation.getFrontendOptions().MainExecutablePath;
SmallVector Arguments;
@@ -653,10 +656,12 @@ constructDetailedTaskDescription(const CompilerInvocation &Invocation,
}
for (const auto &input : PrimaryInputs) {
- // Main outputs
- auto OutputFile = input.outputFilename();
- if (!OutputFile.empty())
- Outputs.push_back(OutputPair(computeFileTypeForPath(OutputFile), OutputFile));
+ if (!isEmitModuleOnly) {
+ // Main per-input outputs
+ auto OutputFile = input.outputFilename();
+ if (!OutputFile.empty())
+ Outputs.push_back(OutputPair(computeFileTypeForPath(OutputFile), OutputFile));
+ }
// Supplementary outputs
const auto &primarySpecificFiles = input.getPrimarySpecificPaths();
@@ -2335,10 +2340,14 @@ int swift::performFrontend(ArrayRef Args,
return false;
});
} else {
- // If no primary inputs are present, we are in WMO.
+ // If no primary inputs are present, we are in WMO or EmitModule.
+ bool isEmitModule =
+ Invocation.getFrontendOptions().RequestedAction ==
+ FrontendOptions::ActionType::EmitModuleOnly;
emitBeganMessage(llvm::errs(),
mapFrontendInvocationToAction(Invocation),
- constructDetailedTaskDescription(Invocation, IO.getAllInputs(), Args),
+ constructDetailedTaskDescription(Invocation, IO.getAllInputs(),
+ Args, isEmitModule),
OSPid, ProcInfo);
}
};
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);
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/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/lib/IRGen/GenConcurrency.cpp b/lib/IRGen/GenConcurrency.cpp
index 428066d348d0c..db73ce029953a 100644
--- a/lib/IRGen/GenConcurrency.cpp
+++ b/lib/IRGen/GenConcurrency.cpp
@@ -472,7 +472,7 @@ static llvm::Value *addOptionRecord(IRGenFunction &IGF,
}
/// Add a task option record to the options list if the given value
-/// is presernt.
+/// is present.
template
static llvm::Value *maybeAddOptionRecord(IRGenFunction &IGF,
llvm::Value *curRecordPointer,
@@ -645,15 +645,15 @@ struct TaskGroupRecordTraits {
}
};
-struct InitialTaskExecutorRecordTraits {
+struct InitialTaskExecutorUnownedRecordTraits {
static StringRef getLabel() {
- return "task_executor";
+ return "task_executor_unowned";
}
static llvm::StructType *getRecordType(IRGenModule &IGM) {
- return IGM.SwiftInitialTaskExecutorPreferenceTaskOptionRecordTy;
+ return IGM.SwiftInitialTaskExecutorUnownedPreferenceTaskOptionRecordTy;
}
static TaskOptionRecordFlags getRecordFlags() {
- return TaskOptionRecordFlags(TaskOptionRecordKind::InitialTaskExecutor);
+ return TaskOptionRecordFlags(TaskOptionRecordKind::InitialTaskExecutorUnowned);
}
static CanType getValueType(ASTContext &ctx) {
return ctx.TheExecutorType;
@@ -670,6 +670,36 @@ struct InitialTaskExecutorRecordTraits {
}
};
+struct InitialTaskExecutorOwnedRecordTraits {
+ static StringRef getLabel() {
+ return "task_executor_owned";
+ }
+ static llvm::StructType *getRecordType(IRGenModule &IGM) {
+ return IGM.SwiftInitialTaskExecutorOwnedPreferenceTaskOptionRecordTy;
+ }
+ static TaskOptionRecordFlags getRecordFlags() {
+ return TaskOptionRecordFlags(TaskOptionRecordKind::InitialTaskExecutorOwned);
+ }
+ static CanType getValueType(ASTContext &ctx) {
+ return OptionalType::get(ctx.getProtocol(KnownProtocolKind::TaskExecutor)
+ ->getDeclaredInterfaceType())
+ ->getCanonicalType();
+ }
+
+ void initialize(IRGenFunction &IGF, Address recordAddr,
+ Explosion &taskExecutor) const {
+ auto executorRecord =
+ IGF.Builder.CreateStructGEP(recordAddr, 1, 2 * IGF.IGM.getPointerSize());
+
+ // This relies on the fact that the HeapObject is directly followed by a
+ // pointer to the witness table.
+ IGF.Builder.CreateStore(taskExecutor.claimNext(),
+ IGF.Builder.CreateStructGEP(executorRecord, 0, Size()));
+ IGF.Builder.CreateStore(taskExecutor.claimNext(),
+ IGF.Builder.CreateStructGEP(executorRecord, 1, Size()));
+ }
+};
+
} // end anonymous namespace
static llvm::Value *
@@ -693,15 +723,25 @@ maybeAddInitialTaskExecutorOptionRecord(IRGenFunction &IGF,
llvm::Value *prevOptions,
OptionalExplosion &taskExecutor) {
return maybeAddOptionRecord(IGF, prevOptions,
- InitialTaskExecutorRecordTraits(),
+ InitialTaskExecutorUnownedRecordTraits(),
taskExecutor);
}
+static llvm::Value *
+maybeAddInitialTaskExecutorOwnedOptionRecord(IRGenFunction &IGF,
+ llvm::Value *prevOptions,
+ OptionalExplosion &taskExecutorExistential) {
+ return maybeAddOptionRecord(IGF, prevOptions,
+ InitialTaskExecutorOwnedRecordTraits(),
+ taskExecutorExistential);
+}
+
std::pair
irgen::emitTaskCreate(IRGenFunction &IGF, llvm::Value *flags,
OptionalExplosion &serialExecutor,
OptionalExplosion &taskGroup,
- OptionalExplosion &taskExecutor,
+ OptionalExplosion &taskExecutorUnowned,
+ OptionalExplosion &taskExecutorExistential,
Explosion &taskFunction,
SubstitutionMap subs) {
llvm::Value *taskOptions =
@@ -729,8 +769,14 @@ irgen::emitTaskCreate(IRGenFunction &IGF, llvm::Value *flags,
taskOptions = maybeAddTaskGroupOptionRecord(IGF, taskOptions, taskGroup);
// Add an option record for the initial task executor, if present.
- taskOptions =
- maybeAddInitialTaskExecutorOptionRecord(IGF, taskOptions, taskExecutor);
+ {
+ // Deprecated: This is the UnownedTaskExecutor? which is NOT consuming
+ taskOptions = maybeAddInitialTaskExecutorOptionRecord(
+ IGF, taskOptions, taskExecutorUnowned);
+ // Take an (any TaskExecutor)? which we retain until task has completed
+ taskOptions = maybeAddInitialTaskExecutorOwnedOptionRecord(
+ IGF, taskOptions, taskExecutorExistential);
+ }
// In embedded Swift, create and pass result type info.
taskOptions = maybeAddEmbeddedSwiftResultTypeInfo(IGF, taskOptions, resultType);
diff --git a/lib/IRGen/GenConcurrency.h b/lib/IRGen/GenConcurrency.h
index 0fbb5169445fc..ec4bc110118b7 100644
--- a/lib/IRGen/GenConcurrency.h
+++ b/lib/IRGen/GenConcurrency.h
@@ -104,7 +104,8 @@ std::pair
emitTaskCreate(IRGenFunction &IGF, llvm::Value *flags,
OptionalExplosion &initialExecutor,
OptionalExplosion &taskGroup,
- OptionalExplosion &taskExecutor,
+ OptionalExplosion &taskExecutorUnowned,
+ OptionalExplosion &taskExecutorExistential,
Explosion &taskFunction,
SubstitutionMap subs);
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/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index 0d9b66255f1ea..2811c362d3370 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -708,11 +708,16 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
SwiftTaskOptionRecordTy, // Base option record
SwiftExecutorTy, // Executor
});
- SwiftInitialTaskExecutorPreferenceTaskOptionRecordTy =
+ SwiftInitialTaskExecutorUnownedPreferenceTaskOptionRecordTy =
createStructType(*this, "swift.task_executor_task_option", {
SwiftTaskOptionRecordTy, // Base option record
SwiftExecutorTy, // Executor
});
+ SwiftInitialTaskExecutorOwnedPreferenceTaskOptionRecordTy =
+ createStructType(*this, "swift.task_executor_owned_task_option", {
+ SwiftTaskOptionRecordTy, // Base option record
+ SwiftExecutorTy, // Executor
+ });
SwiftJobTy = createStructType(*this, "swift.job", {
RefCountedStructTy, // object header
Int8PtrTy, Int8PtrTy, // SchedulerPrivate
@@ -1963,12 +1968,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/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index 9b1e8bf8386d8..c3820bf9e7106 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -821,7 +821,8 @@ class IRGenModule {
llvm::StructType *SwiftTaskOptionRecordTy;
llvm::StructType *SwiftInitialSerialExecutorTaskOptionRecordTy;
llvm::StructType *SwiftTaskGroupTaskOptionRecordTy;
- llvm::StructType *SwiftInitialTaskExecutorPreferenceTaskOptionRecordTy;
+ llvm::StructType *SwiftInitialTaskExecutorUnownedPreferenceTaskOptionRecordTy;
+ llvm::StructType *SwiftInitialTaskExecutorOwnedPreferenceTaskOptionRecordTy;
llvm::StructType *SwiftResultTypeInfoTaskOptionRecordTy;
llvm::PointerType *SwiftJobPtrTy;
llvm::IntegerType *ExecutorFirstTy;
diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp
index d5808be6d7de6..81aab201d0cbc 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);
@@ -3620,14 +3633,18 @@ static void emitBuiltinStackDealloc(IRGenSILFunction &IGF,
static void emitBuiltinCreateAsyncTask(IRGenSILFunction &IGF,
swift::BuiltinInst *i) {
+ assert(i->getOperandValues().size() == 6 &&
+ "createAsyncTask needs 6 operands");
auto flags = IGF.getLoweredSingletonExplosion(i->getOperand(0));
auto serialExecutor = IGF.getLoweredOptionalExplosion(i->getOperand(1));
auto taskGroup = IGF.getLoweredOptionalExplosion(i->getOperand(2));
- auto taskExecutor = IGF.getLoweredOptionalExplosion(i->getOperand(3));
- Explosion taskFunction = IGF.getLoweredExplosion(i->getOperand(4));
+ auto taskExecutorUnowned = IGF.getLoweredOptionalExplosion(i->getOperand(3));
+ auto taskExecutorOwned = IGF.getLoweredOptionalExplosion(i->getOperand(4));
+ Explosion taskFunction = IGF.getLoweredExplosion(i->getOperand(5));
auto taskAndContext =
- emitTaskCreate(IGF, flags, serialExecutor, taskGroup, taskExecutor,
+ emitTaskCreate(IGF, flags, serialExecutor, taskGroup,
+ taskExecutorUnowned, taskExecutorOwned,
taskFunction, i->getSubstitutions());
Explosion out;
out.add(taskAndContext.first);
@@ -5109,6 +5126,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 +5137,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();
diff --git a/lib/Macros/Sources/SwiftMacros/DistributedResolvableMacro.swift b/lib/Macros/Sources/SwiftMacros/DistributedResolvableMacro.swift
index d82a8fce8b1bd..17feebbcf82f9 100644
--- a/lib/Macros/Sources/SwiftMacros/DistributedResolvableMacro.swift
+++ b/lib/Macros/Sources/SwiftMacros/DistributedResolvableMacro.swift
@@ -104,7 +104,7 @@ extension DistributedResolvableMacro {
static func stubFunctionBody() -> DeclSyntax {
"""
- if #available(SwiftStdlib 6.0, *) {
+ if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) {
Distributed._distributedStubFatalError()
} else {
fatalError()
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 068c2be02cab8..f5a707570878b 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -2456,7 +2456,7 @@ Parser::parseDocumentationAttribute(SourceLoc atLoc, SourceLoc loc) {
StringRef finalMetadata = metadata.value_or("");
return makeParserResult(
- new (Context) DocumentationAttr(loc, range, finalMetadata,
+ new (Context) DocumentationAttr(atLoc, range, finalMetadata,
visibility, false));
}
@@ -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/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp
index 278eb0b08e1c6..d768f9f43f3db 100644
--- a/lib/Parse/ParseIfConfig.cpp
+++ b/lib/Parse/ParseIfConfig.cpp
@@ -843,10 +843,16 @@ Result Parser::parseIfConfigRaw(
// Error in the condition;
isActive = false;
isVersionCondition = false;
- } else if (!foundActive && shouldEvaluate) {
+ } else if (!foundActive) {
// Evaluate the condition only if we haven't found any active one and
// we're not in parse-only mode.
- isActive = evaluateIfConfigCondition(Condition, Context);
+ if (shouldEvaluate) {
+ isActive = evaluateIfConfigCondition(Condition, Context);
+ }
+ // Determine isVersionCondition regardless of whether we're active.
+ // This is necessary in some edge cases, e.g. where we're in a nested,
+ // inactive #if block, and we encounter an inactive `#if compiler` check,
+ // as we have to explicitly skip parsing in such edge cases.
isVersionCondition = isVersionIfConfigCondition(Condition);
}
}
diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp
index 4ee647533c4b3..b93fa1a640d5a 100644
--- a/lib/Parse/ParseType.cpp
+++ b/lib/Parse/ParseType.cpp
@@ -1551,6 +1551,8 @@ bool Parser::canParseType() {
consumeToken();
} else if (Tok.isContextualKeyword("each")) {
consumeToken();
+ } else if (Tok.isContextualKeyword("sending")) {
+ consumeToken();
}
switch (Tok.getKind()) {
diff --git a/lib/PrintAsClang/ModuleContentsWriter.cpp b/lib/PrintAsClang/ModuleContentsWriter.cpp
index 1bc8e55811ced..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)));
@@ -874,6 +884,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/lib/PrintAsClang/PrintClangFunction.cpp b/lib/PrintAsClang/PrintClangFunction.cpp
index a85ce54802d99..d73e4756cd921 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) {
@@ -713,6 +719,17 @@ 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().is(name))
+ return ClangRepresentation::unsupported;
+ }
+ }
auto emittedModule = FD->getModuleContext();
OutputLanguageMode outputLang = kind == FunctionSignatureKind::CFunctionProto
? OutputLanguageMode::ObjC
@@ -1521,7 +1538,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/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/lib/SIL/IR/Linker.cpp b/lib/SIL/IR/Linker.cpp
index fffa14f3cd976..415c4b8ba1ede 100644
--- a/lib/SIL/IR/Linker.cpp
+++ b/lib/SIL/IR/Linker.cpp
@@ -59,6 +59,7 @@
#include "llvm/Support/Debug.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SubstitutionMap.h"
+#include "swift/Basic/Require.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/SIL/FormalLinkage.h"
#include "swift/Serialization/SerializedSILLoader.h"
@@ -101,9 +102,9 @@ void SILLinkerVisitor::deserializeAndPushToWorklist(SILFunction *F) {
void SILLinkerVisitor::maybeAddFunctionToWorklist(
SILFunction *F, SerializedKind_t callerSerializedKind) {
SILLinkage linkage = F->getLinkage();
- assert((callerSerializedKind == IsNotSerialized ||
- F->hasValidLinkageForFragileRef(callerSerializedKind) ||
- hasSharedVisibility(linkage) || F->isExternForwardDeclaration()) &&
+ require(callerSerializedKind == IsNotSerialized ||
+ F->hasValidLinkageForFragileRef(callerSerializedKind) ||
+ hasSharedVisibility(linkage) || F->isExternForwardDeclaration(),
"called function has wrong linkage for serialized function");
if (!F->isExternalDeclaration()) {
// The function is already in the module, so no need to de-serialized it.
diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp
index 8025bc44fdca0..b66caf165213b 100644
--- a/lib/SIL/IR/OperandOwnership.cpp
+++ b/lib/SIL/IR/OperandOwnership.cpp
@@ -907,6 +907,8 @@ 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(InstantaneousUse, FlowSensitiveDistributedSelfIsolation)
BUILTIN_OPERAND_OWNERSHIP(ForwardingConsume, COWBufferForReading)
@@ -928,6 +930,12 @@ ::visitStartAsyncLetWithLocalBuffer(BuiltinInst *bi, StringRef attr) {
OperandOwnership
OperandOwnershipBuiltinClassifier::visitCreateAsyncTask(BuiltinInst *bi,
StringRef attr) {
+ if (&op == &bi->getOperandRef(4)) {
+ // The (any TaskExecutor)? (optional) must be consumed by the builtin,
+ // as we will keep it alive and later destroy it as the task runs to completion.
+ return OperandOwnership::ForwardingConsume;
+ }
+
// The function operand is consumed by the new task.
if (&op == &bi->getArgumentOperands().back())
return OperandOwnership::DestroyingConsume;
diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp
index cbf747d547890..e6fc550504118 100644
--- a/lib/SIL/IR/SILDeclRef.cpp
+++ b/lib/SIL/IR/SILDeclRef.cpp
@@ -464,7 +464,9 @@ static LinkageLimit getLinkageLimit(SILDeclRef constant) {
return Limit::OnDemand;
case Kind::GlobalAccessor:
- return cast(d)->isStrictlyResilient() ? Limit::NeverPublic : Limit::None;
+ // global unsafeMutableAddressor should be kept hidden if its decl
+ // is resilient.
+ return cast(d)->isResilient() ? Limit::NeverPublic : Limit::None;
case Kind::DefaultArgGenerator:
// If the default argument is to be serialized, only use non-ABI public
diff --git a/lib/SIL/IR/SILType.cpp b/lib/SIL/IR/SILType.cpp
index d223556c64b4a..4a7747adcdccb 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();
@@ -1266,7 +1271,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];
@@ -1284,6 +1289,17 @@ SILType SILType::removingMoveOnlyWrapperToBoxedType(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();
}
diff --git a/lib/SIL/IR/ValueOwnership.cpp b/lib/SIL/IR/ValueOwnership.cpp
index 335b17e4cab95..0d3509365d56f 100644
--- a/lib/SIL/IR/ValueOwnership.cpp
+++ b/lib/SIL/IR/ValueOwnership.cpp
@@ -630,6 +630,8 @@ 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(Owned, FlowSensitiveDistributedSelfIsolation)
CONSTANT_OWNERSHIP_BUILTIN(None, GetEnumTag)
CONSTANT_OWNERSHIP_BUILTIN(None, InjectEnumTag)
CONSTANT_OWNERSHIP_BUILTIN(Owned, DistributedActorAsAnyActor)
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/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/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/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp
index cee5db011b5ef..d4cecf02173bf 100644
--- a/lib/SIL/Verifier/SILVerifier.cpp
+++ b/lib/SIL/Verifier/SILVerifier.cpp
@@ -2383,8 +2383,8 @@ class SILVerifier : public SILVerifierBase {
if (builtinKind == BuiltinValueKind::CreateAsyncTask) {
requireType(BI->getType(), _object(_tuple(_nativeObject, _rawPointer)),
"result of createAsyncTask");
- require(arguments.size() == 5,
- "createAsyncTask expects five arguments");
+ require(arguments.size() == 6,
+ "createAsyncTask expects six arguments");
requireType(arguments[0]->getType(), _object(_swiftInt),
"first argument of createAsyncTask");
requireType(arguments[1]->getType(), _object(_optional(_executor)),
@@ -2393,7 +2393,18 @@ class SILVerifier : public SILVerifierBase {
"third argument of createAsyncTask");
requireType(arguments[3]->getType(), _object(_optional(_executor)),
"fourth argument of createAsyncTask");
- auto fnType = requireObjectType(SILFunctionType, arguments[4],
+ if (F.getASTContext().getProtocol(swift::KnownProtocolKind::TaskExecutor)) {
+ requireType(arguments[4]->getType(),
+ _object(_optional(_existential(_taskExecutor))),
+ "fifth argument of createAsyncTask");
+ } else {
+ // This is just a placeholder type for being able to pass 'nil' for it
+ // with SDKs which do not have the TaskExecutor type.
+ requireType(arguments[4]->getType(),
+ _object(_optional(_executor)),
+ "fifth argument of createAsyncTask");
+ }
+ auto fnType = requireObjectType(SILFunctionType, arguments[5],
"result of createAsyncTask");
auto expectedExtInfo =
SILExtInfoBuilder().withAsync(true).withSendable(true).build();
@@ -6548,9 +6559,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(
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index 2eb9dbf3b97c7..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());
@@ -6858,22 +6868,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/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/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp
index bcbe3332560a9..059ed94bb984a 100644
--- a/lib/SILGen/SILGenBuiltin.cpp
+++ b/lib/SILGen/SILGenBuiltin.cpp
@@ -1595,7 +1595,7 @@ static ManagedValue emitCreateAsyncTask(SILGenFunction &SGF, SILLocation loc,
}
}();
- ManagedValue taskExecutor = [&] {
+ ManagedValue taskExecutorDeprecated = [&] {
if (options & CreateTaskOptions::OptionalEverything) {
return nextArg().getAsSingleValue(SGF);
} else if (options & CreateTaskOptions::TaskExecutor) {
@@ -1604,6 +1604,19 @@ static ManagedValue emitCreateAsyncTask(SILGenFunction &SGF, SILLocation loc,
return emitOptionalNone(ctx.TheExecutorType);
}
}();
+ ManagedValue taskExecutorConsuming = [&] {
+ if (options & CreateTaskOptions::OptionalEverything) {
+ return nextArg().getAsSingleValue(SGF);
+ } else if (auto theTaskExecutorProto = ctx.getProtocol(KnownProtocolKind::TaskExecutor)) {
+ return emitOptionalNone(theTaskExecutorProto->getDeclaredExistentialType()
+ ->getCanonicalType());
+ } else {
+ // This builtin executor type here is just a placeholder type for being
+ // able to pass 'nil' for it with SDKs which do not have the TaskExecutor
+ // type.
+ return emitOptionalNone(ctx.TheExecutorType);
+ }
+ }();
auto functionValue = [&] {
// No reabstraction required.
@@ -1659,7 +1672,8 @@ static ManagedValue emitCreateAsyncTask(SILGenFunction &SGF, SILLocation loc,
flags.getUnmanagedValue(),
initialExecutor.getUnmanagedValue(),
taskGroup.getUnmanagedValue(),
- taskExecutor.getUnmanagedValue(),
+ taskExecutorDeprecated.getUnmanagedValue(),
+ taskExecutorConsuming.forward(SGF),
functionValue.forward(SGF)
};
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/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 468f9b422800f..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"
@@ -6743,6 +6744,56 @@ 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(
+ isolation.isDistributedActor()
+ ? getBuiltinName(BuiltinValueKind::FlowSensitiveDistributedSelfIsolation)
+ : getBuiltinName(BuiltinValueKind::FlowSensitiveSelfIsolation));
+ SILType resultTy = SGF.getLoweredType(E->getType());
+
+ auto injection = cast(E->getActor());
+ 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);
+
+ SubstitutionMap subs = SubstitutionMap::getProtocolSubstitutions(
+ 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 visit(E->getActor(), C);
}
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/lib/SILGen/SILGenGlobalVariable.cpp b/lib/SILGen/SILGenGlobalVariable.cpp
index cc3f3ed79df3b..815efa5d5dd10 100644
--- a/lib/SILGen/SILGenGlobalVariable.cpp
+++ b/lib/SILGen/SILGenGlobalVariable.cpp
@@ -42,8 +42,8 @@ SILGlobalVariable *SILGenModule::getSILGlobalVariable(VarDecl *gDecl,
// Get the linkage for SILGlobalVariable.
FormalLinkage formalLinkage;
- if (gDecl->isResilient() &&
- !gDecl->getModuleContext()->serializePackageEnabled())
+ // sil_global linkage should be kept private if its decl is resilient.
+ if (gDecl->isResilient())
formalLinkage = FormalLinkage::Private;
else
formalLinkage = getDeclLinkage(gDecl);
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/lib/SILOptimizer/Analysis/RegionAnalysis.cpp b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp
index 773bff7eca002..bd36c7abbe53b 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)
@@ -2804,6 +2819,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/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
index d3d2e0f5110ab..175b18d5db47e 100644
--- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
+++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
@@ -675,22 +675,30 @@ 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 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;
+ 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;
@@ -1394,7 +1402,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) {
diff --git a/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp b/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp
index b2c82c236bdc8..b117ffdaa65fb 100644
--- a/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp
+++ b/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp
@@ -64,6 +64,7 @@
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
#include "swift/SILOptimizer/Utils/CFGOptUtils.h"
+#include "swift/SILOptimizer/Utils/OwnershipOptUtils.h"
#include "swift/SILOptimizer/Utils/LoopUtils.h"
#include "swift/SILOptimizer/Utils/SILSSAUpdater.h"
#include "llvm/ADT/SmallSet.h"
@@ -835,6 +836,8 @@ class SwiftArrayPropertyOptPass : public SILFunctionTransform {
if (getFunction()->getModule().getOptions().VerifyAll)
getFunction()->verifyCriticalEdges();
+ updateBorrowedFrom(getPassManager(), Fn);
+
// We preserve the dominator tree. Let's invalidate everything
// else.
DA->lockInvalidation();
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/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
index cb3615c3a564c..66566a5982ded 100644
--- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
+++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
@@ -1709,6 +1709,19 @@ 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 ||
+ *builtinKind ==
+ BuiltinValueKind::FlowSensitiveDistributedSelfIsolation) {
+ 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..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"
@@ -491,6 +492,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 +567,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 +1163,10 @@ void LifetimeChecker::doIt() {
case DIUseKind::BadExplicitStore:
diagnoseBadExplicitStore(Inst);
break;
+
+ case DIUseKind::FlowSensitiveSelfIsolation:
+ handleFlowSensitiveActorIsolationUse(Use);
+ break;
}
}
@@ -1344,6 +1351,73 @@ 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 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, anyActorValue, 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/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/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/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp b/lib/SILOptimizer/Mandatory/MoveOnlyWrappedTypeEliminator.cpp
index a7a583ab7d955..b606fd7c37107 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");
@@ -294,56 +288,76 @@ static bool isMoveOnlyWrappedTrivial(SILValue value) {
}
bool SILMoveOnlyWrappedTypeEliminator::process() {
- bool madeChange = true;
+ bool madeChange = false;
- 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());
+
+ if (isa(value))
+ value->replaceAllUsesWith(
+ SILUndef::get(fn, value->getType().removingAnyMoveOnlyWrapping(fn)));
+ else
+ value->unsafelyEliminateMoveOnlyWrapper(fn);
+
+ return true;
+ };
+
for (auto &bb : *fn) {
for (auto *arg : bb.getArguments()) {
- if (!arg->getType().isMoveOnlyWrapped() &&
- !arg->getType().isBoxedMoveOnlyWrappedType(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().isMoveOnlyWrapped() &&
- !v->getType().isBoxedMoveOnlyWrappedType(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;
}
}
+ // 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(touchedArgs);
+ SILMoveOnlyWrappedTypeEliminatorVisitor visitor;
while (!touchedInsts.empty()) {
visitor.visit(touchedInsts.pop_back_val());
}
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/Transforms/AccessEnforcementReleaseSinking.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp
index 516fdccb836a6..56b83125ef35a 100644
--- a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp
+++ b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp
@@ -159,6 +159,8 @@ static bool isBarrier(SILInstruction *inst) {
case BuiltinValueKind::GetEnumTag:
case BuiltinValueKind::InjectEnumTag:
case BuiltinValueKind::ExtractFunctionIsolation:
+ case BuiltinValueKind::FlowSensitiveSelfIsolation:
+ case BuiltinValueKind::FlowSensitiveDistributedSelfIsolation:
case BuiltinValueKind::AddressOfRawLayout:
return false;
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/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);
}
diff --git a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
index fe177898f4a26..055fe930260fd 100644
--- a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
+++ b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
@@ -14,6 +14,7 @@
#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h"
#include "swift/SILOptimizer/Utils/PerformanceInlinerUtils.h"
#include "swift/AST/Module.h"
+#include "swift/Basic/Require.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "llvm/Support/CommandLine.h"
@@ -851,8 +852,8 @@ SILFunction *swift::getEligibleFunction(FullApplySite AI,
!Callee->hasValidLinkageForFragileRef(Caller->getSerializedKind())) {
llvm::errs() << "caller: " << Caller->getName() << "\n";
llvm::errs() << "callee: " << Callee->getName() << "\n";
- llvm_unreachable("Should never be inlining a resilient function into "
- "a fragile function");
+ require(false, "Should never be inlining a resilient function into "
+ "a fragile function");
}
return nullptr;
}
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/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/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) {
diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp
index ad0bf49a0bb70..e9394cb6b9a02 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());
@@ -7918,6 +7918,24 @@ bool NonEphemeralConversionFailure::diagnoseAsError() {
return true;
}
+bool SendingOnFunctionParameterMismatchFail::diagnoseAsError() {
+ emitDiagnosticAt(getLoc(), diag::sending_function_wrong_sending,
+ getFromType(), getToType())
+ .warnUntilSwiftVersion(6);
+ emitDiagnosticAt(getLoc(),
+ diag::sending_function_param_with_sending_param_note);
+ return true;
+}
+
+bool SendingOnFunctionResultMismatchFailure::diagnoseAsError() {
+ emitDiagnosticAt(getLoc(), diag::sending_function_wrong_sending,
+ getFromType(), getToType())
+ .warnUntilSwiftVersion(6);
+ emitDiagnosticAt(getLoc(),
+ diag::sending_function_result_with_sending_param_note);
+ return true;
+}
+
bool AssignmentTypeMismatchFailure::diagnoseMissingConformance() const {
auto srcType = getFromType();
auto dstType = getToType()->lookThroughAllOptionalTypes();
diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h
index 8e76d917a879d..e436e0faabb1c 100644
--- a/lib/Sema/CSDiagnostics.h
+++ b/lib/Sema/CSDiagnostics.h
@@ -2292,6 +2292,28 @@ class NonEphemeralConversionFailure final : public ArgumentMismatchFailure {
void emitSuggestionNotes() const;
};
+class SendingOnFunctionParameterMismatchFail final : public ContextualFailure {
+public:
+ SendingOnFunctionParameterMismatchFail(const Solution &solution, Type srcType,
+ Type dstType,
+ ConstraintLocator *locator,
+ FixBehavior fixBehavior)
+ : ContextualFailure(solution, srcType, dstType, locator, fixBehavior) {}
+
+ bool diagnoseAsError() override;
+};
+
+class SendingOnFunctionResultMismatchFailure final : public ContextualFailure {
+public:
+ SendingOnFunctionResultMismatchFailure(const Solution &solution, Type srcType,
+ Type dstType,
+ ConstraintLocator *locator,
+ FixBehavior fixBehavior)
+ : ContextualFailure(solution, srcType, dstType, locator, fixBehavior) {}
+
+ bool diagnoseAsError() override;
+};
+
class AssignmentTypeMismatchFailure final : public ContextualFailure {
public:
AssignmentTypeMismatchFailure(const Solution &solution,
diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp
index a87dfef7e4159..82ac5e2003b3e 100644
--- a/lib/Sema/CSFix.cpp
+++ b/lib/Sema/CSFix.cpp
@@ -1845,6 +1845,34 @@ std::string TreatEphemeralAsNonEphemeral::getName() const {
return name;
}
+bool AllowSendingMismatch::diagnose(const Solution &solution,
+ bool asNote) const {
+ switch (kind) {
+ case Kind::Parameter: {
+ SendingOnFunctionParameterMismatchFail failure(
+ solution, getFromType(), getToType(), getLocator(), fixBehavior);
+ return failure.diagnose(asNote);
+ }
+ case Kind::Result: {
+ SendingOnFunctionResultMismatchFailure failure(
+ solution, getFromType(), getToType(), getLocator(), fixBehavior);
+ return failure.diagnose(asNote);
+ }
+ }
+ llvm_unreachable("Covered switch isn't covered?!");
+}
+
+AllowSendingMismatch *AllowSendingMismatch::create(ConstraintSystem &cs,
+ ConstraintLocator *locator,
+ Type srcType, Type dstType,
+ Kind kind) {
+ auto fixBehavior = cs.getASTContext().LangOpts.isSwiftVersionAtLeast(6)
+ ? FixBehavior::Error
+ : FixBehavior::DowngradeToWarning;
+ return new (cs.getAllocator())
+ AllowSendingMismatch(cs, srcType, dstType, locator, kind, fixBehavior);
+}
+
bool SpecifyBaseTypeForContextualMember::diagnose(const Solution &solution,
bool asNote) const {
MissingContextualBaseInMemberRefFailure failure(solution, MemberName,
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/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/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index 9a9b2cdb365a4..f51506b0d4035 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -3235,6 +3235,16 @@ 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)) {
+ auto *fix = AllowSendingMismatch::create(
+ *this, getConstraintLocator(locator), func1, func2,
+ AllowSendingMismatch::Kind::Result);
+ if (recordFix(fix))
+ return getTypeMatchFailure(locator);
+ }
+
if (!matchFunctionIsolations(func1, func2, kind, flags, locator))
return getTypeMatchFailure(locator);
@@ -3665,6 +3675,17 @@ 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()) {
+ auto *fix = AllowSendingMismatch::create(
+ *this, getConstraintLocator(argumentLocator), func1, func2,
+ AllowSendingMismatch::Kind::Parameter);
+ if (recordFix(fix))
+ return getTypeMatchFailure(argumentLocator);
+ }
+
// FIXME: We should check value ownership too, but it's not completely
// trivial because of inout-to-pointer conversions.
@@ -11785,10 +11806,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()));
}
}
@@ -11915,6 +11936,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(
@@ -15113,6 +15140,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
}
}
+ case FixKind::AllowSendingMismatch:
case FixKind::InsertCall:
case FixKind::RemoveReturn:
case FixKind::RemoveAddressOf:
@@ -15201,7 +15229,12 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
locator.endsWith())
? 1
: 0;
-
+ // An overload choice that isn't settable is least interesting for diagnosis.
+ if (auto overload = findSelectedOverloadFor(getCalleeLocator(fix->getLocator()))) {
+ if (auto *var = dyn_cast_or_null(overload->choice.getDeclOrNull())) {
+ impact += !var->isSettableInSwift(DC) ? 1 : 0;
+ }
+ }
return recordFix(fix, impact) ? SolutionKind::Error : SolutionKind::Solved;
}
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/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/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp
index 3dce3ebf1b379..8b457f14b274a 100644
--- a/lib/Sema/ConstraintSystem.cpp
+++ b/lib/Sema/ConstraintSystem.cpp
@@ -1747,8 +1747,17 @@ 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() &&
+ !locator.endsWith()) {
+ DC = EED->getDeclContext();
+ }
+ }
+
+ if (DC) {
// All global functions should be @Sendable
if (DC->isModuleScopeContext()) {
if (!adjustedTy->getExtInfo().isSendable()) {
@@ -6658,6 +6667,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()) {
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/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
// ```
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/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp
index b3ee16614cf78..cfca7058db1c8 100644
--- a/lib/Sema/ImportResolution.cpp
+++ b/lib/Sema/ImportResolution.cpp
@@ -1365,6 +1365,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.
@@ -1385,12 +1392,6 @@ void ImportResolver::crossImport(ModuleDecl *M, UnboundImport &I) {
// first bind all exported imports in all files, then bind all other imports
// in each file. This may become simpler if we bind all ImportDecls before we
// start computing cross-imports, but I haven't figured that part out yet.
- //
- // Fixing this is tracked within Apple by rdar://problem/59527118. I haven't
- // filed an SR because I plan to address it myself, but if this comment is
- // still here in April 2020 without an SR number, please file a Swift bug and
- // harass @brentdax to fill in the details.
-
if (!SF.shouldCrossImport())
return;
diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp
index 789a6e02fc6b7..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);
@@ -1745,7 +1835,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 +1873,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 +1883,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 +2057,7 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
static bool
hasValidSelfRebinding(const LabeledConditionalStmt *conditionalStmt,
- const AbstractClosureExpr *inClosure) {
+ ASTContext &ctx) {
if (!conditionalStmt) {
return false;
}
@@ -1980,8 +2070,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
@@ -2065,8 +2154,8 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
/// use or capture of "self." for qualification of member references.
static bool
isClosureRequiringSelfQualification(const AbstractClosureExpr *CE,
- ASTContext &Ctx) {
- if (closureHasWeakSelfCapture(CE)) {
+ bool ignoreWeakSelf = false) {
+ if (!ignoreWeakSelf && closureHasWeakSelfCapture(CE)) {
return true;
}
@@ -2112,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.
@@ -2146,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.
@@ -2161,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);
}
@@ -2175,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);
}
@@ -2189,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);
}
@@ -2253,7 +2355,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;
}
@@ -2369,134 +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, ACE)) {
+ 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, ACE);
-
- // 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(ACE->getASTContext(),
- /*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,
- AbstractClosureExpr *ACE) {
- // 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);
- }
-
- /// 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();
}
};
@@ -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();
}
diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp
index 681d1e0ee4c48..0f855431a0e78 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);
}
}
@@ -105,16 +100,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,17 +119,15 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
if (isa(DC) && !Context.isSwiftVersionAtLeast(6))
downgradeToWarning = DowngradeToWarning::Yes;
- if (!allowedForPkgCtx) {
- auto diagID = diag::resilience_decl_unavailable;
- if (downgradeToWarning == DowngradeToWarning::Yes)
- diagID = diag::resilience_decl_unavailable_warn;
+ 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());
+ 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,33 @@ 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)
+ // 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() &&
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 +281,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 +324,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 +373,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 +403,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 +412,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..696088116964a 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);
@@ -1424,16 +1425,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 +1464,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 +2012,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;
}
@@ -2275,7 +2260,7 @@ class DeclAvailabilityChecker : public DeclVisitor {
for (TypeLoc inherited : nominal->getInherited().getEntries()) {
checkType(inherited.getType(), inherited.getTypeRepr(), nominal,
- ExportabilityReason::General, flags);
+ ExportabilityReason::Inheritance, flags);
}
}
@@ -2352,19 +2337,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);
@@ -2383,7 +2362,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);
}
@@ -2391,61 +2370,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(),
+ 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();
-
- });
-
- // Keep track of package (exported) members separately from public
- // members for diags purposes.
- bool hasExportedPackageMembers = 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 +2398,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 +2551,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