Merge pull request #14704 from polac24/ast-nested-enum-type
[SIL] Print full nested enum type name
diff --git a/cmake/modules/SwiftHandleGybSources.cmake b/cmake/modules/SwiftHandleGybSources.cmake
index 057ffc8..c01269b 100644
--- a/cmake/modules/SwiftHandleGybSources.cmake
+++ b/cmake/modules/SwiftHandleGybSources.cmake
@@ -130,7 +130,10 @@
"${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/PatternNodes.py"
"${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/StmtNodes.py"
"${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/TypeNodes.py"
- "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/Token.py")
+ "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/Token.py"
+ "${SWIFT_SOURCE_DIR}/utils/gyb_syntax_support/Traits.py"
+ "${SWIFT_SOURCE_DIR}/utils/gyb_sourcekit_support/__init__.py"
+ "${SWIFT_SOURCE_DIR}/utils/gyb_sourcekit_support/UIDs.py")
foreach (src ${${sources_var_name}})
string(REGEX REPLACE "[.]gyb$" "" src_sans_gyb "${src}")
diff --git a/docs/DriverInternals.rst b/docs/DriverInternals.rst
index ab6bd92..6a8901a 100644
--- a/docs/DriverInternals.rst
+++ b/docs/DriverInternals.rst
@@ -94,14 +94,13 @@
modified since the last build; if it hasn't, we only need to recompile if
something it depends on has changed.
-
-Execute: Running the Jobs in a Compilation using a TaskQueue
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Schedule: Ordering and skipping jobs by dependency analysis
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A Compilation's goal is to make sure every Job in its list of Jobs is handled.
If a Job needs to be run, the Compilation attempts to *schedule* it. If the
Job's dependencies have all been completed (or determined to be skippable), it
-is added to the TaskQueue; otherwise it is marked as *blocked.*
+is scheduled for execution; otherwise it is marked as *blocked.*
To support Jobs compiling individual Swift files, which may or may not need to
be run, the Compilation keeps track of a DependencyGraph. (If file A depends on
@@ -111,6 +110,22 @@
to run based on the DependencyGraph. See the section on :doc:`DependencyAnalysis`
for more information.
+Batch: Optionally combine similar jobs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The Driver has an experimental "batch mode" that examines the set of scheduled
+jobs just prior to execution, looking for jobs that are identical to one another
+aside from the primary input file they are compiling in a module. If it finds
+such a set, it may replace the set with a single BatchJob, before handing it off
+to the TaskQueue; this helps minimize the overall number of frontend processes
+that run (and thus do potentially redundant work).
+
+Once any batching has taken place, the set of scheduled jobs (batched or
+otherwise) is transferred to the TaskQueue for execution.
+
+Execute: Running the Jobs in a Compilation using a TaskQueue
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
The Compilation's TaskQueue controls the low-level aspects of managing
subprocesses. Multiple Jobs may execute simultaneously, but communication with
the parent process (the driver) is handled on a single thread. The level of
diff --git a/docs/Windows.md b/docs/Windows.md
index 8fb86dc..04801b2 100644
--- a/docs/Windows.md
+++ b/docs/Windows.md
@@ -1,216 +1,32 @@
# Getting Started with Swift on Windows
-## clang (cross-compiling)
+One can build and run Swift natively, or through the Windows Subsystem for
+Linux.
-### 1. Setup Visual Studio Environment Variables
-Building for Windows requires that the Visual Studio environment variables are
-setup similar to the values on Windows. The following assumes that
-`WINKIT_ROOT` points to the path where the Windows 10 SDK is available and that
-`VC_ROOT` points to the path where the Visual Studio VC headers and libraries
-are available. Currently, the runtime has been tested to build against the
-Windows 10 SDK at revision 10.10.586.
+## Native Windows
-```bash
-# Visual Studio 2015 does not have VCToolsInstallDir, use VCINSTALLDIR's value
-export UCRTVersion=10.0.10586.0
-export UniversalCRTSdkDir=".../Windows Kits/10"
-export VCToolsInstallDir=".../Microsoft Visual Studio/2017/Community"
-```
+Currently there are three supported ways to build Swift for Windows.
-### 2. Setup `visualc` and `ucrt` modules
-The `visualc.modulemap` located at
-`swift/stdlib/public/Platform/visualc.modulemap` needs to be copied into
-`${VCToolsInstallDir}/include`. The `ucrt.modulemap` located at
-`swift/stdlib/public/Platform/ucrt.modulemap` needs to be copied into
-`${UniversalCRTSdkDir}/Include/${UCRTVersion}/ucrt`.
+1. To cross-compile Swift for Windows from another host operating system (using
+ `clang`), see [Cross Compiling for Windows](./WindowsCrossCompile.md)
-### 3. Configure the runtime to be built with the just built clang
-Ensure that we use the tools from the just built LLVM and clang tools to build
-the Windows SDK. You will need to pass a few extra options to cmake via the
-`build-script` invocation to achieve this. You will need to expand out the
-path where llvm-ar and llvm-ranlib are built. These are needed to correctly
-build the static libraries. Note that cross-compiling will require the use of
-lld. Ensure that lld-link.exe (lld-link) is available to clang via your path.
-Additionally, the ICU headers and libraries need to be provided for the build.
+1. To build on Windows using `clang-cl`, see [Building on
+ Windows](./WindowsBuild.md#clang-cl)
-```bash
---extra-cmake-options=-DSWIFT_BUILD_RUNTIME_WITH_HOST_COMPILER=FALSE,-DCMAKE_AR=<path to llvm-ar>,-DCMAKE_RANLIB=<path to llvm-ranlib>,-DSWIFT_SDKS=WINDOWS,-DSWIFT_WINDOWS_ICU_I18N_INCLUDE=<path to ICU i18n includes>,-DSWIFT_WINDOWS_ICU_UC_INCLUDE=<path to ICU UC includes>,-DSWIFT_WINDOWS_ICU_I18N_LIB=<path to ICU i18n lib>,-DSWIFT_WINDOWS_ICU_UC_LIB=<path to ICU UC lib>
-```
+1. To build on Windows using Microsoft Visual C++ (MSVC), see [Building on
+ Windows](./WindowsBuild.md#MSVC)
-## MSVC
-- Windows doesn't currently have a build script. You'll need to run commands manually to build Swift on Windows.
-- Release/RelWithDebInfo modes have not been tested and may not be supported.
-- Windows support for Swift is very much a work in progress and may not work on your system.
-- Using the latest Visual Studio version is recommended. Swift may fail to build with older C++ compilers.
+`clang-cl` is recommended over MSVC for building Swift on Windows.
+Although it is possible to build the compiler and the standard library with
+MSVC to use those built products to compile a Swift program, it won't be
+possible to run the binary without seperately obtaining the Swift runtime. On
+the other hand, `clang-cl` is able to build the runtime, which makes it
+possible to build and run all the components required for Swift natively on
+Windows.
-### 1. Install dependencies
-- Make sure to add Python, CMake and Ninja to your `Path` environment variable
-1. Latest version (2.7.12 tested) of [Python 2](https://www.python.org/downloads/)
-2. Latest version (3.7.0-rc3 tested) of [CMake](https://cmake.org/download/)
-3. Latest version (1.7.1 tested) of [Ninja](https://github.com/ninja-build/ninja/releases/latest)
-4. Latest version (2015 Update 3 tested) of [Visual Studio](https://www.visualstudio.com/downloads/)
-- Make sure to include `Programming Languages|Visual C++` and `Windows and Web Development|Universal Windows App Development|Windows SDK` in your installation.
-- Windows SDK 10.0.10240 was tested. Some later versions (e.g. 10.0.14393) are known not to work, as they are not supported by `compiler-rt`.
+## Windows Subsystem for Linux
-### 2. Clone the repositories
-1. Create a folder to contain all the Swift repositories
-2. `apple/swift-cmark` into a folder named `cmark`
-3. `apple/swift-clang` into a folder named `clang`
-5. `apple/swift-llvm` into a folder named `llvm`
-5. `apple/swift` into a folder named `swift`
-- Currently, other repositories in the Swift project have not been tested and may not be supported.
-
-### 3. Build ICU
-1. Download and extract the [ICU source code](http://site.icu-project.org/download) to a folder named `icu` in the same directory as the other Swift project repositories.
-2. Open `src/win32/allinone.sln` in Visual Studio.
-3. Make sure to select the correct architecture from the drop-down in Visual Studio.
-4. Right click on the solution in the Solution Explorer window and select `Build Solution`.
-5. When this is done, add the `<icu-source>/bin` folder to your `Path` environment variable.
-
-### 4. Get ready
-- From within a **developer** command prompt (not PowerShell nor cmd, but [the Visual Studio Developer Command Prompt](https://msdn.microsoft.com/en-us/library/f35ctcxw.aspx)), execute the following command if you have an x64 PC.
-```cmd
-VsDevCmd -arch=amd64
-```
-If instead, you're compiling for a 32-bit Windows target, adapt the `arch` argument to `x86` and run
-```cmd
-VsDevCmd -arch=x86
-```
-
-- Then adapt the following command and run it.
-```cmd
-set swift_source_dir=path-to-directory-containing-all-cloned-repositories
-```
-
-### 5. Build CMark
-- This must be done from within a developer command prompt. CMark is a fairly small project and should only take a few minutes to build.
-```cmd
-mkdir "%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64"
-pushd "%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64"
-cmake -G "Ninja" "%swift_source_dir%/cmark"
-popd
-cmake --build "%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64/"
-```
-
-### 6. Build LLVM/Clang/Compiler-RT
-- This must be done from within a developer command prompt. LLVM and Clang are large projects so building might take a few hours. Make sure that the build type (e.g. Debug/Release) for LLVM/Clang matches the build type for Swift.
-- Optionally, you can omit building compiler-rt by removing all lines referring to `compiler-rt` below, which should give faster build times.
-```cmd
-mklink /J "%swift_source_dir%/llvm/tools/clang" "%swift_source_dir%/clang"
-mklink /J "%swift_source_dir%/llvm/tools/compiler-rt" "%swift_source_dir%/compiler-rt"
-mkdir "%swift_source_dir%/build/Ninja-RelWithDebInfoAssert/llvm-windows-amd64"
-pushd "%swift_source_dir%/build/Ninja-RelWithDebInfoAssert/llvm-windows-amd64"
-cmake -G "Ninja"^
- -DLLVM_ENABLE_ASSERTIONS=TRUE^
- -DCMAKE_BUILD_TYPE=RelWithDebInfo^
- -DLLVM_TOOL_SWIFT_BUILD=NO^
- -DLLVM_INCLUDE_DOCS=TRUE^
- -DLLVM_TOOL_COMPILER_RT_BUILD=TRUE^
- -DLLVM_BUILD_EXTERNAL_COMPILER_RT=TRUE^
- -DLLVM_LIT_ARGS=-sv^
- -DLLVM_TARGETS_TO_BUILD=X86^
- "%swift_source_dir%/llvm"
-popd
-cmake --build "%swift_source_dir%/build/Ninja-DebugAssert/llvm-windows-amd64"
-```
-
-### 7. Build Swift
-- This must be done from within a developer command prompt and could take up to two hours depending on your system.
-- You may need to adjust the SWIFT_WINDOWS_LIB_DIRECTORY parameter depending on your target platform or Windows SDK version.
-- While the commands here use MSVC to build, using clang-cl is recommended (see the **Clang-cl** section below).
-```cmd
-mkdir "%swift_source_dir%/build/Ninja-DebugAssert/swift-windows-amd64/ninja"
-pushd "%swift_source_dir%/build/Ninja-DebugAssert/swift-windows-amd64/ninja"
-cmake -G "Ninja" "%swift_source_dir%/swift"^
- -DCMAKE_BUILD_TYPE=Debug^
- -DSWIFT_PATH_TO_CMARK_SOURCE="%swift_source_dir%/cmark"^
- -DSWIFT_PATH_TO_CMARK_BUILD="%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64"^
- -DSWIFT_CMARK_LIBRARY_DIR="%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64/src"^
- -DSWIFT_PATH_TO_LLVM_SOURCE="%swift_source_dir%/llvm"^
- -DSWIFT_PATH_TO_LLVM_BUILD="%swift_source_dir%/build/Ninja-RelWithDebInfoAssert/llvm-windows-amd64"^
- -DSWIFT_PATH_TO_CLANG_SOURCE="%swift_source_dir%/llvm/tools/clang"^
- -DSWIFT_PATH_TO_CLANG_BUILD="%swift_source_dir%/build/Ninja-RelWithDebInfoAssert/llvm-windows-amd64"^
- -DICU_UC_INCLUDE_DIRS="%swift_source_dir%/icu/include"^
- -DICU_UC_LIBRARY_DIRS="%swift_source_dir%/icu/lib64"^
- -DICU_I18N_INCLUDE_DIRS="%swift_source_dir%/icu/include"^
- -DICU_I18N_LIBRARY_DIRS="%swift_source_dir%/icu/lib64"^
- -DICU_UC_LIB_NAME="icuuc"^
- -DICU_I18N_LIB_NAME="icuin"^
- -DSWIFT_INCLUDE_DOCS=FALSE^
- -DSWIFT_INCLUDE_TESTS=FALSE^
- -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY=FALSE^
- -DSWIFT_BUILD_RUNTIME_WITH_HOST_COMPILER=FALSE
-popd
-cmake --build "%swift_source_dir%/build/Ninja-DebugAssert/swift-windows-amd64/ninja"
-```
-
-- To create a VisualStudio project, you'll need to change the generator and, if you have a 64 bit processor, specify the generator platform. Note that you may get multiple build errors compiling the `swift` project due to an MSBuild limitation that file paths cannot exceed 260 characters. These can be ignored, as they occur after the build when writing the last build status to a file.
-```cmd
-cmake -G "Visual Studio 15" "%swift_source_dir%/swift"^
- -DCMAKE_GENERATOR_PLATFORM="x64"^
- ...
-```
-
-## Clang-cl
-
-Follow the instructions for MSVC, but add the following lines to each CMake configuration command. `Clang-cl` 4.0.1 has been tested. You can remove the `SWIFT_BUILD_DYNAMIC_SDK_OVERLAY=FALSE` definition, as overlays are supported with `clang-cl`, as it supports modules. The `Z7` flag is required to produce PDB files that MSVC's `link.exe` can read, and also enables proper stack traces.
-
-```cmd
- -DCMAKE_C_COMPILER="<path-to-llvm-bin>/clang-cl.exe"^
- -DCMAKE_CXX_COMPILER="<path-to-llvm-bin>/bin/clang-cl.exe"^
- -DCMAKE_C_FLAGS="-fms-compatibility-version=19.00 /Z7"^
- -DCMAKE_CXX_FLAGS="-fms-compatibility-version=19.00 -Z7" ^
-```
-
-## Windows Subsystem for Linux (WSL)
-- Note that all compiled Swift binaries are only executable within Bash on Windows and are Ubuntu, not Windows, executables.
-- Make sure to run all commands from Bash, or the project won't compile.
-
-### 1. Install WSL
-Install and run the latest version of [Bash on Ubuntu on Windows](https://msdn.microsoft.com/en-gb/commandline/wsl/about) installed on your PC.
-```
-bash
-```
-
-### 2. Install dependencies
-Install the developer dependencies needed to compile the Swift project. These are identical to the Ubuntu dependencies, with the addition of `make`.
-```bash
-sudo apt-get install git make cmake ninja-build clang python uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config libblocksruntime-dev libcurl4-openssl-dev
-```
-
-### 3. Upgrade clang
-Install a version of clang with C++ 14 support - the default version of clang on WSL results in linker errors during compilation.
-```bash
-sudo apt-get install clang-3.6
-sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.6 100
-sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-3.6 100
-```
-
-### 4. Upgrade CMake
-Install the latest version of CMake - Swift uses new CMake features such as `IN_LIST` and won't build without these features.
-```bash
-wget http://www.cmake.org/files/v3.6/cmake-3.6.2.tar.gz
-tar xf cmake-3.6.2.tar.gz
-cd cmake-3.6.2
-./configure
-make
-sudo make install
-sudo update-alternatives --install /usr/bin/cmake cmake /usr/local/bin/cmake 1 --force
-cmake --version # This should print 3.6.2
-```
-
-### 6. Clone and build the Swift project
-```bash
-mkdir swift-source
-cd swift-source
-git clone https://github.com/apple/swift.git
-./swift/utils/update-checkout --clone
-./swift/utils/build-script -r
-```
-### 7. Hello, Windows (Subsystem for Linux)
-```bash
-cd ./build/Ninja-RelWithDebInfoAssert/swift-linux-x86_64/bin # This path may depend on your build configuration
-echo 'print("Hello, Windows")' >> test.swift
-swiftc test.swift
-./test # Hello, Windows
-```
+On the [Windows Subsystem for
+Linux](https://docs.microsoft.com/en-us/windows/wsl/about), it's possible to
+build and run Swift in a Linux-like environment, on Windows. See [Getting
+Started with Swift on Windows](./WindowsSubsystemForLinux.md) for details.
diff --git a/docs/WindowsBuild.md b/docs/WindowsBuild.md
new file mode 100644
index 0000000..ca3a709
--- /dev/null
+++ b/docs/WindowsBuild.md
@@ -0,0 +1,196 @@
+# Building Swift on Windows
+
+This document describes how to build Swift for Windows natively. See [the
+Windows doc](./Windows.md) for more about what is possible with Swift on
+Windows.
+
+There are two supported ways to build Swift on Windows, they are
+
+1. Using [`clang-cl`](https://clang.llvm.org/docs/UsersManual.html#clang-cl)
+1. Using the Microsoft Visual C++ compiler (MSVC)
+
+`clang-cl` is recommended over MSVC for building Swift on Windows.
+Although it is possible to build the compiler and the standard library with
+MSVC, and use those built products to compile a Swift program, it won't be
+possible to run the binary without seperately obtaining the Swift runtime. On
+the other hand, `clang-cl` is able to build the runtime, which makes it
+possible to build and run all the components required for Swift natively on
+Windows.
+
+## `clang-cl`
+- Windows doesn't currently have a build script. You'll need to run commands
+ manually to build Swift on Windows.
+- Windows support for Swift is a work in progress and may not work on your
+ system, but it has been tested.
+- Using the latest Visual Studio version is recommended (tested with Visual
+ Studio 2017 - Version 15.5.5). Swift may fail to build with older C++
+ compilers.
+
+### 1. Install dependencies
+1. Latest version (2.7.12 tested) of [Python
+ 2](https://www.python.org/downloads/)
+1. Latest version (3.7.0-rc3 tested) of [CMake](https://cmake.org/download/)
+1. Latest version (1.7.1 tested) of
+ [Ninja](https://github.com/ninja-build/ninja/releases/latest)
+1. Latest version (2015 Update 3 tested) of [Visual
+ Studio](https://www.visualstudio.com/downloads/)
+- Make sure to include "Programming Languages|Visual C++" and "Windows and Web
+ Development|Universal Windows App Development|Windows SDK" in your
+ installation.
+- Make sure to add Python, CMake and Ninja to your `Path` environment variable
+
+### 2. Clone the repositories
+1. Create a folder to contain all the Swift repositories
+1. Clone `apple/swift-cmark` into a folder named `cmark`
+1. Clone `apple/swift-clang` into a folder named `clang`
+1. Clone `apple/swift-llvm` into a folder named `llvm`
+1. Clone `apple/swift` into a folder named `swift`
+- Currently, other repositories in the Swift project have not been tested and
+ may not be supported.
+
+### 3. Build ICU
+1. Download and extract the [ICU source
+code](http://site.icu-project.org/download) to a folder named `icu` in the same
+directory as the other Swift project repositories.
+1. Open `src/win32/allinone.sln` in Visual Studio.
+1. Make sure to select the correct architecture from the drop-down in Visual
+Studio.
+1. Right click on the solution in the Solution Explorer window and select
+"Build Solution".
+1. When this is done, add the `<icu-source>/bin` folder to your `Path`
+environment variable.
+
+### 4. Get ready
+- From within a **developer** command prompt (not PowerShell nor cmd, but [the
+ Visual Studio Developer Command
+ Prompt](https://msdn.microsoft.com/en-us/library/f35ctcxw.aspx)), execute the
+ following command if you have an x64 PC.
+```cmd
+VsDevCmd -arch=amd64
+```
+If instead you're compiling for a 32-bit Windows target, adapt the `arch`
+argument to `x86` and run
+```cmd
+VsDevCmd -arch=x86
+```
+
+- Then adapt the following command and run it.
+```cmd
+set swift_source_dir=path-to-directory-containing-all-cloned-repositories
+```
+
+### 5. Build CMark
+- This must be done from within a developer command prompt. CMark is a fairly
+ small project and should only take a few minutes to build.
+```cmd
+mkdir "%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64"
+pushd "%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64"
+cmake -G "Ninja" "%swift_source_dir%/cmark"
+popd
+cmake --build "%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64/"
+```
+
+### 6. Build LLVM/Clang/Compiler-RT
+- This must be done from within a developer command prompt. LLVM and Clang are
+ large projects, so building might take a few hours. Make sure that the build
+ type (e.g. Debug, Release, RelWithDebInfoAssert) for LLVM/Clang matches the
+ build type for Swift.
+- Optionally, you can omit building compiler-rt by removing all lines referring
+ to `compiler-rt` below, which should give faster build times.
+```cmd
+mklink /J "%swift_source_dir%/llvm/tools/clang" "%swift_source_dir%/clang"
+mklink /J "%swift_source_dir%/llvm/tools/compiler-rt" "%swift_source_dir%/compiler-rt"
+mkdir "%swift_source_dir%/build/Ninja-RelWithDebInfoAssert/llvm-windows-amd64"
+pushd "%swift_source_dir%/build/Ninja-RelWithDebInfoAssert/llvm-windows-amd64"
+cmake -G "Ninja"^
+ -DLLVM_ENABLE_ASSERTIONS=TRUE^
+ -DCMAKE_BUILD_TYPE=RelWithDebInfo^
+ -DLLVM_TOOL_SWIFT_BUILD=NO^
+ -DLLVM_INCLUDE_DOCS=TRUE^
+ -DLLVM_TOOL_COMPILER_RT_BUILD=TRUE^
+ -DLLVM_BUILD_EXTERNAL_COMPILER_RT=TRUE^
+ -DLLVM_LIT_ARGS=-sv^
+ -DLLVM_TARGETS_TO_BUILD=X86^
+ "%swift_source_dir%/llvm"
+popd
+cmake --build "%swift_source_dir%/build/Ninja-DebugAssert/llvm-windows-amd64"
+```
+
+### 7. Build Swift
+- This must be done from within a developer command prompt and could take up to
+ two hours depending on your system.
+- You may need to adjust the `SWIFT_WINDOWS_LIB_DIRECTORY` parameter depending on
+ your target platform or Windows SDK version.
+- While the commands here use MSVC to build, using `clang-cl` is recommended (see
+ the **Clang-cl** section below).
+```cmd
+mkdir "%swift_source_dir%/build/Ninja-DebugAssert/swift-windows-amd64/ninja"
+pushd "%swift_source_dir%/build/Ninja-DebugAssert/swift-windows-amd64/ninja"
+cmake -G "Ninja" "%swift_source_dir%/swift"^
+ -DCMAKE_BUILD_TYPE=Debug^
+ -DSWIFT_PATH_TO_CMARK_SOURCE="%swift_source_dir%/cmark"^
+ -DSWIFT_PATH_TO_CMARK_BUILD="%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64"^
+ -DSWIFT_CMARK_LIBRARY_DIR="%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64/src"^
+ -DSWIFT_PATH_TO_LLVM_SOURCE="%swift_source_dir%/llvm"^
+ -DSWIFT_PATH_TO_LLVM_BUILD="%swift_source_dir%/build/Ninja-RelWithDebInfoAssert/llvm-windows-amd64"^
+ -DSWIFT_PATH_TO_CLANG_SOURCE="%swift_source_dir%/llvm/tools/clang"^
+ -DSWIFT_PATH_TO_CLANG_BUILD="%swift_source_dir%/build/Ninja-RelWithDebInfoAssert/llvm-windows-amd64"^
+ -DICU_UC_INCLUDE_DIRS="%swift_source_dir%/icu/include"^
+ -DICU_UC_LIBRARY_DIRS="%swift_source_dir%/icu/lib64"^
+ -DICU_I18N_INCLUDE_DIRS="%swift_source_dir%/icu/include"^
+ -DICU_I18N_LIBRARY_DIRS="%swift_source_dir%/icu/lib64"^
+ -DICU_UC_LIB_NAME="icuuc"^
+ -DICU_I18N_LIB_NAME="icuin"^
+ -DSWIFT_INCLUDE_DOCS=FALSE^
+ -DSWIFT_INCLUDE_TESTS=FALSE^
+ -DCMAKE_C_COMPILER="<path-to-llvm-bin>/clang-cl.exe"^
+ -DCMAKE_CXX_COMPILER="<path-to-llvm-bin>/bin/clang-cl.exe"^
+ -DCMAKE_C_FLAGS="-fms-compatibility-version=19.00 /Z7"^
+ -DCMAKE_CXX_FLAGS="-fms-compatibility-version=19.00 -Z7" ^
+ -DSWIFT_BUILD_RUNTIME_WITH_HOST_COMPILER=FALSE
+popd
+cmake --build "%swift_source_dir%/build/Ninja-DebugAssert/swift-windows-amd64/ninja"
+```
+
+- To create a Visual Studio project, you'll need to change the generator and,
+ if you have a 64 bit processor, specify the generator platform. Note that you
+ may get multiple build errors compiling the `swift` project due to an MSBuild
+ limitation that file paths cannot exceed 260 characters. These can be
+ ignored, as they occur after the build when writing the last build status to
+ a file.
+
+```cmd
+cmake -G "Visual Studio 15" "%swift_source_dir%/swift"^
+ -DCMAKE_GENERATOR_PLATFORM="x64"^
+ ...
+```
+
+## MSVC
+
+Follow instructions 1-6 for `clang-cl`, but run the following instead to build Swift
+
+```cmd
+mkdir "%swift_source_dir%/build/Ninja-DebugAssert/swift-windows-amd64/ninja"
+pushd "%swift_source_dir%/build/Ninja-DebugAssert/swift-windows-amd64/ninja"
+cmake -G "Ninja" "%swift_source_dir%/swift"^
+ -DCMAKE_BUILD_TYPE=Debug^
+ -DSWIFT_PATH_TO_CMARK_SOURCE="%swift_source_dir%/cmark"^
+ -DSWIFT_PATH_TO_CMARK_BUILD="%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64"^
+ -DSWIFT_CMARK_LIBRARY_DIR="%swift_source_dir%/build/Ninja-DebugAssert/cmark-windows-amd64/src"^
+ -DSWIFT_PATH_TO_LLVM_SOURCE="%swift_source_dir%/llvm"^
+ -DSWIFT_PATH_TO_LLVM_BUILD="%swift_source_dir%/build/Ninja-RelWithDebInfoAssert/llvm-windows-amd64"^
+ -DSWIFT_PATH_TO_CLANG_SOURCE="%swift_source_dir%/llvm/tools/clang"^
+ -DSWIFT_PATH_TO_CLANG_BUILD="%swift_source_dir%/build/Ninja-RelWithDebInfoAssert/llvm-windows-amd64"^
+ -DICU_UC_INCLUDE_DIRS="%swift_source_dir%/icu/include"^
+ -DICU_UC_LIBRARY_DIRS="%swift_source_dir%/icu/lib64"^
+ -DICU_I18N_INCLUDE_DIRS="%swift_source_dir%/icu/include"^
+ -DICU_I18N_LIBRARY_DIRS="%swift_source_dir%/icu/lib64"^
+ -DICU_UC_LIB_NAME="icuuc"^
+ -DICU_I18N_LIB_NAME="icuin"^
+ -DSWIFT_INCLUDE_DOCS=FALSE^
+ -DSWIFT_INCLUDE_TESTS=FALSE^
+ -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY=FALSE^
+ -DSWIFT_BUILD_RUNTIME_WITH_HOST_COMPILER=FALSE
+popd
+cmake --build "%swift_source_dir%/build/Ninja-DebugAssert/swift-windows-amd64/ninja"
+```
diff --git a/docs/WindowsCrossCompile.md b/docs/WindowsCrossCompile.md
new file mode 100644
index 0000000..c20bf19
--- /dev/null
+++ b/docs/WindowsCrossCompile.md
@@ -0,0 +1,44 @@
+# Cross-compiling Swift for Windows with `clang`
+
+This document describes how to cross compile Swift on Windows on a non-Windows
+host. For more context on the status of Swift on Windows in general, see
+[Getting Started with Swift on Windows](./Windows.md)
+
+## 1. Set up Visual Studio environment variables
+Building for Windows requires that the Visual Studio environment variables are
+setup similar to the values on Windows. Currently, the runtime has been tested
+to build against the Windows 10 SDK at revision 10.10.586.
+
+```bash
+# Visual Studio 2015 does not have VCToolsInstallDir, use VCINSTALLDIR's value
+export UCRTVersion=10.0.10586.0
+export UniversalCRTSdkDir=".../Windows Kits/10"
+export VCToolsInstallDir=".../Microsoft Visual Studio/2017/Community"
+```
+
+## 2. Set up the `visualc` and `ucrt` modules
+The `visualc.modulemap` located at
+`swift/stdlib/public/Platform/visualc.modulemap` needs to be copied into
+`${VCToolsInstallDir}/include`. The `ucrt.modulemap` located at
+`swift/stdlib/public/Platform/ucrt.modulemap` needs to be copied into
+`${UniversalCRTSdkDir}/Include/${UCRTVersion}/ucrt`.
+
+## 3. Configure the runtime to be built with the just built `clang`
+Ensure that we use the tools from the just built LLVM and `clang` tools to
+build the Windows SDK. You will need to pass a few extra options to cmake via
+the `build-script` invocation to achieve this. You will need to expand out the
+path where `llvm-ar` and `llvm-ranlib` are built. These are needed to correctly
+build the static libraries. Note that cross-compiling will require the use of
+`lld`. Ensure that `lld-link.exe` is available to clang via your path.
+Additionally, the ICU headers and libraries need to be provided for the build.
+
+```bash
+--extra-cmake-options=-DSWIFT_BUILD_RUNTIME_WITH_HOST_COMPILER=FALSE, \
+ -DCMAKE_AR=<path to llvm-ar>, \
+ -DCMAKE_RANLIB=<path to llvm-ranlib>, \
+ -DSWIFT_SDKS=WINDOWS, \
+ -DSWIFT_WINDOWS_ICU_I18N_INCLUDE=<path to ICU i18n includes>, \
+ -DSWIFT_WINDOWS_ICU_UC_INCLUDE=<path to ICU UC includes>, \
+ -DSWIFT_WINDOWS_ICU_I18N=<path to ICU i18n lib>, \
+ -DSWIFT_WINDOWS_ICU_UC=<path to ICU UC lib>
+```
diff --git a/docs/WindowsSubsystemForLinux.md b/docs/WindowsSubsystemForLinux.md
new file mode 100644
index 0000000..bbfcab5
--- /dev/null
+++ b/docs/WindowsSubsystemForLinux.md
@@ -0,0 +1,60 @@
+# Windows Subsystem for Linux (WSL)
+
+- Note that all compiled Swift binaries are only executable within Bash on
+ Windows and are Ubuntu, not Windows, executables (WSL can natively run Ubuntu
+ executables).
+- Make sure to run all commands from `bash`, or the project won't compile.
+
+### 1. Install WSL
+Install and run the latest version of [Bash on Ubuntu on
+Windows](https://msdn.microsoft.com/en-gb/commandline/wsl/about) installed on
+your PC.
+```
+bash
+```
+
+### 2. Install dependencies
+Install the developer dependencies needed to compile the Swift project. These
+are identical to the Ubuntu dependencies, with the addition of `make`.
+```bash
+sudo apt-get install git make cmake ninja-build clang python uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config libblocksruntime-dev libcurl4-openssl-dev
+```
+
+### 3. Upgrade `clang`
+Install a version of `clang` with C++ 14 support; the default version of `clang`
+on WSL results in linker errors during compilation.
+```bash
+sudo apt-get install clang-3.6
+sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.6 100
+sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-3.6 100
+```
+
+### 4. Upgrade CMake
+Install the latest version of CMake; Swift uses new CMake features such as
+`IN_LIST` and won't build without these features.
+```bash
+wget http://www.cmake.org/files/v3.6/cmake-3.6.2.tar.gz
+tar xf cmake-3.6.2.tar.gz
+cd cmake-3.6.2
+./configure
+make
+sudo make install
+sudo update-alternatives --install /usr/bin/cmake cmake /usr/local/bin/cmake 1 --force
+cmake --version # This should print 3.6.2
+```
+
+### 6. Clone and build the Swift project
+```bash
+mkdir swift-source
+cd swift-source
+git clone https://github.com/apple/swift.git
+./swift/utils/update-checkout --clone
+./swift/utils/build-script -r
+```
+### 7. Hello, Windows (Subsystem for Linux)
+```bash
+cd ./build/Ninja-RelWithDebInfoAssert/swift-linux-x86_64/bin # This path may depend on your build configuration
+echo 'print("Hello, Windows")' >> test.swift
+swiftc test.swift
+./test # Hello, Windows
+```
diff --git a/docs/tools/swift.pod b/docs/tools/swift.pod
index 853815d..1989ed8 100644
--- a/docs/tools/swift.pod
+++ b/docs/tools/swift.pod
@@ -72,7 +72,7 @@
Objective-C). As such, Swift must be comparable to those languages in
performance for most tasks. Performance must also be predictable and consistent,
not just fast in short bursts that require clean-up later. There are lots of
-languages with novel features — being fast is rare.
+languages with novel features - being fast is rare.
B<Expressive.> Swift benefits from decades of advancement in computer science to
offer syntax that is a joy to use, with modern features developers expect. But
@@ -81,12 +81,11 @@
=head1 BUGS
-Reporting bugs is a great way for anyone to help improve Swift.
-The bug tracker for Swift, an open-source project, is located at
-L<https://bugs.swift.org>.
+Reporting bugs is a great way for anyone to help improve Swift. The bug tracker
+for Swift, an open-source project, is located at L<https://bugs.swift.org>.
If a bug can be reproduced only within an Xcode project or a playground, or if
-the bug is associated with an Apple NDA, please file a report to Apple’s
+the bug is associated with an Apple NDA, please file a report to Apple's
bug reporter at L<https://bugreport.apple.com> instead.
=head1 SEE ALSO
diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def
index e91a2b9..2bcaf62 100644
--- a/include/swift/AST/Attr.def
+++ b/include/swift/AST/Attr.def
@@ -308,6 +308,12 @@
LongAttribute | NotSerialized | RejectByParser | UserInaccessible,
/*Not serialized*/74)
+SIMPLE_DECL_ATTR(_weakLinked, WeakLinked,
+ OnEnum | OnStruct | OnClass | OnProtocol |
+ OnFunc | OnVar | OnSubscript | OnConstructor | OnEnumElement |
+ UserInaccessible,
+ 75)
+
#undef TYPE_ATTR
#undef DECL_ATTR_ALIAS
#undef SIMPLE_DECL_ATTR
diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h
index 3b1c7de..784ed2a 100644
--- a/include/swift/AST/Identifier.h
+++ b/include/swift/AST/Identifier.h
@@ -671,15 +671,15 @@
}
friend bool operator<=(ObjCSelector lhs, ObjCSelector rhs) {
- return lhs.compare(lhs) <= 0;
+ return lhs.compare(rhs) <= 0;
}
friend bool operator>(ObjCSelector lhs, ObjCSelector rhs) {
- return lhs.compare(lhs) > 0;
+ return lhs.compare(rhs) > 0;
}
friend bool operator>=(ObjCSelector lhs, ObjCSelector rhs) {
- return lhs.compare(lhs) >= 0;
+ return lhs.compare(rhs) >= 0;
}
};
diff --git a/include/swift/AST/RawComment.h b/include/swift/AST/RawComment.h
index 853ba45..cc86dc2 100644
--- a/include/swift/AST/RawComment.h
+++ b/include/swift/AST/RawComment.h
@@ -32,7 +32,7 @@
unsigned Kind : 8;
unsigned StartColumn : 16;
unsigned StartLine;
- const unsigned EndLine;
+ unsigned EndLine;
SingleRawComment(CharSourceRange Range, const SourceManager &SourceMgr);
SingleRawComment(StringRef RawText, unsigned StartColumn);
diff --git a/include/swift/Basic/Statistic.h b/include/swift/Basic/Statistic.h
index b1750a0..7f9e48b 100644
--- a/include/swift/Basic/Statistic.h
+++ b/include/swift/Basic/Statistic.h
@@ -15,8 +15,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Statistic.h"
-#include "swift/AST/Identifier.h"
-#include "swift/Basic/SourceLoc.h"
+#include "swift/Basic/LLVM.h"
#include "swift/Basic/Timer.h"
#define SWIFT_FUNC_STAT \
@@ -56,35 +55,29 @@
namespace swift {
class Decl;
+class ProtocolConformance;
class Expr;
class SILFunction;
+class FrontendStatsTracer;
+class SourceManager;
class UnifiedStatsReporter {
public:
struct AlwaysOnDriverCounters
{
-#define DRIVER_STATISTIC(ID) size_t ID;
+#define DRIVER_STATISTIC(ID) int64_t ID;
#include "Statistics.def"
#undef DRIVER_STATISTIC
};
struct AlwaysOnFrontendCounters
{
-#define FRONTEND_STATISTIC(NAME, ID) size_t ID;
+#define FRONTEND_STATISTIC(NAME, ID) int64_t ID;
#include "Statistics.def"
#undef FRONTEND_STATISTIC
};
- struct AlwaysOnFrontendRecursiveSharedTimers {
- AlwaysOnFrontendRecursiveSharedTimers();
-#define FRONTEND_RECURSIVE_SHARED_TIMER(ID) RecursiveSharedTimer ID;
-#include "Statistics.def"
-#undef FRONTEND_RECURSIVE_SHARED_TIMER
-
- int dummyInstanceVariableToGetConstructorToParse;
- };
-
// To trace an entity, you have to provide a TraceFormatter for it. This is a
// separate type since we do not have retroactive conformances in C++, and it
// is a type that takes void* arguments since we do not have existentials
@@ -98,25 +91,6 @@
virtual ~TraceFormatter();
};
- struct FrontendStatsTracer
- {
- UnifiedStatsReporter *Reporter;
- llvm::TimeRecord SavedTime;
- StringRef EventName;
- const void *Entity;
- const TraceFormatter *Formatter;
- FrontendStatsTracer(StringRef EventName,
- const void *Entity,
- const TraceFormatter *Formatter,
- UnifiedStatsReporter *Reporter);
- FrontendStatsTracer();
- FrontendStatsTracer(FrontendStatsTracer&& other);
- FrontendStatsTracer& operator=(FrontendStatsTracer&&);
- ~FrontendStatsTracer();
- FrontendStatsTracer(const FrontendStatsTracer&) = delete;
- FrontendStatsTracer& operator=(const FrontendStatsTracer&) = delete;
- };
-
struct FrontendStatsEvent
{
uint64_t TimeUSec;
@@ -124,37 +98,60 @@
bool IsEntry;
StringRef EventName;
StringRef CounterName;
- size_t CounterDelta;
- size_t CounterValue;
+ int64_t CounterDelta;
+ int64_t CounterValue;
const void *Entity;
const TraceFormatter *Formatter;
};
+ // We only write fine-grained trace entries when the user passed
+ // -trace-stats-events, but we recycle the same FrontendStatsTracers to give
+ // us some free recursion-save phase timings whenever -trace-stats-dir is
+ // active at all. Reduces redundant machinery.
+ class RecursionSafeTimers;
+
+ // We also keep a few banks of optional hierarchical profilers for times and
+ // statistics, activated with -profile-stats-events and
+ // -profile-stats-entities, which are part way between the detail level of the
+ // aggregate statistic JSON files and the fine-grained CSV traces. Naturally
+ // these are written in yet a different file format: the input format for
+ // flamegraphs.
+ struct StatsProfilers;
+
private:
bool currentProcessExitStatusSet;
int currentProcessExitStatus;
SmallString<128> StatsFilename;
SmallString<128> TraceFilename;
+ SmallString<128> ProfileDirname;
llvm::TimeRecord StartedTime;
+
+ // This is unique_ptr because NamedRegionTimer is non-copy-constructable.
std::unique_ptr<llvm::NamedRegionTimer> Timer;
+
SourceManager *SourceMgr;
clang::SourceManager *ClangSourceMgr;
- std::unique_ptr<AlwaysOnDriverCounters> DriverCounters;
- std::unique_ptr<AlwaysOnFrontendCounters> FrontendCounters;
- std::unique_ptr<AlwaysOnFrontendCounters> LastTracedFrontendCounters;
- std::vector<FrontendStatsEvent> FrontendStatsEvents;
- std::unique_ptr<AlwaysOnFrontendRecursiveSharedTimers>
- FrontendRecursiveSharedTimers;
+ Optional<AlwaysOnDriverCounters> DriverCounters;
+ Optional<AlwaysOnFrontendCounters> FrontendCounters;
+ Optional<AlwaysOnFrontendCounters> LastTracedFrontendCounters;
+ Optional<std::vector<FrontendStatsEvent>> FrontendStatsEvents;
+
+ // These are unique_ptr so we can use incomplete types here.
+ std::unique_ptr<RecursionSafeTimers> RecursiveTimers;
+ std::unique_ptr<StatsProfilers> EventProfilers;
+ std::unique_ptr<StatsProfilers> EntityProfilers;
void publishAlwaysOnStatsToLLVM();
- void printAlwaysOnStatsAndTimers(llvm::raw_ostream &OS);
+ void printAlwaysOnStatsAndTimers(raw_ostream &OS);
UnifiedStatsReporter(StringRef ProgramName,
StringRef AuxName,
StringRef Directory,
SourceManager *SM,
clang::SourceManager *CSM,
- bool TraceEvents);
+ bool TraceEvents,
+ bool ProfileEvents,
+ bool ProfileEntities);
public:
UnifiedStatsReporter(StringRef ProgramName,
StringRef ModuleName,
@@ -165,23 +162,83 @@
StringRef Directory,
SourceManager *SM=nullptr,
clang::SourceManager *CSM=nullptr,
- bool TraceEvents=false);
+ bool TraceEvents=false,
+ bool ProfileEvents=false,
+ bool ProfileEntities=false);
~UnifiedStatsReporter();
AlwaysOnDriverCounters &getDriverCounters();
AlwaysOnFrontendCounters &getFrontendCounters();
- AlwaysOnFrontendRecursiveSharedTimers &getFrontendRecursiveSharedTimers();
void noteCurrentProcessExitStatus(int);
- // We declare 4 explicit overloads here, but the _definitions_ live in the
- // upper-level files (in libswiftAST or libswiftSIL) that provide the types
- // being traced. If you want to trace those types, it's assumed you're linking
- // with the object files that define the tracer.
- FrontendStatsTracer getStatsTracer(StringRef EventName, const Decl *D);
- FrontendStatsTracer getStatsTracer(StringRef EventName, const clang::Decl*D);
- FrontendStatsTracer getStatsTracer(StringRef EventName, const Expr *E);
- FrontendStatsTracer getStatsTracer(StringRef EventName, const SILFunction *F);
void saveAnyFrontendStatsEvents(FrontendStatsTracer const &T, bool IsEntry);
};
+// This is a non-nested type just to make it less work to write at call sites.
+class FrontendStatsTracer
+{
+ FrontendStatsTracer(UnifiedStatsReporter *Reporter,
+ StringRef EventName,
+ const void *Entity,
+ const UnifiedStatsReporter::TraceFormatter *Formatter);
+
+ // In the general case we do not know how to format an entity for tracing.
+ template<typename T> static
+ const UnifiedStatsReporter::TraceFormatter *getTraceFormatter() {
+ return nullptr;
+ }
+
+public:
+ UnifiedStatsReporter *Reporter;
+ llvm::TimeRecord SavedTime;
+ StringRef EventName;
+ const void *Entity;
+ const UnifiedStatsReporter::TraceFormatter *Formatter;
+ FrontendStatsTracer();
+ FrontendStatsTracer(FrontendStatsTracer&& other);
+ FrontendStatsTracer& operator=(FrontendStatsTracer&&);
+ ~FrontendStatsTracer();
+ FrontendStatsTracer(const FrontendStatsTracer&) = delete;
+ FrontendStatsTracer& operator=(const FrontendStatsTracer&) = delete;
+
+ /// These are the convenience constructors you want to be calling throughout
+ /// the compiler: they select an appropriate trace formatter for the provided
+ /// entity type, and produce a tracer that's either active or inert depending
+ /// on whether the provided \p Reporter is null (nullptr means "tracing is
+ /// disabled").
+ FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName);
+ FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
+ const Decl *D);
+ FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
+ const ProtocolConformance *P);
+ FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
+ const clang::Decl *D);
+ FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
+ const Expr *E);
+ FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
+ const SILFunction *F);
+};
+
+// In particular cases, we do know how to format traced entities: we declare
+// explicit specializations of getTraceFormatter() here, matching the overloaded
+// constructors of FrontendStatsTracer above, where the _definitions_ live in
+// the upper-level files (in libswiftAST or libswiftSIL), and provide tracing
+// for those entity types. If you want to trace those types, it's assumed you're
+// linking with the object files that define the tracer.
+
+template<> const UnifiedStatsReporter::TraceFormatter*
+FrontendStatsTracer::getTraceFormatter<const Decl *>();
+
+template<> const UnifiedStatsReporter::TraceFormatter*
+FrontendStatsTracer::getTraceFormatter<const ProtocolConformance *>();
+
+template<> const UnifiedStatsReporter::TraceFormatter*
+FrontendStatsTracer::getTraceFormatter<const clang::Decl *>();
+
+template<> const UnifiedStatsReporter::TraceFormatter*
+FrontendStatsTracer::getTraceFormatter<const Expr *>();
+
+template<> const UnifiedStatsReporter::TraceFormatter*
+FrontendStatsTracer::getTraceFormatter<const SILFunction *>();
+
}
#endif // SWIFT_BASIC_STATISTIC_H
diff --git a/include/swift/Basic/Statistics.def b/include/swift/Basic/Statistics.def
index 36033a2..6c7b764 100644
--- a/include/swift/Basic/Statistics.def
+++ b/include/swift/Basic/Statistics.def
@@ -19,9 +19,6 @@
// - Subsystem is a token to be stringified as a name prefix
// - Id is an identifier suitable for use in C++
//
-// FRONTEND_RECURSIVE_SHARED_TIMER(Id)
-// - Id is an identifier suitable for use in C++
-//
//===----------------------------------------------------------------------===//
/// Driver statistics are collected for driver processes
@@ -219,13 +216,3 @@
/// the .o file you find on disk after the frontend exits.
FRONTEND_STATISTIC(LLVM, NumLLVMBytesOutput)
#endif
-
-/// Frontend timers for recursive routines
-#ifdef FRONTEND_RECURSIVE_SHARED_TIMER
-
-/// Time spent in NominalTypeDecl::lookupDirect.
-FRONTEND_RECURSIVE_SHARED_TIMER(NominalTypeDecl__lookupDirect)
-
-/// Time spent in ClangImporter::Implementation::loadAllMembers.
-FRONTEND_RECURSIVE_SHARED_TIMER(ClangImporter__Implementation__loadAllMembers)
-#endif
diff --git a/include/swift/Basic/Timer.h b/include/swift/Basic/Timer.h
index dab7abc..20f199c 100644
--- a/include/swift/Basic/Timer.h
+++ b/include/swift/Basic/Timer.h
@@ -45,66 +45,6 @@
CompilationTimersEnabled = State::Enabled;
}
};
-
- /// A SharedTimer for recursive routines.
- /// void example() {
- /// RecursiveSharedTimer::Guard guard; // MUST BE AT TOP SCOPE of function to
- /// work right! if (auto s = getASTContext().Stats) {
- /// guard =
- /// ctx.Stats->getFrontendRecursiveSharedTimers().NominalTypeDecl__lookupDirect.getGuard();
- // }
- /// ...
- /// }
-
- class RecursiveSharedTimer {
- private:
- int recursionCount = 0;
- const StringRef name;
- llvm::Optional<SharedTimer> timer;
-
- void enterRecursiveFunction() {
- assert(recursionCount >= 0 && "too many exits");
- if (recursionCount++ == 0)
- timer.emplace(name);
- }
- void exitRecursiveFunction() {
- assert(recursionCount > 0 && "too many exits");
- if (--recursionCount == 0)
- timer.reset();
- }
-
- public:
- RecursiveSharedTimer(StringRef name) : name(name) {}
-
- struct Guard {
- RecursiveSharedTimer *recursiveTimerOrNull;
-
- Guard(RecursiveSharedTimer *rst) : recursiveTimerOrNull(rst) {
- if (recursiveTimerOrNull)
- recursiveTimerOrNull->enterRecursiveFunction();
- }
- ~Guard() {
- if (recursiveTimerOrNull)
- recursiveTimerOrNull->exitRecursiveFunction();
- }
-
- // All this stuff is to do an RAII object that be moved.
- Guard() : recursiveTimerOrNull(nullptr) {}
- Guard(Guard &&other) {
- recursiveTimerOrNull = other.recursiveTimerOrNull;
- other.recursiveTimerOrNull = nullptr;
- }
- Guard &operator=(Guard &&other) {
- recursiveTimerOrNull = other.recursiveTimerOrNull;
- other.recursiveTimerOrNull = nullptr;
- return *this;
- }
- Guard(const Guard &) = delete;
- Guard &operator=(const Guard &) = delete;
- };
-
- Guard getGuard() { return Guard(this); }
- };
} // end namespace swift
#endif // SWIFT_BASIC_TIMER_H
diff --git a/include/swift/Demangling/Demangle.h b/include/swift/Demangling/Demangle.h
index 61ea600..b17f9cd 100644
--- a/include/swift/Demangling/Demangle.h
+++ b/include/swift/Demangling/Demangle.h
@@ -24,6 +24,7 @@
#include <cassert>
#include <cstdint>
#include "llvm/ADT/StringRef.h"
+#include "swift/Runtime/Config.h"
namespace llvm {
class raw_ostream;
@@ -246,6 +247,31 @@
/// This does not include the old (<= swift 3.x) mangling prefix "_T".
llvm::StringRef dropSwiftManglingPrefix(llvm::StringRef mangledName);
+/// Returns true if the mangled name is an alias type name.
+///
+/// \param mangledName A null-terminated string containing a mangled name.
+bool isAlias(llvm::StringRef mangledName);
+
+/// Returns true if the mangled name is a class type name.
+///
+/// \param mangledName A null-terminated string containing a mangled name.
+bool isClass(llvm::StringRef mangledName);
+
+/// Returns true if the mangled name is an enum type name.
+///
+/// \param mangledName A null-terminated string containing a mangled name.
+bool isEnum(llvm::StringRef mangledName);
+
+/// Returns true if the mangled name is a protocol type name.
+///
+/// \param mangledName A null-terminated string containing a mangled name.
+bool isProtocol(llvm::StringRef mangledName);
+
+/// Returns true if the mangled name is a structure type name.
+///
+/// \param mangledName A null-terminated string containing a mangled name.
+bool isStruct(llvm::StringRef mangledName);
+
/// Returns true if the mangled name has the old scheme of function type
/// mangling where labels are part of the type.
///
@@ -528,4 +554,30 @@
} // end namespace Demangle
} // end namespace swift
+// NB: This function is not used directly in the Swift codebase, but is
+// exported for Xcode support and is used by the sanitizers. Please coordinate
+// before changing.
+//
+/// Demangles a Swift symbol name.
+///
+/// \param mangledName is the symbol name that needs to be demangled.
+/// \param mangledNameLength is the length of the string that should be
+/// demangled.
+/// \param outputBuffer is the user provided buffer where the demangled name
+/// will be placed. If nullptr, a new buffer will be malloced. In that case,
+/// the user of this API is responsible for freeing the returned buffer.
+/// \param outputBufferSize is the size of the output buffer. If the demangled
+/// name does not fit into the outputBuffer, the output will be truncated and
+/// the size will be updated, indicating how large the buffer should be.
+/// \param flags can be used to select the demangling style. TODO: We should
+//// define what these will be.
+/// \returns the demangled name. Returns nullptr if the input String is not a
+/// Swift mangled name.
+SWIFT_RUNTIME_EXPORT
+char *swift_demangle(const char *mangledName,
+ size_t mangledNameLength,
+ char *outputBuffer,
+ size_t *outputBufferSize,
+ uint32_t flags);
+
#endif // SWIFT_DEMANGLING_DEMANGLE_H
diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h
index 7b21afb..d2bd7dd 100644
--- a/include/swift/Demangling/TypeDecoder.h
+++ b/include/swift/Demangling/TypeDecoder.h
@@ -124,7 +124,8 @@
}
case NodeKind::BoundGenericClass:
case NodeKind::BoundGenericEnum:
- case NodeKind::BoundGenericStructure: {
+ case NodeKind::BoundGenericStructure:
+ case NodeKind::BoundGenericOtherNominalType: {
if (Node->getNumChildren() != 2)
return BuiltType();
diff --git a/include/swift/Driver/Compilation.h b/include/swift/Driver/Compilation.h
index c2a5513..96112d7 100644
--- a/include/swift/Driver/Compilation.h
+++ b/include/swift/Driver/Compilation.h
@@ -161,6 +161,9 @@
/// redundant work.
bool EnableBatchMode;
+ /// Provides a randomization seed to batch-mode partitioning, for debugging.
+ unsigned BatchSeed;
+
/// True if temporary files should not be deleted.
bool SaveTemps;
@@ -203,6 +206,7 @@
unsigned NumberOfParallelCommands = 1,
bool EnableIncrementalBuild = false,
bool EnableBatchMode = false,
+ unsigned BatchSeed = 0,
bool SkipTaskExecution = false,
bool SaveTemps = false,
bool ShowDriverTimeCompilation = false,
diff --git a/include/swift/Driver/Driver.h b/include/swift/Driver/Driver.h
index dab4b8c..cf3394a 100644
--- a/include/swift/Driver/Driver.h
+++ b/include/swift/Driver/Driver.h
@@ -156,6 +156,9 @@
/// Indicates whether the driver should check that the input files exist.
bool CheckInputFilesExist = true;
+ /// Provides a randomization seed to batch-mode partitioning, for debugging.
+ unsigned DriverBatchSeed = 0;
+
public:
Driver(StringRef DriverExecutable, StringRef Name,
ArrayRef<const char *> Args, DiagnosticEngine &Diags);
@@ -205,9 +208,11 @@
std::unique_ptr<llvm::opt::InputArgList>
parseArgStrings(ArrayRef<const char *> Args);
- /// Translate the input arguments into a DerivedArgList.
- llvm::opt::DerivedArgList *translateInputArgs(
- const llvm::opt::InputArgList &ArgList) const;
+ /// Resolve path arguments if \p workingDirectory is non-empty, and translate
+ /// inputs from -- arguments into a DerivedArgList.
+ llvm::opt::DerivedArgList *
+ translateInputAndPathArgs(const llvm::opt::InputArgList &ArgList,
+ StringRef workingDirectory) const;
/// Construct the list of inputs and their types from the given arguments.
///
@@ -247,7 +252,8 @@
/// Construct the OutputFileMap for the driver from the given arguments.
std::unique_ptr<OutputFileMap>
- buildOutputFileMap(const llvm::opt::DerivedArgList &Args) const;
+ buildOutputFileMap(const llvm::opt::DerivedArgList &Args,
+ StringRef workingDirectory) const;
/// Add top-level Jobs to Compilation \p C for the given \p Actions and
/// OutputInfo.
@@ -255,12 +261,13 @@
/// \param TopLevelActions The main Actions to build Jobs for.
/// \param OI The OutputInfo for which Jobs should be generated.
/// \param OFM The OutputFileMap for which Jobs should be generated.
+ /// \param workingDirectory If non-empty, used to resolve any generated paths.
/// \param TC The ToolChain to build Jobs with.
/// \param C The Compilation containing the Actions for which Jobs should be
/// created.
void buildJobs(ArrayRef<const Action *> TopLevelActions, const OutputInfo &OI,
- const OutputFileMap *OFM, const ToolChain &TC,
- Compilation &C) const;
+ const OutputFileMap *OFM, StringRef workingDirectory,
+ const ToolChain &TC, Compilation &C) const;
/// A map for caching Jobs for a given Action/ToolChain pair
using JobCacheMap =
@@ -280,8 +287,8 @@
/// \returns a Job for the given Action/ToolChain pair
Job *buildJobsForAction(Compilation &C, const JobAction *JA,
const OutputInfo &OI, const OutputFileMap *OFM,
- const ToolChain &TC, bool AtTopLevel,
- JobCacheMap &JobCache) const;
+ StringRef workingDirectory, const ToolChain &TC,
+ bool AtTopLevel, JobCacheMap &JobCache) const;
private:
void computeMainOutput(Compilation &C, const JobAction *JA,
@@ -290,6 +297,7 @@
SmallVectorImpl<const Action *> &InputActions,
SmallVectorImpl<const Job *> &InputJobs,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
StringRef BaseInput,
StringRef PrimaryInput,
llvm::SmallString<128> &Buf,
@@ -298,10 +306,12 @@
void chooseSwiftModuleOutputPath(Compilation &C, const OutputInfo &OI,
const OutputFileMap *OFM,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
CommandOutput *Output) const;
void chooseSwiftModuleDocOutputPath(Compilation &C,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
CommandOutput *Output) const;
void chooseRemappingOutputPath(Compilation &C, const TypeToPathMap *OutputMap,
CommandOutput *Output) const;
@@ -309,27 +319,33 @@
void chooseSerializedDiagnosticsPath(Compilation &C, const JobAction *JA,
const OutputInfo &OI,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
CommandOutput *Output) const;
void chooseDependenciesOutputPaths(Compilation &C, const OutputInfo &OI,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
llvm::SmallString<128> &Buf,
CommandOutput *Output) const;
void chooseOptimizationRecordPath(Compilation &C, const OutputInfo &OI,
+ StringRef workingDirectory,
llvm::SmallString<128> &Buf,
CommandOutput *Output) const;
void chooseObjectiveCHeaderOutputPath(Compilation &C, const OutputInfo &OI,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
CommandOutput *Output) const;
void chooseLoadedModuleTracePath(Compilation &C, const OutputInfo &OI,
+ StringRef workingDirectory,
llvm::SmallString<128> &Buf,
CommandOutput *Output) const;
void chooseTBDPath(Compilation &C, const OutputInfo &OI,
- llvm::SmallString<128> &Buf, CommandOutput *Output) const;
+ StringRef workingDirectory, llvm::SmallString<128> &Buf,
+ CommandOutput *Output) const;
public:
/// Handle any arguments which should be treated before building actions or
diff --git a/include/swift/Driver/OutputFileMap.h b/include/swift/Driver/OutputFileMap.h
index 8e06cb4..b020eb9 100644
--- a/include/swift/Driver/OutputFileMap.h
+++ b/include/swift/Driver/OutputFileMap.h
@@ -39,14 +39,23 @@
~OutputFileMap() = default;
/// Loads an OutputFileMap from the given \p Path, if possible.
- static std::unique_ptr<OutputFileMap> loadFromPath(StringRef Path);
+ ///
+ /// When non-empty, \p workingDirectory is used to resolve relative paths in
+ /// the output file map.
+ static std::unique_ptr<OutputFileMap>
+ loadFromPath(StringRef Path, StringRef workingDirectory);
- static std::unique_ptr<OutputFileMap> loadFromBuffer(StringRef Data);
+ static std::unique_ptr<OutputFileMap>
+ loadFromBuffer(StringRef Data, StringRef workingDirectory);
/// Loads an OutputFileMap from the given \p Buffer, taking ownership
/// of the buffer in the process.
+ ///
+ /// When non-empty, \p workingDirectory is used to resolve relative paths in
+ /// the output file map.
static std::unique_ptr<OutputFileMap>
- loadFromBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer);
+ loadFromBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ StringRef workingDirectory);
/// Get the map of outputs for the given \p Input, if present in the
/// OutputFileMap. (If not present, returns nullptr.)
@@ -69,8 +78,12 @@
/// \brief Parses the given \p Buffer into the OutputFileMap, taking ownership
/// of \p Buffer in the process.
///
+ /// When non-empty, \p workingDirectory is used to resolve relative paths in
+ /// the output file map.
+ ///
/// \returns true on error, false on success
- bool parse(std::unique_ptr<llvm::MemoryBuffer> Buffer);
+ bool parse(std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ StringRef workingDirectory);
};
} // end namespace driver
diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h
index 6feaab1..e3ff790 100644
--- a/include/swift/Frontend/Frontend.h
+++ b/include/swift/Frontend/Frontend.h
@@ -34,7 +34,6 @@
#include "swift/Migrator/MigratorOptions.h"
#include "swift/Parse/CodeCompletionCallbacks.h"
#include "swift/Parse/Parser.h"
-#include "swift/SIL/SILModule.h"
#include "swift/Sema/SourceLoader.h"
#include "swift/Serialization/Validation.h"
#include "swift/Subsystems.h"
@@ -49,6 +48,7 @@
namespace swift {
class SerializedModuleLoader;
+class SILModule;
/// The abstract configuration of the compiler, including:
/// - options for all stages of translation,
@@ -371,6 +371,15 @@
void createSILModule();
public:
+ // Out of line to avoid having to import SILModule.h.
+ CompilerInstance();
+ ~CompilerInstance();
+
+ CompilerInstance(const CompilerInstance &) = delete;
+ void operator=(const CompilerInstance &) = delete;
+ CompilerInstance(CompilerInstance &&) = delete;
+ void operator=(CompilerInstance &&) = delete;
+
SourceManager &getSourceMgr() { return SourceMgr; }
DiagnosticEngine &getDiags() { return Diagnostics; }
@@ -398,9 +407,7 @@
/// Set the SIL module for this compilation instance.
///
/// The CompilerInstance takes ownership of the given SILModule object.
- void setSILModule(std::unique_ptr<SILModule> M) {
- TheSILModule = std::move(M);
- }
+ void setSILModule(std::unique_ptr<SILModule> M);
SILModule *getSILModule() {
return TheSILModule.get();
diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h
index 1a9a520..05552ae 100644
--- a/include/swift/Frontend/FrontendOptions.h
+++ b/include/swift/Frontend/FrontendOptions.h
@@ -164,6 +164,13 @@
/// Trace changes to stats to files in StatsOutputDir.
bool TraceStats = false;
+ /// Profile changes to stats to files in StatsOutputDir.
+ bool ProfileEvents = false;
+
+ /// Profile changes to stats to files in StatsOutputDir, grouped by source
+ /// entity.
+ bool ProfileEntities = false;
+
/// If true, serialization encodes an extra lookup table for use in module-
/// merging when emitting partial modules (the per-file modules in a non-WMO
/// build).
diff --git a/include/swift/IDE/SyntaxModel.h b/include/swift/IDE/SyntaxModel.h
index dad32d0..a80b181 100644
--- a/include/swift/IDE/SyntaxModel.h
+++ b/include/swift/IDE/SyntaxModel.h
@@ -48,6 +48,8 @@
BuildConfigKeyword,
/// An identifier in a #if condition.
BuildConfigId,
+ /// #-keywords like #warning, #sourceLocation
+ PoundDirectiveKeyword,
/// Any occurrence of '@<attribute-name>' anywhere.
AttributeId,
/// A "resolved/active" attribute. Mis-applied attributes will be AttributeId.
diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h
index 55e75d3..420f0ee 100644
--- a/include/swift/IRGen/Linking.h
+++ b/include/swift/IRGen/Linking.h
@@ -733,9 +733,12 @@
getSILGlobalVariable()->getDecl())
return getSILGlobalVariable()->getDecl()->isWeakImported(module);
- if (getKind() == Kind::SILFunction)
+ if (getKind() == Kind::SILFunction) {
if (auto clangOwner = getSILFunction()->getClangNodeOwner())
return clangOwner->isWeakImported(module);
+ if (getSILFunction()->isWeakLinked())
+ return getSILFunction()->isAvailableExternally();
+ }
if (!isDeclKind(getKind()))
return false;
diff --git a/include/swift/Option/Options.h b/include/swift/Option/Options.h
index bf5137d..7e6572f 100644
--- a/include/swift/Option/Options.h
+++ b/include/swift/Option/Options.h
@@ -34,6 +34,7 @@
AutolinkExtractOption = (1 << 9),
ModuleWrapOption = (1 << 10),
SwiftFormatOption = (1 << 11),
+ ArgumentIsPath = (1 << 12),
};
enum ID {
diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td
index d1c1030..7b891d4 100644
--- a/include/swift/Option/Options.td
+++ b/include/swift/Option/Options.td
@@ -43,6 +43,10 @@
// The option should not force a full rebuild if added, changed, or removed.
def DoesNotAffectIncrementalBuild : OptionFlag;
+// The option's argument is a file-system path that may be affected by the
+// current working directory.
+def ArgumentIsPath : OptionFlag;
+
/////////
// Options
@@ -98,6 +102,9 @@
HelpText<"Show every step in the lifecycle of driver jobs">;
def driver_use_filelists : Flag<["-"], "driver-use-filelists">,
InternalDebugOpt, HelpText<"Pass input files as filelists whenever possible">;
+def driver_batch_seed : Separate<["-"], "driver-batch-seed">,
+ InternalDebugOpt,
+ HelpText<"Use the given seed value to randomize batch-mode partitions">;
def driver_always_rebuild_dependents :
Flag<["-"], "driver-always-rebuild-dependents">, InternalDebugOpt,
@@ -129,13 +136,13 @@
def o : JoinedOrSeparate<["-"], "o">,
Flags<[FrontendOption, AutolinkExtractOption, ModuleWrapOption,
- NoInteractiveOption, SwiftFormatOption]>,
+ NoInteractiveOption, SwiftFormatOption, ArgumentIsPath]>,
HelpText<"Write output to <file>">, MetaVarName<"<file>">;
def j : JoinedOrSeparate<["-"], "j">, Flags<[DoesNotAffectIncrementalBuild]>,
HelpText<"Number of commands to execute in parallel">, MetaVarName<"<n>">;
-def sdk : Separate<["-"], "sdk">, Flags<[FrontendOption]>,
+def sdk : Separate<["-"], "sdk">, Flags<[FrontendOption, ArgumentIsPath]>,
HelpText<"Compile against <sdk>">, MetaVarName<"<sdk>">;
def swift_version : Separate<["-"], "swift-version">, Flags<[FrontendOption]>,
@@ -143,33 +150,37 @@
MetaVarName<"<vers>">;
def tools_directory : Separate<["-"], "tools-directory">,
- Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
+ Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild,
+ ArgumentIsPath]>,
HelpText<"Look for external executables (ld, clang, binutils) in <directory>">, MetaVarName<"<directory>">;
def D : JoinedOrSeparate<["-"], "D">, Flags<[FrontendOption]>,
HelpText<"Marks a conditional compilation flag as true">;
-def F : JoinedOrSeparate<["-"], "F">, Flags<[FrontendOption]>,
+def F : JoinedOrSeparate<["-"], "F">, Flags<[FrontendOption, ArgumentIsPath]>,
HelpText<"Add directory to framework search path">;
-def F_EQ : Joined<["-"], "F=">, Flags<[FrontendOption]>, Alias<F>;
+def F_EQ : Joined<["-"], "F=">, Flags<[FrontendOption, ArgumentIsPath]>,
+ Alias<F>;
-def Fsystem : Separate<["-"], "Fsystem">, Flags<[FrontendOption]>,
+def Fsystem : Separate<["-"], "Fsystem">,
+ Flags<[FrontendOption, ArgumentIsPath]>,
HelpText<"Add directory to system framework search path">;
-def I : JoinedOrSeparate<["-"], "I">, Flags<[FrontendOption]>,
+def I : JoinedOrSeparate<["-"], "I">, Flags<[FrontendOption, ArgumentIsPath]>,
HelpText<"Add directory to the import search path">;
-def I_EQ : Joined<["-"], "I=">, Flags<[FrontendOption]>, Alias<I>;
+def I_EQ : Joined<["-"], "I=">, Flags<[FrontendOption, ArgumentIsPath]>,
+ Alias<I>;
def import_underlying_module : Flag<["-"], "import-underlying-module">,
Flags<[FrontendOption, NoInteractiveOption]>,
HelpText<"Implicitly imports the Objective-C half of a module">;
def import_objc_header : Separate<["-"], "import-objc-header">,
- Flags<[FrontendOption, HelpHidden]>,
+ Flags<[FrontendOption, HelpHidden, ArgumentIsPath]>,
HelpText<"Implicitly imports an Objective-C header file">;
def pch_output_dir: Separate<["-"], "pch-output-dir">,
- Flags<[FrontendOption, HelpHidden]>,
+ Flags<[FrontendOption, HelpHidden, ArgumentIsPath]>,
HelpText<"Directory to persist automatically created precompiled bridging headers">;
// FIXME: Unhide this once it doesn't depend on an output file map.
@@ -181,10 +192,11 @@
HelpText<"Don't search the standard library import path for modules">;
def output_file_map : Separate<["-"], "output-file-map">,
- Flags<[NoInteractiveOption]>,
+ Flags<[NoInteractiveOption, ArgumentIsPath]>,
HelpText<"A file which specifies the location of outputs">,
MetaVarName<"<path>">;
def output_file_map_EQ : Joined<["-"], "output-file-map=">,
+ Flags<[NoInteractiveOption, ArgumentIsPath]>,
Alias<output_file_map>;
def save_temps : Flag<["-"], "save-temps">,
@@ -194,11 +206,17 @@
Flags<[NoInteractiveOption,DoesNotAffectIncrementalBuild]>,
HelpText<"Prints the total time it took to execute all compilation tasks">;
def stats_output_dir: Separate<["-"], "stats-output-dir">,
- Flags<[FrontendOption, HelpHidden]>,
+ Flags<[FrontendOption, HelpHidden, ArgumentIsPath]>,
HelpText<"Directory to write unified compilation-statistics files to">;
def trace_stats_events: Flag<["-"], "trace-stats-events">,
Flags<[FrontendOption, HelpHidden]>,
HelpText<"Trace changes to stats in -stats-output-dir">;
+def profile_stats_events: Flag<["-"], "profile-stats-events">,
+ Flags<[FrontendOption, HelpHidden]>,
+ HelpText<"Profile changes to stats in -stats-output-dir">;
+def profile_stats_entities: Flag<["-"], "profile-stats-entities">,
+ Flags<[FrontendOption, HelpHidden]>,
+ HelpText<"Profile changes to stats in -stats-output-dir, subdivided by source entity">;
def emit_dependencies : Flag<["-"], "emit-dependencies">,
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
@@ -208,28 +226,30 @@
Flags<[FrontendOption, NoInteractiveOption]>,
HelpText<"Emit a JSON file containing information about what modules were loaded">;
def emit_loaded_module_trace_path : Separate<["-"], "emit-loaded-module-trace-path">,
- Flags<[FrontendOption, NoInteractiveOption]>,
+ Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath]>,
HelpText<"Emit the loaded module trace JSON to <path>">,
MetaVarName<"<path>">;
def emit_loaded_module_trace_path_EQ : Joined<["-"], "emit-loaded-module-trace-path=">,
- Flags<[FrontendOption, NoInteractiveOption]>, Alias<emit_loaded_module_trace_path>;
+ Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath]>,
+ Alias<emit_loaded_module_trace_path>;
def emit_tbd : Flag<["-"], "emit-tbd">,
HelpText<"Emit a TBD file">,
Flags<[FrontendOption, NoInteractiveOption]>;
def emit_tbd_path : Separate<["-"], "emit-tbd-path">,
- Flags<[FrontendOption, NoInteractiveOption]>,
+ Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath]>,
HelpText<"Emit the TBD file to <path>">,
MetaVarName<"<path>">;
def emit_tbd_path_EQ : Joined<["-"], "emit-tbd-path=">,
- Flags<[FrontendOption, NoInteractiveOption]>, Alias<emit_tbd_path>;
+ Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath]>,
+ Alias<emit_tbd_path>;
def serialize_diagnostics : Flag<["-"], "serialize-diagnostics">,
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
HelpText<"Serialize diagnostics in a binary format">;
def module_cache_path : Separate<["-"], "module-cache-path">,
- Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
+ Flags<[FrontendOption, DoesNotAffectIncrementalBuild, ArgumentIsPath]>,
HelpText<"Specifies the Clang module cache path">;
def module_name : Separate<["-"], "module-name">, Flags<[FrontendOption]>,
@@ -250,17 +270,21 @@
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
HelpText<"Emit an importable module">;
def emit_module_path : Separate<["-"], "emit-module-path">,
- Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
+ Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild,
+ ArgumentIsPath]>,
HelpText<"Emit an importable module to <path>">,
MetaVarName<"<path>">;
def emit_module_path_EQ : Joined<["-"], "emit-module-path=">,
- Flags<[FrontendOption, NoInteractiveOption]>, Alias<emit_module_path>;
+ Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild,
+ ArgumentIsPath]>,
+ Alias<emit_module_path>;
def emit_objc_header : Flag<["-"], "emit-objc-header">,
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
HelpText<"Emit an Objective-C header file">;
def emit_objc_header_path : Separate<["-"], "emit-objc-header-path">,
- Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
+ Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild,
+ ArgumentIsPath]>,
MetaVarName<"<path>">, HelpText<"Emit an Objective-C header file to <path>">;
def import_cf_types : Flag<["-"], "import-cf-types">,
@@ -337,7 +361,7 @@
Flags<[FrontendOption]>, HelpText<"Generate a YAML optimization record file">;
def save_optimization_record_path :
Separate<["-"], "save-optimization-record-path">,
- Flags<[FrontendOption]>,
+ Flags<[FrontendOption, ArgumentIsPath]>,
HelpText<"Specify the file name of any generated YAML optimization record">;
// Platform options.
@@ -357,9 +381,11 @@
HelpText<"Specifies a framework which should be linked against">;
def L : JoinedOrSeparate<["-"], "L">, Group<linker_option_Group>,
- Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
+ Flags<[FrontendOption, DoesNotAffectIncrementalBuild, ArgumentIsPath]>,
HelpText<"Add directory to library link search path">;
-def L_EQ : Joined<["-"], "L=">, Alias<L>;
+def L_EQ : Joined<["-"], "L=">,
+ Flags<[FrontendOption, DoesNotAffectIncrementalBuild, ArgumentIsPath]>,
+ Alias<L>;
def link_objc_runtime : Flag<["-"], "link-objc-runtime">,
Flags<[DoesNotAffectIncrementalBuild]>;
@@ -495,12 +521,14 @@
MetaVarName<"<path>">;
def dump_migration_states_dir: Separate<["-"], "dump-migration-states-dir">,
- Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
+ Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild,
+ ArgumentIsPath]>,
HelpText<"Dump the input text, output text, and states for migration to <path>">,
MetaVarName<"<path>">;
def api_diff_data_file: Separate<["-"], "api-diff-data-file">,
- Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
+ Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild,
+ ArgumentIsPath]>,
HelpText<"API migration data is from <path>">,
MetaVarName<"<path>">;
@@ -654,7 +682,7 @@
MetaVarName<"<arg>">, HelpText<"Pass <arg> to LLVM.">;
def resource_dir : Separate<["-"], "resource-dir">,
- Flags<[FrontendOption, HelpHidden]>,
+ Flags<[FrontendOption, HelpHidden, ArgumentIsPath]>,
MetaVarName<"</usr/lib/swift>">,
HelpText<"The directory that holds the compiler resource files">;
@@ -672,7 +700,8 @@
HelpText<"Generate instrumented code to collect execution counts">;
def profile_use : CommaJoined<["-"], "profile-use=">,
- Flags<[FrontendOption, NoInteractiveOption]>, MetaVarName<"<profdata>">,
+ Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath]>,
+ MetaVarName<"<profdata>">,
HelpText<"Supply a profdata file to enable profile-guided optimization">;
def profile_coverage_mapping : Flag<["-"], "profile-coverage-mapping">,
@@ -705,16 +734,22 @@
HelpText<"Produce index data for a source file">, ModeOpt,
Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>;
def index_file_path : Separate<["-"], "index-file-path">,
- Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
+ Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild, ArgumentIsPath]>,
HelpText<"Produce index data for file <path>">,
MetaVarName<"<path>">;
def index_store_path : Separate<["-"], "index-store-path">,
- Flags<[FrontendOption]>, MetaVarName<"<path>">,
+ Flags<[FrontendOption, ArgumentIsPath]>, MetaVarName<"<path>">,
HelpText<"Store indexing data to <path>">;
def enforce_exclusivity_EQ : Joined<["-"], "enforce-exclusivity=">,
Flags<[FrontendOption]>, MetaVarName<"<enforcement>">,
HelpText<"Enforce law of exclusivity">;
+def working_directory : Separate<["-"], "working-directory">,
+ HelpText<"Resolve file paths relative to the specified directory">,
+ MetaVarName<"<path>">;
+def working_directory_EQ : Joined<["-"], "working-directory=">,
+ Alias<working_directory>;
+
include "FrontendOptions.td"
diff --git a/include/swift/Reflection/Records.h b/include/swift/Reflection/Records.h
index e2c3354..2bda25a 100644
--- a/include/swift/Reflection/Records.h
+++ b/include/swift/Reflection/Records.h
@@ -19,6 +19,7 @@
#include "swift/Basic/RelativePointer.h"
#include "swift/Demangling/Demangle.h"
+#include "llvm/ADT/ArrayRef.h"
const uint16_t SWIFT_REFLECTION_METADATA_VERSION = 3; // superclass field
@@ -204,6 +205,10 @@
return const_iterator { End, End };
}
+ llvm::ArrayRef<FieldRecord> getFields() const {
+ return {getFieldRecordBuffer(), NumFields};
+ }
+
bool hasMangledTypeName() const {
return MangledTypeName;
}
diff --git a/include/swift/Reflection/TypeRef.h b/include/swift/Reflection/TypeRef.h
index d2cc903..8894627 100644
--- a/include/swift/Reflection/TypeRef.h
+++ b/include/swift/Reflection/TypeRef.h
@@ -668,8 +668,8 @@
static bool classof(const TypeRef *TR) {
auto Kind = TR->getKind();
- return (Kind == TypeRefKind::UnownedStorage &&
- Kind == TypeRefKind::WeakStorage &&
+ return (Kind == TypeRefKind::UnownedStorage ||
+ Kind == TypeRefKind::WeakStorage ||
Kind == TypeRefKind::UnmanagedStorage);
}
};
diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h
index a7ed640..39656b5 100644
--- a/include/swift/Remote/MetadataReader.h
+++ b/include/swift/Remote/MetadataReader.h
@@ -540,23 +540,44 @@
llvm::Optional<uint32_t>
readGenericArgsOffset(MetadataRef metadata,
ContextDescriptorRef descriptor) {
- auto type = cast<TargetTypeContextDescriptor<Runtime>>(descriptor);
- if (auto *classMetadata = dyn_cast<TargetClassMetadata<Runtime>>(metadata)){
- if (classMetadata->SuperClass) {
- auto superMetadata = readMetadata(classMetadata->SuperClass);
- if (!superMetadata)
- return llvm::None;
+ switch (descriptor->getKind()) {
+ case ContextDescriptorKind::Class: {
+ auto type = cast<TargetClassDescriptor<Runtime>>(descriptor);
- auto result =
- type->getGenericArgumentOffset(
- classMetadata,
- cast<TargetClassMetadata<Runtime>>(superMetadata));
+ auto *classMetadata = dyn_cast<TargetClassMetadata<Runtime>>(metadata);
+ if (!classMetadata)
+ return llvm::None;
- return result;
- }
+ if (!classMetadata->SuperClass)
+ return type->getGenericArgumentOffset(nullptr, nullptr);
+
+ auto superMetadata = readMetadata(classMetadata->SuperClass);
+ if (!superMetadata)
+ return llvm::None;
+
+ auto superClassMetadata =
+ dyn_cast<TargetClassMetadata<Runtime>>(superMetadata);
+ if (!superClassMetadata)
+ return llvm::None;
+
+ auto result =
+ type->getGenericArgumentOffset(classMetadata, superClassMetadata);
+ return result;
}
- return type->getGenericArgumentOffset();
+ case ContextDescriptorKind::Enum: {
+ auto type = cast<TargetEnumDescriptor<Runtime>>(descriptor);
+ return type->getGenericArgumentOffset();
+ }
+
+ case ContextDescriptorKind::Struct: {
+ auto type = cast<TargetStructDescriptor<Runtime>>(descriptor);
+ return type->getGenericArgumentOffset();
+ }
+
+ default:
+ return llvm::None;
+ }
}
/// Read a single generic type argument from a bound generic type
@@ -959,15 +980,21 @@
case ContextDescriptorKind::Anonymous:
baseSize = sizeof(TargetAnonymousContextDescriptor<Runtime>);
break;
+ case ContextDescriptorKind::Class:
+ baseSize = sizeof(TargetClassDescriptor<Runtime>);
+ genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
+ hasVTable = flags.getKindSpecificFlags()
+ & (uint16_t)TypeContextDescriptorFlags::HasVTable;
+ break;
+ case ContextDescriptorKind::Enum:
+ baseSize = sizeof(TargetEnumDescriptor<Runtime>);
+ genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
+ break;
+ case ContextDescriptorKind::Struct:
+ baseSize = sizeof(TargetStructDescriptor<Runtime>);
+ genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
+ break;
default:
- if (kind >= ContextDescriptorKind::Type_First
- && kind <= ContextDescriptorKind::Type_Last) {
- baseSize = sizeof(TargetTypeContextDescriptor<Runtime>);
- genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader);
- hasVTable = flags.getKindSpecificFlags()
- & (uint16_t)TypeContextDescriptorFlags::HasVTable;
- break;
- }
// We don't know about this kind of context.
return nullptr;
}
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index 8244e84..3501251 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -37,11 +37,13 @@
#include "swift/Basic/RelativePointer.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Demangling/ManglingMacros.h"
+#include "swift/Reflection/Records.h"
#include "swift/Runtime/Unreachable.h"
#include "../../../stdlib/public/SwiftShims/HeapObject.h"
#if SWIFT_OBJC_INTEROP
#include <objc/runtime.h>
#endif
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
namespace swift {
@@ -739,7 +741,10 @@
template <typename Runtime> struct TargetOpaqueMetadata;
template <typename Runtime> struct TargetValueMetadata;
template <typename Runtime> struct TargetForeignClassMetadata;
-template <typename Runtime> struct TargetTypeContextDescriptor;
+template <typename Runtime> class TargetTypeContextDescriptor;
+template <typename Runtime> class TargetClassDescriptor;
+template <typename Runtime> class TargetEnumDescriptor;
+template <typename Runtime> class TargetStructDescriptor;
// FIXME: https://bugs.swift.org/browse/SR-1155
#pragma clang diagnostic push
@@ -1171,7 +1176,7 @@
/// if this is an artificial subclass. We currently provide no
/// supported mechanism for making a non-artificial subclass
/// dynamically.
- ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor> Description;
+ ConstTargetMetadataPointer<Runtime, TargetClassDescriptor> Description;
/// A function for destroying instance variables, used to clean up
/// after an early return from a constructor.
@@ -1185,14 +1190,13 @@
// - "tabulated" virtual methods
public:
- ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>
+ ConstTargetMetadataPointer<Runtime, TargetClassDescriptor>
getDescription() const {
assert(isTypeMetadata());
return Description;
}
- void setDescription(const TargetTypeContextDescriptor<Runtime> *
- description) {
+ void setDescription(const TargetClassDescriptor<Runtime> *description) {
Description = description;
}
@@ -1279,22 +1283,12 @@
/// Get a pointer to the field offset vector, if present, or null.
const StoredPointer *getFieldOffsets() const {
assert(isTypeMetadata());
- auto offset = getDescription()->Class.getFieldOffsetVectorOffset(this);
+ auto offset = getDescription()->getFieldOffsetVectorOffset(this);
if (offset == 0)
return nullptr;
auto asWords = reinterpret_cast<const void * const*>(this);
return reinterpret_cast<const StoredPointer *>(asWords + offset);
}
-
- /// Get a pointer to the field type vector, if present, or null.
- const FieldType *getFieldTypes() const {
- assert(isTypeMetadata());
- auto *getter = getDescription()->Class.GetFieldTypes.get();
- if (!getter)
- return nullptr;
-
- return getter(this);
- }
uint32_t getSizeInWords() const {
assert(isTypeMetadata());
@@ -1511,7 +1505,7 @@
using StoredPointer = typename Runtime::StoredPointer;
/// An out-of-line description of the type.
- const TargetTypeContextDescriptor<Runtime> *Description;
+ const TargetClassDescriptor<Runtime> *Description;
/// The superclass of the foreign class, if any.
ConstTargetMetadataPointer<Runtime, swift::TargetForeignClassMetadata>
@@ -1555,23 +1549,18 @@
using StoredPointer = typename Runtime::StoredPointer;
using TargetValueMetadata<Runtime>::TargetValueMetadata;
+ const TargetStructDescriptor<Runtime> *getDescription() const {
+ return llvm::cast<TargetStructDescriptor<Runtime>>(this->Description);
+ }
+
/// Get a pointer to the field offset vector, if present, or null.
const StoredPointer *getFieldOffsets() const {
- auto offset = this->Description->Struct.FieldOffsetVectorOffset;
+ auto offset = getDescription()->FieldOffsetVectorOffset;
if (offset == 0)
return nullptr;
auto asWords = reinterpret_cast<const void * const*>(this);
return reinterpret_cast<const StoredPointer *>(asWords + offset);
}
-
- /// Get a pointer to the field type vector, if present, or null.
- const FieldType *getFieldTypes() const {
- auto *getter = this->Description->Struct.GetFieldTypes.get();
- if (!getter)
- return nullptr;
-
- return getter(this);
- }
static bool classof(const TargetMetadata<Runtime> *metadata) {
return metadata->getKind() == MetadataKind::Struct;
@@ -1586,9 +1575,13 @@
using StoredSize = typename Runtime::StoredSize;
using TargetValueMetadata<Runtime>::TargetValueMetadata;
+ const TargetEnumDescriptor<Runtime> *getDescription() const {
+ return llvm::cast<TargetEnumDescriptor<Runtime>>(this->Description);
+ }
+
/// True if the metadata records the size of the payload area.
bool hasPayloadSize() const {
- return this->Description->Enum.hasPayloadSizeOffset();
+ return getDescription()->hasPayloadSizeOffset();
}
/// Retrieve the size of the payload area.
@@ -1596,7 +1589,7 @@
/// `hasPayloadSize` must be true for this to be valid.
StoredSize getPayloadSize() const {
assert(hasPayloadSize());
- auto offset = this->Description->Enum.getPayloadSizeOffset();
+ auto offset = getDescription()->getPayloadSizeOffset();
const StoredSize *asWords = reinterpret_cast<const StoredSize *>(this);
asWords += offset;
return *asWords;
@@ -1604,7 +1597,7 @@
StoredSize &getPayloadSize() {
assert(hasPayloadSize());
- auto offset = this->Description->Enum.getPayloadSizeOffset();
+ auto offset = getDescription()->getPayloadSizeOffset();
StoredSize *asWords = reinterpret_cast<StoredSize *>(this);
asWords += offset;
return *asWords;
@@ -2521,6 +2514,12 @@
/// context is not generic.
const TargetGenericContext<Runtime> *getGenericContext() const;
+ unsigned getNumGenericParams() const {
+ auto *genericContext = getGenericContext();
+ return genericContext
+ ? genericContext->getGenericContextHeader().NumParams
+ : 0;
+ }
private:
TargetContextDescriptor(const TargetContextDescriptor &) = delete;
TargetContextDescriptor(TargetContextDescriptor &&) = delete;
@@ -3042,30 +3041,75 @@
}
};
-template<typename Runtime>
-struct TargetTypeContextDescriptor final
- : TargetContextDescriptor<Runtime>,
- TrailingGenericContextObjects<TargetTypeContextDescriptor<Runtime>,
- TypeGenericContextDescriptorHeader,
- /*additional trailing objects:*/
- TargetVTableDescriptorHeader<Runtime>,
- TargetMethodDescriptor<Runtime>>
-{
+template <typename Runtime>
+class TargetTypeContextDescriptor
+ : public TargetContextDescriptor<Runtime> {
+public:
+ /// The name of the type.
+ TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;
+
+ /// A pointer to the metadata access function for this type.
+ ///
+ /// The function type here is a stand-in. You should use getAccessFunction()
+ /// to wrap the function pointer in an accessor that uses the proper calling
+ /// convention for a given number of arguments.
+ TargetRelativeDirectPointer<Runtime, const Metadata *(...),
+ /*Nullable*/ true> AccessFunctionPtr;
+
+ MetadataAccessFunction getAccessFunction() const {
+ return MetadataAccessFunction(AccessFunctionPtr.get());
+ }
+
+ const GenericContextDescriptorHeader &getGenericContextHeader() const;
+
+ /// Return the offset of the start of generic arguments in the nominal
+ /// type's metadata. The returned value is measured in sizeof(void*).
+ uint32_t getGenericArgumentOffset(
+ const TargetMetadata<Runtime> *metadata) const;
+
+ /// Return the start of the generic arguments array in the nominal
+ /// type's metadata. The returned value is measured in sizeof(void*).
+ const TargetMetadata<Runtime> * const *getGenericArguments(
+ const TargetMetadata<Runtime> *metadata) const {
+ auto offset = getGenericArgumentOffset(metadata);
+ auto words =
+ reinterpret_cast<const TargetMetadata<Runtime> * const *>(metadata);
+ return words + offset;
+ }
+
+ static bool classof(const TargetContextDescriptor<Runtime> *cd) {
+ return cd->getKind() >= ContextDescriptorKind::Type_First
+ && cd->getKind() <= ContextDescriptorKind::Type_Last;
+ }
+};
+
+using TypeContextDescriptor = TargetTypeContextDescriptor<InProcess>;
+
+template <typename Runtime>
+class TargetClassDescriptor final
+ : public TargetTypeContextDescriptor<Runtime>,
+ public TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
+ TypeGenericContextDescriptorHeader,
+ /*additional trailing objects:*/
+ TargetVTableDescriptorHeader<Runtime>,
+ TargetMethodDescriptor<Runtime>> {
private:
using TrailingGenericContextObjects =
- TrailingGenericContextObjects<TargetTypeContextDescriptor<Runtime>,
+ TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
TypeGenericContextDescriptorHeader,
TargetVTableDescriptorHeader<Runtime>,
TargetMethodDescriptor<Runtime>>;
-
+
using TrailingObjects =
typename TrailingGenericContextObjects::TrailingObjects;
-
+ friend TrailingObjects;
+
public:
using MethodDescriptor = TargetMethodDescriptor<Runtime>;
using VTableDescriptorHeader = TargetVTableDescriptorHeader<Runtime>;
using TrailingGenericContextObjects::getGenericContext;
+ using TrailingGenericContextObjects::getGenericContextHeader;
using TrailingGenericContextObjects::getFullGenericContextHeader;
/// This bit is set in the context descriptor header's kind-specific flags
@@ -3078,127 +3122,56 @@
static constexpr const uint16_t HasResilientSuperclassFlag =
uint16_t(TypeContextDescriptorFlags::HasResilientSuperclass);
- /// The name of the type.
- TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;
-
- /// A pointer to the metadata access function for this type.
+ /// The number of stored properties in the class, not including its
+ /// superclasses. If there is a field offset vector, this is its length.
+ uint32_t NumFields;
+
+private:
+ /// The offset of the field offset vector for this class's stored
+ /// properties in its metadata, in words. 0 means there is no field offset
+ /// vector.
///
- /// The function type here is a stand-in. You should use getAccessFunction()
- /// to wrap the function pointer in an accessor that uses the proper calling
- /// convention for a given number of arguments.
- TargetRelativeDirectPointer<Runtime, const Metadata *(...),
- /*Nullable*/ true> AccessFunctionPtr;
+ /// If this class has a resilient superclass, this offset is relative to
+ /// the size of the resilient superclass metadata. Otherwise, it is
+ /// absolute.
+ uint32_t FieldOffsetVectorOffset;
+
+ template<typename T>
+ using OverloadToken =
+ typename TrailingGenericContextObjects::template OverloadToken<T>;
- MetadataAccessFunction getAccessFunction() const {
- return MetadataAccessFunction(AccessFunctionPtr.get());
+ using TrailingGenericContextObjects::numTrailingObjects;
+
+ size_t numTrailingObjects(OverloadToken<VTableDescriptorHeader>) const {
+ return hasVTable() ? 1 : 0;
}
- // ABI TODO: These fields ought to be superseded by remote mirror metadata for
- // the type.
- union {
- /// Information about class types.
- struct {
- /// The number of stored properties in the class, not including its
- /// superclasses. If there is a field offset vector, this is its length.
- uint32_t NumFields;
+ size_t numTrailingObjects(OverloadToken<MethodDescriptor>) const {
+ if (!hasVTable())
+ return 0;
- private:
- /// The offset of the field offset vector for this class's stored
- /// properties in its metadata, in words. 0 means there is no field offset
- /// vector.
- ///
- /// If this class has a resilient superclass, this offset is relative to
- /// the size of the resilient superclass metadata. Otherwise, it is
- /// absolute.
- uint32_t FieldOffsetVectorOffset;
+ return getVTableDescriptor()->VTableSize;
+ }
- public:
- /// The field names. A doubly-null-terminated list of strings, whose
- /// length and order is consistent with that of the field offset vector.
- RelativeDirectPointer<const char, /*nullable*/ true> FieldNames;
+public:
+ /// Indicates if the type represented by this descriptor
+ /// supports reflection (C and Obj-C enums currently don't).
+ /// FIXME: This is temporarily left as 32-bit integer to avoid
+ /// changing layout of context descriptor.
+ uint32_t IsReflectable;
- /// The field type vector accessor. Returns a pointer to an array of
- /// type metadata references whose order is consistent with that of the
- /// field offset vector.
- RelativeDirectPointer<const FieldType *
- (const TargetMetadata<Runtime> *)> GetFieldTypes;
+ /// True if metadata records for this type have a field offset vector for
+ /// its stored properties.
+ bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
- /// True if metadata records for this type have a field offset vector for
- /// its stored properties.
- bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
+ unsigned getFieldOffsetVectorOffset(const ClassMetadata *metadata) const {
+ const auto *description = metadata->getDescription();
- unsigned getFieldOffsetVectorOffset(const ClassMetadata *metadata) const {
- const auto *description = metadata->getDescription();
+ if (description->hasResilientSuperclass())
+ return metadata->SuperClass->getSizeInWords() + FieldOffsetVectorOffset;
- if (description->hasResilientSuperclass())
- return metadata->SuperClass->getSizeInWords() + FieldOffsetVectorOffset;
-
- return FieldOffsetVectorOffset;
- }
- } Class;
-
- /// Information about struct types.
- struct {
- /// The number of stored properties in the class, not including its
- /// superclasses. If there is a field offset vector, this is its length.
- uint32_t NumFields;
- /// The offset of the field offset vector for this class's stored
- /// properties in its metadata, if any. 0 means there is no field offset
- /// vector.
- uint32_t FieldOffsetVectorOffset;
-
- /// The field names. A doubly-null-terminated list of strings, whose
- /// length and order is consistent with that of the field offset vector.
- RelativeDirectPointer<const char, /*nullable*/ true> FieldNames;
-
- /// The field type vector accessor. Returns a pointer to an array of
- /// type metadata references whose order is consistent with that of the
- /// field offset vector.
- RelativeDirectPointer<const FieldType *
- (const TargetMetadata<Runtime> *)> GetFieldTypes;
-
- /// True if metadata records for this type have a field offset vector for
- /// its stored properties.
- bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
- } Struct;
-
- /// Information about enum types.
- struct {
- /// The number of non-empty cases in the enum are in the low 24 bits;
- /// the offset of the payload size in the metadata record in words,
- /// if any, is stored in the high 8 bits.
- uint32_t NumPayloadCasesAndPayloadSizeOffset;
- /// The number of empty cases in the enum.
- uint32_t NumEmptyCases;
- /// The names of the cases. A doubly-null-terminated list of strings,
- /// whose length is NumNonEmptyCases + NumEmptyCases. Cases are named in
- /// tag order, non-empty cases first, followed by empty cases.
- RelativeDirectPointer<const char, /*nullable*/ true> CaseNames;
- /// The field type vector accessor. Returns a pointer to an array of
- /// type metadata references whose order is consistent with that of the
- /// CaseNames. Only types for payload cases are provided.
- RelativeDirectPointer<
- const FieldType * (const TargetMetadata<Runtime> *)>
- GetCaseTypes;
-
- uint32_t getNumPayloadCases() const {
- return NumPayloadCasesAndPayloadSizeOffset & 0x00FFFFFFU;
- }
- uint32_t getNumEmptyCases() const {
- return NumEmptyCases;
- }
- uint32_t getNumCases() const {
- return getNumPayloadCases() + NumEmptyCases;
- }
- size_t getPayloadSizeOffset() const {
- return ((NumPayloadCasesAndPayloadSizeOffset & 0xFF000000U) >> 24);
- }
-
- bool hasPayloadSizeOffset() const {
- return getPayloadSizeOffset() != 0;
- }
- } Enum;
- };
+ return FieldOffsetVectorOffset;
+ }
bool hasVTable() const {
return (this->Flags.getKindSpecificFlags() & HasVTableFlag) != 0;
@@ -3222,17 +3195,6 @@
numTrailingObjects(OverloadToken<MethodDescriptor>{})};
}
- void *getMethod(unsigned i) const {
- assert(hasVTable()
- && i < numTrailingObjects(OverloadToken<MethodDescriptor>{}));
- return getMethodDescriptors()[i].Impl.get();
- }
-
- static bool classof(const TargetContextDescriptor<Runtime> *cd) {
- return cd->getKind() >= ContextDescriptorKind::Type_First
- && cd->getKind() <= ContextDescriptorKind::Type_Last;
- }
-
/// This is factored in a silly way because remote mirrors cannot directly
/// dereference the SuperClass field of class metadata.
uint32_t getGenericArgumentOffset(
@@ -3246,14 +3208,6 @@
}
/// Return the offset of the start of generic arguments in the nominal
- /// type's metadata. This method should only be used with value type
- /// metadata and class metadata with a non-resilient superclass.
- uint32_t getGenericArgumentOffset() const {
- assert(!hasResilientSuperclass());
- return getFullGenericContextHeader().ArgumentOffset;
- }
-
- /// Return the offset of the start of generic arguments in the nominal
/// type's metadata. The returned value is measured in sizeof(void*).
uint32_t
getGenericArgumentOffset(const TargetMetadata<Runtime> *metadata) const {
@@ -3263,39 +3217,131 @@
return getGenericArgumentOffset(classMetadata, superMetadata);
}
- return getGenericArgumentOffset();
+ return getFullGenericContextHeader().ArgumentOffset;
}
-
- const TargetMetadata<Runtime> * const *getGenericArguments(
- const TargetMetadata<Runtime> *metadata) const {
- auto offset = getGenericArgumentOffset(metadata);
- auto words =
- reinterpret_cast<const TargetMetadata<Runtime> * const *>(metadata);
- return words + offset;
- }
-
-private:
- template<typename T>
- using OverloadToken =
- typename TrailingGenericContextObjects::template OverloadToken<T>;
-
- friend TrailingObjects;
-
- using TrailingGenericContextObjects::numTrailingObjects;
-
- size_t numTrailingObjects(OverloadToken<VTableDescriptorHeader>) const {
- return hasVTable() ? 1 : 0;
- }
-
- size_t numTrailingObjects(OverloadToken<MethodDescriptor>) const {
- if (!hasVTable())
- return 0;
- return getVTableDescriptor()->VTableSize;
+ void *getMethod(unsigned i) const {
+ assert(hasVTable()
+ && i < numTrailingObjects(OverloadToken<MethodDescriptor>{}));
+ return getMethodDescriptors()[i].Impl.get();
+ }
+
+ static bool classof(const TargetContextDescriptor<Runtime> *cd) {
+ return cd->getKind() == ContextDescriptorKind::Class;
}
};
-using TypeContextDescriptor = TargetTypeContextDescriptor<InProcess>;
+using ClassDescriptor = TargetClassDescriptor<InProcess>;
+
+template <typename Runtime>
+class TargetStructDescriptor final
+ : public TargetTypeContextDescriptor<Runtime>,
+ public TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,
+ TypeGenericContextDescriptorHeader> {
+private:
+ using TrailingGenericContextObjects =
+ TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,
+ TypeGenericContextDescriptorHeader>;
+
+ using TrailingObjects =
+ typename TrailingGenericContextObjects::TrailingObjects;
+ friend TrailingObjects;
+
+public:
+ using TrailingGenericContextObjects::getGenericContext;
+ using TrailingGenericContextObjects::getGenericContextHeader;
+ using TrailingGenericContextObjects::getFullGenericContextHeader;
+
+ /// The number of stored properties in the struct.
+ /// If there is a field offset vector, this is its length.
+ uint32_t NumFields;
+ /// The offset of the field offset vector for this struct's stored
+ /// properties in its metadata, if any. 0 means there is no field offset
+ /// vector.
+ uint32_t FieldOffsetVectorOffset;
+
+ /// Indicates if the type represented by this descriptor
+ /// supports reflection (C and Obj-C enums currently don't).
+ /// FIXME: This is temporarily left as 32-bit integer to avoid
+ /// changing layout of context descriptor.
+ uint32_t IsReflectable;
+
+ /// True if metadata records for this type have a field offset vector for
+ /// its stored properties.
+ bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
+
+ uint32_t getGenericArgumentOffset() const {
+ return getFullGenericContextHeader().ArgumentOffset;
+ }
+
+ static bool classof(const TargetContextDescriptor<Runtime> *cd) {
+ return cd->getKind() == ContextDescriptorKind::Struct;
+ }
+};
+
+using StructDescriptor = TargetStructDescriptor<InProcess>;
+
+template <typename Runtime>
+class TargetEnumDescriptor final
+ : public TargetTypeContextDescriptor<Runtime>,
+ public TrailingGenericContextObjects<TargetEnumDescriptor<Runtime>,
+ TypeGenericContextDescriptorHeader> {
+private:
+ using TrailingGenericContextObjects =
+ TrailingGenericContextObjects<TargetEnumDescriptor<Runtime>,
+ TypeGenericContextDescriptorHeader>;
+
+ using TrailingObjects =
+ typename TrailingGenericContextObjects::TrailingObjects;
+ friend TrailingObjects;
+
+public:
+ using TrailingGenericContextObjects::getGenericContext;
+ using TrailingGenericContextObjects::getGenericContextHeader;
+ using TrailingGenericContextObjects::getFullGenericContextHeader;
+
+ /// The number of non-empty cases in the enum are in the low 24 bits;
+ /// the offset of the payload size in the metadata record in words,
+ /// if any, is stored in the high 8 bits.
+ uint32_t NumPayloadCasesAndPayloadSizeOffset;
+
+ /// The number of empty cases in the enum.
+ uint32_t NumEmptyCases;
+
+ /// Indicates if the type represented by this descriptor
+ /// supports reflection (C and Obj-C enums currently don't).
+ /// FIXME: This is temporarily left as 32-bit integer to avoid
+ /// changing layout of context descriptor.
+ uint32_t IsReflectable;
+
+ uint32_t getNumPayloadCases() const {
+ return NumPayloadCasesAndPayloadSizeOffset & 0x00FFFFFFU;
+ }
+
+ uint32_t getNumEmptyCases() const {
+ return NumEmptyCases;
+ }
+ uint32_t getNumCases() const {
+ return getNumPayloadCases() + NumEmptyCases;
+ }
+ size_t getPayloadSizeOffset() const {
+ return ((NumPayloadCasesAndPayloadSizeOffset & 0xFF000000U) >> 24);
+ }
+
+ bool hasPayloadSizeOffset() const {
+ return getPayloadSizeOffset() != 0;
+ }
+
+ uint32_t getGenericArgumentOffset() const {
+ return getFullGenericContextHeader().ArgumentOffset;
+ }
+
+ static bool classof(const TargetContextDescriptor<Runtime> *cd) {
+ return cd->getKind() == ContextDescriptorKind::Enum;
+ }
+};
+
+using EnumDescriptor = TargetEnumDescriptor<InProcess>;
template<typename Runtime>
inline const TargetGenericContext<Runtime> *
@@ -3313,18 +3359,57 @@
case ContextDescriptorKind::Anonymous:
return llvm::cast<TargetAnonymousContextDescriptor<Runtime>>(this)
->getGenericContext();
- default:
- if (getKind() >= ContextDescriptorKind::Type_First
- && getKind() <= ContextDescriptorKind::Type_Last) {
- return llvm::cast<TargetTypeContextDescriptor<Runtime>>(this)
+ case ContextDescriptorKind::Class:
+ return llvm::cast<TargetClassDescriptor<Runtime>>(this)
->getGenericContext();
- }
-
+ case ContextDescriptorKind::Enum:
+ return llvm::cast<TargetEnumDescriptor<Runtime>>(this)
+ ->getGenericContext();
+ case ContextDescriptorKind::Struct:
+ return llvm::cast<TargetStructDescriptor<Runtime>>(this)
+ ->getGenericContext();
+ default:
// We don't know about this kind of descriptor.
return nullptr;
}
}
-
+
+template <typename Runtime>
+uint32_t TargetTypeContextDescriptor<Runtime>::getGenericArgumentOffset(
+ const TargetMetadata<Runtime> *metadata) const {
+ switch (this->getKind()) {
+ case ContextDescriptorKind::Class:
+ return llvm::cast<TargetClassDescriptor<Runtime>>(this)
+ ->getGenericArgumentOffset(metadata);
+ case ContextDescriptorKind::Enum:
+ return llvm::cast<TargetEnumDescriptor<Runtime>>(this)
+ ->getGenericArgumentOffset();
+ case ContextDescriptorKind::Struct:
+ return llvm::cast<TargetStructDescriptor<Runtime>>(this)
+ ->getGenericArgumentOffset();
+ default:
+ swift_runtime_unreachable("Not a type context descriptor.");
+ }
+}
+
+template <typename Runtime>
+const GenericContextDescriptorHeader &
+TargetTypeContextDescriptor<Runtime>::getGenericContextHeader() const {
+ switch (this->getKind()) {
+ case ContextDescriptorKind::Class:
+ return llvm::cast<TargetClassDescriptor<Runtime>>(this)
+ ->getGenericContextHeader();
+ case ContextDescriptorKind::Enum:
+ return llvm::cast<TargetEnumDescriptor<Runtime>>(this)
+ ->getGenericContextHeader();
+ case ContextDescriptorKind::Struct:
+ return llvm::cast<TargetStructDescriptor<Runtime>>(this)
+ ->getGenericContextHeader();
+ default:
+ swift_runtime_unreachable("Not a type context descriptor.");
+ }
+}
+
/// \brief Fetch a uniqued metadata object for a generic nominal type.
///
/// The basic algorithm for fetching a metadata object is:
@@ -3650,12 +3735,22 @@
void swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin,
const TypeMetadataRecord *end);
+/// Register a block of type field records for dynamic lookup.
+SWIFT_RUNTIME_EXPORT
+void swift_registerFieldDescriptors(const reflection::FieldDescriptor **records,
+ size_t size);
+
/// Return the superclass, if any. The result is nullptr for root
/// classes and class protocol types.
SWIFT_CC(swift)
SWIFT_RUNTIME_STDLIB_INTERFACE
const Metadata *_swift_class_getSuperclass(const Metadata *theClass);
+SWIFT_RUNTIME_STDLIB_INTERFACE
+void swift_getFieldAt(
+ const Metadata *type, unsigned index,
+ std::function<void(llvm::StringRef name, FieldType type)> callback);
+
} // end namespace swift
#pragma clang diagnostic pop
diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def
index 735902a..56de9d7 100644
--- a/include/swift/Runtime/RuntimeFunctions.def
+++ b/include/swift/Runtime/RuntimeFunctions.def
@@ -1198,6 +1198,11 @@
RETURNS(VoidTy),
ARGS(TypeMetadataRecordPtrTy, TypeMetadataRecordPtrTy),
ATTRS(NoUnwind))
+FUNCTION(RegisterFieldDescriptors,
+ swift_registerFieldDescriptors, DefaultCC,
+ RETURNS(VoidTy),
+ ARGS(FieldDescriptorPtrPtrTy, SizeTy),
+ ATTRS(NoUnwind))
// void swift_beginAccess(void *pointer, ValueBuffer *scratch, size_t flags);
FUNCTION(BeginAccess, swift_beginAccess, C_CC,
diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h
index b27df80..7d41f41 100644
--- a/include/swift/SIL/SILBuilder.h
+++ b/include/swift/SIL/SILBuilder.h
@@ -286,7 +286,7 @@
//===--------------------------------------------------------------------===//
AllocStackInst *createAllocStack(SILLocation Loc, SILType elementType,
- SILDebugVariable Var = SILDebugVariable()) {
+ Optional<SILDebugVariable> Var = None) {
Loc.markAsPrologue();
return insert(AllocStackInst::create(getSILDebugLocation(Loc),
elementType, getFunction(),
@@ -327,7 +327,7 @@
}
AllocBoxInst *createAllocBox(SILLocation Loc, CanSILBoxType BoxType,
- SILDebugVariable Var = SILDebugVariable()) {
+ Optional<SILDebugVariable> Var = None) {
Loc.markAsPrologue();
return insert(AllocBoxInst::create(getSILDebugLocation(Loc), BoxType, *F,
OpenedArchetypes, Var));
@@ -733,13 +733,13 @@
}
DebugValueInst *createDebugValue(SILLocation Loc, SILValue src,
- SILDebugVariable Var = SILDebugVariable()) {
+ SILDebugVariable Var) {
return insert(DebugValueInst::create(getSILDebugLocation(Loc), src,
getModule(), Var));
}
DebugValueAddrInst *
createDebugValueAddr(SILLocation Loc, SILValue src,
- SILDebugVariable Var = SILDebugVariable()) {
+ SILDebugVariable Var) {
return insert(DebugValueAddrInst::create(getSILDebugLocation(Loc), src,
getModule(), Var));
}
diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h
index d17f066..2203560 100644
--- a/include/swift/SIL/SILCloner.h
+++ b/include/swift/SIL/SILCloner.h
@@ -886,7 +886,7 @@
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
doPostProcess(Inst, getBuilder().createDebugValue(
Inst->getLoc(), getOpValue(Inst->getOperand()),
- Inst->getVarInfo()));
+ *Inst->getVarInfo()));
}
template<typename ImplClass>
void
@@ -900,8 +900,8 @@
// Do not remap the location for a debug Instruction.
SILValue OpValue = getOpValue(Inst->getOperand());
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
- doPostProcess(Inst, getBuilder().createDebugValueAddr(
- Inst->getLoc(), OpValue, Inst->getVarInfo()));
+ doPostProcess(Inst, getBuilder().createDebugValueAddr(Inst->getLoc(), OpValue,
+ *Inst->getVarInfo()));
}
diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h
index 5ad8c0b..5cf8da4 100644
--- a/include/swift/SIL/SILFunction.h
+++ b/include/swift/SIL/SILFunction.h
@@ -171,6 +171,9 @@
/// would indicate.
unsigned HasCReferences : 1;
+ /// Whether cross-module references to this function should use weak linking.
+ unsigned IsWeakLinked : 1;
+
/// If != OptimizationMode::NotSet, the optimization mode specified with an
/// function attribute.
OptimizationMode OptMode;
@@ -450,6 +453,16 @@
bool hasCReferences() const { return HasCReferences; }
void setHasCReferences(bool value) { HasCReferences = value; }
+ /// Returns whether this function's symbol must always be weakly referenced
+ /// across module boundaries.
+ bool isWeakLinked() const { return IsWeakLinked; }
+ /// Forces IRGen to treat references to this function as weak across module
+ /// boundaries (i.e. if it has external linkage).
+ void setWeakLinked(bool value = true) {
+ assert(!IsWeakLinked && "already set");
+ IsWeakLinked = value;
+ }
+
/// Get the DeclContext of this function. (Debug info only).
DeclContext *getDeclContext() const {
return getLocation().getAsDeclContext();
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index 8ce73c4..914a7f6 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -1196,14 +1196,14 @@
/// arguments that are needed by DebugValueInst, DebugValueAddrInst,
/// AllocStackInst, and AllocBoxInst.
struct SILDebugVariable {
- SILDebugVariable() : Constant(true), ArgNo(0) {}
- SILDebugVariable(bool Constant, unsigned ArgNo)
- : Constant(Constant), ArgNo(ArgNo) {}
+ SILDebugVariable() : ArgNo(0), Constant(false) {}
+ SILDebugVariable(bool Constant, uint16_t ArgNo)
+ : ArgNo(ArgNo), Constant(Constant) {}
SILDebugVariable(StringRef Name, bool Constant, unsigned ArgNo)
- : Name(Name), Constant(Constant), ArgNo(ArgNo) {}
+ : Name(Name), ArgNo(ArgNo), Constant(Constant) {}
StringRef Name;
- bool Constant;
- unsigned ArgNo;
+ unsigned ArgNo : 16;
+ unsigned Constant : 1;
};
/// A DebugVariable where storage for the strings has been
@@ -1212,18 +1212,21 @@
union {
uint32_t RawValue;
struct {
+ /// Whether this is a debug variable at all.
+ unsigned HasValue : 1;
+ /// True if this is a let-binding.
+ unsigned Constant : 1;
/// The source function argument position from left to right
/// starting with 1 or 0 if this is a local variable.
unsigned ArgNo : 16;
- unsigned Constant : 1;
/// When this is nonzero there is a tail-allocated string storing
/// variable name present. This typically only happens for
/// instructions that were created from parsing SIL assembler.
- unsigned NameLength : 15;
+ unsigned NameLength : 14;
} Data;
};
public:
- TailAllocatedDebugVariable(SILDebugVariable DbgVar, char *buf);
+ TailAllocatedDebugVariable(Optional<SILDebugVariable>, char *buf);
TailAllocatedDebugVariable(uint32_t RawValue) : RawValue(RawValue) {}
uint32_t getRawValue() const { return RawValue; }
@@ -1234,12 +1237,14 @@
StringRef getName(const char *buf) const;
bool isLet() const { return Data.Constant; }
- SILDebugVariable get(VarDecl *VD, const char *buf) const {
+ Optional<SILDebugVariable> get(VarDecl *VD, const char *buf) const {
+ if (!Data.HasValue)
+ return None;
if (VD)
- return {VD->getName().empty() ? "" : VD->getName().str(), VD->isLet(),
- getArgNo()};
+ return SILDebugVariable(VD->getName().empty() ? "" : VD->getName().str(),
+ VD->isLet(), getArgNo());
else
- return {getName(buf), isLet(), getArgNo()};
+ return SILDebugVariable(getName(buf), isLet(), getArgNo());
}
};
static_assert(sizeof(TailAllocatedDebugVariable) == 4,
@@ -1272,12 +1277,12 @@
AllocStackInst(SILDebugLocation Loc, SILType elementType,
ArrayRef<SILValue> TypeDependentOperands,
SILFunction &F,
- SILDebugVariable Var);
+ Optional<SILDebugVariable> Var);
static AllocStackInst *create(SILDebugLocation Loc, SILType elementType,
SILFunction &F,
SILOpenedArchetypesState &OpenedArchetypes,
- SILDebugVariable Var);
+ Optional<SILDebugVariable> Var);
size_t numTrailingObjects(OverloadToken<Operand>) const {
return SILInstruction::Bits.AllocStackInst.NumOperands;
@@ -1297,7 +1302,7 @@
VarDecl *getDecl() const;
/// Return the debug variable information attached to this instruction.
- SILDebugVariable getVarInfo() const {
+ Optional<SILDebugVariable> getVarInfo() const {
auto RawValue = SILInstruction::Bits.AllocStackInst.VarInfo;
auto VI = TailAllocatedDebugVariable(RawValue);
return VI.get(getDecl(), getTrailingObjects<char>());
@@ -1514,12 +1519,12 @@
AllocBoxInst(SILDebugLocation DebugLoc, CanSILBoxType BoxType,
ArrayRef<SILValue> TypeDependentOperands, SILFunction &F,
- SILDebugVariable Var);
+ Optional<SILDebugVariable> Var);
static AllocBoxInst *create(SILDebugLocation Loc, CanSILBoxType boxType,
SILFunction &F,
SILOpenedArchetypesState &OpenedArchetypes,
- SILDebugVariable Var);
+ Optional<SILDebugVariable> Var);
public:
CanSILBoxType getBoxType() const {
@@ -1536,7 +1541,7 @@
VarDecl *getDecl() const;
/// Return the debug variable information attached to this instruction.
- SILDebugVariable getVarInfo() const {
+ Optional<SILDebugVariable> getVarInfo() const {
return VarInfo.get(getDecl(), getTrailingObjects<char>());
};
@@ -3629,7 +3634,7 @@
/// or null if we don't have one.
VarDecl *getDecl() const;
/// Return the debug variable information attached to this instruction.
- SILDebugVariable getVarInfo() const {
+ Optional<SILDebugVariable> getVarInfo() const {
return VarInfo.get(getDecl(), getTrailingObjects<char>());
}
};
@@ -3655,7 +3660,7 @@
/// or null if we don't have one.
VarDecl *getDecl() const;
/// Return the debug variable information attached to this instruction.
- SILDebugVariable getVarInfo() const {
+ Optional<SILDebugVariable> getVarInfo() const {
return VarInfo.get(getDecl(), getTrailingObjects<char>());
};
};
diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h
index 48fa897..bfc202c 100644
--- a/include/swift/SIL/SILValue.h
+++ b/include/swift/SIL/SILValue.h
@@ -146,6 +146,23 @@
/// ownership kind otherwise.
ValueOwnershipKind getProjectedOwnershipKind(SILModule &M,
SILType Proj) const;
+
+ /// Returns true if \p Other can be merged successfully with this, implying
+ /// that the two ownership kinds are "compatibile".
+ ///
+ /// The reason why we do not compare directy is to allow for
+ /// ValueOwnershipKind::Any to merge into other forms of ValueOwnershipKind.
+ bool isCompatibleWith(ValueOwnershipKind other) const {
+ return merge(other).hasValue();
+ }
+
+ /// Returns true if \p Other is compatible with ValueOwnershipKind::Trivial or
+ /// this. See isCompatibleWith for more information on what "compatibility"
+ /// means.
+ bool isTrivialOrCompatibleWith(ValueOwnershipKind other) const {
+ return isCompatibleWith(ValueOwnershipKind::Trivial) ||
+ isCompatibleWith(other);
+ }
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, ValueOwnershipKind Kind);
diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def
index f0e424e..a8fb74d 100644
--- a/include/swift/SILOptimizer/PassManager/Passes.def
+++ b/include/swift/SILOptimizer/PassManager/Passes.def
@@ -162,7 +162,7 @@
"Print Induction Variable Information for Testing")
PASS(InstCount, "inst-count",
"Record SIL Instruction, Block, and Function Counts as LLVM Statistics")
-PASS(JumpThreadSimplifyCFG, "simplify-cfg",
+PASS(JumpThreadSimplifyCFG, "jumpthread-simplify-cfg",
"Simplify CFG via Jump Threading")
PASS(LetPropertiesOpt, "let-properties-opt",
"Let Property Optimization")
@@ -244,8 +244,7 @@
"Scalar Replacement of Aggregate SIL Block Arguments")
PASS(SimplifyBBArgs, "simplify-bb-args",
"SIL Block Argument Simplification")
-// TODO: Rename this command line string.
-PASS(SimplifyCFG, "normal-simplify-cfg",
+PASS(SimplifyCFG, "-simplify-cfg",
"SIL CFG Simplification")
PASS(SpeculativeDevirtualization, "specdevirt",
"Speculative Devirtualization via Guarded Calls")
diff --git a/include/swift/SILOptimizer/Utils/Devirtualize.h b/include/swift/SILOptimizer/Utils/Devirtualize.h
index 1ccdaf0..9119be7 100644
--- a/include/swift/SILOptimizer/Utils/Devirtualize.h
+++ b/include/swift/SILOptimizer/Utils/Devirtualize.h
@@ -70,15 +70,17 @@
bool canDevirtualizeApply(FullApplySite AI, ClassHierarchyAnalysis *CHA);
bool isNominalTypeWithUnboundGenericParameters(SILType Ty, SILModule &M);
bool canDevirtualizeClassMethod(FullApplySite AI, SILType ClassInstanceType,
- OptRemark::Emitter *ORE = nullptr);
+ OptRemark::Emitter *ORE = nullptr,
+ bool isEffectivelyFinalMethod = false);
SILFunction *getTargetClassMethod(SILModule &M, SILType ClassOrMetatypeType,
MethodInst *MI);
DevirtualizationResult devirtualizeClassMethod(FullApplySite AI,
SILValue ClassInstance,
OptRemark::Emitter *ORE);
-DevirtualizationResult tryDevirtualizeClassMethod(FullApplySite AI,
- SILValue ClassInstance,
- OptRemark::Emitter *ORE);
+DevirtualizationResult
+tryDevirtualizeClassMethod(FullApplySite AI, SILValue ClassInstance,
+ OptRemark::Emitter *ORE,
+ bool isEffectivelyFinalMethod = false);
DevirtualizationResult
tryDevirtualizeWitnessMethod(ApplySite AI, OptRemark::Emitter *ORE);
}
diff --git a/include/swift/SILOptimizer/Utils/Local.h b/include/swift/SILOptimizer/Utils/Local.h
index d6ebd5c..9ef601c 100644
--- a/include/swift/SILOptimizer/Utils/Local.h
+++ b/include/swift/SILOptimizer/Utils/Local.h
@@ -161,8 +161,6 @@
bool tryCheckedCastBrJumpThreading(SILFunction *Fn, DominanceInfo *DT,
SmallVectorImpl<SILBasicBlock *> &BlocksForWorklist);
-void recalcDomTreeForCCBOpt(DominanceInfo *DT, SILFunction &F);
-
/// A structure containing callbacks that are called when an instruction is
/// removed or added.
struct InstModCallbacks {
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 492d385..459b3b6 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -54,7 +54,8 @@
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
-const uint16_t VERSION_MINOR = 398; // Private discriminators for type xrefs
+/// Don't worry about adhering to the 80-column limit for this line.
+const uint16_t VERSION_MINOR = 399; // Last change: @_weakLinked
using DeclIDField = BCFixed<31>;
diff --git a/include/swift/Syntax/TokenKinds.def b/include/swift/Syntax/TokenKinds.def
index 4fa46d6..0d69fcd 100644
--- a/include/swift/Syntax/TokenKinds.def
+++ b/include/swift/Syntax/TokenKinds.def
@@ -24,6 +24,8 @@
/// POUND_OBJECT_LITERAL(kw, desc, proto)
/// POUND_OLD_OBJECT_LITERAL(kw, new_kw, old_arg, new_arg)
/// POUND_CONFIG(kw)
+/// POUND_DIRECTIVE_KEYWORD(kw)
+/// POUND_COND_DIRECTIVE_KEYWORD(kw)
/// PUNCTUATOR(name, str)
/// LITERAL(name)
/// MISC(name)
@@ -107,6 +109,19 @@
#define POUND_CONFIG(kw) POUND_KEYWORD(kw)
#endif
+/// POUND_DIRECTIVE_KEYWORD(kw)
+/// Every keyword prefixed with a '#' that is a compiler control directive.
+#ifndef POUND_DIRECTIVE_KEYWORD
+#define POUND_DIRECTIVE_KEYWORD(kw) POUND_KEYWORD(kw)
+#endif
+
+/// POUND_COND_DIRECTIVE_KEYWORD(kw)
+/// Every keyword prefixed with a '#' that is part of conditional compilation
+/// control.
+#ifndef POUND_COND_DIRECTIVE_KEYWORD
+#define POUND_COND_DIRECTIVE_KEYWORD(kw) POUND_DIRECTIVE_KEYWORD(kw)
+#endif
+
/// PUNCTUATOR(name, str)
/// Expands for every Swift punctuator.
/// \param name The symbolic name of the punctuator, such as
@@ -250,22 +265,29 @@
PUNCTUATOR(l_square_lit, "[#")
PUNCTUATOR(r_square_lit, "#]")
-// Keywords prefixed with a '#'. "if" becomes "tok::pound_if".
-POUND_KEYWORD(if)
-POUND_KEYWORD(else)
-POUND_KEYWORD(elseif)
-POUND_KEYWORD(endif)
+// Keywords prefixed with a '#'. "keyPath" becomes "tok::pound_keyPath".
POUND_KEYWORD(keyPath)
POUND_KEYWORD(line)
-POUND_KEYWORD(sourceLocation)
POUND_KEYWORD(selector)
-POUND_KEYWORD(warning)
-POUND_KEYWORD(error)
+POUND_KEYWORD(file)
+POUND_KEYWORD(column)
+POUND_KEYWORD(function)
+POUND_KEYWORD(dsohandle)
+
+// Directive '#' keywords.
+POUND_DIRECTIVE_KEYWORD(sourceLocation)
+POUND_DIRECTIVE_KEYWORD(warning)
+POUND_DIRECTIVE_KEYWORD(error)
+
+// Conditional compilation '#' keywords.
+POUND_COND_DIRECTIVE_KEYWORD(if)
+POUND_COND_DIRECTIVE_KEYWORD(else)
+POUND_COND_DIRECTIVE_KEYWORD(elseif)
+POUND_COND_DIRECTIVE_KEYWORD(endif)
// Keywords prefixed with a '#' that are build configurations.
POUND_CONFIG(available)
-
// Object literals and their corresponding protocols.
POUND_OBJECT_LITERAL(fileLiteral, "file reference", ExpressibleByFileReferenceLiteral)
POUND_OBJECT_LITERAL(imageLiteral, "image", ExpressibleByImageLiteral)
@@ -275,11 +297,6 @@
POUND_OLD_OBJECT_LITERAL(Image, imageLiteral, imageLiteral, resourceName)
POUND_OLD_OBJECT_LITERAL(Color, colorLiteral, colorLiteralRed, red)
-POUND_KEYWORD(file)
-POUND_KEYWORD(column)
-POUND_KEYWORD(function)
-POUND_KEYWORD(dsohandle)
-
// Single-token literals
LITERAL(integer_literal)
LITERAL(floating_literal)
@@ -314,6 +331,8 @@
#undef POUND_OBJECT_LITERAL
#undef POUND_OLD_OBJECT_LITERAL
#undef POUND_CONFIG
+#undef POUND_DIRECTIVE_KEYWORD
+#undef POUND_COND_DIRECTIVE_KEYWORD
#undef PUNCTUATOR
#undef LITERAL
#undef MISC
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 28b234f..84d9a8a 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1402,7 +1402,7 @@
void ASTContext::verifyAllLoadedModules() const {
#ifndef NDEBUG
- SharedTimer("verifyAllLoadedModules");
+ FrontendStatsTracer tracer(Stats, "verify-all-loaded-modules");
for (auto &loader : Impl.ModuleLoaders)
loader->verifyAllModules();
diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp
index 5713e5f..366ea07 100644
--- a/lib/AST/Attr.cpp
+++ b/lib/AST/Attr.cpp
@@ -498,14 +498,6 @@
break;
}
- case DAK_StaticInitializeObjCMetadata:
- Printer.printAttrName("@_staticInitializeObjCMetadata");
- break;
-
- case DAK_DowngradeExhaustivityCheck:
- Printer.printAttrName("@_downgrade_exhaustivity_check");
- break;
-
case DAK_ClangImporterSynthesizedType: {
Printer.printAttrName("@_clangImporterSynthesizedType");
auto *attr = cast<ClangImporterSynthesizedTypeAttr>(this);
@@ -517,8 +509,13 @@
case DAK_Count:
llvm_unreachable("exceed declaration attribute kinds");
+#define SIMPLE_DECL_ATTR(X, CLASS, ...) case DAK_##CLASS:
+#include "swift/AST/Attr.def"
+ llvm_unreachable("handled above");
+
default:
- llvm_unreachable("handled before this switch");
+ assert(DeclAttribute::isDeclModifier(getKind()) &&
+ "handled above");
}
return true;
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 17e9664..12f2edd 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -482,7 +482,14 @@
return clangDecl->isWeakImported();
}
- // FIXME: Implement using AvailableAttr::getVersionAvailability().
+ auto *containingModule = getModuleContext();
+ if (containingModule == fromModule)
+ return false;
+
+ if (getAttrs().hasAttribute<WeakLinkedAttr>())
+ return true;
+
+ // FIXME: Also check availability when containingModule is resilient.
return false;
}
@@ -5471,7 +5478,11 @@
// always delegating. This occurs if the struct type is not fixed layout,
// and the constructor is either inlinable or defined in another module.
if (Kind == BodyInitKind::None && isa<StructDecl>(NTD)) {
- if (NTD->isFormallyResilient() &&
+ // Note: This is specifically not using isFormallyResilient. We relax this
+ // rule for structs in non-resilient modules so that they can have inlinable
+ // constructors, as long as those constructors don't reference private
+ // declarations.
+ if (NTD->isResilient() &&
getResilienceExpansion() == ResilienceExpansion::Minimal) {
Kind = BodyInitKind::Delegating;
@@ -5666,6 +5677,10 @@
const Decl *D = static_cast<const Decl *>(Entity);
if (auto const *VD = dyn_cast<const ValueDecl>(D)) {
VD->getFullName().print(OS, false);
+ } else {
+ OS << "<"
+ << Decl::getDescriptiveKindName(D->getDescriptiveKind())
+ << ">";
}
}
void traceLoc(const void *Entity, SourceManager *SM,
@@ -5679,14 +5694,10 @@
static DeclTraceFormatter TF;
-UnifiedStatsReporter::FrontendStatsTracer
-UnifiedStatsReporter::getStatsTracer(StringRef EventName, const Decl *D) {
- if (LastTracedFrontendCounters)
- // Return live tracer object.
- return FrontendStatsTracer(EventName, D, &TF, this);
- else
- // Return inert tracer object.
- return FrontendStatsTracer();
+template<>
+const UnifiedStatsReporter::TraceFormatter*
+FrontendStatsTracer::getTraceFormatter<const Decl *>() {
+ return &TF;
}
TypeOrExtensionDecl::TypeOrExtensionDecl(NominalTypeDecl *D) : Decl(D) {}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index daf0fbf..477416d 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -2297,12 +2297,8 @@
static ExprTraceFormatter TF;
-UnifiedStatsReporter::FrontendStatsTracer
-UnifiedStatsReporter::getStatsTracer(StringRef EventName, const Expr *E) {
- if (LastTracedFrontendCounters)
- // Return live tracer object.
- return FrontendStatsTracer(EventName, E, &TF, this);
- else
- // Return inert tracer object.
- return FrontendStatsTracer();
+template<>
+const UnifiedStatsReporter::TraceFormatter*
+FrontendStatsTracer::getTraceFormatter<const Expr *>() {
+ return &TF;
}
diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp
index e68d49c..129f6db 100644
--- a/lib/AST/NameLookup.cpp
+++ b/lib/AST/NameLookup.cpp
@@ -1352,12 +1352,10 @@
TinyPtrVector<ValueDecl *> NominalTypeDecl::lookupDirect(
DeclName name,
bool ignoreNewExtensions) {
- RecursiveSharedTimer::Guard guard;
ASTContext &ctx = getASTContext();
+ FrontendStatsTracer tracer(ctx.Stats, "lookup-direct", this);
if (auto s = ctx.Stats) {
++s->getFrontendCounters().NominalTypeLookupDirectCount;
- guard = s->getFrontendRecursiveSharedTimers()
- .NominalTypeDecl__lookupDirect.getGuard();
}
// We only use NamedLazyMemberLoading when a user opts-in and we have
diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp
index cf8af58..27e7750 100644
--- a/lib/AST/ProtocolConformance.cpp
+++ b/lib/AST/ProtocolConformance.cpp
@@ -24,6 +24,7 @@
#include "swift/AST/Substitution.h"
#include "swift/AST/Types.h"
#include "swift/AST/TypeWalker.h"
+#include "swift/Basic/Statistic.h"
#include "swift/ClangImporter/ClangModule.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/Statistic.h"
@@ -1367,3 +1368,39 @@
return *this;
return ProtocolConformanceRef(getConcrete()->getCanonicalConformance());
}
+
+// See swift/Basic/Statistic.h for declaration: this enables tracing
+// ProtocolConformances, is defined here to avoid too much layering violation /
+// circular linkage dependency.
+
+struct ProtocolConformanceTraceFormatter
+ : public UnifiedStatsReporter::TraceFormatter {
+ void traceName(const void *Entity, raw_ostream &OS) const {
+ if (!Entity)
+ return;
+ const ProtocolConformance *C =
+ static_cast<const ProtocolConformance *>(Entity);
+ C->printName(OS);
+ }
+ void traceLoc(const void *Entity, SourceManager *SM,
+ clang::SourceManager *CSM, raw_ostream &OS) const {
+ if (!Entity)
+ return;
+ const ProtocolConformance *C =
+ static_cast<const ProtocolConformance *>(Entity);
+ if (auto const *NPC = dyn_cast<NormalProtocolConformance>(C)) {
+ NPC->getLoc().print(OS, *SM);
+ } else if (auto const *DC = C->getDeclContext()) {
+ if (auto const *D = DC->getAsDeclOrDeclExtensionContext())
+ D->getLoc().print(OS, *SM);
+ }
+ }
+};
+
+static ProtocolConformanceTraceFormatter TF;
+
+template<>
+const UnifiedStatsReporter::TraceFormatter*
+FrontendStatsTracer::getTraceFormatter<const ProtocolConformance *>() {
+ return &TF;
+}
diff --git a/lib/AST/RawComment.cpp b/lib/AST/RawComment.cpp
index 7acdd36..cc9509e 100644
--- a/lib/AST/RawComment.cpp
+++ b/lib/AST/RawComment.cpp
@@ -57,11 +57,11 @@
SingleRawComment::SingleRawComment(CharSourceRange Range,
const SourceManager &SourceMgr)
: Range(Range), RawText(SourceMgr.extractText(Range)),
- Kind(static_cast<unsigned>(getCommentKind(RawText))),
- EndLine(SourceMgr.getLineNumber(Range.getEnd())) {
+ Kind(static_cast<unsigned>(getCommentKind(RawText))) {
auto StartLineAndColumn = SourceMgr.getLineAndColumn(Range.getStart());
StartLine = StartLineAndColumn.first;
StartColumn = StartLineAndColumn.second;
+ EndLine = SourceMgr.getLineNumber(Range.getEnd());
}
SingleRawComment::SingleRawComment(StringRef RawText, unsigned StartColumn)
diff --git a/lib/Basic/PartsOfSpeech.def b/lib/Basic/PartsOfSpeech.def
index 05326b7..a134ab9 100644
--- a/lib/Basic/PartsOfSpeech.def
+++ b/lib/Basic/PartsOfSpeech.def
@@ -370,7 +370,6 @@
VERB(hand)
VERB(handle)
VERB(hang)
-VERB(hang)
VERB(happen)
VERB(harass)
VERB(harm)
diff --git a/lib/Basic/Statistic.cpp b/lib/Basic/Statistic.cpp
index 6508e4f..8e465fb 100644
--- a/lib/Basic/Statistic.cpp
+++ b/lib/Basic/Statistic.cpp
@@ -14,16 +14,19 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "swift/Basic/Statistic.h"
+#include "swift/Basic/Timer.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/SIL/SILFunction.h"
#include "swift/Driver/DependencyGraph.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/Config/config.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
#include <chrono>
+#include <limits>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
@@ -36,12 +39,15 @@
using namespace llvm;
using namespace llvm::sys;
-static size_t
+static int64_t
getChildrenMaxResidentSetSize() {
#if defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
struct rusage RU;
::getrusage(RUSAGE_CHILDREN, &RU);
- return RU.ru_maxrss;
+ int64_t M = static_cast<int64_t>(RU.ru_maxrss);
+ if (M < 0)
+ M = std::numeric_limits<int64_t>::max();
+ return M;
#else
return 0;
#endif
@@ -78,6 +84,12 @@
return makeFileName("trace", ProgramName, AuxName, "csv");
}
+static std::string
+makeProfileDirName(StringRef ProgramName,
+ StringRef AuxName) {
+ return makeFileName("profile", ProgramName, AuxName, "dir");
+}
+
// LLVM's statistics-reporting machinery is sensitive to filenames containing
// YAML-quote-requiring characters, which occur surprisingly often in the wild;
// we only need a recognizable and likely-unique name for a target here, not an
@@ -126,6 +138,165 @@
+ "-" + cleanName(OptType));
}
+class UnifiedStatsReporter::RecursionSafeTimers {
+
+ struct RecursionSafeTimer {
+ llvm::Optional<SharedTimer> Timer;
+ size_t RecursionDepth;
+ };
+
+ StringMap<RecursionSafeTimer> Timers;
+
+public:
+
+ void beginTimer(StringRef Name) {
+ RecursionSafeTimer &T = Timers[Name];
+ if (T.RecursionDepth == 0) {
+ T.Timer.emplace(Name);
+ }
+ T.RecursionDepth++;
+ }
+
+ void endTimer(StringRef Name) {
+ auto I = Timers.find(Name);
+ assert(I != Timers.end());
+ RecursionSafeTimer &T = I->getValue();
+ assert(T.RecursionDepth != 0);
+ T.RecursionDepth--;
+ if (T.RecursionDepth == 0) {
+ T.Timer.reset();
+ }
+ }
+};
+
+class StatsProfiler {
+ struct Node {
+ int64_t SelfCount;
+ typedef std::tuple<StringRef,
+ const void*,
+ const UnifiedStatsReporter::TraceFormatter*> Key;
+ Node *Parent;
+ DenseMap<Key, std::unique_ptr<Node>> Children;
+
+ Node(Node *P=nullptr) : SelfCount(0), Parent(P)
+ {}
+
+ void print(std::vector<Key> &Context, raw_ostream &OS) const {
+ StringRef delim;
+ if (!(SelfCount == 0 || Context.empty())) {
+ for (auto const &K : Context) {
+ StringRef Name;
+ const void* Entity;
+ const UnifiedStatsReporter::TraceFormatter *Formatter;
+ std::tie(Name, Entity, Formatter) = K;
+ OS << delim << Name;
+ if (Formatter && Entity) {
+ OS << ' ';
+ Formatter->traceName(Entity, OS);
+ }
+ delim = ";";
+ }
+ OS << ' ' << SelfCount << '\n';
+ }
+ for (auto const &I : Children) {
+ Context.push_back(I.getFirst());
+ I.getSecond()->print(Context, OS);
+ Context.pop_back();
+ }
+ }
+
+ Node *getChild(StringRef Name,
+ const void *Entity,
+ const UnifiedStatsReporter::TraceFormatter *TF) {
+ Key K(Name, Entity, TF);
+ auto I = Children.find(K);
+ if (I != Children.end()) {
+ return I->getSecond().get();
+ } else {
+ auto N = llvm::make_unique<Node>(this);
+ auto P = N.get();
+ Children.insert(std::make_pair(K, std::move(N)));
+ return P;
+ }
+ }
+ };
+ Node Root;
+ Node *Curr;
+public:
+
+ StatsProfiler()
+ : Curr(&Root)
+ {}
+ StatsProfiler(StatsProfiler const &Other) = delete;
+ StatsProfiler& operator=(const StatsProfiler&) = delete;
+
+ void print(raw_ostream &OS) const {
+ std::vector<Node::Key> Context;
+ Root.print(Context, OS);
+ }
+
+ void printToFile(StringRef Dirname, StringRef Filename) const {
+ SmallString<256> Path(Dirname);
+ llvm::sys::path::append(Path, Filename);
+ std::error_code EC;
+ raw_fd_ostream Stream(Path, EC, fs::F_Append | fs::F_Text);
+ if (EC) {
+ llvm::errs() << "Error opening profile file '"
+ << Path << "' for writing\n";
+ return;
+ }
+ print(Stream);
+ }
+
+ void profileEvent(StringRef Name,
+ double DeltaSeconds,
+ bool IsEntry,
+ const void *Entity=nullptr,
+ const UnifiedStatsReporter::TraceFormatter *TF=nullptr) {
+ int64_t DeltaUSec = int64_t(1000000.0 * DeltaSeconds);
+ profileEvent(Name, DeltaUSec, IsEntry, Entity, TF);
+ }
+
+ void profileEvent(StringRef Name,
+ int64_t Delta,
+ bool IsEntry,
+ const void *Entity=nullptr,
+ const UnifiedStatsReporter::TraceFormatter *TF=nullptr) {
+ assert(Curr);
+ Curr->SelfCount += Delta;
+ if (IsEntry) {
+ Node *Child = Curr->getChild(Name, Entity, TF);
+ assert(Child);
+ assert(Child->Parent == Curr);
+ Curr = Child;
+ } else {
+ Curr = Curr->Parent;
+ assert(Curr);
+ }
+ }
+};
+
+struct UnifiedStatsReporter::StatsProfilers
+{
+ // Timerecord of last update.
+ llvm::TimeRecord LastUpdated;
+
+ // One profiler for each time category.
+ StatsProfiler UserTime;
+ StatsProfiler SystemTime;
+ StatsProfiler ProcessTime;
+ StatsProfiler WallTime;
+
+ // Then one profiler for each frontend statistic.
+#define FRONTEND_STATISTIC(TY, NAME) StatsProfiler NAME;
+#include "swift/Basic/Statistics.def"
+#undef FRONTEND_STATISTIC
+
+ StatsProfilers()
+ : LastUpdated(llvm::TimeRecord::getCurrentTime())
+ {}
+};
+
UnifiedStatsReporter::UnifiedStatsReporter(StringRef ProgramName,
StringRef ModuleName,
StringRef InputName,
@@ -135,7 +306,9 @@
StringRef Directory,
SourceManager *SM,
clang::SourceManager *CSM,
- bool TraceEvents)
+ bool TraceEvents,
+ bool ProfileEvents,
+ bool ProfileEntities)
: UnifiedStatsReporter(ProgramName,
auxName(ModuleName,
InputName,
@@ -143,7 +316,8 @@
OutputType,
OptType),
Directory,
- SM, CSM, TraceEvents)
+ SM, CSM,
+ TraceEvents, ProfileEvents, ProfileEntities)
{
}
@@ -152,31 +326,42 @@
StringRef Directory,
SourceManager *SM,
clang::SourceManager *CSM,
- bool TraceEvents)
+ bool TraceEvents,
+ bool ProfileEvents,
+ bool ProfileEntities)
: currentProcessExitStatusSet(false),
currentProcessExitStatus(EXIT_FAILURE),
StatsFilename(Directory),
TraceFilename(Directory),
+ ProfileDirname(Directory),
StartedTime(llvm::TimeRecord::getCurrentTime()),
Timer(make_unique<NamedRegionTimer>(AuxName,
"Building Target",
ProgramName, "Running Program")),
SourceMgr(SM),
- ClangSourceMgr(CSM)
+ ClangSourceMgr(CSM),
+ RecursiveTimers(llvm::make_unique<RecursionSafeTimers>())
{
path::append(StatsFilename, makeStatsFileName(ProgramName, AuxName));
path::append(TraceFilename, makeTraceFileName(ProgramName, AuxName));
+ path::append(ProfileDirname, makeProfileDirName(ProgramName, AuxName));
EnableStatistics(/*PrintOnExit=*/false);
SharedTimer::enableCompilationTimers();
+ if (TraceEvents || ProfileEvents || ProfileEntities)
+ LastTracedFrontendCounters.emplace();
if (TraceEvents)
- LastTracedFrontendCounters = make_unique<AlwaysOnFrontendCounters>();
+ FrontendStatsEvents.emplace();
+ if (ProfileEvents)
+ EventProfilers = make_unique<StatsProfilers>();
+ if (ProfileEntities)
+ EntityProfilers = make_unique<StatsProfilers>();
}
UnifiedStatsReporter::AlwaysOnDriverCounters &
UnifiedStatsReporter::getDriverCounters()
{
if (!DriverCounters)
- DriverCounters = make_unique<AlwaysOnDriverCounters>();
+ DriverCounters.emplace();
return *DriverCounters;
}
@@ -184,18 +369,10 @@
UnifiedStatsReporter::getFrontendCounters()
{
if (!FrontendCounters)
- FrontendCounters = make_unique<AlwaysOnFrontendCounters>();
+ FrontendCounters.emplace();
return *FrontendCounters;
}
-UnifiedStatsReporter::AlwaysOnFrontendRecursiveSharedTimers &
-UnifiedStatsReporter::getFrontendRecursiveSharedTimers() {
- if (!FrontendRecursiveSharedTimers)
- FrontendRecursiveSharedTimers =
- make_unique<AlwaysOnFrontendRecursiveSharedTimers>();
- return *FrontendRecursiveSharedTimers;
-}
-
void
UnifiedStatsReporter::noteCurrentProcessExitStatus(int status) {
assert(!currentProcessExitStatusSet);
@@ -258,31 +435,50 @@
OS.flush();
}
-UnifiedStatsReporter::FrontendStatsTracer::FrontendStatsTracer(
- StringRef EventName,
- const void *Entity,
- const TraceFormatter *Formatter,
- UnifiedStatsReporter *Reporter)
- : Reporter(Reporter),
- SavedTime(llvm::TimeRecord::getCurrentTime()),
- EventName(EventName),
- Entity(Entity),
- Formatter(Formatter)
-{
- if (Reporter)
+FrontendStatsTracer::FrontendStatsTracer(
+ UnifiedStatsReporter *Reporter, StringRef EventName, const void *Entity,
+ const UnifiedStatsReporter::TraceFormatter *Formatter)
+ : Reporter(Reporter), SavedTime(), EventName(EventName), Entity(Entity),
+ Formatter(Formatter) {
+ if (Reporter) {
+ SavedTime = llvm::TimeRecord::getCurrentTime();
Reporter->saveAnyFrontendStatsEvents(*this, true);
+ }
}
-UnifiedStatsReporter::FrontendStatsTracer::FrontendStatsTracer()
- : Reporter(nullptr),
- Entity(nullptr),
- Formatter(nullptr)
-{
-}
+FrontendStatsTracer::FrontendStatsTracer() = default;
-UnifiedStatsReporter::FrontendStatsTracer&
-UnifiedStatsReporter::FrontendStatsTracer::operator=(
- FrontendStatsTracer&& other)
+FrontendStatsTracer::FrontendStatsTracer(UnifiedStatsReporter *R, StringRef S)
+ : FrontendStatsTracer(R, S, nullptr, nullptr)
+{}
+
+FrontendStatsTracer::FrontendStatsTracer(UnifiedStatsReporter *R, StringRef S,
+ const Decl *D)
+ : FrontendStatsTracer(R, S, D, getTraceFormatter<const Decl *>())
+{}
+
+FrontendStatsTracer::FrontendStatsTracer(UnifiedStatsReporter *R, StringRef S,
+ const ProtocolConformance *P)
+ : FrontendStatsTracer(R, S, P,
+ getTraceFormatter<const ProtocolConformance *>()) {}
+
+FrontendStatsTracer::FrontendStatsTracer(UnifiedStatsReporter *R, StringRef S,
+ const Expr *E)
+ : FrontendStatsTracer(R, S, E, getTraceFormatter<const Expr *>())
+{}
+
+FrontendStatsTracer::FrontendStatsTracer(UnifiedStatsReporter *R, StringRef S,
+ const clang::Decl *D)
+ : FrontendStatsTracer(R, S, D, getTraceFormatter<const clang::Decl *>())
+{}
+
+FrontendStatsTracer::FrontendStatsTracer(UnifiedStatsReporter *R, StringRef S,
+ const SILFunction *F)
+ : FrontendStatsTracer(R, S, F, getTraceFormatter<const SILFunction *>())
+{}
+
+FrontendStatsTracer&
+FrontendStatsTracer::operator=(FrontendStatsTracer&& other)
{
Reporter = other.Reporter;
SavedTime = other.SavedTime;
@@ -293,8 +489,7 @@
return *this;
}
-UnifiedStatsReporter::FrontendStatsTracer::FrontendStatsTracer(
- FrontendStatsTracer&& other)
+FrontendStatsTracer::FrontendStatsTracer(FrontendStatsTracer&& other)
: Reporter(other.Reporter),
SavedTime(other.SavedTime),
EventName(other.EventName),
@@ -304,47 +499,105 @@
other.Reporter = nullptr;
}
-UnifiedStatsReporter::FrontendStatsTracer::~FrontendStatsTracer()
+FrontendStatsTracer::~FrontendStatsTracer()
{
if (Reporter)
Reporter->saveAnyFrontendStatsEvents(*this, false);
}
+static inline void
+saveEvent(StringRef StatName,
+ int64_t Curr, int64_t Last,
+ uint64_t NowUS, uint64_t LiveUS,
+ std::vector<UnifiedStatsReporter::FrontendStatsEvent> &Events,
+ FrontendStatsTracer const& T,
+ bool IsEntry) {
+ int64_t Delta = Curr - Last;
+ if (Delta != 0) {
+ Events.emplace_back(UnifiedStatsReporter::FrontendStatsEvent{
+ NowUS, LiveUS, IsEntry, T.EventName, StatName, Delta, Curr,
+ T.Entity, T.Formatter});
+ }
+}
+
void
UnifiedStatsReporter::saveAnyFrontendStatsEvents(
FrontendStatsTracer const& T,
bool IsEntry)
{
+ // First make a note in the recursion-safe timers; these
+ // are active anytime UnifiedStatsReporter is active.
+ if (IsEntry) {
+ RecursiveTimers->beginTimer(T.EventName);
+ } else {
+ RecursiveTimers->endTimer(T.EventName);
+ }
+
+ // If we don't have a saved entry to form deltas against in the trace buffer
+ // or profilers, we're not tracing or profiling: return early.
if (!LastTracedFrontendCounters)
return;
auto Now = llvm::TimeRecord::getCurrentTime();
- auto StartUS = uint64_t(1000000.0 * T.SavedTime.getProcessTime());
- auto NowUS = uint64_t(1000000.0 * Now.getProcessTime());
- auto LiveUS = IsEntry ? 0 : NowUS - StartUS;
- auto &C = getFrontendCounters();
-#define FRONTEND_STATISTIC(TY, NAME) \
- do { \
- auto total = C.NAME; \
- auto delta = C.NAME - LastTracedFrontendCounters->NAME; \
- static char const *name = #TY "." #NAME; \
- if (delta != 0) { \
- LastTracedFrontendCounters->NAME = C.NAME; \
- FrontendStatsEvents.emplace_back(FrontendStatsEvent { \
- NowUS, LiveUS, IsEntry, T.EventName, name, \
- delta, total, T.Entity, T.Formatter}); \
- } \
- } while (0);
+ auto &Curr = getFrontendCounters();
+ auto &Last = *LastTracedFrontendCounters;
+ if (EventProfilers) {
+ auto TimeDelta = Now;
+ TimeDelta -= EventProfilers->LastUpdated;
+ EventProfilers->UserTime.profileEvent(T.EventName,
+ TimeDelta.getUserTime(),
+ IsEntry);
+ EventProfilers->SystemTime.profileEvent(T.EventName,
+ TimeDelta.getSystemTime(),
+ IsEntry);
+ EventProfilers->ProcessTime.profileEvent(T.EventName,
+ TimeDelta.getProcessTime(),
+ IsEntry);
+ EventProfilers->WallTime.profileEvent(T.EventName,
+ TimeDelta.getWallTime(),
+ IsEntry);
+#define FRONTEND_STATISTIC(TY, N) \
+ EventProfilers->N.profileEvent(T.EventName, Curr.N - Last.N, IsEntry);
#include "swift/Basic/Statistics.def"
#undef FRONTEND_STATISTIC
-}
+ EventProfilers->LastUpdated = Now;
+ }
-UnifiedStatsReporter::AlwaysOnFrontendRecursiveSharedTimers::
- AlwaysOnFrontendRecursiveSharedTimers()
- :
-#define FRONTEND_RECURSIVE_SHARED_TIMER(ID) ID(#ID),
+ if (EntityProfilers) {
+ auto TimeDelta = Now;
+ TimeDelta -= EntityProfilers->LastUpdated;
+ EntityProfilers->UserTime.profileEvent(T.EventName,
+ TimeDelta.getUserTime(),
+ IsEntry, T.Entity, T.Formatter);
+ EntityProfilers->SystemTime.profileEvent(T.EventName,
+ TimeDelta.getSystemTime(),
+ IsEntry, T.Entity, T.Formatter);
+ EntityProfilers->ProcessTime.profileEvent(T.EventName,
+ TimeDelta.getProcessTime(),
+ IsEntry, T.Entity, T.Formatter);
+ EntityProfilers->WallTime.profileEvent(T.EventName,
+ TimeDelta.getWallTime(),
+ IsEntry, T.Entity, T.Formatter);
+#define FRONTEND_STATISTIC(TY, N) \
+ EntityProfilers->N.profileEvent(T.EventName, Curr.N - Last.N, IsEntry, \
+ T.Entity, T.Formatter);
#include "swift/Basic/Statistics.def"
-#undef FRONTEND_RECURSIVE_SHARED_TIMER
- dummyInstanceVariableToGetConstructorToParse(0) {
+#undef FRONTEND_STATISTIC
+ EntityProfilers->LastUpdated = Now;
+ }
+
+ if (FrontendStatsEvents) {
+ auto StartUS = uint64_t(1000000.0 * T.SavedTime.getProcessTime());
+ auto NowUS = uint64_t(1000000.0 * Now.getProcessTime());
+ auto LiveUS = IsEntry ? 0 : NowUS - StartUS;
+ auto &Events = *FrontendStatsEvents;
+#define FRONTEND_STATISTIC(TY, N) \
+ saveEvent(#TY "." #N, Curr.N, Last.N, NowUS, LiveUS, Events, T, IsEntry);
+#include "swift/Basic/Statistics.def"
+#undef FRONTEND_STATISTIC
+ }
+
+ // Save all counters (changed or otherwise).
+ Last = Curr;
}
UnifiedStatsReporter::TraceFormatter::~TraceFormatter() {}
@@ -384,8 +637,8 @@
auto &C = getFrontendCounters();
// Convenience calculation for crude top-level "absolute speed".
if (C.NumSourceLines != 0 && ElapsedTime.getProcessTime() != 0.0)
- C.NumSourceLinesPerSecond = (size_t) (((double)C.NumSourceLines) /
- ElapsedTime.getProcessTime());
+ C.NumSourceLinesPerSecond = (int64_t) (((double)C.NumSourceLines) /
+ ElapsedTime.getProcessTime());
}
std::error_code EC;
@@ -416,7 +669,7 @@
printAlwaysOnStatsAndTimers(ostream);
#endif
- if (LastTracedFrontendCounters && SourceMgr) {
+ if (FrontendStatsEvents && SourceMgr) {
std::error_code EC;
raw_fd_ostream tstream(TraceFilename, EC, fs::F_Append | fs::F_Text);
if (EC) {
@@ -426,7 +679,7 @@
}
tstream << "Time,Live,IsEntry,EventName,CounterName,"
<< "CounterDelta,CounterValue,EntityName,EntityRange\n";
- for (auto const &E : FrontendStatsEvents) {
+ for (auto const &E : *FrontendStatsEvents) {
tstream << E.TimeUSec << ','
<< E.LiveUSec << ','
<< (E.IsEntry ? "\"entry\"," : "\"exit\",")
@@ -444,6 +697,39 @@
tstream << '"' << '\n';
}
}
+
+ if (EventProfilers || EntityProfilers) {
+ std::error_code EC = llvm::sys::fs::create_directories(ProfileDirname);
+ if (EC) {
+ llvm::errs() << "Failed to create directory '" << ProfileDirname << "': "
+ << EC.message() << "\n";
+ return;
+ }
+ if (EventProfilers) {
+ auto D = ProfileDirname;
+ EventProfilers->UserTime.printToFile(D, "Time.User.events");
+ EventProfilers->SystemTime.printToFile(D, "Time.System.events");
+ EventProfilers->ProcessTime.printToFile(D, "Time.Process.events");
+ EventProfilers->WallTime.printToFile(D, "Time.Wall.events");
+#define FRONTEND_STATISTIC(TY, NAME) \
+ EventProfilers->NAME.printToFile(ProfileDirname, \
+ #TY "." #NAME ".events");
+#include "swift/Basic/Statistics.def"
+#undef FRONTEND_STATISTIC
+ }
+ if (EntityProfilers) {
+ auto D = ProfileDirname;
+ EntityProfilers->UserTime.printToFile(D, "Time.User.entities");
+ EntityProfilers->SystemTime.printToFile(D, "Time.System.entities");
+ EntityProfilers->ProcessTime.printToFile(D, "Time.Process.entities");
+ EntityProfilers->WallTime.printToFile(D, "Time.Wall.entities");
+#define FRONTEND_STATISTIC(TY, NAME) \
+ EntityProfilers->NAME.printToFile(ProfileDirname, \
+ #TY "." #NAME ".entities");
+#include "swift/Basic/Statistics.def"
+#undef FRONTEND_STATISTIC
+ }
+ }
}
} // namespace swift
diff --git a/lib/ClangImporter/CFTypeInfo.cpp b/lib/ClangImporter/CFTypeInfo.cpp
index f150199..a4f69d3 100644
--- a/lib/ClangImporter/CFTypeInfo.cpp
+++ b/lib/ClangImporter/CFTypeInfo.cpp
@@ -20,18 +20,7 @@
using namespace swift;
using namespace importer;
-/// The maximum length of any particular string in the list of known CF types.
-const size_t MaxCFTypeNameLength = 38;
namespace {
- // FIXME: This is only needed because llvm::StringRef doesn't have a constexpr
- // constructor.
- struct CFTypeListEntry {
- unsigned char Length;
- char Data[MaxCFTypeNameLength + 1];
-
- operator StringRef() const { return StringRef(Data, Length); }
- };
-
// Quasi-lexicographic order: string length first, then string data.
// Since we don't care about the actual length, we can use this, which
// lets us ignore the string data a larger proportion of the time.
@@ -43,16 +32,11 @@
};
} // end anonymous namespace
-template <size_t Len>
-static constexpr size_t string_lengthof(const char (&data)[Len]) {
- return Len - 1;
-}
-
/// The list of known CF types. We use 'constexpr' to verify that this is
/// emitted as a constant. Note that this is expected to be sorted in
/// quasi-lexicographic order.
-static constexpr const CFTypeListEntry KnownCFTypes[] = {
-#define CF_TYPE(NAME) { string_lengthof(#NAME), #NAME },
+static constexpr const llvm::StringLiteral KnownCFTypes[] = {
+#define CF_TYPE(NAME) #NAME,
#define NON_CF_TYPE(NAME)
#include "SortedCFDatabase.def"
};
diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp
index 666fab4..b2d18ca 100644
--- a/lib/ClangImporter/ClangImporter.cpp
+++ b/lib/ClangImporter/ClangImporter.cpp
@@ -995,6 +995,7 @@
if (importerOpts.Mode == ClangImporterOptions::Modes::EmbedBitcode)
return importer;
+ instance.getLangOpts().NeededByPCHOrCompilationUsesPCH = true;
bool canBegin = action->BeginSourceFile(instance,
instance.getFrontendOpts().Inputs[0]);
if (!canBegin)
@@ -1373,6 +1374,7 @@
invocation->getFrontendOpts().OutputFile = outputPCHPath;
invocation->getFrontendOpts().ProgramAction = clang::frontend::GeneratePCH;
invocation->getPreprocessorOpts().resetNonModularOptions();
+ invocation->getLangOpts()->NeededByPCHOrCompilationUsesPCH = true;
clang::CompilerInstance emitInstance(
Impl.Instance->getPCHContainerOperations());
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 57c2a15..3089929 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -4511,15 +4511,15 @@
}
Decl *VisitObjCInterfaceDecl(const clang::ObjCInterfaceDecl *decl) {
- auto createRootClass = [=](Identifier name,
- DeclContext *dc = nullptr) -> ClassDecl * {
+ auto createFakeRootClass = [=](Identifier name,
+ DeclContext *dc = nullptr) -> ClassDecl * {
if (!dc) {
dc = Impl.getClangModuleForDecl(decl->getCanonicalDecl(),
/*allowForwardDeclaration=*/true);
}
auto result = Impl.createDeclWithClangNode<ClassDecl>(decl,
- AccessLevel::Open,
+ AccessLevel::Public,
SourceLoc(), name,
SourceLoc(), None,
nullptr, dc);
@@ -4547,7 +4547,7 @@
const ClassDecl *nsObjectDecl =
nsObjectTy->getClassOrBoundGenericClass();
- auto result = createRootClass(Impl.SwiftContext.Id_Protocol,
+ auto result = createFakeRootClass(Impl.SwiftContext.Id_Protocol,
nsObjectDecl->getDeclContext());
result->setForeignClassKind(ClassDecl::ForeignKind::RuntimeOnly);
return result;
@@ -4579,7 +4579,7 @@
if (Impl.ImportForwardDeclarations) {
// Fake it by making an unavailable opaque @objc root class.
- auto result = createRootClass(name);
+ auto result = createFakeRootClass(name);
result->setImplicit();
auto attr = AvailableAttr::createPlatformAgnostic(Impl.SwiftContext,
"This Objective-C class has only been forward-declared; "
@@ -4602,13 +4602,16 @@
if (declaredNative && nativeDecl)
return nativeDecl;
+ auto access = AccessLevel::Open;
+ if (decl->hasAttr<clang::ObjCSubclassingRestrictedAttr>() &&
+ Impl.SwiftContext.isSwiftVersionAtLeast(5)) {
+ access = AccessLevel::Public;
+ }
+
// Create the class declaration and record it.
- auto result = Impl.createDeclWithClangNode<ClassDecl>(decl,
- AccessLevel::Open,
- Impl.importSourceLoc(decl->getLocStart()),
- name,
- Impl.importSourceLoc(decl->getLocation()),
- None, nullptr, dc);
+ auto result = Impl.createDeclWithClangNode<ClassDecl>(
+ decl, access, Impl.importSourceLoc(decl->getLocStart()), name,
+ Impl.importSourceLoc(decl->getLocation()), None, nullptr, dc);
// Import generic arguments, if any.
if (auto gpImportResult = importObjCGenericParams(decl, dc)) {
@@ -7875,11 +7878,8 @@
if (!ClangDecl)
return nullptr;
- UnifiedStatsReporter::FrontendStatsTracer Tracer;
- if (SwiftContext.Stats)
- Tracer = SwiftContext.Stats->getStatsTracer("import-clang-decl",
- ClangDecl);
-
+ FrontendStatsTracer StatsTracer(SwiftContext.Stats,
+ "import-clang-decl", ClangDecl);
clang::PrettyStackTraceDecl trace(ClangDecl, clang::SourceLocation(),
Instance->getSourceManager(), "importing");
@@ -8346,12 +8346,8 @@
void
ClangImporter::Implementation::loadAllMembers(Decl *D, uint64_t extra) {
- RecursiveSharedTimer::Guard guard;
- if (auto s = D->getASTContext().Stats) {
- guard = s->getFrontendRecursiveSharedTimers()
- .ClangImporter__Implementation__loadAllMembers.getGuard();
- }
+ FrontendStatsTracer tracer(D->getASTContext().Stats, "load-all-members", D);
assert(D);
// Check whether we're importing an Objective-C container of some sort.
@@ -8601,17 +8597,20 @@
const clang::Decl *CD = static_cast<const clang::Decl *>(Entity);
if (auto const *ND = dyn_cast<const clang::NamedDecl>(CD)) {
ND->printName(OS);
+ } else {
+ OS << "<unnamed-clang-decl>";
}
}
- static inline void printClangShortLoc(raw_ostream &OS,
+ static inline bool printClangShortLoc(raw_ostream &OS,
clang::SourceManager *CSM,
clang::SourceLocation L) {
if (!L.isValid() || !L.isFileID())
- return;
+ return false;
auto PLoc = CSM->getPresumedLoc(L);
OS << llvm::sys::path::filename(PLoc.getFilename()) << ':' << PLoc.getLine()
<< ':' << PLoc.getColumn();
+ return true;
}
void traceLoc(const void *Entity, SourceManager *SM,
@@ -8621,8 +8620,8 @@
if (CSM) {
const clang::Decl *CD = static_cast<const clang::Decl *>(Entity);
auto Range = CD->getSourceRange();
- printClangShortLoc(OS, CSM, Range.getBegin());
- OS << '-';
+ if (printClangShortLoc(OS, CSM, Range.getBegin()))
+ OS << '-';
printClangShortLoc(OS, CSM, Range.getEnd());
}
}
@@ -8630,13 +8629,8 @@
static ClangDeclTraceFormatter TF;
-UnifiedStatsReporter::FrontendStatsTracer
-UnifiedStatsReporter::getStatsTracer(StringRef EventName,
- const clang::Decl *D) {
- if (LastTracedFrontendCounters)
- // Return live tracer object.
- return FrontendStatsTracer(EventName, D, &TF, this);
- else
- // Return inert tracer object.
- return FrontendStatsTracer();
+template<>
+const UnifiedStatsReporter::TraceFormatter*
+FrontendStatsTracer::getTraceFormatter<const clang::Decl *>() {
+ return &TF;
}
diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index e5c53d0..b8d905a 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -65,7 +65,10 @@
case Node::Kind::Class:
case Node::Kind::Enum:
case Node::Kind::Protocol:
+ case Node::Kind::OtherNominalType:
case Node::Kind::TypeAlias:
+ case Node::Kind::SymbolicReference:
+ case Node::Kind::UnresolvedSymbolicReference:
return true;
default:
return false;
@@ -168,6 +171,94 @@
return mangledName.drop_front(getManglingPrefixLength(mangledName));
}
+static bool isAliasNode(Demangle::NodePointer Node) {
+ switch (Node->getKind()) {
+ case Demangle::Node::Kind::Type:
+ return isAliasNode(Node->getChild(0));
+ case Demangle::Node::Kind::TypeAlias:
+ return true;
+ default:
+ return false;
+ }
+ llvm_unreachable("Unhandled node kind!");
+}
+
+bool swift::Demangle::isAlias(llvm::StringRef mangledName) {
+ Demangle::Demangler Dem;
+ return isAliasNode(Dem.demangleType(mangledName));
+}
+
+static bool isClassNode(Demangle::NodePointer Node) {
+ switch (Node->getKind()) {
+ case Demangle::Node::Kind::Type:
+ return isClassNode(Node->getChild(0));
+ case Demangle::Node::Kind::Class:
+ case Demangle::Node::Kind::BoundGenericClass:
+ return true;
+ default:
+ return false;
+ }
+ llvm_unreachable("Unhandled node kind!");
+}
+
+bool swift::Demangle::isClass(llvm::StringRef mangledName) {
+ Demangle::Demangler Dem;
+ return isClassNode(Dem.demangleType(mangledName));
+}
+
+static bool isEnumNode(Demangle::NodePointer Node) {
+ switch (Node->getKind()) {
+ case Demangle::Node::Kind::Type:
+ return isEnumNode(Node->getChild(0));
+ case Demangle::Node::Kind::Enum:
+ case Demangle::Node::Kind::BoundGenericEnum:
+ return true;
+ default:
+ return false;
+ }
+ llvm_unreachable("Unhandled node kind!");
+}
+
+bool swift::Demangle::isEnum(llvm::StringRef mangledName) {
+ Demangle::Demangler Dem;
+ return isEnumNode(Dem.demangleType(mangledName));
+}
+
+static bool isProtocolNode(Demangle::NodePointer Node) {
+ switch (Node->getKind()) {
+ case Demangle::Node::Kind::Type:
+ return isProtocolNode(Node->getChild(0));
+ case Demangle::Node::Kind::Protocol:
+ return true;
+ default:
+ return false;
+ }
+ llvm_unreachable("Unhandled node kind!");
+}
+
+bool swift::Demangle::isProtocol(llvm::StringRef mangledName) {
+ Demangle::Demangler Dem;
+ return isProtocolNode(Dem.demangleType(dropSwiftManglingPrefix(mangledName)));
+}
+
+static bool isStructNode(Demangle::NodePointer Node) {
+ switch (Node->getKind()) {
+ case Demangle::Node::Kind::Type:
+ return isStructNode(Node->getChild(0));
+ case Demangle::Node::Kind::Structure:
+ case Demangle::Node::Kind::BoundGenericStructure:
+ return true;
+ default:
+ return false;
+ }
+ llvm_unreachable("Unhandled node kind!");
+}
+
+bool swift::Demangle::isStruct(llvm::StringRef mangledName) {
+ Demangle::Demangler Dem;
+ return isStructNode(Dem.demangleType(mangledName));
+}
+
namespace swift {
namespace Demangle {
@@ -1149,11 +1240,35 @@
NodePointer Demangler::demangleBoundGenericArgs(NodePointer Nominal,
const Vector<NodePointer> &TypeLists,
size_t TypeListIdx) {
- if (!Nominal || Nominal->getNumChildren() < 2)
+ // TODO: This would be a lot easier if we represented bound generic args
+ // flatly in the demangling tree, since that's how they're mangled and also
+ // how the runtime generally wants to consume them.
+
+ if (!Nominal)
return nullptr;
if (TypeListIdx >= TypeLists.size())
return nullptr;
+
+ // Associate a symbolic reference with all remaining generic arguments.
+ if (Nominal->getKind() == Node::Kind::SymbolicReference
+ || Nominal->getKind() == Node::Kind::UnresolvedSymbolicReference) {
+ auto remainingTypeList = createNode(Node::Kind::TypeList);
+ for (unsigned i = TypeLists.size() - 1;
+ i >= TypeListIdx && i < TypeLists.size();
+ --i) {
+ auto list = TypeLists[i];
+ for (auto child : *list) {
+ remainingTypeList->addChild(child, *this);
+ }
+ }
+ return createWithChildren(Node::Kind::BoundGenericOtherNominalType,
+ createType(Nominal), remainingTypeList);
+ }
+
+ if (Nominal->getNumChildren() < 2)
+ return nullptr;
+
NodePointer args = TypeLists[TypeListIdx++];
// Generic arguments for the outermost type come first.
@@ -1198,6 +1313,9 @@
case Node::Kind::Enum:
kind = Node::Kind::BoundGenericEnum;
break;
+ case Node::Kind::OtherNominalType:
+ kind = Node::Kind::BoundGenericOtherNominalType;
+ break;
default:
return nullptr;
}
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index 56a7747..b684122 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -470,6 +470,7 @@
Separator = '_';
break;
+ case Node::Kind::BoundGenericOtherNominalType:
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericEnum:
case Node::Kind::BoundGenericClass: {
@@ -1983,11 +1984,13 @@
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericEnum:
case Node::Kind::BoundGenericClass:
+ case Node::Kind::BoundGenericOtherNominalType:
return true;
case Node::Kind::Structure:
case Node::Kind::Enum:
case Node::Kind::Class:
+ case Node::Kind::OtherNominalType:
return isSpecialized(node->getChild(0));
case Node::Kind::Extension:
@@ -2002,7 +2005,8 @@
switch (node->getKind()) {
case Node::Kind::Structure:
case Node::Kind::Enum:
- case Node::Kind::Class: {
+ case Node::Kind::Class:
+ case Node::Kind::OtherNominalType: {
NodePointer result = Factory.createNode(node->getKind());
NodePointer parentOrModule = node->getChild(0);
if (isSpecialized(parentOrModule))
@@ -2015,7 +2019,8 @@
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericEnum:
- case Node::Kind::BoundGenericClass: {
+ case Node::Kind::BoundGenericClass:
+ case Node::Kind::BoundGenericOtherNominalType: {
NodePointer unboundType = node->getChild(0);
assert(unboundType->getKind() == Node::Kind::Type);
NodePointer nominalType = unboundType->getChild(0);
diff --git a/lib/Demangling/TypeDecoder.cpp b/lib/Demangling/TypeDecoder.cpp
index 30714ab..a30f037 100644
--- a/lib/Demangling/TypeDecoder.cpp
+++ b/lib/Demangling/TypeDecoder.cpp
@@ -24,6 +24,7 @@
case Demangle::Node::Kind::BoundGenericClass:
case Demangle::Node::Kind::BoundGenericEnum:
case Demangle::Node::Kind::BoundGenericStructure:
+ case Demangle::Node::Kind::BoundGenericOtherNominalType:
// Bound generic types have a 'Type' node under them, whose child is
// the non-generic reference. If we don't see that structure, do nothing.
if (node->getNumChildren() < 2 ||
@@ -37,7 +38,8 @@
case Demangle::Node::Kind::Class:
case Demangle::Node::Kind::Enum:
- case Demangle::Node::Kind::Structure: {
+ case Demangle::Node::Kind::Structure:
+ case Demangle::Node::Kind::OtherNominalType: {
if (node->getNumChildren() < 2)
return node;
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 7360d18..f43a17a 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -42,6 +42,10 @@
#include "CompilationRecord.h"
+// Batch-mode has a sub-mode for testing that randomizes batch partitions,
+// by user-provided seed. That is the only thing randomized here.
+#include <random>
+
using namespace swift;
using namespace swift::sys;
using namespace swift::driver;
@@ -97,6 +101,7 @@
unsigned NumberOfParallelCommands,
bool EnableIncrementalBuild,
bool EnableBatchMode,
+ unsigned BatchSeed,
bool SkipTaskExecution,
bool SaveTemps,
bool ShowDriverTimeCompilation,
@@ -112,6 +117,7 @@
SkipTaskExecution(SkipTaskExecution),
EnableIncrementalBuild(EnableIncrementalBuild),
EnableBatchMode(EnableBatchMode),
+ BatchSeed(BatchSeed),
SaveTemps(SaveTemps),
ShowDriverTimeCompilation(ShowDriverTimeCompilation),
Stats(std::move(StatsReporter)) {
@@ -120,7 +126,8 @@
static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags);
using CommandSet = llvm::SmallPtrSet<const Job *, 16>;
-
+using CommandSetVector = llvm::SetVector<const Job*>;
+using BatchPartition = std::vector<std::vector<const Job*>>;
using InputInfoMap = llvm::SmallMapVector<const llvm::opt::Arg *,
CompileJobAction::InputInfo, 16>;
@@ -140,7 +147,7 @@
/// A temporary buffer to hold commands that were scheduled but haven't been
/// added to the Task Queue yet, because we might try batching them together
/// first.
- CommandSet PendingExecution;
+ CommandSetVector PendingExecution;
/// Set of synthetic BatchJobs that serve to cluster subsets of jobs waiting
/// in PendingExecution. Also used to identify (then unpack) BatchJobs back
@@ -680,7 +687,8 @@
/// Insert all jobs in \p Cmds (of descriptive name \p Kind) to the \c
/// TaskQueue, and clear \p Cmds.
- void transferJobsToTaskQueue(CommandSet &Cmds, StringRef Kind) {
+ template <typename Container>
+ void transferJobsToTaskQueue(Container &Cmds, StringRef Kind) {
for (const Job *Cmd : Cmds) {
if (Comp.ShowJobLifecycle)
llvm::outs() << "Adding " << Kind
@@ -694,8 +702,8 @@
/// Partition the jobs in \c PendingExecution into those that are \p
/// Batchable and those that are \p NonBatchable, clearing \p
/// PendingExecution.
- void getPendingBatchableJobs(CommandSet &Batchable,
- CommandSet &NonBatchable) {
+ void getPendingBatchableJobs(CommandSetVector &Batchable,
+ CommandSetVector &NonBatchable) {
for (const Job *Cmd : PendingExecution) {
if (Comp.getToolChain().jobIsBatchable(Comp, Cmd)) {
if (Comp.ShowJobLifecycle)
@@ -710,49 +718,83 @@
PendingExecution.clear();
}
- /// If \p CurrentBatch is nonempty, construct a new \c BatchJob from its
+ /// If \p Batch is nonempty, construct a new \c BatchJob from its
/// contents by calling \p ToolChain::constructBatchJob, then insert the
- /// new \c BatchJob into \p Batches and clear \p CurrentBatch.
+ /// new \c BatchJob into \p Batches.
void
- formBatchJobFromCurrentBatch(CommandSet &Batches,
- llvm::SetVector<const Job *> &CurrentBatch) {
- if (CurrentBatch.empty())
+ formBatchJobFromPartitionBatch(std::vector<const Job *> &Batches,
+ std::vector<const Job *> const &Batch) {
+ if (Batch.empty())
return;
if (Comp.ShowJobLifecycle)
llvm::outs() << "Forming batch job from "
- << CurrentBatch.size() << " constituents\n";
+ << Batch.size() << " constituents\n";
auto const &TC = Comp.getToolChain();
- auto J = TC.constructBatchJob(CurrentBatch.getArrayRef(), Comp);
+ auto J = TC.constructBatchJob(Batch, Comp);
if (J)
- Batches.insert(Comp.addJob(std::move(J)));
- CurrentBatch.clear();
+ Batches.push_back(Comp.addJob(std::move(J)));
}
- /// Return true iff \p Cmd can be expanded by \p CurrentBatch, meaning
- /// that \p CurrentBatch is smaller than \p TargetBatchSize and \p Cmd
- /// is batch-combinable with the equivalence class of \p CurrentBatch
- /// (as represented by element 0 of \p CurrentBatch).
- bool canExpandBatch(const Job *Cmd,
- llvm::SetVector<const Job *> &CurrentBatch,
- size_t TargetBatchSize) {
- auto const &TC = Comp.getToolChain();
- return (CurrentBatch.empty() ||
- (TC.jobsAreBatchCombinable(Comp, Cmd, CurrentBatch[0]) &&
- CurrentBatch.size() < TargetBatchSize));
+ /// Inspect current batch \p i of the \p Partition currently being built
+ /// and, if that batch is "full" (in the sense of holding an evenly-divided
+ /// portion of NumJobs) then advance \p i to the next batch index in the
+ /// partition.
+ void maybeAdvanceToNextPartition(size_t &i,
+ BatchPartition const &Partition,
+ size_t NumJobs) {
+ assert(i < Partition.size());
+ size_t Remainder = NumJobs % Partition.size();
+ size_t TargetSize = NumJobs / Partition.size();
+ // Spread remainder evenly across partitions by adding 1 to the target
+ // size of the first Remainder of them.
+ if (i < Remainder)
+ TargetSize++;
+ if (Partition[i].size() >= TargetSize)
+ ++i;
+ assert(i < Partition.size());
}
- /// If \p CurrentBatch can't be expanded with \p Cmd, form a new \c BatchJob
- /// from \p CurrentBatch, add it to \p Batches, and reset\p CurrentBatch;
- /// then in either case, insert \p Cmd into \p CurrentBatch.
- void expandBatch(const Job *Cmd,
- CommandSet &Batches,
- llvm::SetVector<const Job *> &CurrentBatch,
- size_t TargetBatchSize) {
- if (!canExpandBatch(Cmd, CurrentBatch, TargetBatchSize)) {
- formBatchJobFromCurrentBatch(Batches, CurrentBatch);
+ /// Shuffle \p Batchable if -driver-batch-seed is nonzero.
+ void maybeShuffleBatchable(std::vector<const Job *> &Batchable) {
+ if (Comp.BatchSeed != 0) {
+ std::minstd_rand gen(Comp.BatchSeed);
+ std::shuffle(Batchable.begin(), Batchable.end(), gen);
}
- llvm::outs() << "Adding to batch: " << LogJob(Cmd) << "\n";
- CurrentBatch.insert(Cmd);
+ }
+
+ /// Create \c NumberOfParallelCommands batches and assign each job to a
+ /// batch either filling each partition in order or, if seeded with a
+ /// nonzero value, pseudo-randomly (but determinstically and nearly-evenly).
+ void partitionIntoBatches(std::vector<const Job *> Batchable,
+ BatchPartition &Partition) {
+ if (Comp.ShowJobLifecycle) {
+ llvm::outs() << "Found " << Batchable.size() << " batchable jobs\n";
+ llvm::outs() << "Forming into " << Partition.size() << " batches\n";
+ }
+
+ assert(Partition.size() > 0);
+ maybeShuffleBatchable(Batchable);
+
+ size_t i = 0;
+ auto const &TC = Comp.getToolChain();
+ for (const Job *Cmd : Batchable) {
+ maybeAdvanceToNextPartition(i, Partition, Batchable.size());
+ std::vector<const Job*> &P = Partition[i];
+ if (P.empty() || TC.jobsAreBatchCombinable(Comp, P[0], Cmd)) {
+ if (Comp.ShowJobLifecycle)
+ llvm::outs() << "Adding " << LogJob(Cmd)
+ << " to batch " << i << '\n';
+ P.push_back(Cmd);
+ } else {
+ // Strange but theoretically possible that we have a batchable job
+ // that's not combinable with others; tack a new batch on for it.
+ if (Comp.ShowJobLifecycle)
+ llvm::outs() << "Adding " << LogJob(Cmd)
+ << " to new batch " << Partition.size() << '\n';
+ Partition.push_back(std::vector<const Job*>());
+ Partition.back().push_back(Cmd);
+ }
+ }
}
/// Select jobs that are batch-combinable from \c PendingExecution, combine
@@ -768,25 +810,18 @@
return;
}
- // Partition the pending jobs.
- CommandSet Batchable, NonBatchable, Batches;
+ // Split the batchable from non-batchable pending jobs.
+ CommandSetVector Batchable, NonBatchable;
getPendingBatchableJobs(Batchable, NonBatchable);
- size_t TargetBatchSize = Batchable.size() / Comp.NumberOfParallelCommands;
- if (Comp.ShowJobLifecycle) {
- llvm::outs() << "Found " << Batchable.size() << " batchable jobs\n";
- llvm::outs() << "Aiming for batch size " << TargetBatchSize << '\n';
- }
+ // Partition the batchable jobs into sets.
+ BatchPartition Partition(Comp.NumberOfParallelCommands);
+ partitionIntoBatches(Batchable.takeVector(), Partition);
- // Batch the batchable jobs.
- llvm::SetVector<const Job *> CurrentBatch;
- for (const Job *Cmd : Batchable) {
- expandBatch(Cmd, Batches, CurrentBatch, TargetBatchSize);
- }
-
- // Form a residual incomplete batch if any jobs remain.
- if (!CurrentBatch.empty()) {
- formBatchJobFromCurrentBatch(Batches, CurrentBatch);
+ // Construct a BatchJob from each batch in the partition.
+ std::vector<const Job *> Batches;
+ for (auto const &Batch : Partition) {
+ formBatchJobFromPartitionBatch(Batches, Batch);
}
// Save batches so we can locate and decompose them on task-exit.
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index e3f7545..e23d936 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -522,6 +522,12 @@
ArgList->hasArg(options::OPT_driver_show_incremental);
bool ShowJobLifecycle =
ArgList->hasArg(options::OPT_driver_show_job_lifecycle);
+ if (const Arg *A = ArgList->getLastArg(options::OPT_driver_batch_seed)) {
+ if (StringRef(A->getValue()).getAsInteger(10, DriverBatchSeed)) {
+ Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
+ A->getAsString(*ArgList), A->getValue());
+ }
+ }
bool Incremental = ArgList->hasArg(options::OPT_incremental);
if (ArgList->hasArg(options::OPT_whole_module_optimization)) {
@@ -550,8 +556,14 @@
bool ShowDriverTimeCompilation =
ArgList->hasArg(options::OPT_driver_time_compilation);
+ SmallString<128> workingDirectory;
+ if (auto *A = ArgList->getLastArg(options::OPT_working_directory)) {
+ workingDirectory = A->getValue();
+ llvm::sys::fs::make_absolute(workingDirectory);
+ }
+
std::unique_ptr<DerivedArgList> TranslatedArgList(
- translateInputArgs(*ArgList));
+ translateInputAndPathArgs(*ArgList, workingDirectory));
validateArgs(Diags, *TranslatedArgList);
@@ -606,7 +618,8 @@
// REPL mode expects no input files, so suppress the error.
SuppressNoInputFilesError = true;
- std::unique_ptr<OutputFileMap> OFM = buildOutputFileMap(*TranslatedArgList);
+ std::unique_ptr<OutputFileMap> OFM =
+ buildOutputFileMap(*TranslatedArgList, workingDirectory);
if (Diags.hadAnyError())
return nullptr;
@@ -684,6 +697,7 @@
NumberOfParallelCommands,
Incremental,
BatchMode,
+ DriverBatchSeed,
DriverSkipExecution,
SaveTemps,
ShowDriverTimeCompilation,
@@ -701,7 +715,7 @@
return nullptr;
}
- buildJobs(TopLevelActions, OI, OFM.get(), TC, *C);
+ buildJobs(TopLevelActions, OI, OFM.get(), workingDirectory, TC, *C);
if (DriverPrintDerivedOutputFileMap) {
C->getDerivedOutputFileMap().dump(llvm::outs(), true);
@@ -884,20 +898,48 @@
return ArgList;
}
-DerivedArgList *Driver::translateInputArgs(const InputArgList &ArgList) const {
+DerivedArgList *
+Driver::translateInputAndPathArgs(const InputArgList &ArgList,
+ StringRef workingDirectory) const {
DerivedArgList *DAL = new DerivedArgList(ArgList);
+ auto addPath = [workingDirectory, DAL](Arg *A) {
+ assert(A->getNumValues() == 1 && "multiple values not handled");
+ StringRef path = A->getValue();
+ if (workingDirectory.empty() || path == "-" ||
+ llvm::sys::path::is_absolute(path)) {
+ DAL->append(A);
+ return;
+ }
+
+ SmallString<64> fullPath{workingDirectory};
+ llvm::sys::path::append(fullPath, path);
+ unsigned index = DAL->getBaseArgs().MakeIndex(fullPath);
+ Arg *newArg = new Arg(A->getOption(), A->getSpelling(), index,
+ DAL->getBaseArgs().getArgString(index), A);
+ DAL->AddSynthesizedArg(newArg);
+ DAL->append(newArg);
+ };
+
for (Arg *A : ArgList) {
+ if (A->getOption().hasFlag(options::ArgumentIsPath) ||
+ A->getOption().matches(options::OPT_INPUT)) {
+ addPath(A);
+ continue;
+ }
+
// If we're not in immediate mode, pick up inputs via the -- option.
if (driverKind != DriverKind::Interactive && A->getOption().matches(options::OPT__DASH_DASH)) {
A->claim();
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
- DAL->append(makeInputArg(*DAL, *Opts, A->getValue(i)));
+ addPath(makeInputArg(*DAL, *Opts, A->getValue(i)));
}
continue;
}
+
DAL->append(A);
}
+
return DAL;
}
@@ -1655,13 +1697,14 @@
}
std::unique_ptr<OutputFileMap>
-Driver::buildOutputFileMap(const llvm::opt::DerivedArgList &Args) const {
+Driver::buildOutputFileMap(const llvm::opt::DerivedArgList &Args,
+ StringRef workingDirectory) const {
const Arg *A = Args.getLastArg(options::OPT_output_file_map);
if (!A)
return nullptr;
// TODO: perform some preflight checks to ensure the file exists.
- auto OFM = OutputFileMap::loadFromPath(A->getValue());
+ auto OFM = OutputFileMap::loadFromPath(A->getValue(), workingDirectory);
if (!OFM) {
// TODO: emit diagnostic with error string
Diags.diagnose(SourceLoc(), diag::error_unable_to_load_output_file_map);
@@ -1671,7 +1714,8 @@
void Driver::buildJobs(ArrayRef<const Action *> TopLevelActions,
const OutputInfo &OI, const OutputFileMap *OFM,
- const ToolChain &TC, Compilation &C) const {
+ StringRef workingDirectory, const ToolChain &TC,
+ Compilation &C) const {
llvm::PrettyStackTraceString CrashInfo("Building compilation jobs");
const DerivedArgList &Args = C.getArgs();
@@ -1700,15 +1744,35 @@
for (const Action *A : TopLevelActions) {
if (auto *JA = dyn_cast<JobAction>(A)) {
- (void)buildJobsForAction(C, JA, OI, OFM, TC, /*TopLevel*/true, JobCache);
+ (void)buildJobsForAction(C, JA, OI, OFM, workingDirectory, TC,
+ /*TopLevel=*/true, JobCache);
}
}
}
+/// Form a filename based on \p base in \p result, optionally setting its
+/// extension to \p newExt and in \p workingDirectory.
+static void formFilenameFromBaseAndExt(StringRef base, StringRef newExt,
+ StringRef workingDirectory,
+ SmallVectorImpl<char> &result) {
+ if (workingDirectory.empty() || llvm::sys::path::is_absolute(base)) {
+ result.assign(base.begin(), base.end());
+ } else {
+ assert(!base.empty() && base != "-" && "unexpected basename");
+ result.assign(workingDirectory.begin(), workingDirectory.end());
+ llvm::sys::path::append(result, base);
+ }
+
+ if (!newExt.empty()) {
+ llvm::sys::path::replace_extension(result, newExt);
+ }
+}
+
static Optional<StringRef> getOutputFilenameFromPathArgOrAsTopLevel(
const OutputInfo &OI, const llvm::opt::DerivedArgList &Args,
llvm::opt::OptSpecifier PathArg, types::ID ExpectedOutputType,
- bool TreatAsTopLevelOutput, StringRef ext, llvm::SmallString<128> &Buffer) {
+ bool TreatAsTopLevelOutput, StringRef workingDirectory, StringRef ext,
+ llvm::SmallString<128> &Buffer) {
if (const Arg *A = Args.getLastArg(PathArg))
return StringRef(A->getValue());
@@ -1727,8 +1791,7 @@
// A top-level output wasn't specified, so just output to
// <ModuleName>.<ext>.
- Buffer = OI.ModuleName;
- llvm::sys::path::replace_extension(Buffer, ext);
+ formFilenameFromBaseAndExt(OI.ModuleName, ext, workingDirectory, Buffer);
return Buffer.str();
}
@@ -1783,6 +1846,7 @@
const JobAction *JA,
const OutputInfo &OI,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
const llvm::Triple &Triple,
const llvm::opt::DerivedArgList &Args,
bool AtTopLevel,
@@ -1806,8 +1870,8 @@
if (isa<MergeModuleJobAction>(JA)) {
auto optFilename = getOutputFilenameFromPathArgOrAsTopLevel(
OI, Args, options::OPT_emit_module_path, types::TY_SwiftModuleFile,
- OI.ShouldTreatModuleAsTopLevelOutput, SERIALIZED_MODULE_EXTENSION,
- Buffer);
+ OI.ShouldTreatModuleAsTopLevelOutput, workingDirectory,
+ SERIALIZED_MODULE_EXTENSION, Buffer);
if (optFilename)
return *optFilename;
}
@@ -1852,15 +1916,19 @@
return assignOutputName(C, JA, Diags, Buffer, BaseName,
ShouldPreserveOnSignal);
- if (JA->getType() == types::TY_Image)
- return baseNameForImage(JA, OI, Triple, Buffer, BaseInput, BaseName);
+ if (JA->getType() == types::TY_Image) {
+ SmallString<16> Base =
+ baseNameForImage(JA, OI, Triple, Buffer, BaseInput, BaseName);
+ formFilenameFromBaseAndExt(Base, /*newExt=*/"", workingDirectory, Buffer);
+ return Buffer.str();
+ }
StringRef Suffix = types::getTypeTempSuffix(JA->getType());
assert(Suffix.data() &&
"All types used for output should have a suffix.");
- Buffer = llvm::sys::path::filename(BaseName);
- llvm::sys::path::replace_extension(Buffer, Suffix);
+ formFilenameFromBaseAndExt(llvm::sys::path::filename(BaseName), Suffix,
+ workingDirectory, Buffer);
return Buffer.str();
}
@@ -1879,6 +1947,7 @@
static void addAuxiliaryOutput(Compilation &C, CommandOutput &output,
types::ID outputType, const OutputInfo &OI,
const TypeToPathMap *outputMap,
+ StringRef workingDirectory,
StringRef outputPath = StringRef()) {
if (hasExistingAdditionalOutput(output, outputType, outputPath))
@@ -1903,8 +1972,10 @@
path = output.getPrimaryOutputFilenames()[0];
else if (!output.getBaseInput(0).empty())
path = llvm::sys::path::stem(output.getBaseInput(0));
- else
- path = OI.ModuleName;
+ else {
+ formFilenameFromBaseAndExt(OI.ModuleName, /*newExt=*/"", workingDirectory,
+ path);
+ }
bool isTempFile = C.isTemporaryFile(path);
llvm::sys::path::replace_extension(path,
@@ -1915,12 +1986,10 @@
}
}
-static void addDiagFileOutputForPersistentPCHAction(Compilation &C,
- const GeneratePCHJobAction *JA,
- CommandOutput &output,
- const OutputInfo &OI,
- const TypeToPathMap *outputMap,
- DiagnosticEngine &diags) {
+static void addDiagFileOutputForPersistentPCHAction(
+ Compilation &C, const GeneratePCHJobAction *JA, CommandOutput &output,
+ const OutputInfo &OI, const TypeToPathMap *outputMap,
+ StringRef workingDirectory, DiagnosticEngine &diags) {
assert(JA->isPersistentPCH());
// For a persistent PCH we don't use an output, the frontend determines
@@ -1963,7 +2032,7 @@
if (!outPathBuf.empty()) {
addAuxiliaryOutput(C, output, types::TY_SerializedDiagnostics, OI,
- outputMap, outPathBuf.str());
+ outputMap, workingDirectory, outPathBuf.str());
}
}
@@ -2015,10 +2084,9 @@
}
Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA,
- const OutputInfo &OI,
- const OutputFileMap *OFM,
- const ToolChain &TC, bool AtTopLevel,
- JobCacheMap &JobCache) const {
+ const OutputInfo &OI, const OutputFileMap *OFM,
+ StringRef workingDirectory, const ToolChain &TC,
+ bool AtTopLevel, JobCacheMap &JobCache) const {
PrettyStackTraceDriverAction CrashInfo("building jobs", JA);
@@ -2036,8 +2104,8 @@
SmallVector<const Job *, 4> InputJobs;
for (const Action *Input : *JA) {
if (auto *InputJobAction = dyn_cast<JobAction>(Input)) {
- InputJobs.push_back(buildJobsForAction(C, InputJobAction, OI, OFM,
- TC, false, JobCache));
+ InputJobs.push_back(buildJobsForAction(
+ C, InputJobAction, OI, OFM, workingDirectory, TC, false, JobCache));
} else {
InputActions.push_back(Input);
}
@@ -2080,14 +2148,17 @@
Output.get());
llvm::SmallString<128> Buf;
computeMainOutput(C, JA, OI, OFM, TC, AtTopLevel, InputActions, InputJobs,
- OutputMap, BaseInput, PrimaryInput, Buf, Output.get());
+ OutputMap, workingDirectory, BaseInput, PrimaryInput, Buf,
+ Output.get());
if (OI.ShouldGenerateModule && isa<CompileJobAction>(JA))
- chooseSwiftModuleOutputPath(C, OI, OFM, OutputMap, Output.get());
+ chooseSwiftModuleOutputPath(C, OI, OFM, OutputMap, workingDirectory,
+ Output.get());
if (OI.ShouldGenerateModule &&
(isa<CompileJobAction>(JA) || isa<MergeModuleJobAction>(JA)))
- chooseSwiftModuleDocOutputPath(C, OutputMap, Output.get());
+ chooseSwiftModuleDocOutputPath(C, OutputMap, workingDirectory,
+ Output.get());
if (C.getArgs().hasArg(options::OPT_update_code) && isa<CompileJobAction>(JA))
chooseRemappingOutputPath(C, OutputMap, Output.get());
@@ -2095,22 +2166,25 @@
if (isa<CompileJobAction>(JA) || isa<GeneratePCHJobAction>(JA)) {
// Choose the serialized diagnostics output path.
if (C.getArgs().hasArg(options::OPT_serialize_diagnostics))
- chooseSerializedDiagnosticsPath(C, JA, OI, OutputMap, Output.get());
+ chooseSerializedDiagnosticsPath(C, JA, OI, OutputMap, workingDirectory,
+ Output.get());
}
if (isa<CompileJobAction>(JA))
- chooseDependenciesOutputPaths(C, OI, OutputMap, Buf, Output.get());
+ chooseDependenciesOutputPaths(C, OI, OutputMap, workingDirectory, Buf,
+ Output.get());
if (C.getArgs().hasArg(options::OPT_save_optimization_record,
options::OPT_save_optimization_record_path))
- chooseOptimizationRecordPath(C, OI, Buf, Output.get());
+ chooseOptimizationRecordPath(C, OI, workingDirectory, Buf, Output.get());
if ((isa<MergeModuleJobAction>(JA) ||
(isa<CompileJobAction>(JA) &&
OI.CompilerMode == OutputInfo::Mode::SingleCompile)) &&
C.getArgs().hasArg(options::OPT_emit_objc_header,
options::OPT_emit_objc_header_path))
- chooseObjectiveCHeaderOutputPath(C, OI, OutputMap, Output.get());
+ chooseObjectiveCHeaderOutputPath(C, OI, OutputMap, workingDirectory,
+ Output.get());
// 4. Construct a Job which produces the right CommandOutput.
std::unique_ptr<Job> ownedJob = TC.constructJob(*JA, C, std::move(InputJobs),
@@ -2196,15 +2270,13 @@
return J;
}
-void Driver::computeMainOutput(Compilation &C, const JobAction *JA,
- const OutputInfo &OI, const OutputFileMap *OFM,
- const ToolChain &TC, bool AtTopLevel,
- SmallVectorImpl<const Action *> &InputActions,
- SmallVectorImpl<const Job *> &InputJobs,
- const TypeToPathMap *OutputMap,
- StringRef BaseInput, StringRef PrimaryInput,
- llvm::SmallString<128> &Buf,
- CommandOutput *Output) const {
+void Driver::computeMainOutput(
+ Compilation &C, const JobAction *JA, const OutputInfo &OI,
+ const OutputFileMap *OFM, const ToolChain &TC, bool AtTopLevel,
+ SmallVectorImpl<const Action *> &InputActions,
+ SmallVectorImpl<const Job *> &InputJobs, const TypeToPathMap *OutputMap,
+ StringRef workingDirectory, StringRef BaseInput, StringRef PrimaryInput,
+ llvm::SmallString<128> &Buf, CommandOutput *Output) const {
StringRef OutputFile;
if (OI.isMultiThreading() && isa<CompileJobAction>(JA) &&
types::isAfterLLVM(JA->getType())) {
@@ -2215,9 +2287,9 @@
if (OFM)
OMForInput = OFM->getOutputMapForInput(Base);
- OutputFile = getOutputFilename(C, JA, OI, OMForInput, TC.getTriple(),
- C.getArgs(), AtTopLevel, Base, Primary,
- Diags, Buf);
+ OutputFile = getOutputFilename(C, JA, OI, OMForInput, workingDirectory,
+ TC.getTriple(), C.getArgs(), AtTopLevel,
+ Base, Primary, Diags, Buf);
Output->addPrimaryOutput(CommandInputPair{Base, Primary},
OutputFile);
};
@@ -2237,9 +2309,9 @@
}
} else {
// The common case: there is a single output file.
- OutputFile =
- getOutputFilename(C, JA, OI, OutputMap, TC.getTriple(), C.getArgs(),
- AtTopLevel, BaseInput, PrimaryInput, Diags, Buf);
+ OutputFile = getOutputFilename(C, JA, OI, OutputMap, workingDirectory,
+ TC.getTriple(), C.getArgs(), AtTopLevel,
+ BaseInput, PrimaryInput, Diags, Buf);
Output->addPrimaryOutput(
CommandInputPair{BaseInput, PrimaryInput},
OutputFile);
@@ -2249,6 +2321,7 @@
void Driver::chooseSwiftModuleOutputPath(Compilation &C, const OutputInfo &OI,
const OutputFileMap *OFM,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
CommandOutput *Output) const {
if (hasExistingAdditionalOutput(*Output, types::TY_SwiftModuleFile))
@@ -2310,6 +2383,7 @@
void Driver::chooseSwiftModuleDocOutputPath(Compilation &C,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
CommandOutput *Output) const {
if (hasExistingAdditionalOutput(*Output, types::TY_SwiftModuleDocFile))
@@ -2367,15 +2441,16 @@
const JobAction *JA,
const OutputInfo &OI,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
CommandOutput *Output) const {
if (C.getArgs().hasArg(options::OPT_serialize_diagnostics)) {
auto pchJA = dyn_cast<GeneratePCHJobAction>(JA);
if (pchJA && pchJA->isPersistentPCH()) {
addDiagFileOutputForPersistentPCHAction(C, pchJA, *Output, OI, OutputMap,
- Diags);
+ workingDirectory, Diags);
} else {
addAuxiliaryOutput(C, *Output, types::TY_SerializedDiagnostics, OI,
- OutputMap);
+ OutputMap, workingDirectory);
}
// Remove any existing diagnostics files so that clients can detect their
@@ -2389,19 +2464,23 @@
void Driver::chooseDependenciesOutputPaths(Compilation &C, const OutputInfo &OI,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
llvm::SmallString<128> &Buf,
CommandOutput *Output) const {
if (C.getArgs().hasArg(options::OPT_emit_dependencies)) {
- addAuxiliaryOutput(C, *Output, types::TY_Dependencies, OI, OutputMap);
+ addAuxiliaryOutput(C, *Output, types::TY_Dependencies, OI, OutputMap,
+ workingDirectory);
}
if (C.getIncrementalBuildEnabled()) {
- addAuxiliaryOutput(C, *Output, types::TY_SwiftDeps, OI, OutputMap);
+ addAuxiliaryOutput(C, *Output, types::TY_SwiftDeps, OI, OutputMap,
+ workingDirectory);
}
- chooseLoadedModuleTracePath(C, OI, Buf, Output);
- chooseTBDPath(C, OI, Buf, Output);
+ chooseLoadedModuleTracePath(C, OI, workingDirectory, Buf, Output);
+ chooseTBDPath(C, OI, workingDirectory, Buf, Output);
}
void Driver::chooseLoadedModuleTracePath(Compilation &C, const OutputInfo &OI,
+ StringRef workingDirectory,
llvm::SmallString<128> &Buf,
CommandOutput *Output) const {
// The loaded-module-trace is the same for all compile jobs: all `import`
@@ -2426,7 +2505,7 @@
filename = *getOutputFilenameFromPathArgOrAsTopLevel(
OI, C.getArgs(), options::OPT_emit_loaded_module_trace_path,
types::TY_ModuleTrace,
- /*TreatAsTopLevelOutput=*/true, "trace.json", Buf);
+ /*TreatAsTopLevelOutput=*/true, workingDirectory, "trace.json", Buf);
}
Output->setAdditionalOutputForType(types::TY_ModuleTrace, filename);
@@ -2434,6 +2513,7 @@
}
void Driver::chooseTBDPath(Compilation &C, const OutputInfo &OI,
+ StringRef workingDirectory,
llvm::SmallString<128> &Buf,
CommandOutput *Output) const {
if (C.getArgs().hasArg(options::OPT_emit_tbd, options::OPT_emit_tbd_path)) {
@@ -2444,7 +2524,7 @@
} else {
auto filename = *getOutputFilenameFromPathArgOrAsTopLevel(
OI, C.getArgs(), options::OPT_emit_tbd_path, types::TY_TBD,
- /*TreatAsTopLevelOutput=*/true, "tbd", Buf);
+ /*TreatAsTopLevelOutput=*/true, workingDirectory, "tbd", Buf);
Output->setAdditionalOutputForType(types::TY_TBD, filename);
}
@@ -2452,12 +2532,14 @@
}
void Driver::chooseOptimizationRecordPath(Compilation &C, const OutputInfo &OI,
+ StringRef workingDirectory,
llvm::SmallString<128> &Buf,
CommandOutput *Output) const {
if (OI.CompilerMode == OutputInfo::Mode::SingleCompile) {
auto filename = *getOutputFilenameFromPathArgOrAsTopLevel(
OI, C.getArgs(), options::OPT_save_optimization_record_path,
- types::TY_OptRecord, /*TreatAsTopLevelOutput=*/true, "opt.yaml", Buf);
+ types::TY_OptRecord, /*TreatAsTopLevelOutput=*/true, workingDirectory,
+ "opt.yaml", Buf);
Output->setAdditionalOutputForType(types::TY_OptRecord, filename);
} else
@@ -2468,6 +2550,7 @@
void Driver::chooseObjectiveCHeaderOutputPath(Compilation &C,
const OutputInfo &OI,
const TypeToPathMap *OutputMap,
+ StringRef workingDirectory,
CommandOutput *Output) const {
if (hasExistingAdditionalOutput(*Output, types::TY_ObjCHeader))
@@ -2491,7 +2574,7 @@
// FIXME: That's not correct if the user /just/ passed -emit-header
// and not -emit-module.
addAuxiliaryOutput(C, *Output, types::TY_ObjCHeader, OI,
- /*output file map*/ nullptr);
+ /*output file map*/ nullptr, workingDirectory);
}
}
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index bd191de..c53f052 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -244,36 +244,44 @@
// from a JobAction that itself has InputActions sources, then we collect
// those up. Otherwise it's more correct to talk about our inputs as the
// outputs of our input-jobs.
- SmallVector<std::string, 4> Inputs;
+ SmallVector<StringRef, 4> Inputs;
+ SmallVector<StringRef, 4> Outputs = getOutput().getPrimaryOutputFilenames();
for (const Action *A : getSource().getInputs())
if (const auto *IA = dyn_cast<InputAction>(A))
Inputs.push_back(IA->getInputArg().getValue());
for (const Job *J : getInputs())
- for (const std::string &f : J->getOutput().getPrimaryOutputFilenames())
+ for (StringRef f : J->getOutput().getPrimaryOutputFilenames())
Inputs.push_back(f);
size_t limit = 3;
- size_t actual = Inputs.size();
- if (actual > limit) {
+ size_t actual_in = Inputs.size();
+ size_t actual_out = Outputs.size();
+ if (actual_in > limit) {
Inputs.erase(Inputs.begin() + limit, Inputs.end());
}
+ if (actual_out > limit) {
+ Outputs.erase(Outputs.begin() + limit, Outputs.end());
+ }
os << "{" << getSource().getClassName() << ": ";
- interleave(getOutput().getPrimaryOutputFilenames(),
+ interleave(Outputs,
[&](const std::string &Arg) {
os << llvm::sys::path::filename(Arg);
},
[&] { os << ' '; });
+ if (actual_out > limit) {
+ os << " ... " << (actual_out-limit) << " more";
+ }
os << " <= ";
interleave(Inputs,
[&](const std::string &Arg) {
os << llvm::sys::path::filename(Arg);
},
[&] { os << ' '; });
- if (actual > limit) {
- os << " ... " << (actual-limit) << " more";
+ if (actual_in > limit) {
+ os << " ... " << (actual_in-limit) << " more";
}
os << "}";
}
diff --git a/lib/Driver/OutputFileMap.cpp b/lib/Driver/OutputFileMap.cpp
index 40f743b..ce134ec 100644
--- a/lib/Driver/OutputFileMap.cpp
+++ b/lib/Driver/OutputFileMap.cpp
@@ -13,32 +13,36 @@
#include "swift/Driver/OutputFileMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <system_error>
using namespace swift;
using namespace swift::driver;
-std::unique_ptr<OutputFileMap> OutputFileMap::loadFromPath(StringRef Path) {
+std::unique_ptr<OutputFileMap>
+OutputFileMap::loadFromPath(StringRef Path, StringRef workingDirectory) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
llvm::MemoryBuffer::getFile(Path);
if (!FileBufOrErr)
return nullptr;
- return loadFromBuffer(std::move(FileBufOrErr.get()));
-}
-
-std::unique_ptr<OutputFileMap> OutputFileMap::loadFromBuffer(StringRef Data) {
- std::unique_ptr<llvm::MemoryBuffer> Buffer{
- llvm::MemoryBuffer::getMemBuffer(Data)
- };
- return loadFromBuffer(std::move(Buffer));
+ return loadFromBuffer(std::move(FileBufOrErr.get()), workingDirectory);
}
std::unique_ptr<OutputFileMap>
-OutputFileMap::loadFromBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+OutputFileMap::loadFromBuffer(StringRef Data, StringRef workingDirectory) {
+ std::unique_ptr<llvm::MemoryBuffer> Buffer{
+ llvm::MemoryBuffer::getMemBuffer(Data)
+ };
+ return loadFromBuffer(std::move(Buffer), workingDirectory);
+}
+
+std::unique_ptr<OutputFileMap>
+OutputFileMap::loadFromBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ StringRef workingDirectory) {
std::unique_ptr<OutputFileMap> OFM(new OutputFileMap());
- if (OFM->parse(std::move(Buffer)))
+ if (OFM->parse(std::move(Buffer), workingDirectory))
return nullptr;
return OFM;
@@ -104,7 +108,8 @@
}
}
-bool OutputFileMap::parse(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
+bool OutputFileMap::parse(std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ StringRef workingDirectory) {
llvm::SourceMgr SM;
llvm::yaml::Stream YAMLStream(Buffer->getMemBufferRef(), SM);
auto I = YAMLStream.begin();
@@ -119,6 +124,26 @@
if (!Map)
return true;
+ auto resolvePath =
+ [workingDirectory](
+ llvm::yaml::ScalarNode *Path,
+ llvm::SmallVectorImpl<char> &PathStorage) -> StringRef {
+ StringRef PathStr = Path->getValue(PathStorage);
+ if (workingDirectory.empty() || PathStr.empty() || PathStr == "-" ||
+ llvm::sys::path::is_absolute(PathStr)) {
+ return PathStr;
+ }
+ // Copy the path to avoid making assumptions about how getValue deals with
+ // Storage.
+ SmallString<128> PathStrCopy(PathStr);
+ PathStorage.clear();
+ PathStorage.reserve(PathStrCopy.size() + workingDirectory.size() + 1);
+ PathStorage.insert(PathStorage.begin(), workingDirectory.begin(),
+ workingDirectory.end());
+ llvm::sys::path::append(PathStorage, PathStrCopy);
+ return StringRef(PathStorage.data(), PathStorage.size());
+ };
+
for (auto Pair : *Map) {
llvm::yaml::Node *Key = Pair.getKey();
llvm::yaml::Node *Value = Pair.getValue();
@@ -162,12 +187,13 @@
continue;
llvm::SmallString<128> PathStorage;
- OutputMap.insert(
- std::pair<types::ID, std::string>(Kind, Path->getValue(PathStorage)));
+ OutputMap.insert(std::pair<types::ID, std::string>(
+ Kind, resolvePath(Path, PathStorage)));
}
llvm::SmallString<128> InputStorage;
- InputToOutputsMap[InputPath->getValue(InputStorage)] = std::move(OutputMap);
+ InputToOutputsMap[resolvePath(InputPath, InputStorage)] =
+ std::move(OutputMap);
}
return false;
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index d46e61e..d251cc1 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -167,6 +167,8 @@
inputArgs.AddLastArg(arguments, options::OPT_enforce_exclusivity_EQ);
inputArgs.AddLastArg(arguments, options::OPT_stats_output_dir);
inputArgs.AddLastArg(arguments, options::OPT_trace_stats_events);
+ inputArgs.AddLastArg(arguments, options::OPT_profile_stats_events);
+ inputArgs.AddLastArg(arguments, options::OPT_profile_stats_entities);
inputArgs.AddLastArg(arguments,
options::OPT_solver_shrink_unsolved_threshold);
inputArgs.AddLastArg(arguments, options::OPT_O_Group);
@@ -179,6 +181,18 @@
// Pass through the values passed to -Xfrontend.
inputArgs.AddAllArgValues(arguments, options::OPT_Xfrontend);
+ if (auto *A = inputArgs.getLastArg(options::OPT_working_directory)) {
+ // Add -Xcc -working-directory before any other -Xcc options to ensure it is
+ // overridden by an explicit -Xcc -working-directory, although having a
+ // different working directory is probably incorrect.
+ SmallString<128> workingDirectory(A->getValue());
+ llvm::sys::fs::make_absolute(workingDirectory);
+ arguments.push_back("-Xcc");
+ arguments.push_back("-working-directory");
+ arguments.push_back("-Xcc");
+ arguments.push_back(inputArgs.MakeArgString(workingDirectory));
+ }
+
// Pass through any subsystem flags.
inputArgs.AddAllArgs(arguments, options::OPT_Xllvm);
inputArgs.AddAllArgs(arguments, options::OPT_Xcc);
diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
index af86810..2013a98 100644
--- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
+++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp
@@ -179,6 +179,12 @@
if (Args.getLastArg(OPT_trace_stats_events)) {
Opts.TraceStats = true;
}
+ if (Args.getLastArg(OPT_profile_stats_events)) {
+ Opts.ProfileEvents = true;
+ }
+ if (Args.getLastArg(OPT_profile_stats_entities)) {
+ Opts.ProfileEntities = true;
+ }
}
}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index a8886f3..dd32dc2 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -528,11 +528,6 @@
Diags.diagnose(SourceLoc(), diag::error_unsupported_option_argument,
A->getOption().getPrefixedName(), A->getValue());
}
- if (Opts.shouldOptimize() && Opts.EnforceExclusivityDynamic) {
- Diags.diagnose(SourceLoc(),
- diag::warning_argument_not_supported_with_optimization,
- A->getOption().getPrefixedName() + A->getValue());
- }
}
static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp
index 21bac6f..7d25224 100644
--- a/lib/Frontend/Frontend.cpp
+++ b/lib/Frontend/Frontend.cpp
@@ -37,6 +37,9 @@
using namespace swift;
+CompilerInstance::CompilerInstance() = default;
+CompilerInstance::~CompilerInstance() = default;
+
std::string CompilerInvocation::getPCHHash() const {
using llvm::hash_code;
using llvm::hash_value;
@@ -76,6 +79,10 @@
Invocation.getFrontendOptions().InputsAndOutputs.isWholeModule());
}
+void CompilerInstance::setSILModule(std::unique_ptr<SILModule> M) {
+ TheSILModule = std::move(M);
+}
+
void CompilerInstance::recordPrimaryInputBuffer(unsigned BufID) {
PrimaryBufferIDs.insert(BufID);
}
@@ -384,7 +391,7 @@
}
void CompilerInstance::performSema() {
- SharedTimer timer("performSema");
+ FrontendStatsTracer tracer(Context->Stats, "perform-sema");
Context->LoadedModules[MainModule->getName()] = getMainModule();
if (Invocation.getInputKind() == InputFileKind::IFK_SIL) {
@@ -432,7 +439,7 @@
}
bool CompilerInstance::loadStdlib() {
- SharedTimer timer("performSema-loadStdlib");
+ FrontendStatsTracer tracer(Context->Stats, "load-stdlib");
ModuleDecl *M = Context->getStdlibModule(true);
if (!M) {
@@ -451,7 +458,7 @@
}
ModuleDecl *CompilerInstance::importUnderlyingModule() {
- SharedTimer timer("performSema-importUnderlyingModule");
+ FrontendStatsTracer tracer(Context->Stats, "import-underlying-module");
ModuleDecl *objCModuleUnderlyingMixedFramework =
static_cast<ClangImporter *>(Context->getClangModuleLoader())
->loadModule(SourceLoc(),
@@ -464,7 +471,7 @@
}
ModuleDecl *CompilerInstance::importBridgingHeader() {
- SharedTimer timer("performSema-importBridgingHeader");
+ FrontendStatsTracer tracer(Context->Stats, "import-bridging-header");
const StringRef implicitHeaderPath =
Invocation.getFrontendOptions().ImplicitObjCHeaderPath;
auto clangImporter =
@@ -479,7 +486,7 @@
void CompilerInstance::getImplicitlyImportedModules(
SmallVectorImpl<ModuleDecl *> &importModules) {
- SharedTimer timer("performSema-getImplicitlyImportedModules");
+ FrontendStatsTracer tracer(Context->Stats, "get-implicitly-imported-modules");
for (auto &ImplicitImportModuleName :
Invocation.getFrontendOptions().ImplicitImportModuleNames) {
if (Lexer::isIdentifier(ImplicitImportModuleName)) {
@@ -535,7 +542,7 @@
void CompilerInstance::parseAndCheckTypes(
const ImplicitImports &implicitImports) {
- SharedTimer timer("performSema-parseAndCheckTypes");
+ FrontendStatsTracer tracer(Context->Stats, "parse-and-check-types");
// Delayed parsing callback for the primary file, or all files
// in non-WMO mode.
std::unique_ptr<DelayedParsingCallbacks> PrimaryDelayedCB{
@@ -599,7 +606,7 @@
PersistentParserState &PersistentState,
DelayedParsingCallbacks *PrimaryDelayedCB,
DelayedParsingCallbacks *SecondaryDelayedCB) {
- SharedTimer timer("performSema-parseLibraryFile");
+ FrontendStatsTracer tracer(Context->Stats, "parse-library-file");
auto *NextInput = createSourceFileForMainModule(
SourceFileKind::Library, implicitImports.kind, BufferID);
@@ -653,7 +660,8 @@
PersistentParserState &PersistentState,
DelayedParsingCallbacks *PrimaryDelayedCB,
DelayedParsingCallbacks *SecondaryDelayedCB) {
- SharedTimer timer("performSema-parsePartialModulesAndLibraryFiles");
+ FrontendStatsTracer tracer(Context->Stats,
+ "parse-partial-modules-and-library-files");
bool hadLoadError = false;
// Parse all the partial modules first.
for (auto &PM : PartialModules) {
@@ -677,8 +685,8 @@
PersistentParserState &PersistentState,
DelayedParsingCallbacks *DelayedParseCB,
OptionSet<TypeCheckingFlags> TypeCheckOptions) {
- SharedTimer timer(
- "performSema-checkTypesWhileParsingMain-parseAndTypeCheckMainFile");
+ FrontendStatsTracer tracer(Context->Stats,
+ "parse-and-typecheck-main-file");
bool mainIsPrimary =
(isWholeModuleCompilation() || isPrimaryInput(MainBufferID));
diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index 27c51d9..08022fc 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -1477,6 +1477,8 @@
StringRef OutputType = llvm::sys::path::extension(OutFile);
std::string TripleName = LangOpts.Target.normalize();
auto Trace = Invocation.getFrontendOptions().TraceStats;
+ auto ProfileEvents = Invocation.getFrontendOptions().ProfileEvents;
+ auto ProfileEntities = Invocation.getFrontendOptions().ProfileEntities;
SourceManager *SM = &Instance->getSourceMgr();
clang::SourceManager *CSM = nullptr;
if (auto *clangImporter = static_cast<ClangImporter *>(
@@ -1485,7 +1487,8 @@
}
return llvm::make_unique<UnifiedStatsReporter>(
"swift-frontend", FEOpts.ModuleName, InputName, TripleName, OutputType,
- OptType, StatsOutputDir, SM, CSM, Trace);
+ OptType, StatsOutputDir, SM, CSM, Trace,
+ ProfileEvents, ProfileEntities);
}
int swift::performFrontend(ArrayRef<const char *> Args,
diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp
index 9ff734d..e79980a 100644
--- a/lib/IDE/SyntaxModel.cpp
+++ b/lib/IDE/SyntaxModel.cpp
@@ -107,8 +107,20 @@
LiteralStartLoc = Loc;
continue;
+#define POUND_COND_DIRECTIVE_KEYWORD(Name) case tok::pound_##Name:
+#include "swift/Syntax/TokenKinds.def"
+ Kind = SyntaxNodeKind::BuildConfigKeyword;
+ break;
+
+#define POUND_DIRECTIVE_KEYWORD(Name) case tok::pound_##Name:
+#define POUND_COND_DIRECTIVE_KEYWORD(Name)
+#include "swift/Syntax/TokenKinds.def"
+ Kind = SyntaxNodeKind::PoundDirectiveKeyword;
+ break;
+
#define POUND_OBJECT_LITERAL(Name, Desc, Proto)
#define POUND_OLD_OBJECT_LITERAL(Name, NewName, OldArg, NewArg)
+#define POUND_DIRECTIVE_KEYWORD(Name)
#define POUND_KEYWORD(Name) case tok::pound_##Name:
#include "swift/Syntax/TokenKinds.def"
Kind = SyntaxNodeKind::Keyword;
@@ -816,17 +828,6 @@
} else if (auto *ConfigD = dyn_cast<IfConfigDecl>(D)) {
for (auto &Clause : ConfigD->getClauses()) {
- unsigned TokLen;
- if (&Clause == &*ConfigD->getClauses().begin())
- TokLen = 3; // '#if'
- else if (Clause.Cond == nullptr)
- TokLen = 5; // '#else'
- else
- TokLen = 7; // '#elseif'
- if (!passNonTokenNode({SyntaxNodeKind::BuildConfigKeyword,
- CharSourceRange(Clause.Loc, TokLen) }))
- return false;
-
if (Clause.Cond && !annotateIfConfigConditionIdentifiers(Clause.Cond))
return false;
@@ -841,11 +842,6 @@
VisitedNodesInsideIfConfig.insert(Element);
}
}
-
- if (!ConfigD->hadMissingEnd())
- if (!passNonTokenNode({ SyntaxNodeKind::BuildConfigKeyword,
- CharSourceRange(ConfigD->getEndLoc(), 6/*'#endif'*/) }))
- return false;
} else if (auto *EnumCaseD = dyn_cast<EnumCaseDecl>(D)) {
SyntaxStructureNode SN;
diff --git a/lib/IDE/TypeReconstruction.cpp b/lib/IDE/TypeReconstruction.cpp
index bc79800..a8e779d 100644
--- a/lib/IDE/TypeReconstruction.cpp
+++ b/lib/IDE/TypeReconstruction.cpp
@@ -2105,6 +2105,7 @@
case Demangle::Node::Kind::BoundGenericClass:
case Demangle::Node::Kind::BoundGenericStructure:
case Demangle::Node::Kind::BoundGenericEnum:
+ case Demangle::Node::Kind::BoundGenericOtherNominalType:
VisitNodeBoundGeneric(ast, node, result);
break;
@@ -2115,6 +2116,7 @@
case Demangle::Node::Kind::Structure:
case Demangle::Node::Kind::Class:
case Demangle::Node::Kind::Enum:
+ case Demangle::Node::Kind::OtherNominalType:
case Demangle::Node::Kind::Protocol:
VisitNodeNominal(ast, node, result);
break;
diff --git a/lib/IRGen/GenCast.cpp b/lib/IRGen/GenCast.cpp
index 52324d3..95df8d0 100644
--- a/lib/IRGen/GenCast.cpp
+++ b/lib/IRGen/GenCast.cpp
@@ -422,10 +422,7 @@
}
case CheckedCastMode::Unconditional: {
- llvm::Function *trapIntrinsic = llvm::Intrinsic::getDeclaration(&IGM.Module,
- llvm::Intrinsic::ID::trap);
- IGF.Builder.CreateCall(trapIntrinsic, {});
- IGF.Builder.CreateUnreachable();
+ IGF.emitTrap(/*EmitUnreachable=*/true);
break;
}
}
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index 8d73f7f..8a7507c 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -554,12 +554,11 @@
void IRGenModule::emitRuntimeRegistration() {
// Duck out early if we have nothing to register.
- if (SwiftProtocols.empty()
- && ProtocolConformances.empty()
- && RuntimeResolvableTypes.empty()
- && (!ObjCInterop || (ObjCProtocols.empty() &&
- ObjCClasses.empty() &&
- ObjCCategoryDecls.empty())))
+ if (SwiftProtocols.empty() && ProtocolConformances.empty() &&
+ RuntimeResolvableTypes.empty() &&
+ (!ObjCInterop || (ObjCProtocols.empty() && ObjCClasses.empty() &&
+ ObjCCategoryDecls.empty())) &&
+ FieldDescriptors.empty())
return;
// Find the entry point.
@@ -721,6 +720,14 @@
RegIGF.Builder.CreateCall(getRegisterTypeMetadataRecordsFn(), {begin, end});
}
+ if (!FieldDescriptors.empty()) {
+ auto *records = emitFieldDescriptors();
+ auto *begin =
+ llvm::ConstantExpr::getBitCast(records, FieldDescriptorPtrPtrTy);
+ auto *size = llvm::ConstantInt::get(SizeTy, FieldDescriptors.size());
+ RegIGF.Builder.CreateCall(getRegisterFieldDescriptorsFn(), {begin, size});
+ }
+
RegIGF.Builder.CreateRetVoid();
}
@@ -802,7 +809,7 @@
return getAddrOfLLVMVariableOrGOTEquivalent(
LinkEntity::forNominalTypeDescriptor(nominal),
Alignment(4),
- NominalTypeDescriptorTy,
+ TypeContextDescriptorTy,
shouldBeIndirect);
}
}
@@ -1144,9 +1151,30 @@
while (!LazyMetadata.empty() ||
!LazyTypeContextDescriptors.empty() ||
!LazyFunctionDefinitions.empty() ||
- !LazyFieldTypeAccessors.empty() ||
+ !LazyFieldTypes.empty() ||
!LazyWitnessTables.empty()) {
+ while (!LazyFieldTypes.empty()) {
+ auto info = LazyFieldTypes.pop_back_val();
+ auto &IGM = *info.IGM;
+
+ for (auto fieldType : info.fieldTypes) {
+ if (fieldType->hasArchetype())
+ continue;
+
+ // All of the required attributes are going to be preserved
+ // by field reflection metadata in the mangled name, so
+ // there is no need to worry about ownership semantics here.
+ if (auto refStorTy = dyn_cast<ReferenceStorageType>(fieldType))
+ fieldType = refStorTy.getReferentType();
+
+ // Make sure that all of the field type metadata is forced,
+ // otherwise there might be a problem when fields are accessed
+ // through reflection.
+ (void)irgen::getOrCreateTypeMetadataAccessFunction(IGM, fieldType);
+ }
+ }
+
// Emit any lazy type metadata we require.
while (!LazyMetadata.empty()) {
NominalTypeDecl *Nominal = LazyMetadata.pop_back_val();
@@ -1164,11 +1192,6 @@
emitLazyTypeContextDescriptor(*IGM.get(), Nominal);
}
}
- while (!LazyFieldTypeAccessors.empty()) {
- auto accessor = LazyFieldTypeAccessors.pop_back_val();
- emitFieldTypeAccessor(*accessor.IGM, accessor.type, accessor.fn,
- accessor.fieldTypes);
- }
while (!LazyWitnessTables.empty()) {
SILWitnessTable *wt = LazyWitnessTables.pop_back_val();
CurrentIGMPtr IGM = getGenModule(wt->getConformance()->getDeclContext());
@@ -2472,8 +2495,8 @@
// are represented by referencing the nominal type descriptor.
typeKind = TypeMetadataRecordKind::DirectNominalTypeDescriptor;
entity = LinkEntity::forNominalTypeDescriptor(nom);
- defaultTy = IGM.NominalTypeDescriptorTy;
- defaultPtrTy = IGM.NominalTypeDescriptorPtrTy;
+ defaultTy = IGM.TypeContextDescriptorTy;
+ defaultPtrTy = IGM.TypeContextDescriptorPtrTy;
}
return {typeKind, *entity, defaultTy, defaultPtrTy};
@@ -2848,6 +2871,52 @@
return var;
}
+llvm::Constant *IRGenModule::emitFieldDescriptors() {
+ std::string sectionName;
+ switch (TargetInfo.OutputObjectFormat) {
+ case llvm::Triple::MachO:
+ sectionName = "__TEXT, __swift5_fieldmd, regular, no_dead_strip";
+ break;
+ case llvm::Triple::ELF:
+ sectionName = "swift5_fieldmd";
+ break;
+ case llvm::Triple::COFF:
+ sectionName = ".swift5_fieldmd";
+ break;
+ default:
+ llvm_unreachable("Don't know how to emit field records table for "
+ "the selected object format.");
+ }
+
+ // Do nothing if the list is empty.
+ if (FieldDescriptors.empty())
+ return nullptr;
+
+ // Define the global variable for the field record list.
+ // We have to do this before defining the initializer since the entries will
+ // contain offsets relative to themselves.
+ auto arrayTy =
+ llvm::ArrayType::get(FieldDescriptorPtrTy, FieldDescriptors.size());
+
+ // FIXME: This needs to be a linker-local symbol in order for Darwin ld to
+ // resolve relocations relative to it.
+ auto var = new llvm::GlobalVariable(
+ Module, arrayTy,
+ /*isConstant*/ true, llvm::GlobalValue::PrivateLinkage,
+ /*initializer*/ nullptr, "\x01l_type_metadata_table");
+
+ SmallVector<llvm::Constant *, 8> elts;
+ for (auto *descriptor : FieldDescriptors)
+ elts.push_back(
+ llvm::ConstantExpr::getBitCast(descriptor, FieldDescriptorPtrTy));
+
+ var->setInitializer(llvm::ConstantArray::get(arrayTy, elts));
+ var->setSection(sectionName);
+ var->setAlignment(4);
+ addUsedGlobal(var);
+ return var;
+}
+
/// Fetch a global reference to a reference to the given Objective-C class.
/// The result is of type ObjCClassPtrTy->getPointerTo().
Address IRGenModule::getAddrOfObjCClassRef(ClassDecl *theClass) {
@@ -3236,7 +3305,7 @@
auto entity = LinkEntity::forNominalTypeDescriptor(D);
return getAddrOfLLVMVariable(entity, Alignment(4),
definition,
- NominalTypeDescriptorTy,
+ TypeContextDescriptorTy,
DebugTypeInfo());
}
diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp
index 59881a5..1f9ba17 100644
--- a/lib/IRGen/GenEnum.cpp
+++ b/lib/IRGen/GenEnum.cpp
@@ -158,21 +158,7 @@
TI->initializeWithTake(IGF, dest, src, T, isOutlined);
}
-llvm::Constant *EnumImplStrategy::emitCaseNames() const {
- // Build the list of case names, payload followed by no-payload.
- llvm::SmallString<64> fieldNames;
- for (auto &payloadCase : getElementsWithPayload()) {
- fieldNames.append(payloadCase.decl->getName().str());
- fieldNames.push_back('\0');
- }
- for (auto &noPayloadCase : getElementsWithNoPayload()) {
- fieldNames.append(noPayloadCase.decl->getName().str());
- fieldNames.push_back('\0');
- }
- // The final null terminator is provided by getAddrOfGlobalString.
- return IGM.getAddrOfGlobalString(fieldNames,
- /*willBeRelativelyAddressed*/ true);
-}
+bool EnumImplStrategy::isReflectable() const { return true; }
unsigned EnumImplStrategy::getPayloadSizeForMetadata() const {
llvm_unreachable("don't need payload size for this enum kind");
@@ -1109,11 +1095,11 @@
llvm_unreachable("no extra inhabitants");
}
- llvm::Constant *emitCaseNames() const override {
+ bool isReflectable() const override {
// C enums have arbitrary values and we don't preserve the mapping
- // between the case and raw value at runtime, so don't emit any
- // case names at all so that reflection can give up in this case.
- return nullptr;
+ // between the case and raw value at runtime, so don't mark it as
+ // reflectable.
+ return false;
}
};
diff --git a/lib/IRGen/GenEnum.h b/lib/IRGen/GenEnum.h
index 262f88e..24dbbd6 100644
--- a/lib/IRGen/GenEnum.h
+++ b/lib/IRGen/GenEnum.h
@@ -224,7 +224,7 @@
}
/// Emit field names for enum reflection.
- virtual llvm::Constant *emitCaseNames() const;
+ virtual bool isReflectable() const;
/// \brief Return the bits used for discriminators for payload cases.
///
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index 55511d3..8a1b98e 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -2709,69 +2709,43 @@
///
/// ABI TODO: This should be unnecessary when the fields that use it are
/// superseded.
- static llvm::Function *
- getFieldTypeAccessorFn(IRGenModule &IGM,
- NominalTypeDecl *type,
- ArrayRef<FieldTypeInfo> fieldTypes) {
- // The accessor function has the following signature:
- // const Metadata * const *(*GetFieldTypes)(const Metadata *T);
- auto metadataArrayPtrTy = IGM.TypeMetadataPtrTy->getPointerTo();
- auto fnTy = llvm::FunctionType::get(metadataArrayPtrTy,
- IGM.TypeMetadataPtrTy,
- /*vararg*/ false);
- auto fn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage,
- llvm::Twine("get_field_types_")
- + type->getName().str(),
- IGM.getModule());
- fn->setAttributes(IGM.constructInitialAttributes());
-
- // Emit the body of the field type accessor later. We need to access
- // the type metadata for the fields, which could lead to infinite recursion
- // in recursive types if we build the field type accessor during metadata
- // generation.
- IGM.addLazyFieldTypeAccessor(type, fieldTypes, fn);
-
- return fn;
+ static void addFieldTypes(IRGenModule &IGM, ArrayRef<CanType> fieldTypes) {
+ IGM.addFieldTypes(fieldTypes);
}
/// Build a field type accessor for stored properties.
///
/// ABI TODO: This should be unnecessary when the fields that use it are
/// superseded.
- static llvm::Function *
- getFieldTypeAccessorFn(IRGenModule &IGM,
- NominalTypeDecl *type,
- NominalTypeDecl::StoredPropertyRange storedProperties){
- SmallVector<FieldTypeInfo, 4> types;
+ static void
+ addFieldTypes(IRGenModule &IGM, NominalTypeDecl *type,
+ NominalTypeDecl::StoredPropertyRange storedProperties) {
+ SmallVector<CanType, 4> types;
for (VarDecl *prop : storedProperties) {
auto propertyType = type->mapTypeIntoContext(prop->getInterfaceType())
->getCanonicalType();
- types.push_back(FieldTypeInfo(propertyType,
- /*indirect*/ false,
- propertyType->is<WeakStorageType>()));
+ types.push_back(propertyType);
}
- return getFieldTypeAccessorFn(IGM, type, types);
+
+ addFieldTypes(IGM, types);
}
/// Build a case type accessor for enum payloads.
///
/// ABI TODO: This should be unnecessary when the fields that use it are
/// superseded.
- static llvm::Function *
- getFieldTypeAccessorFn(IRGenModule &IGM,
- NominalTypeDecl *type,
- ArrayRef<EnumImplStrategy::Element> enumElements) {
- SmallVector<FieldTypeInfo, 4> types;
+ static void addFieldTypes(IRGenModule &IGM,
+ ArrayRef<EnumImplStrategy::Element> enumElements) {
+ SmallVector<CanType, 4> types;
for (auto &elt : enumElements) {
auto caseType = elt.decl->getParentEnum()->mapTypeIntoContext(
elt.decl->getArgumentInterfaceType())
->getCanonicalType();
- bool isIndirect = elt.decl->isIndirect()
- || elt.decl->getParentEnum()->isIndirect();
- types.push_back(FieldTypeInfo(caseType, isIndirect, /*weak*/ false));
+ types.push_back(caseType);
}
- return getFieldTypeAccessorFn(IGM, type, types);
+
+ addFieldTypes(IGM, types);
}
@@ -2805,28 +2779,12 @@
}
void addLayoutInfo() {
- // Build the field name list.
- llvm::SmallString<64> fieldNames;
- unsigned numFields = getFieldNameString(getType()->getStoredProperties(),
- fieldNames);
-
- B.addInt32(numFields);
+ auto properties = getType()->getStoredProperties();
+ B.addInt32(std::distance(properties.begin(), properties.end()));
B.addInt32(FieldVectorOffset / IGM.getPointerSize());
- B.addRelativeAddress(IGM.getAddrOfGlobalString(fieldNames,
- /*willBeRelativelyAddressed*/ true));
-
- // Don't emit the field type accessor function if we're only lazily
- // emitting the context descriptor.
- if (Lazy) {
- B.addInt32(0);
- } else {
- // Build the field type accessor function.
- llvm::Function *fieldTypeVectorAccessor
- = getFieldTypeAccessorFn(IGM, getType(),
- getType()->getStoredProperties());
-
- B.addRelativeAddress(fieldTypeVectorAccessor);
- }
+ B.addInt32(1); // struct always reflectable
+
+ addFieldTypes(IGM, getType(), properties);
}
uint16_t getKindSpecificFlags() {
@@ -2881,21 +2839,9 @@
B.addInt32(numPayloads | (PayloadSizeOffsetInWords << 24));
// # empty cases
B.addInt32(strategy.getElementsWithNoPayload().size());
+ B.addInt32(strategy.isReflectable());
- B.addRelativeAddressOrNull(strategy.emitCaseNames());
-
- // Don't emit the field type accessor function if we're only lazily
- // emitting the context descriptor.
- if (Lazy) {
- B.addInt32(0);
- } else {
- // Build the case type accessor.
- llvm::Function *caseTypeVectorAccessor
- = getFieldTypeAccessorFn(IGM, getType(),
- strategy.getElementsWithPayload());
-
- B.addRelativeAddress(caseTypeVectorAccessor);
- }
+ addFieldTypes(IGM, strategy.getElementsWithPayload());
}
uint16_t getKindSpecificFlags() {
@@ -3029,28 +2975,12 @@
}
void addLayoutInfo() {
- // Build the field name list.
- llvm::SmallString<64> fieldNames;
- unsigned numFields = getFieldNameString(getType()->getStoredProperties(),
- fieldNames);
-
- B.addInt32(numFields);
+ auto properties = getType()->getStoredProperties();
+ B.addInt32(std::distance(properties.begin(), properties.end()));
B.addInt32(FieldVectorOffset / IGM.getPointerSize());
- B.addRelativeAddress(IGM.getAddrOfGlobalString(fieldNames,
- /*willBeRelativelyAddressed*/ true));
-
- // Don't emit the field type accessor function if we're only lazily
- // emitting the context descriptor.
- if (Lazy) {
- B.addInt32(0);
- } else {
- // Build the field type accessor function.
- llvm::Function *fieldTypeVectorAccessor
- = getFieldTypeAccessorFn(IGM, getType(),
- getType()->getStoredProperties());
+ B.addInt32(1); // class is always reflectable
- B.addRelativeAddress(fieldTypeVectorAccessor);
- }
+ addFieldTypes(IGM, getType(), properties);
}
};
} // end anonymous namespace
@@ -3100,7 +3030,7 @@
return getAddrOfLLVMVariable(entity, Alignment(4),
definition,
- NominalTypeDescriptorTy,
+ TypeContextDescriptorTy,
DebugTypeInfo());
}
@@ -3146,158 +3076,8 @@
[&]{ AnonymousContextDescriptorBuilder(*this, DC).emit(); });
}
-void
-IRGenModule::addLazyFieldTypeAccessor(NominalTypeDecl *type,
- ArrayRef<FieldTypeInfo> fieldTypes,
- llvm::Function *fn) {
- IRGen.addLazyFieldTypeAccessor(type, fieldTypes, fn, this);
-}
-
-void
-irgen::emitFieldTypeAccessor(IRGenModule &IGM,
- NominalTypeDecl *type,
- llvm::Function *fn,
- ArrayRef<FieldTypeInfo> fieldTypes)
-{
- IRGenFunction IGF(IGM, fn);
- if (IGM.DebugInfo)
- IGM.DebugInfo->emitArtificialFunction(IGF, fn);
-
- auto metadataArrayPtrTy = IGM.TypeMetadataPtrTy->getPointerTo();
-
- CanType formalType = type->getDeclaredTypeInContext()->getCanonicalType();
- llvm::Value *metadata = IGF.collectParameters().claimNext();
- setTypeMetadataName(IGM, metadata, formalType);
-
- // Get the address at which the field type vector reference should be
- // cached.
- llvm::Value *vectorPtr;
- auto nullVector = llvm::ConstantPointerNull::get(metadataArrayPtrTy);
-
- // If the type is not generic, we can use a global variable to cache the
- // address of the field type vector for the single instance.
- if (!type->isGenericContext()) {
- vectorPtr = new llvm::GlobalVariable(*IGM.getModule(),
- metadataArrayPtrTy,
- /*constant*/ false,
- llvm::GlobalValue::PrivateLinkage,
- nullVector,
- llvm::Twine("field_type_vector_")
- + type->getName().str());
- // For a generic type, use a slot we saved in the generic metadata pattern
- // immediately after the metadata object itself, which should be
- // instantiated with every generic metadata instance.
- } else {
- auto size = IGM.getMetadataLayout(type).getSize();
- auto index = -(size.AddressPoint.getValue() /
- int64_t(IGM.getPointerSize().getValue())) - 1;
- auto offset = IGM.getSize(Size(index));
-
- vectorPtr = IGF.Builder.CreateBitCast(metadata,
- metadataArrayPtrTy->getPointerTo());
- vectorPtr = IGF.Builder.CreateInBoundsGEP(
- /*Ty=*/nullptr, vectorPtr, offset);
- }
-
- // First, see if the field type vector has already been populated. This
- // load can be nonatomic; if we race to build the field offset vector, we
- // will detect so when we try to commit our pointer and simply discard the
- // redundant work.
- llvm::Value *initialVector
- = IGF.Builder.CreateLoad(vectorPtr, IGM.getPointerAlignment());
-
- auto entryBB = IGF.Builder.GetInsertBlock();
- auto buildBB = IGF.createBasicBlock("build_field_types");
- auto raceLostBB = IGF.createBasicBlock("race_lost");
- auto doneBB = IGF.createBasicBlock("done");
-
- llvm::Value *isNull
- = IGF.Builder.CreateICmpEQ(initialVector, nullVector);
- IGF.Builder.CreateCondBr(isNull, buildBB, doneBB);
-
- // Build the field type vector if we didn't already.
- IGF.Builder.emitBlock(buildBB);
-
- // Bind the metadata instance to our local type data so we
- // use it to provide metadata for generic parameters in field types.
- IGF.bindLocalTypeDataFromTypeMetadata(formalType, IsExact, metadata);
-
- // Allocate storage for the field vector.
- unsigned allocSize = fieldTypes.size() * IGM.getPointerSize().getValue();
- auto allocSizeVal = llvm::ConstantInt::get(IGM.IntPtrTy, allocSize);
- auto allocAlignMaskVal =
- IGM.getSize(IGM.getPointerAlignment().asSize() - Size(1));
- llvm::Value *builtVectorAlloc
- = IGF.emitAllocRawCall(allocSizeVal, allocAlignMaskVal);
-
- llvm::Value *builtVector
- = IGF.Builder.CreateBitCast(builtVectorAlloc, metadataArrayPtrTy);
-
- // Emit type metadata for the fields into the vector.
- for (unsigned i : indices(fieldTypes)) {
- auto fieldTy = fieldTypes[i].getType();
- auto slot = IGF.Builder.CreateInBoundsGEP(builtVector,
- llvm::ConstantInt::get(IGM.Int32Ty, i));
-
- // Strip reference storage qualifiers like unowned and weak.
- // FIXME: Some clients probably care about them.
- if (auto refStorTy = dyn_cast<ReferenceStorageType>(fieldTy))
- fieldTy = refStorTy.getReferentType();
-
- auto metadata = IGF.emitTypeMetadataRef(fieldTy);
-
- auto fieldTypeInfo = fieldTypes[i];
-
- // Mix in flag bits.
- if (fieldTypeInfo.hasFlags()) {
- auto flags = FieldType()
- .withIndirect(fieldTypeInfo.isIndirect())
- .withWeak(fieldTypeInfo.isWeak());
- auto metadataBits = IGF.Builder.CreatePtrToInt(metadata, IGF.IGM.SizeTy);
- metadataBits = IGF.Builder.CreateOr(metadataBits,
- llvm::ConstantInt::get(IGF.IGM.SizeTy, flags.getIntValue()));
- metadata = IGF.Builder.CreateIntToPtr(metadataBits, metadata->getType());
- }
-
- IGF.Builder.CreateStore(metadata, slot, IGM.getPointerAlignment());
- }
-
- // Atomically compare-exchange a pointer to our vector into the slot.
- auto vectorIntPtr = IGF.Builder.CreateBitCast(vectorPtr,
- IGM.IntPtrTy->getPointerTo());
- auto builtVectorInt = IGF.Builder.CreatePtrToInt(builtVector,
- IGM.IntPtrTy);
- auto zero = llvm::ConstantInt::get(IGM.IntPtrTy, 0);
-
- llvm::Value *raceVectorInt = IGF.Builder.CreateAtomicCmpXchg(vectorIntPtr,
- zero, builtVectorInt,
- llvm::AtomicOrdering::SequentiallyConsistent,
- llvm::AtomicOrdering::SequentiallyConsistent);
-
- // We might have added internal control flow above.
- buildBB = IGF.Builder.GetInsertBlock();
-
- // The pointer in the slot should still have been null.
- auto didStore = IGF.Builder.CreateExtractValue(raceVectorInt, 1);
- raceVectorInt = IGF.Builder.CreateExtractValue(raceVectorInt, 0);
- IGF.Builder.CreateCondBr(didStore, doneBB, raceLostBB);
-
- // If the cmpxchg failed, someone beat us to landing their field type
- // vector. Deallocate ours and return the winner.
- IGF.Builder.emitBlock(raceLostBB);
- IGF.emitDeallocRawCall(builtVectorAlloc, allocSizeVal, allocAlignMaskVal);
- auto raceVector = IGF.Builder.CreateIntToPtr(raceVectorInt,
- metadataArrayPtrTy);
- IGF.Builder.CreateBr(doneBB);
-
- // Return the result.
- IGF.Builder.emitBlock(doneBB);
- auto phi = IGF.Builder.CreatePHI(metadataArrayPtrTy, 3);
- phi->addIncoming(initialVector, entryBB);
- phi->addIncoming(builtVector, buildBB);
- phi->addIncoming(raceVector, raceLostBB);
-
- IGF.Builder.CreateRet(phi);
+void IRGenModule::addFieldTypes(ArrayRef<CanType> fieldTypes) {
+ IRGen.addFieldTypes(fieldTypes, this);
}
/*****************************************************************************/
diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp
index 9b5994a..5377b02 100644
--- a/lib/IRGen/GenProto.cpp
+++ b/lib/IRGen/GenProto.cpp
@@ -1968,10 +1968,7 @@
// The counts didn't match; abort.
IGF.Builder.emitBlock(failBB);
- llvm::Function *trapIntrinsic =
- llvm::Intrinsic::getDeclaration(&IGM.Module, llvm::Intrinsic::ID::trap);
- IGF.Builder.CreateCall(trapIntrinsic, {});
- IGF.Builder.CreateUnreachable();
+ IGF.emitTrap(/*EmitUnreachable=*/true);
return fn;
}
diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp
index cd195b6..2b209cc 100644
--- a/lib/IRGen/GenReflection.cpp
+++ b/lib/IRGen/GenReflection.cpp
@@ -963,7 +963,7 @@
}
FieldTypeMetadataBuilder builder(*this, Decl);
- builder.emit();
+ FieldDescriptors.push_back(builder.emit());
}
void IRGenModule::emitReflectionMetadataVersion() {
diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp
index c71c3c3..6090a40 100644
--- a/lib/IRGen/IRGen.cpp
+++ b/lib/IRGen/IRGen.cpp
@@ -767,6 +767,7 @@
// Register our info with the runtime if needed.
if (Opts.UseJIT) {
+ IGM.emitBuiltinReflectionMetadata();
IGM.emitRuntimeRegistration();
} else {
// Emit protocol conformances into a section we can recognize at runtime.
diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp
index 5afd28b..c18a018 100644
--- a/lib/IRGen/IRGenFunction.cpp
+++ b/lib/IRGen/IRGenFunction.cpp
@@ -431,3 +431,28 @@
auto slotPtr = emitByteOffsetGEP(base, offsetValue, objectTy);
return Address(slotPtr, objectAlignment);
}
+
+void IRGenFunction::emitTrap(bool EmitUnreachable) {
+ if (IGM.IRGen.Opts.shouldOptimize()) {
+ // Emit unique side-effecting inline asm calls in order to eliminate
+ // the possibility that an LLVM optimization or code generation pass
+ // will merge these blocks back together again. We emit an empty asm
+ // string with the side-effect flag set, and with a unique integer
+ // argument for each cond_fail we see in the function.
+ llvm::IntegerType *asmArgTy = IGM.Int32Ty;
+ llvm::Type *argTys = {asmArgTy};
+ llvm::FunctionType *asmFnTy =
+ llvm::FunctionType::get(IGM.VoidTy, argTys, false /* = isVarArg */);
+ llvm::InlineAsm *inlineAsm =
+ llvm::InlineAsm::get(asmFnTy, "", "n", true /* = SideEffects */);
+ Builder.CreateAsmCall(inlineAsm,
+ llvm::ConstantInt::get(asmArgTy, NumTrapBarriers++));
+ }
+
+ // Emit the trap instruction.
+ llvm::Function *trapIntrinsic =
+ llvm::Intrinsic::getDeclaration(&IGM.Module, llvm::Intrinsic::ID::trap);
+ Builder.CreateCall(trapIntrinsic, {});
+ if (EmitUnreachable)
+ Builder.CreateUnreachable();
+}
diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h
index fc52571..1802f99 100644
--- a/lib/IRGen/IRGenFunction.h
+++ b/lib/IRGen/IRGenFunction.h
@@ -276,7 +276,11 @@
/// Mark a load as dereferenceable to `size` bytes.
void setDereferenceableLoad(llvm::LoadInst *load, unsigned size);
+ /// Emit a non-mergeable trap call, optionally followed by a terminator.
+ void emitTrap(bool EmitUnreachable);
+
private:
+ unsigned NumTrapBarriers = 0;
llvm::Instruction *AllocaIP;
const SILDebugScope *DbgScope;
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index 5c97108..4901c85 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -307,26 +307,30 @@
ProtocolConformanceDescriptorPtrTy
= ProtocolConformanceDescriptorTy->getPointerTo(DefaultAS);
- NominalTypeDescriptorTy
+ TypeContextDescriptorTy
= llvm::StructType::create(LLVMContext, "swift.type_descriptor");
- NominalTypeDescriptorPtrTy
- = NominalTypeDescriptorTy->getPointerTo(DefaultAS);
+ TypeContextDescriptorPtrTy
+ = TypeContextDescriptorTy->getPointerTo(DefaultAS);
- ClassNominalTypeDescriptorTy =
+ ClassContextDescriptorTy =
llvm::StructType::get(LLVMContext, {
- Int32Ty,
- Int32Ty,
- Int32Ty,
- Int32Ty,
- Int32Ty,
- Int32Ty,
- Int32Ty,
- Int32Ty,
- Int32Ty,
- Int32Ty,
- Int16Ty,
- Int16Ty,
- Int32Ty,
+ Int32Ty, // context flags
+ Int32Ty, // parent
+ Int32Ty, // name
+ Int32Ty, // kind
+ Int32Ty, // accessor function
+ Int32Ty, // num fields
+ Int32Ty, // field offset vector
+ Int32Ty, // is_reflectable flag
+ Int32Ty, // (Generics Descriptor) argument offset
+ Int32Ty, // (Generics Descriptor) num params
+ Int32Ty, // (Generics Descriptor) num requirements
+ Int32Ty, // (Generics Descriptor) num key arguments
+ Int32Ty, // (Generics Descriptor) num extra arguments
+ Int32Ty, // (VTable Descriptor) offset
+ Int32Ty, // (VTable Descriptor) size
+ Int32Ty, // (Methods Descriptor) accessor
+ Int32Ty, // (Methods Descriptor) flags
}, /*packed=*/true);
MethodDescriptorStructTy
@@ -345,6 +349,7 @@
FieldDescriptorTy
= llvm::StructType::create(LLVMContext, "swift.field_descriptor");
FieldDescriptorPtrTy = FieldDescriptorTy->getPointerTo(DefaultAS);
+ FieldDescriptorPtrPtrTy = FieldDescriptorPtrTy->getPointerTo(DefaultAS);
FixedBufferTy = nullptr;
for (unsigned i = 0; i != MaxNumValueWitnesses; ++i)
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index 25ee44e..a3d0337 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -212,15 +212,13 @@
llvm::SmallPtrSet<SILFunction*, 4> LazilyEmittedFunctions;
- struct LazyFieldTypeAccessor {
- NominalTypeDecl *type;
- std::vector<FieldTypeInfo> fieldTypes;
- llvm::Function *fn;
+ struct FieldTypeMetadata {
IRGenModule *IGM;
+ std::vector<CanType> fieldTypes;
};
-
- /// Field type accessors we need to emit.
- llvm::SmallVector<LazyFieldTypeAccessor, 4> LazyFieldTypeAccessors;
+
+ /// Field types we need to verify are present.
+ llvm::SmallVector<FieldTypeMetadata, 4> LazyFieldTypes;
/// SIL functions that we need to emit lazily.
llvm::SmallVector<SILFunction*, 4> LazyFunctionDefinitions;
@@ -363,13 +361,8 @@
/// Adds \p Conf to LazyWitnessTables if it has not been added yet.
void addLazyWitnessTable(const ProtocolConformance *Conf);
- void addLazyFieldTypeAccessor(NominalTypeDecl *type,
- ArrayRef<FieldTypeInfo> fieldTypes,
- llvm::Function *fn,
- IRGenModule *IGM) {
- LazyFieldTypeAccessors.push_back({type,
- {fieldTypes.begin(), fieldTypes.end()},
- fn, IGM});
+ void addFieldTypes(ArrayRef<CanType> fieldTypes, IRGenModule *IGM) {
+ LazyFieldTypes.push_back({IGM, {fieldTypes.begin(), fieldTypes.end()}});
}
void addClassForEagerInitialization(ClassDecl *ClassDecl);
@@ -537,14 +530,15 @@
llvm::PointerType *ProtocolRecordPtrTy;
llvm::StructType *ProtocolConformanceDescriptorTy;
llvm::PointerType *ProtocolConformanceDescriptorPtrTy;
- llvm::StructType *NominalTypeDescriptorTy;
- llvm::PointerType *NominalTypeDescriptorPtrTy;
- llvm::StructType *ClassNominalTypeDescriptorTy;
+ llvm::StructType *TypeContextDescriptorTy;
+ llvm::PointerType *TypeContextDescriptorPtrTy;
+ llvm::StructType *ClassContextDescriptorTy;
llvm::StructType *MethodDescriptorStructTy; /// %swift.method_descriptor
llvm::StructType *TypeMetadataRecordTy;
llvm::PointerType *TypeMetadataRecordPtrTy;
llvm::StructType *FieldDescriptorTy;
llvm::PointerType *FieldDescriptorPtrTy;
+ llvm::PointerType *FieldDescriptorPtrPtrTy;
llvm::PointerType *ErrorPtrTy; /// %swift.error*
llvm::StructType *OpenedErrorTripleTy; /// { %swift.opaque*, %swift.type*, i8** }
llvm::PointerType *OpenedErrorTriplePtrTy; /// { %swift.opaque*, %swift.type*, i8** }*
@@ -764,14 +758,13 @@
void addUsedGlobal(llvm::GlobalValue *global);
void addCompilerUsedGlobal(llvm::GlobalValue *global);
void addObjCClass(llvm::Constant *addr, bool nonlazy);
+ void addFieldTypes(ArrayRef<CanType> fieldTypes);
+ void addProtocolConformance(const NormalProtocolConformance *conformance);
- void addLazyFieldTypeAccessor(NominalTypeDecl *type,
- ArrayRef<FieldTypeInfo> fieldTypes,
- llvm::Function *fn);
llvm::Constant *emitSwiftProtocols();
llvm::Constant *emitProtocolConformances();
- void addProtocolConformance(const NormalProtocolConformance *conformance);
llvm::Constant *emitTypeMetadataRecords();
+ llvm::Constant *emitFieldDescriptors();
llvm::Constant *getOrCreateHelperFunction(StringRef name,
llvm::Type *resultType,
@@ -886,7 +879,10 @@
/// List of ExtensionDecls corresponding to the generated
/// categories.
SmallVector<ExtensionDecl*, 4> ObjCCategoryDecls;
-
+
+ /// List of fields descriptors to register in runtime.
+ SmallVector<llvm::GlobalVariable *, 4> FieldDescriptors;
+
/// Map of Objective-C protocols and protocol references, bitcast to i8*.
/// The interesting global variables relating to an ObjC protocol.
struct ObjCProtocolPair {
diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp
index fe53067..5622535 100644
--- a/lib/IRGen/IRGenSIL.cpp
+++ b/lib/IRGen/IRGenSIL.cpp
@@ -388,7 +388,6 @@
/// Holds the DominancePoint of values that are storage for a source variable.
SmallVector<std::pair<llvm::Instruction *, DominancePoint>, 8> ValueDomPoints;
unsigned NumAnonVars = 0;
- unsigned NumCondFails = 0;
/// Accumulative amount of allocated bytes on the stack. Used to limit the
/// size for stack promoted objects.
@@ -631,7 +630,11 @@
template <class DebugVarCarryingInst>
StringRef getVarName(DebugVarCarryingInst *i, bool &IsAnonymous) {
- StringRef Name = i->getVarInfo().Name;
+ auto VarInfo = i->getVarInfo();
+ if (!VarInfo)
+ return StringRef();
+
+ StringRef Name = i->getVarInfo()->Name;
// The $match variables generated by the type checker are not
// guaranteed to be unique within their scope, but they have
// unique VarDecls.
@@ -3589,15 +3592,16 @@
if (IGM.IsSwiftErrorInRegister)
return;
auto ErrorResultSlot = getErrorResultSlot(IGM.silConv.getSILType(ErrorInfo));
- SILDebugVariable Var = DbgValue->getVarInfo();
+ auto Var = DbgValue->getVarInfo();
+ assert(Var && "error result without debug info");
auto Storage =
emitShadowCopyIfNeeded(ErrorResultSlot.getAddress(), getDebugScope(),
- Var.Name, Var.ArgNo, false);
+ Var->Name, Var->ArgNo, false);
DebugTypeInfo DTI(nullptr, nullptr, ErrorInfo.getType(),
ErrorResultSlot->getType(), IGM.getPointerSize(),
IGM.getPointerAlignment(), true);
IGM.DebugInfo->emitVariableDeclaration(Builder, Storage, DTI, getDebugScope(),
- nullptr, Var.Name, Var.ArgNo,
+ nullptr, Var->Name, Var->ArgNo,
IndirectValue, ArtificialValue);
}
@@ -3605,12 +3609,13 @@
if (!IGM.DebugInfo)
return;
+ auto VarInfo = i->getVarInfo();
+ assert(VarInfo && "debug_value without debug info");
auto SILVal = i->getOperand();
if (isa<SILUndef>(SILVal)) {
// We cannot track the location of inlined error arguments because it has no
// representation in SIL.
- if (!i->getDebugScope()->InlinedCallSite &&
- i->getVarInfo().Name == "$error") {
+ if (!i->getDebugScope()->InlinedCallSite && VarInfo->Name == "$error") {
auto funcTy = CurSILFn->getLoweredFunctionType();
emitErrorResultVar(funcTy->getErrorResult(), i);
}
@@ -3636,12 +3641,11 @@
return;
// Put the value into a stack slot at -Onone.
- llvm::SmallVector<llvm::Value *, 8> Copy;
- unsigned ArgNo = i->getVarInfo().ArgNo;
- emitShadowCopyIfNeeded(SILVal, i->getDebugScope(), Name, ArgNo, IsAnonymous,
- Copy);
+ llvm::SmallVector<llvm::Value *, 8> Copy;
+ emitShadowCopyIfNeeded(SILVal, i->getDebugScope(), Name, VarInfo->ArgNo,
+ IsAnonymous, Copy);
emitDebugVariableDeclaration(Copy, DbgTy, SILTy, i->getDebugScope(),
- i->getDecl(), Name, ArgNo);
+ i->getDecl(), Name, VarInfo->ArgNo);
}
void IRGenSILFunction::visitDebugValueAddrInst(DebugValueAddrInst *i) {
@@ -3655,6 +3659,8 @@
if (isa<SILUndef>(SILVal))
return;
+ auto VarInfo = i->getVarInfo();
+ assert(VarInfo && "debug_value_addr without debug info");
bool IsAnonymous = false;
bool IsLoadablyByAddress = isa<AllocStackInst>(SILVal);
StringRef Name = getVarName(i, IsAnonymous);
@@ -3669,19 +3675,16 @@
// FIXME: Should this check if the lowered SILType is address only
// instead? Otherwise optionals of archetypes etc will still have
// 'Unwrap' set to false.
- bool Unwrap =
- i->getVarInfo().Constant ||
- SILTy.is<ArchetypeType>();
+ bool Unwrap = VarInfo->Constant || SILTy.is<ArchetypeType>();
auto DbgTy = DebugTypeInfo::getLocalVariable(
CurSILFn->getDeclContext(), CurSILFn->getGenericEnvironment(), Decl,
RealType, getTypeInfo(SILVal->getType()), Unwrap);
// Put the value's address into a stack slot at -Onone and emit a debug
// intrinsic.
- unsigned ArgNo = i->getVarInfo().ArgNo;
emitDebugVariableDeclaration(
- emitShadowCopyIfNeeded(Addr, i->getDebugScope(), Name, ArgNo,
+ emitShadowCopyIfNeeded(Addr, i->getDebugScope(), Name, VarInfo->ArgNo,
IsAnonymous),
- DbgTy, SILType(), i->getDebugScope(), Decl, Name, ArgNo,
+ DbgTy, SILType(), i->getDebugScope(), Decl, Name, VarInfo->ArgNo,
(IsLoadablyByAddress || DbgTy.isImplicitlyIndirect()) ? DirectValue
: IndirectValue);
}
@@ -3851,9 +3854,7 @@
static llvm::Value *emitIsUnique(IRGenSILFunction &IGF, SILValue operand,
SourceLoc loc, bool checkPinned) {
if (!hasReferenceSemantics(IGF, operand->getType())) {
- llvm::Function *trapIntrinsic = llvm::Intrinsic::getDeclaration(
- &IGF.IGM.Module, llvm::Intrinsic::ID::trap);
- IGF.Builder.CreateCall(trapIntrinsic, {});
+ IGF.emitTrap(/*EmitUnreachable=*/false);
return llvm::UndefValue::get(IGF.IGM.Int1Ty);
}
@@ -3885,6 +3886,10 @@
void IRGenSILFunction::emitDebugInfoForAllocStack(AllocStackInst *i,
const TypeInfo &type,
llvm::Value *addr) {
+ auto VarInfo = i->getVarInfo();
+ if (!VarInfo)
+ return;
+
VarDecl *Decl = i->getDecl();
// Describe the underlying alloca. This way an llvm.dbg.declare instrinsic
// is used, which is valid for the entire lifetime of the alloca.
@@ -3897,7 +3902,6 @@
return;
bool IsAnonymous = false;
- unsigned ArgNo = i->getVarInfo().ArgNo;
StringRef Name = getVarName(i, IsAnonymous);
// At this point addr must be an alloca or an undef.
@@ -3907,7 +3911,8 @@
if (auto *Alloca = dyn_cast<llvm::AllocaInst>(addr))
if (!Alloca->isStaticAlloca()) {
// Store the address of the dynamic alloca on the stack.
- addr = emitShadowCopy(addr, DS, Name, ArgNo, IGM.getPointerAlignment());
+ addr = emitShadowCopy(addr, DS, Name, VarInfo->ArgNo,
+ IGM.getPointerAlignment());
Indirection = IndirectValue;
}
@@ -3928,8 +3933,8 @@
if (DbgTy.isImplicitlyIndirect())
Indirection = DirectValue;
- emitDebugVariableDeclaration(addr, DbgTy, SILTy, DS, Decl, Name, ArgNo,
- Indirection);
+ emitDebugVariableDeclaration(addr, DbgTy, SILTy, DS, Decl, Name,
+ VarInfo->ArgNo, Indirection);
}
}
@@ -4480,10 +4485,7 @@
IGF.FailBBs.push_back(failBB);
IGF.Builder.emitBlock(failBB);
- llvm::Function *trapIntrinsic = llvm::Intrinsic::getDeclaration(
- &IGF.IGM.Module, llvm::Intrinsic::ID::trap);
- IGF.Builder.CreateCall(trapIntrinsic, {});
- IGF.Builder.CreateUnreachable();
+ IGF.emitTrap(/*EmitUnreachable=*/true);
llvm::BasicBlock *contBB = llvm::BasicBlock::Create(IGF.IGM.getLLVMContext());
IGF.Builder.emitBlock(contBB);
@@ -5377,28 +5379,7 @@
llvm::BasicBlock *contBB = llvm::BasicBlock::Create(IGM.getLLVMContext());
Builder.CreateCondBr(cond, failBB, contBB);
Builder.emitBlock(failBB);
-
- if (IGM.IRGen.Opts.shouldOptimize()) {
- // Emit unique side-effecting inline asm calls in order to eliminate
- // the possibility that an LLVM optimization or code generation pass
- // will merge these blocks back together again. We emit an empty asm
- // string with the side-effect flag set, and with a unique integer
- // argument for each cond_fail we see in the function.
- llvm::IntegerType *asmArgTy = IGM.Int32Ty;
- llvm::Type *argTys = { asmArgTy };
- llvm::FunctionType *asmFnTy =
- llvm::FunctionType::get(IGM.VoidTy, argTys, false /* = isVarArg */);
- llvm::InlineAsm *inlineAsm =
- llvm::InlineAsm::get(asmFnTy, "", "n", true /* = SideEffects */);
- Builder.CreateAsmCall(inlineAsm,
- llvm::ConstantInt::get(asmArgTy, NumCondFails++));
- }
-
- // Emit the trap instruction.
- llvm::Function *trapIntrinsic =
- llvm::Intrinsic::getDeclaration(&IGM.Module, llvm::Intrinsic::ID::trap);
- Builder.CreateCall(trapIntrinsic, {});
- Builder.CreateUnreachable();
+ emitTrap(/*EmitUnreachable=*/true);
Builder.emitBlock(contBB);
FailBBs.push_back(failBB);
}
diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp
index 73d2680..0113e5f 100644
--- a/lib/IRGen/LoadableByAddress.cpp
+++ b/lib/IRGen/LoadableByAddress.cpp
@@ -110,6 +110,27 @@
return false;
}
+static bool containsFunctionSignature(GenericEnvironment *genEnv,
+ irgen::IRGenModule &Mod,
+ SILType storageType, SILType newSILType) {
+ if (!isLargeLoadableType(genEnv, storageType, Mod) &&
+ (newSILType != storageType)) {
+ return true;
+ }
+ if (auto origType = storageType.getAs<TupleType>()) {
+ for (auto canElem : origType.getElementTypes()) {
+ SILType objectType = SILType::getPrimitiveObjectType(canElem);
+ if (auto optionalObject = objectType.getOptionalObjectType()) {
+ objectType = optionalObject;
+ }
+ if (auto fnType = objectType.getAs<SILFunctionType>()) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
// Forward declarations - functions depend on each other
static SmallVector<SILParameterInfo, 4>
getNewParameters(GenericEnvironment *env, CanSILFunctionType fnType,
@@ -128,14 +149,30 @@
SILType currResultTy = result.getSILStorageType();
SILType newSILType = getNewSILType(GenericEnv, currResultTy, Mod);
// We (currently) only care about function signatures
- if (!isLargeLoadableType(GenericEnv, currResultTy, Mod) &&
- (newSILType != currResultTy)) {
+ if (containsFunctionSignature(GenericEnv, Mod, currResultTy, newSILType)) {
return true;
}
}
return false;
}
+static bool modNonFuncTypeResultType(GenericEnvironment *genEnv,
+ CanSILFunctionType loweredTy,
+ irgen::IRGenModule &Mod) {
+ if (!modifiableFunction(loweredTy)) {
+ return false;
+ }
+ if (loweredTy->getNumResults() != 1) {
+ return false;
+ }
+ auto singleResult = loweredTy->getSingleResult();
+ auto resultStorageType = singleResult.getSILStorageType();
+ if (isLargeLoadableType(genEnv, resultStorageType, Mod)) {
+ return true;
+ }
+ return false;
+}
+
static SmallVector<SILResultInfo, 2>
getNewResults(GenericEnvironment *GenericEnv,
CanSILFunctionType fnType, irgen::IRGenModule &Mod) {
@@ -148,14 +185,12 @@
SILType currResultTy = result.getSILStorageType();
SILType newSILType = getNewSILType(GenericEnv, currResultTy, Mod);
// We (currently) only care about function signatures
- if (!isLargeLoadableType(GenericEnv, currResultTy, Mod) &&
- (newSILType != currResultTy)) {
+ if (containsFunctionSignature(GenericEnv, Mod, currResultTy, newSILType)) {
// Case (1) Above
SILResultInfo newResult(newSILType.getSwiftRValueType(),
result.getConvention());
newResults.push_back(newResult);
- } else if ((newSILType != currResultTy) &&
- shouldTransformResults(GenericEnv, fnType, Mod)) {
+ } else if (modNonFuncTypeResultType(GenericEnv, fnType, Mod)) {
// Case (2) Above
SILResultInfo newSILResultInfo(newSILType.getSwiftRValueType(),
ResultConvention::Indirect);
@@ -236,7 +271,7 @@
if (resultStorageType != newResultStorageType) {
return true;
}
- return false;
+ return modNonFuncTypeResultType(genEnv, loweredTy, Mod);
}
static bool modResultType(SILFunction *F, irgen::IRGenModule &Mod) {
@@ -293,7 +328,9 @@
return SILParameterInfo(storageType.getSwiftRValueType(),
ParameterConvention::Indirect_In_Constant);
} else {
- return param;
+ auto newType = getNewSILType(env, storageType, IGM);
+ return SILParameterInfo(newType.getSwiftRValueType(),
+ param.getConvention());
}
}
@@ -320,8 +357,50 @@
return newYields;
}
+static SILType getNewTupleType(GenericEnvironment *GenericEnv,
+ irgen::IRGenModule &Mod,
+ const SILType &nonOptionalType,
+ const SILType &storageType) {
+ auto origType = nonOptionalType.getAs<TupleType>();
+ assert(origType && "Expected a tuple type");
+ SmallVector<TupleTypeElt, 2> newElems;
+ for (TupleTypeElt canElem : origType->getElements()) {
+ auto origCanType = CanType(canElem.getRawType());
+ auto elem = SILType::getPrimitiveObjectType(origCanType);
+ auto newElem = getNewSILType(GenericEnv, elem, Mod);
+ auto newTupleType =
+ TupleTypeElt(newElem.getSwiftRValueType(), canElem.getName(),
+ canElem.getParameterFlags());
+ newElems.push_back(newTupleType);
+ }
+ auto type = TupleType::get(newElems, nonOptionalType.getASTContext());
+ auto canType = CanType(type);
+ SILType newSILType = SILType::getPrimitiveObjectType(canType);
+ if (nonOptionalType.isAddress()) {
+ newSILType = newSILType.getAddressType();
+ }
+ if (nonOptionalType != storageType) {
+ newSILType = SILType::getOptionalType(newSILType);
+ }
+ if (storageType.isAddress()) {
+ newSILType = newSILType.getAddressType();
+ }
+ return newSILType;
+}
+
static SILType getNewSILType(GenericEnvironment *GenericEnv,
SILType storageType, irgen::IRGenModule &Mod) {
+ SILType nonOptionalType = storageType;
+ if (auto optType = storageType.getOptionalObjectType()) {
+ nonOptionalType = optType;
+ }
+ if (nonOptionalType.getAs<TupleType>()) {
+ SILType newSILType =
+ getNewTupleType(GenericEnv, Mod, nonOptionalType, storageType);
+ return isLargeLoadableType(GenericEnv, newSILType, Mod)
+ ? newSILType.getAddressType()
+ : newSILType;
+ }
SILType newSILType = getNewOptionalFunctionType(GenericEnv, storageType, Mod);
if (newSILType != storageType) {
return newSILType;
@@ -657,8 +736,7 @@
}
SILType newSILType = getNewSILType(genEnv, storageType, Mod);
// We (currently) only care about function signatures
- if (!isLargeLoadableType(genEnv, storageType, Mod) &&
- (newSILType != storageType)) {
+ if (containsFunctionSignature(genEnv, Mod, storageType, newSILType)) {
return true;
}
return false;
@@ -671,7 +749,8 @@
pass.switchEnumInstsToMod.push_back(instr);
return;
}
- // In case we converted the target BB type of this enum - need to modify!
+ // In case we converted the target BB type of this enum,
+ // to an address based one - need to modify
unsigned numOfCases = instr->getNumCases();
SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 16> caseBBs;
for (unsigned i = 0; i < numOfCases; ++i) {
@@ -679,8 +758,13 @@
auto *currBB = currCase.second;
for (SILArgument *arg : currBB->getArguments()) {
if (shouldConvertBBArg(arg, pass.Mod)) {
- pass.switchEnumInstsToMod.push_back(instr);
- return;
+ SILType storageType = arg->getType();
+ auto *genEnv = instr->getFunction()->getGenericEnvironment();
+ SILType newSILType = getNewSILType(genEnv, storageType, pass.Mod);
+ if (newSILType.isAddress()) {
+ pass.switchEnumInstsToMod.push_back(instr);
+ return;
+ }
}
}
}
@@ -749,13 +833,12 @@
void LargeValueVisitor::visitTupleInst(SingleValueInstruction *instr) {
SILType currSILType = instr->getType().getObjectType();
- if (auto funcType = currSILType.getAs<SILFunctionType>()) {
+ if (auto funcType = getInnerFunctionType(currSILType)) {
GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment();
if (!genEnv && funcType->isPolymorphic()) {
genEnv = getGenericEnvironment(funcType);
}
- auto newSILFunctionType =
- getNewSILFunctionType(genEnv, funcType, pass.Mod);
+ auto newSILFunctionType = getNewSILFunctionType(genEnv, funcType, pass.Mod);
if (funcType != newSILFunctionType) {
pass.tupleInstsToMod.push_back(instr);
}
@@ -777,23 +860,6 @@
}
}
-static bool modNonFuncTypeResultType(GenericEnvironment *genEnv,
- CanSILFunctionType loweredTy,
- irgen::IRGenModule &Mod) {
- if (!modifiableFunction(loweredTy)) {
- return false;
- }
- if (loweredTy->getNumResults() != 1) {
- return false;
- }
- auto singleResult = loweredTy->getSingleResult();
- auto resultStorageType = singleResult.getSILStorageType();
- if (isLargeLoadableType(genEnv, resultStorageType, Mod)) {
- return true;
- }
- return false;
-}
-
static bool modNonFuncTypeResultType(SILFunction *F, irgen::IRGenModule &Mod) {
GenericEnvironment *genEnv = F->getGenericEnvironment();
auto loweredTy = F->getLoweredFunctionType();
@@ -1279,8 +1345,7 @@
SILType storageType = arg->getType();
GenericEnvironment *genEnv = pass.F->getGenericEnvironment();
SILType newSILType = getNewSILType(genEnv, storageType, pass.Mod);
- if (!isLargeLoadableType(genEnv, storageType, pass.Mod) &&
- (newSILType != storageType)) {
+ if (containsFunctionSignature(genEnv, pass.Mod, storageType, newSILType)) {
auto *castInstr = argBuilder.createUncheckedBitCast(
RegularLocation(const_cast<ValueDecl *>(arg->getDecl())), arg,
newSILType);
@@ -1449,7 +1514,8 @@
} else if (auto *dbgInst = dyn_cast<DebugValueInst>(user)) {
SILBuilderWithScope dbgBuilder(dbgInst);
// Rewrite the debug_value to point to the variable in the alloca.
- dbgBuilder.createDebugValueAddr(dbgInst->getLoc(), allocInstr);
+ dbgBuilder.createDebugValueAddr(dbgInst->getLoc(), allocInstr,
+ *dbgInst->getVarInfo());
dbgInst->eraseFromParent();
}
}
@@ -1572,14 +1638,16 @@
static void castTupleInstr(SingleValueInstruction *instr, IRGenModule &Mod) {
SILType currSILType = instr->getType();
- auto funcType = currSILType.castTo<SILFunctionType>();
+ auto funcType = getInnerFunctionType(currSILType);
+ assert(funcType && "Expected a function Type");
GenericEnvironment *genEnv = instr->getFunction()->getGenericEnvironment();
if (!genEnv && funcType->isPolymorphic()) {
genEnv = getGenericEnvironment(funcType);
}
- auto newFnType = getNewSILFunctionType(genEnv, funcType, Mod);
- SILType newSILType =
- SILType::getPrimitiveType(newFnType, currSILType.getCategory());
+ SILType newSILType = getNewSILType(genEnv, currSILType, Mod);
+ if (currSILType == newSILType) {
+ return;
+ }
auto II = instr->getIterator();
++II;
@@ -1642,6 +1710,47 @@
return allocInstr;
}
+static void createResultTyInstrAndLoad(LoadableStorageAllocation &allocator,
+ SingleValueInstruction *instr,
+ StructLoweringState &pass) {
+ bool updateResultTy = pass.resultTyInstsToMod.count(instr) != 0;
+ if (updateResultTy) {
+ pass.resultTyInstsToMod.remove(instr);
+ }
+ SILBuilderWithScope builder(instr);
+ auto *currStructExtractInst = dyn_cast<StructExtractInst>(instr);
+ assert(currStructExtractInst && "Expected StructExtractInst");
+ SingleValueInstruction *newInstr = builder.createStructElementAddr(
+ currStructExtractInst->getLoc(), currStructExtractInst->getOperand(),
+ currStructExtractInst->getField(),
+ currStructExtractInst->getType().getAddressType());
+ // Load the struct element then see if we can get rid of the load:
+ LoadInst *loadArg = nullptr;
+ if (!pass.F->hasQualifiedOwnership()) {
+ loadArg = builder.createLoad(newInstr->getLoc(), newInstr,
+ LoadOwnershipQualifier::Unqualified);
+ } else {
+ loadArg = builder.createLoad(newInstr->getLoc(), newInstr,
+ LoadOwnershipQualifier::Take);
+ }
+ instr->replaceAllUsesWith(loadArg);
+ instr->getParent()->erase(instr);
+
+ // If the load is of a function type - do not replace it.
+ if (loadArg->getType().is<SILFunctionType>()) {
+ return;
+ }
+
+ if (allUsesAreReplaceable(loadArg, pass.Mod)) {
+ allocator.replaceLoadWithCopyAddr(loadArg);
+ } else {
+ allocator.replaceLoadWithCopyAddrForModifiable(loadArg);
+ }
+ if (updateResultTy) {
+ pass.resultTyInstsToMod.insert(newInstr);
+ }
+}
+
static void rewriteFunction(StructLoweringState &pass,
LoadableStorageAllocation &allocator) {
@@ -1710,39 +1819,7 @@
while (!pass.structExtractInstsToMod.empty()) {
auto *instr = pass.structExtractInstsToMod.pop_back_val();
- bool updateResultTy = pass.resultTyInstsToMod.count(instr) != 0;
- if (updateResultTy) {
- pass.resultTyInstsToMod.remove(instr);
- }
- SILBuilderWithScope structBuilder(instr);
- auto *newInstr = structBuilder.createStructElementAddr(
- instr->getLoc(), instr->getOperand(), instr->getField(),
- instr->getType().getAddressType());
- // Load the struct element then see if we can get rid of the load:
- LoadInst *loadArg = nullptr;
- if (!pass.F->hasQualifiedOwnership()) {
- loadArg = structBuilder.createLoad(newInstr->getLoc(), newInstr,
- LoadOwnershipQualifier::Unqualified);
- } else {
- loadArg = structBuilder.createLoad(newInstr->getLoc(), newInstr,
- LoadOwnershipQualifier::Take);
- }
- instr->replaceAllUsesWith(loadArg);
- instr->getParent()->erase(instr);
-
- // If the load is of a function type - do not replace it.
- if (loadArg->getType().is<SILFunctionType>()) {
- continue;
- }
-
- if (allUsesAreReplaceable(loadArg, pass.Mod)) {
- allocator.replaceLoadWithCopyAddr(loadArg);
- } else {
- allocator.replaceLoadWithCopyAddrForModifiable(loadArg);
- }
- if (updateResultTy) {
- pass.resultTyInstsToMod.insert(newInstr);
- }
+ createResultTyInstrAndLoad(allocator, instr, pass);
}
while (!pass.applies.empty()) {
@@ -1807,7 +1884,8 @@
SILBuilderWithScope allocBuilder(instr);
SILType currSILType = instr->getType();
SILType newSILType = getNewSILType(genEnv, currSILType, pass.Mod);
- auto *newInstr = allocBuilder.createAllocStack(instr->getLoc(), newSILType);
+ auto *newInstr = allocBuilder.createAllocStack(instr->getLoc(), newSILType,
+ instr->getVarInfo());
instr->replaceAllUsesWith(newInstr);
instr->getParent()->erase(instr);
}
@@ -1840,7 +1918,7 @@
"Expected an address type");
SILBuilderWithScope debugBuilder(instr);
debugBuilder.createDebugValueAddr(instr->getLoc(), currOperand,
- instr->getVarInfo());
+ *instr->getVarInfo());
instr->getParent()->erase(instr);
}
}
@@ -1909,6 +1987,13 @@
newSILType.getAddressType());
break;
}
+ case SILInstructionKind::UncheckedTakeEnumDataAddrInst: {
+ auto *convInstr = cast<UncheckedTakeEnumDataAddrInst>(instr);
+ newInstr = resultTyBuilder.createUncheckedTakeEnumDataAddr(
+ Loc, convInstr->getOperand(), convInstr->getElement(),
+ newSILType.getAddressType());
+ break;
+ }
case SILInstructionKind::RefTailAddrInst: {
auto *convInstr = cast<RefTailAddrInst>(instr);
newInstr = resultTyBuilder.createRefTailAddr(Loc, convInstr->getOperand(),
@@ -2042,8 +2127,11 @@
SILType resultTy = loweredTy->getAllResultsType();
SILType newSILType = getNewSILType(genEnv, resultTy, pass.Mod);
// We (currently) only care about function signatures
- if (!isLargeLoadableType(genEnv, resultTy, pass.Mod) &&
- (newSILType != resultTy)) {
+ if (isLargeLoadableType(genEnv, resultTy, pass.Mod)) {
+ return true;
+ } else if (containsFunctionSignature(genEnv, pass.Mod, resultTy,
+ newSILType) &&
+ (resultTy != newSILType)) {
assert(loweredTy->getNumResults() == 1 && "Expected a single result");
SILResultInfo origResultInfo = loweredTy->getSingleResult();
SILResultInfo newSILResultInfo(newSILType.getSwiftRValueType(),
@@ -2058,8 +2146,6 @@
loweredTy->getWitnessMethodConformanceOrNone());
F->rewriteLoweredTypeUnsafe(NewTy);
return true;
- } else if (isLargeLoadableType(genEnv, resultTy, pass.Mod)) {
- return true;
}
return false;
}
@@ -2306,6 +2392,9 @@
auto caseTy = enumInstr->getOperand()->getType().getEnumElementType(
enumInstr->getElement(), F->getModule());
SingleValueInstruction *newInstr = nullptr;
+ if (newType.isAddress()) {
+ newType = newType.getObjectType();
+ }
if (caseTy != newType) {
auto *takeEnum = enumBuilder.createUncheckedEnumData(
enumInstr->getLoc(), enumInstr->getOperand(), enumInstr->getElement(),
@@ -2552,29 +2641,11 @@
conversionInstrs.insert(TTI);
} else if (auto *LI = dyn_cast<LoadInst>(&I)) {
- SILType currType = LI->getType();
- if (auto fType = getInnerFunctionType(currType)) {
- if (modifiableFunction(fType)) {
- // need to re-create these loads: re-write type cache
- loadInstrsOfFunc.insert(LI);
- }
- }
+ loadInstrsOfFunc.insert(LI);
} else if (auto *UED = dyn_cast<UncheckedEnumDataInst>(&I)) {
- SILType currType = UED->getType();
- if (auto fType = getInnerFunctionType(currType)) {
- if (modifiableFunction(fType)) {
- // need to re-create these loads: re-write type cache
- uncheckedEnumDataOfFunc.insert(UED);
- }
- }
+ uncheckedEnumDataOfFunc.insert(UED);
} else if (auto *UED = dyn_cast<UncheckedTakeEnumDataAddrInst>(&I)) {
- SILType currType = UED->getType();
- if (auto fType = getInnerFunctionType(currType)) {
- if (modifiableFunction(fType)) {
- // need to re-create these loads: re-write type cache
- uncheckedTakeEnumDataAddrOfFunc.insert(UED);
- }
- }
+ uncheckedTakeEnumDataAddrOfFunc.insert(UED);
} else if (auto *SI = dyn_cast<StoreInst>(&I)) {
auto dest = SI->getDest();
if (isa<ProjectBlockStorageInst>(dest)) {
diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp
index b072069..263e496 100644
--- a/lib/Parse/SyntaxParsingContext.cpp
+++ b/lib/Parse/SyntaxParsingContext.cpp
@@ -250,7 +250,7 @@
if (SF.hasSyntaxRoot()) {
auto SourceRaw = SF.getSyntaxRoot().getRaw();
auto Decls =
- SourceRaw->getChild(SourceFileSyntax::Cursor::Items)->getLayout();
+ SourceRaw->getChild(SourceFileSyntax::Cursor::Statements)->getLayout();
std::copy(Decls.begin(), Decls.end(), std::back_inserter(AllTopLevel));
EOFToken = SourceRaw->getChild(SourceFileSyntax::Cursor::EOFToken);
}
diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp
index 1bd228f..496feee 100644
--- a/lib/ParseSIL/ParseSIL.cpp
+++ b/lib/ParseSIL/ParseSIL.cpp
@@ -882,7 +882,7 @@
IsThunk_t *isThunk, bool *isGlobalInit,
Inline_t *inlineStrategy,
OptimizationMode *optimizationMode,
- bool *isLet,
+ bool *isLet, bool *isWeakLinked,
SmallVectorImpl<std::string> *Semantics,
SmallVectorImpl<ParsedSpecAttr> *SpecAttrs,
ValueDecl **ClangDecl,
@@ -909,6 +909,8 @@
*isThunk = IsReabstractionThunk;
else if (isGlobalInit && SP.P.Tok.getText() == "global_init")
*isGlobalInit = true;
+ else if (isWeakLinked && SP.P.Tok.getText() == "_weakLinked")
+ *isWeakLinked = true;
else if (inlineStrategy && SP.P.Tok.getText() == "noinline")
*inlineStrategy = NoInline;
else if (optimizationMode && SP.P.Tok.getText() == "Onone")
@@ -1450,8 +1452,10 @@
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "integer");
return true;
}
- if (P.Tok.getText().getAsInteger(0, Var.ArgNo))
+ uint16_t ArgNo;
+ if (P.Tok.getText().getAsInteger(0, ArgNo))
return true;
+ Var.ArgNo = ArgNo;
} else if (Key == "let") {
Var.Constant = true;
} else if (Key == "var") {
@@ -5089,7 +5093,7 @@
bool isTransparent = false;
IsSerialized_t isSerialized = IsNotSerialized;
IsThunk_t isThunk = IsNotThunk;
- bool isGlobalInit = false;
+ bool isGlobalInit = false, isWeakLinked = false;
Inline_t inlineStrategy = InlineDefault;
OptimizationMode optimizationMode = OptimizationMode::NotSet;
SmallVector<std::string, 1> Semantics;
@@ -5099,7 +5103,7 @@
if (parseSILLinkage(FnLinkage, P) ||
parseDeclSILOptional(&isTransparent, &isSerialized, &isThunk, &isGlobalInit,
&inlineStrategy, &optimizationMode, nullptr,
- &Semantics, &SpecAttrs,
+ &isWeakLinked, &Semantics, &SpecAttrs,
&ClangDecl, &MRK, FunctionState) ||
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
P.parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) ||
@@ -5125,6 +5129,7 @@
FunctionState.F->setSerialized(IsSerialized_t(isSerialized));
FunctionState.F->setThunk(IsThunk_t(isThunk));
FunctionState.F->setGlobalInit(isGlobalInit);
+ FunctionState.F->setWeakLinked(isWeakLinked);
FunctionState.F->setInlineStrategy(inlineStrategy);
FunctionState.F->setOptimizationMode(optimizationMode);
FunctionState.F->setEffectsKind(MRK);
@@ -5257,7 +5262,7 @@
if (parseSILLinkage(GlobalLinkage, P) ||
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr,
nullptr, nullptr, &isLet, nullptr, nullptr, nullptr,
- nullptr, State) ||
+ nullptr, nullptr, State) ||
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
P.parseIdentifier(GlobalName, NameLoc, diag::expected_sil_value_name) ||
P.parseToken(tok::colon, diag::expected_sil_type))
@@ -5300,7 +5305,7 @@
IsSerialized_t Serialized = IsNotSerialized;
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, VTableState))
+ nullptr, nullptr, VTableState))
return true;
// Parse the class name.
@@ -5650,7 +5655,7 @@
IsSerialized_t isSerialized = IsNotSerialized;
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, WitnessState))
+ nullptr, nullptr, WitnessState))
return true;
Scope S(&P, ScopeKind::TopLevel);
diff --git a/lib/SIL/SILFunction.cpp b/lib/SIL/SILFunction.cpp
index b45147f..5ee94ae 100644
--- a/lib/SIL/SILFunction.cpp
+++ b/lib/SIL/SILFunction.cpp
@@ -98,7 +98,7 @@
Serialized(isSerialized), Thunk(isThunk),
ClassSubclassScope(unsigned(classSubclassScope)), GlobalInitFlag(false),
InlineStrategy(inlineStrategy), Linkage(unsigned(Linkage)),
- HasCReferences(false),
+ HasCReferences(false), IsWeakLinked(false),
OptMode(OptimizationMode::NotSet), EffectsKindAttr(E),
EntryCount(entryCount) {
if (InsertBefore)
@@ -515,13 +515,8 @@
static SILFunctionTraceFormatter TF;
-UnifiedStatsReporter::FrontendStatsTracer
-UnifiedStatsReporter::getStatsTracer(StringRef EventName,
- const SILFunction *F) {
- if (LastTracedFrontendCounters)
- // Return live tracer object.
- return FrontendStatsTracer(EventName, F, &TF, this);
- else
- // Return inert tracer object.
- return FrontendStatsTracer();
+template<>
+const UnifiedStatsReporter::TraceFormatter*
+FrontendStatsTracer::getTraceFormatter<const SILFunction *>() {
+ return &TF;
}
diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp
index 00ddcd5..c6bfb20 100644
--- a/lib/SIL/SILInstructions.cpp
+++ b/lib/SIL/SILInstructions.cpp
@@ -117,21 +117,28 @@
//===----------------------------------------------------------------------===//
template <typename INST>
-static void *allocateDebugVarCarryingInst(SILModule &M, SILDebugVariable Var,
+static void *allocateDebugVarCarryingInst(SILModule &M,
+ Optional<SILDebugVariable> Var,
ArrayRef<SILValue> Operands = {}) {
- return M.allocateInst(sizeof(INST) + Var.Name.size() +
+ return M.allocateInst(sizeof(INST) + (Var ? Var->Name.size() : 0) +
sizeof(Operand) * Operands.size(),
alignof(INST));
}
-TailAllocatedDebugVariable::TailAllocatedDebugVariable(SILDebugVariable Var,
- char *buf) {
- Data.ArgNo = Var.ArgNo;
- Data.Constant = Var.Constant;
- Data.NameLength = Var.Name.size();
- assert(Data.ArgNo == Var.ArgNo && "Truncation");
- assert(Data.NameLength == Var.Name.size() && "Truncation");
- memcpy(buf, Var.Name.data(), Var.Name.size());
+TailAllocatedDebugVariable::TailAllocatedDebugVariable(
+ Optional<SILDebugVariable> Var, char *buf) {
+ if (!Var) {
+ RawValue = 0;
+ return;
+ }
+
+ Data.HasValue = true;
+ Data.Constant = Var->Constant;
+ Data.ArgNo = Var->ArgNo;
+ Data.NameLength = Var->Name.size();
+ assert(Data.ArgNo == Var->ArgNo && "Truncation");
+ assert(Data.NameLength == Var->Name.size() && "Truncation");
+ memcpy(buf, Var->Name.data(), Data.NameLength);
}
StringRef TailAllocatedDebugVariable::getName(const char *buf) const {
@@ -141,7 +148,7 @@
AllocStackInst::AllocStackInst(SILDebugLocation Loc, SILType elementType,
ArrayRef<SILValue> TypeDependentOperands,
SILFunction &F,
- SILDebugVariable Var)
+ Optional<SILDebugVariable> Var)
: InstructionBase(Loc, elementType.getAddressType()) {
SILInstruction::Bits.AllocStackInst.NumOperands =
TypeDependentOperands.size();
@@ -157,7 +164,7 @@
AllocStackInst::create(SILDebugLocation Loc,
SILType elementType, SILFunction &F,
SILOpenedArchetypesState &OpenedArchetypes,
- SILDebugVariable Var) {
+ Optional<SILDebugVariable> Var) {
SmallVector<SILValue, 8> TypeDependentOperands;
collectTypeDependentOperands(TypeDependentOperands, OpenedArchetypes, F,
elementType.getSwiftRValueType());
@@ -167,8 +174,6 @@
AllocStackInst(Loc, elementType, TypeDependentOperands, F, Var);
}
-/// getDecl - Return the underlying variable declaration associated with this
-/// allocation, or null if this is a temporary allocation.
VarDecl *AllocStackInst::getDecl() const {
return getLoc().getAsASTNode<VarDecl>();
}
@@ -234,7 +239,7 @@
AllocBoxInst::AllocBoxInst(SILDebugLocation Loc, CanSILBoxType BoxType,
ArrayRef<SILValue> TypeDependentOperands,
- SILFunction &F, SILDebugVariable Var)
+ SILFunction &F, Optional<SILDebugVariable> Var)
: InstructionBaseWithTrailingOperands(TypeDependentOperands, Loc,
SILType::getPrimitiveObjectType(BoxType)),
VarInfo(Var, getTrailingObjects<char>()) {
@@ -244,18 +249,16 @@
CanSILBoxType BoxType,
SILFunction &F,
SILOpenedArchetypesState &OpenedArchetypes,
- SILDebugVariable Var) {
+ Optional<SILDebugVariable> Var) {
SmallVector<SILValue, 8> TypeDependentOperands;
collectTypeDependentOperands(TypeDependentOperands, OpenedArchetypes, F,
BoxType);
auto Sz = totalSizeToAlloc<swift::Operand, char>(TypeDependentOperands.size(),
- Var.Name.size());
+ Var ? Var->Name.size() : 0);
auto Buf = F.getModule().allocateInst(Sz, alignof(AllocBoxInst));
return ::new (Buf) AllocBoxInst(Loc, BoxType, TypeDependentOperands, F, Var);
}
-/// getDecl - Return the underlying variable declaration associated with this
-/// allocation, or null if this is a temporary allocation.
VarDecl *AllocBoxInst::getDecl() const {
return getLoc().getAsASTNode<VarDecl>();
}
@@ -273,7 +276,8 @@
}
DebugValueAddrInst::DebugValueAddrInst(SILDebugLocation DebugLoc,
- SILValue Operand, SILDebugVariable Var)
+ SILValue Operand,
+ SILDebugVariable Var)
: UnaryInstructionBase(DebugLoc, Operand),
VarInfo(Var, getTrailingObjects<char>()) {}
diff --git a/lib/SIL/SILModule.cpp b/lib/SIL/SILModule.cpp
index db0a944..f9d745e 100644
--- a/lib/SIL/SILModule.cpp
+++ b/lib/SIL/SILModule.cpp
@@ -310,6 +310,9 @@
if (Attrs.hasAttribute<SILGenNameAttr>() ||
Attrs.hasAttribute<CDeclAttr>())
F->setHasCReferences(true);
+
+ if (Attrs.hasAttribute<WeakLinkedAttr>())
+ F->setWeakLinked();
}
SILFunction *SILModule::getOrCreateFunction(SILLocation loc,
diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp
index 53fc058..4a9784e 100644
--- a/lib/SIL/SILOwnershipVerifier.cpp
+++ b/lib/SIL/SILOwnershipVerifier.cpp
@@ -170,20 +170,6 @@
// Utility
//===----------------------------------------------------------------------===//
-static bool compatibleOwnershipKinds(ValueOwnershipKind K1,
- ValueOwnershipKind K2) {
- return K1.merge(K2).hasValue();
-}
-
-/// Returns true if \p Kind is trivial or if \p Kind is compatible with \p
-/// ComparisonKind.
-static bool
-trivialOrCompatibleOwnershipKinds(ValueOwnershipKind Kind,
- ValueOwnershipKind ComparisonKind) {
- return compatibleOwnershipKinds(Kind, ValueOwnershipKind::Trivial) ||
- compatibleOwnershipKinds(Kind, ComparisonKind);
-}
-
static bool isValueAddressOrTrivial(SILValue V, SILModule &M) {
return V->getType().isAddress() ||
V.getOwnershipKind() == ValueOwnershipKind::Trivial ||
@@ -333,7 +319,7 @@
SILType getType() const { return Op.get()->getType(); }
bool compatibleWithOwnership(ValueOwnershipKind Kind) const {
- return compatibleOwnershipKinds(getOwnershipKind(), Kind);
+ return getOwnershipKind().isCompatibleWith(Kind);
}
bool hasExactOwnership(ValueOwnershipKind Kind) const {
@@ -1049,8 +1035,7 @@
} else {
lifetimeConstraint = UseLifetimeConstraint::MustBeLive;
}
- return {compatibleOwnershipKinds(ownership, RequiredKind),
- lifetimeConstraint};
+ return {ownership.isCompatibleWith(RequiredKind), lifetimeConstraint};
}
// We allow for trivial cases of enums with non-trivial cases to be passed in
@@ -1805,14 +1790,14 @@
// TODO: Add a flag that associates the terminator instruction with
// needing to be verified. If it isn't verified appropriately, assert
// when the verifier is destroyed.
- if (!trivialOrCompatibleOwnershipKinds(BBArg->getOwnershipKind(),
- OwnershipKind)) {
+ auto BBArgOwnershipKind = BBArg->getOwnershipKind();
+ if (!BBArgOwnershipKind.isTrivialOrCompatibleWith(OwnershipKind)) {
// This is where the error would go.
continue;
}
// If we have a trivial value, just continue.
- if (BBArg->getOwnershipKind() == ValueOwnershipKind::Trivial)
+ if (BBArgOwnershipKind == ValueOwnershipKind::Trivial)
continue;
// Otherwise,
@@ -1921,11 +1906,16 @@
if (!isValueAddressOrTrivial(Value, Mod)) {
return !handleError([&] {
- llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n"
- << "Non trivial values, non address values, and non "
- "guaranteed function args must have at least one "
- "lifetime ending use?!\n"
- << "Value: " << *Value << '\n';
+ llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n";
+ if (Value.getOwnershipKind() == ValueOwnershipKind::Owned) {
+ llvm::errs() << "Error! Found a leaked owned value that was never "
+ "consumed.\n";
+ } else {
+ llvm::errs() << "Non trivial values, non address values, and non "
+ "guaranteed function args must have at least one "
+ "lifetime ending use?!\n";
+ }
+ llvm::errs() << "Value: " << *Value << '\n';
});
}
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index 2333b6c..39e8c6d 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -1013,16 +1013,16 @@
}
}
- void printDebugVar(SILDebugVariable Var) {
- if (Var.Name.empty())
+ void printDebugVar(Optional<SILDebugVariable> Var) {
+ if (!Var || Var->Name.empty())
return;
- if (Var.Constant)
+ if (Var->Constant)
*this << ", let";
else
*this << ", var";
- *this << ", name \"" << Var.Name << '"';
- if (Var.ArgNo)
- *this << ", argno " << Var.ArgNo;
+ *this << ", name \"" << Var->Name << '"';
+ if (Var->ArgNo)
+ *this << ", argno " << Var->ArgNo;
}
void visitAllocStackInst(AllocStackInst *AVI) {
@@ -2280,7 +2280,9 @@
if (isGlobalInit())
OS << "[global_init] ";
-
+ if (isWeakLinked())
+ OS << "[_weakLinked] ";
+
switch (getInlineStrategy()) {
case NoInline: OS << "[noinline] "; break;
case AlwaysInline: OS << "[always_inline] "; break;
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index eca1743..d08c0a0 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -474,30 +474,31 @@
// that accidentally remove inline information (stored in the SILDebugScope)
// from debug-variable-carrying instructions.
if (!DS->InlinedCallSite) {
- SILDebugVariable VarInfo;
- if (auto *DI = dyn_cast<AllocStackInst>(I)) {
+ Optional<SILDebugVariable> VarInfo;
+ if (auto *DI = dyn_cast<AllocStackInst>(I))
VarInfo = DI->getVarInfo();
- } else if (auto *DI = dyn_cast<AllocBoxInst>(I)) {
+ else if (auto *DI = dyn_cast<AllocBoxInst>(I))
VarInfo = DI->getVarInfo();
- } else if (auto *DI = dyn_cast<DebugValueInst>(I)) {
+ else if (auto *DI = dyn_cast<DebugValueInst>(I))
VarInfo = DI->getVarInfo();
- } else if (auto *DI = dyn_cast<DebugValueAddrInst>(I)) {
+ else if (auto *DI = dyn_cast<DebugValueAddrInst>(I))
VarInfo = DI->getVarInfo();
- }
- if (unsigned ArgNo = VarInfo.ArgNo) {
- // It is a function argument.
- if (ArgNo < DebugVars.size() && !DebugVars[ArgNo].empty()) {
- require(DebugVars[ArgNo] == VarInfo.Name,
- "Scope contains conflicting debug variables for one function "
- "argument");
- } else {
- // Reserve enough space.
- while (DebugVars.size() <= ArgNo) {
- DebugVars.push_back(StringRef());
+ if (VarInfo)
+ if (unsigned ArgNo = VarInfo->ArgNo) {
+ // It is a function argument.
+ if (ArgNo < DebugVars.size() && !DebugVars[ArgNo].empty()) {
+ require(
+ DebugVars[ArgNo] == VarInfo->Name,
+ "Scope contains conflicting debug variables for one function "
+ "argument");
+ } else {
+ // Reserve enough space.
+ while (DebugVars.size() <= ArgNo) {
+ DebugVars.push_back(StringRef());
+ }
}
- }
- DebugVars[ArgNo] = VarInfo.Name;
+ DebugVars[ArgNo] = VarInfo->Name;
}
}
@@ -3462,8 +3463,12 @@
if (dest->getArguments().size() == 1) {
SILType eltArgTy = uTy.getEnumElementType(elt, F.getModule());
SILType bbArgTy = dest->getArguments()[0]->getType();
- require(eltArgTy == bbArgTy,
- "switch_enum destination bbarg must match case arg type");
+ if (F.getModule().getStage() != SILStage::Lowered) {
+ // During the lowered stage, a function type might have different
+ // signature
+ require(eltArgTy == bbArgTy,
+ "switch_enum destination bbarg must match case arg type");
+ }
require(!dest->getArguments()[0]->getType().isAddress(),
"switch_enum destination bbarg type must not be an address");
}
diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp
index 4d2ee227..e3be135 100644
--- a/lib/SILGen/SILGen.cpp
+++ b/lib/SILGen/SILGen.cpp
@@ -707,9 +707,7 @@
emitAbstractFuncDecl(fd);
if (hasSILBody(fd)) {
- UnifiedStatsReporter::FrontendStatsTracer Tracer;
- if (getASTContext().Stats)
- Tracer = getASTContext().Stats->getStatsTracer("emit-SIL", fd);
+ FrontendStatsTracer Tracer(getASTContext().Stats, "emit-SIL", fd);
PrettyStackTraceDecl stackTrace("emitting SIL for", fd);
SILDeclRef constant(decl);
diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp
index d4663cc..d2aa8ad 100644
--- a/lib/SILGen/SILGenConstructor.cpp
+++ b/lib/SILGen/SILGenConstructor.cpp
@@ -588,8 +588,9 @@
// Emit the prolog for the non-self arguments.
// FIXME: Handle self along with the other body patterns.
- emitProlog(ctor->getParameterList(1),
- TupleType::getEmpty(F.getASTContext()), ctor, ctor->hasThrows());
+ uint16_t ArgNo = emitProlog(ctor->getParameterList(1),
+ TupleType::getEmpty(F.getASTContext()), ctor,
+ ctor->hasThrows());
SILType selfTy = getLoweredLoadableType(selfDecl->getType());
ManagedValue selfArg = B.createFunctionArgument(selfTy, selfDecl);
@@ -597,7 +598,8 @@
if (!NeedsBoxForSelf) {
SILLocation PrologueLoc(selfDecl);
PrologueLoc.markAsPrologue();
- B.createDebugValue(PrologueLoc, selfArg.getValue());
+ SILDebugVariable DbgVar(selfDecl->isLet(), ++ArgNo);
+ B.createDebugValue(PrologueLoc, selfArg.getValue(), DbgVar);
}
if (!ctor->hasStubImplementation()) {
@@ -1035,7 +1037,9 @@
SILValue selfArg = F.begin()->createFunctionArgument(selfTy, selfDecl);
SILLocation PrologueLoc(selfDecl);
PrologueLoc.markAsPrologue();
- B.createDebugValue(PrologueLoc, selfArg);
+ // Hard-code self as argument number 1.
+ SILDebugVariable DbgVar(selfDecl->isLet(), 1);
+ B.createDebugValue(PrologueLoc, selfArg, DbgVar);
selfArg = B.createMarkUninitialized(selfDecl, selfArg,
MarkUninitializedInst::RootSelf);
assert(selfTy.hasReferenceSemantics() && "can't emit a value type ctor here");
diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp
index 9597e69..af78cf4 100644
--- a/lib/SILGen/SILGenDecl.cpp
+++ b/lib/SILGen/SILGenDecl.cpp
@@ -385,7 +385,7 @@
/// initialization is completed.
LocalVariableInitialization(VarDecl *decl,
Optional<MarkUninitializedInst::Kind> kind,
- unsigned ArgNo, SILGenFunction &SGF)
+ uint16_t ArgNo, SILGenFunction &SGF)
: decl(decl), SGF(SGF) {
assert(decl->getDeclContext()->isLocalContext() &&
"can't emit a local var for a non-local var decl");
@@ -400,8 +400,8 @@
// The variable may have its lifetime extended by a closure, heap-allocate
// it using a box.
- SILValue allocBox =
- SGF.B.createAllocBox(decl, boxType, {decl->isLet(), ArgNo});
+ SILDebugVariable DbgVar(decl->isLet(), ArgNo);
+ SILValue allocBox = SGF.B.createAllocBox(decl, boxType, DbgVar);
// Mark the memory as uninitialized, so DI will track it for us.
if (kind)
@@ -577,10 +577,11 @@
// lifetime.
SILLocation PrologueLoc(vd);
PrologueLoc.markAsPrologue();
+ SILDebugVariable DbgVar(vd->isLet(), /*ArgNo=*/0);
if (address)
- SGF.B.createDebugValueAddr(PrologueLoc, value);
+ SGF.B.createDebugValueAddr(PrologueLoc, value, DbgVar);
else
- SGF.B.createDebugValue(PrologueLoc, value);
+ SGF.B.createDebugValue(PrologueLoc, value, DbgVar);
}
void copyOrInitValueInto(SILGenFunction &SGF, SILLocation loc,
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index d8f5248..2c3ae77 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -1409,7 +1409,10 @@
SILValue SILGenFunction::emitTemporaryAllocation(SILLocation loc,
SILType ty) {
ty = ty.getObjectType();
- auto alloc = B.createAllocStack(loc, ty);
+ Optional<SILDebugVariable> DbgVar;
+ if (auto *VD = loc.getAsASTNode<VarDecl>())
+ DbgVar = SILDebugVariable(VD->isLet(), 0);
+ auto alloc = B.createAllocStack(loc, ty, DbgVar);
enterDeallocStackCleanup(alloc);
return alloc;
}
diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h
index 7372b1e..3b18174 100644
--- a/lib/SILGen/SILGenFunction.h
+++ b/lib/SILGen/SILGenFunction.h
@@ -661,7 +661,7 @@
ArrayRef<ParameterList *> paramPatterns, Type resultType,
bool throws);
/// returns the number of variables in paramPatterns.
- unsigned emitProlog(ArrayRef<ParameterList *> paramPatterns, Type resultType,
+ uint16_t emitProlog(ArrayRef<ParameterList *> paramPatterns, Type resultType,
DeclContext *DeclCtx, bool throws);
/// Create SILArguments in the entry block that bind all the values
diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp
index 6f7956f..3f25973 100644
--- a/lib/SILGen/SILGenPattern.cpp
+++ b/lib/SILGen/SILGenPattern.cpp
@@ -1679,6 +1679,111 @@
[&] { (*innerFailure)(loc); }, rows[0].Count);
}
+namespace {
+ struct CaseInfo {
+ EnumElementDecl *FormalElement;
+ Pattern *FirstMatcher;
+ bool Irrefutable = false;
+ SmallVector<SpecializedRow, 2> SpecializedRows;
+ };
+} // end anonymous namespace
+
+/// Create destination blocks for switching over the cases in an enum defined
+/// by \p rows.
+static void generateEnumCaseBlocks(
+ SILGenFunction &SGF,
+ ArrayRef<RowToSpecialize> rows,
+ CanType sourceType,
+ SILBasicBlock *curBB,
+ SmallVectorImpl<std::pair<EnumElementDecl *, SILBasicBlock *>> &caseBBs,
+ SmallVectorImpl<ProfileCounter> &caseCounts,
+ SmallVectorImpl<CaseInfo> &caseInfos,
+ SILBasicBlock *&defaultBB) {
+
+ assert(caseBBs.empty());
+ assert(caseCounts.empty());
+ assert(caseInfos.empty());
+ assert(defaultBB == nullptr);
+
+ caseBBs.reserve(rows.size());
+ caseInfos.reserve(rows.size());
+
+ auto enumDecl = sourceType.getEnumOrBoundGenericEnum();
+
+ llvm::SmallDenseMap<EnumElementDecl *, unsigned, 16> caseToIndex;
+ for (auto &row : rows) {
+ EnumElementDecl *formalElt;
+ Pattern *subPattern = nullptr;
+ if (auto eep = dyn_cast<EnumElementPattern>(row.Pattern)) {
+ formalElt = eep->getElementDecl();
+ subPattern = eep->getSubPattern();
+ } else {
+ auto *osp = cast<OptionalSomePattern>(row.Pattern);
+ formalElt = osp->getElementDecl();
+ subPattern = osp->getSubPattern();
+ }
+ auto elt = SGF.SGM.getLoweredEnumElementDecl(formalElt);
+ assert(elt->getParentEnum() == enumDecl);
+
+ unsigned index = caseInfos.size();
+ auto insertionResult = caseToIndex.insert({elt, index});
+ if (!insertionResult.second) {
+ index = insertionResult.first->second;
+ } else {
+ curBB = SGF.createBasicBlock(curBB);
+ caseBBs.push_back({elt, curBB});
+ caseInfos.push_back(CaseInfo());
+ caseInfos.back().FormalElement = formalElt;
+ caseInfos.back().FirstMatcher = row.Pattern;
+ caseCounts.push_back(row.Count);
+ }
+ assert(caseToIndex[elt] == index);
+ assert(caseBBs[index].first == elt);
+
+ auto &info = caseInfos[index];
+ info.Irrefutable = (info.Irrefutable || row.Irrefutable);
+ info.SpecializedRows.push_back(SpecializedRow());
+ auto &specRow = info.SpecializedRows.back();
+ specRow.RowIndex = row.RowIndex;
+
+ // Use the row pattern, if it has one.
+ if (subPattern) {
+ specRow.Patterns.push_back(subPattern);
+ // It's also legal to write:
+ // case .Some { ... }
+ // which is an implicit wildcard.
+ } else {
+ specRow.Patterns.push_back(nullptr);
+ }
+ }
+
+ assert(caseBBs.size() == caseInfos.size());
+
+ // Check to see if the enum may have values beyond the cases we can see
+ // at compile-time. This includes future cases (for resilient enums) and
+ // random values crammed into C enums.
+ //
+ // Note: This relies on the fact that there are no "non-resilient" enums that
+ // are still non-exhaustive, except for @objc enums.
+ bool canAssumeExhaustive = !enumDecl->isObjC();
+ if (canAssumeExhaustive) {
+ canAssumeExhaustive =
+ !enumDecl->isResilient(SGF.SGM.SwiftModule,
+ SGF.F.getResilienceExpansion());
+ }
+ if (canAssumeExhaustive) {
+ // Check that Sema didn't let any cases slip through. (This can happen
+ // with @_downgrade_exhaustivity_check.)
+ canAssumeExhaustive = llvm::all_of(enumDecl->getAllElements(),
+ [&](const EnumElementDecl *elt) {
+ return caseToIndex.count(elt);
+ });
+ }
+
+ if (!canAssumeExhaustive)
+ defaultBB = SGF.createBasicBlock(curBB);
+}
+
/// Perform specialized dispatch for a sequence of EnumElementPattern or an
/// OptionalSomePattern.
void PatternMatchEmission::emitEnumElementDispatchWithOwnership(
@@ -1690,102 +1795,25 @@
CanType sourceType = rows[0].Pattern->getType()->getCanonicalType();
- struct CaseInfo {
- EnumElementDecl *FormalElement;
- Pattern *FirstMatcher;
- bool Irrefutable = false;
- SmallVector<SpecializedRow, 2> SpecializedRows;
- };
-
- SILBasicBlock *curBB = SGF.B.getInsertionBB();
-
// Collect the cases and specialized rows.
//
// These vectors are completely parallel, but the switch
// instructions want only the first information, so we split them up.
SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 4> caseBBs;
+ SmallVector<ProfileCounter, 4> caseCounts;
SmallVector<CaseInfo, 4> caseInfos;
SILBasicBlock *defaultBB = nullptr;
- caseBBs.reserve(rows.size());
- caseInfos.reserve(rows.size());
-
- {
- // Create destination blocks for all the cases.
- llvm::DenseMap<EnumElementDecl *, unsigned> caseToIndex;
- for (auto &row : rows) {
- EnumElementDecl *formalElt;
- Pattern *subPattern = nullptr;
- if (auto eep = dyn_cast<EnumElementPattern>(row.Pattern)) {
- formalElt = eep->getElementDecl();
- subPattern = eep->getSubPattern();
- } else {
- auto *osp = cast<OptionalSomePattern>(row.Pattern);
- formalElt = osp->getElementDecl();
- subPattern = osp->getSubPattern();
- }
- auto elt = SGF.SGM.getLoweredEnumElementDecl(formalElt);
-
- unsigned index = caseInfos.size();
- auto insertionResult = caseToIndex.insert({elt, index});
- if (!insertionResult.second) {
- index = insertionResult.first->second;
- } else {
- curBB = SGF.createBasicBlock(curBB);
- caseBBs.push_back({elt, curBB});
- caseInfos.resize(caseInfos.size() + 1);
- caseInfos.back().FormalElement = formalElt;
- caseInfos.back().FirstMatcher = row.Pattern;
- }
- assert(caseToIndex[elt] == index);
- assert(caseBBs[index].first == elt);
-
- auto &info = caseInfos[index];
- info.Irrefutable = (info.Irrefutable || row.Irrefutable);
- info.SpecializedRows.resize(info.SpecializedRows.size() + 1);
- auto &specRow = info.SpecializedRows.back();
- specRow.RowIndex = row.RowIndex;
-
- // Use the row pattern, if it has one.
- if (subPattern) {
- specRow.Patterns.push_back(subPattern);
- // It's also legal to write:
- // case .Some { ... }
- // which is an implicit wildcard.
- } else {
- specRow.Patterns.push_back(nullptr);
- }
- }
-
- // We always need a default block if the enum is resilient.
- // If the enum is @_fixed_layout, we only need one if the
- // switch is not exhaustive.
- bool exhaustive = false;
- auto enumDecl = sourceType.getEnumOrBoundGenericEnum();
-
- if (!enumDecl->isResilient(SGF.SGM.M.getSwiftModule(),
- SGF.F.getResilienceExpansion())) {
- exhaustive = true;
-
- for (auto elt : enumDecl->getAllElements()) {
- if (!caseToIndex.count(elt)) {
- exhaustive = false;
- break;
- }
- }
- }
-
- if (!exhaustive)
- defaultBB = SGF.createBasicBlock(curBB);
- }
-
- assert(caseBBs.size() == caseInfos.size());
+ generateEnumCaseBlocks(SGF, rows, sourceType, SGF.B.getInsertionBB(),
+ caseBBs, caseCounts, caseInfos, defaultBB);
SILLocation loc = PatternMatchStmt;
loc.setDebugLoc(rows[0].Pattern);
// SEMANTIC SIL TODO: Once we have the representation of a switch_enum that
// can take a +0 value, this extra copy should be a borrow.
SILValue srcValue = src.getFinalManagedValue().copy(SGF, loc).forward(SGF);
+ // FIXME: Pass caseCounts in here as well, as it is in
+ // emitEnumElementDispatch.
SGF.B.createSwitchEnum(loc, srcValue, defaultBB, caseBBs);
// Okay, now emit all the cases.
@@ -1910,15 +1938,6 @@
CanType sourceType = rows[0].Pattern->getType()->getCanonicalType();
- struct CaseInfo {
- EnumElementDecl *FormalElement;
- Pattern *FirstMatcher;
- bool Irrefutable = false;
- SmallVector<SpecializedRow, 2> SpecializedRows;
- };
-
- SILBasicBlock *curBB = SGF.B.getInsertionBB();
-
// Collect the cases and specialized rows.
//
// These vectors are completely parallel, but the switch
@@ -1928,80 +1947,8 @@
SmallVector<ProfileCounter, 4> caseCounts;
SILBasicBlock *defaultBB = nullptr;
- caseBBs.reserve(rows.size());
- caseInfos.reserve(rows.size());
-
- {
- // Create destination blocks for all the cases.
- llvm::DenseMap<EnumElementDecl*, unsigned> caseToIndex;
- for (auto &row : rows) {
- EnumElementDecl *formalElt;
- Pattern *subPattern = nullptr;
- if (auto eep = dyn_cast<EnumElementPattern>(row.Pattern)) {
- formalElt = eep->getElementDecl();
- subPattern = eep->getSubPattern();
- } else {
- auto *osp = cast<OptionalSomePattern>(row.Pattern);
- formalElt = osp->getElementDecl();
- subPattern = osp->getSubPattern();
- }
- auto elt = SGF.SGM.getLoweredEnumElementDecl(formalElt);
-
- unsigned index = caseInfos.size();
- auto insertionResult = caseToIndex.insert({elt, index});
- if (!insertionResult.second) {
- index = insertionResult.first->second;
- } else {
- curBB = SGF.createBasicBlock(curBB);
- caseBBs.push_back({elt, curBB});
- caseInfos.resize(caseInfos.size() + 1);
- caseInfos.back().FormalElement = formalElt;
- caseInfos.back().FirstMatcher = row.Pattern;
- caseCounts.push_back(row.Count);
- }
- assert(caseToIndex[elt] == index);
- assert(caseBBs[index].first == elt);
-
- auto &info = caseInfos[index];
- info.Irrefutable = (info.Irrefutable || row.Irrefutable);
- info.SpecializedRows.resize(info.SpecializedRows.size() + 1);
- auto &specRow = info.SpecializedRows.back();
- specRow.RowIndex = row.RowIndex;
-
- // Use the row pattern, if it has one.
- if (subPattern) {
- specRow.Patterns.push_back(subPattern);
- // It's also legal to write:
- // case .Some { ... }
- // which is an implicit wildcard.
- } else {
- specRow.Patterns.push_back(nullptr);
- }
- }
-
- // We always need a default block if the enum is resilient.
- // If the enum is @_fixed_layout, we only need one if the
- // switch is not exhaustive.
- bool exhaustive = false;
- auto enumDecl = sourceType.getEnumOrBoundGenericEnum();
-
- if (!enumDecl->isResilient(SGF.SGM.M.getSwiftModule(),
- SGF.F.getResilienceExpansion())) {
- exhaustive = true;
-
- for (auto elt : enumDecl->getAllElements()) {
- if (!caseToIndex.count(elt)) {
- exhaustive = false;
- break;
- }
- }
- }
-
- if (!exhaustive)
- defaultBB = SGF.createBasicBlock(curBB);
- }
-
- assert(caseBBs.size() == caseInfos.size());
+ generateEnumCaseBlocks(SGF, rows, sourceType, SGF.B.getInsertionBB(),
+ caseBBs, caseCounts, caseInfos, defaultBB);
// Emit the switch_enum{_addr} instruction.
bool addressOnlyEnum = src.getType().isAddress();
@@ -2600,17 +2547,21 @@
DEBUG(llvm::dbgs() << "emitting switch stmt\n";
S->print(llvm::dbgs());
llvm::dbgs() << '\n');
- auto failure = [&](SILLocation location) {
- // If we fail to match anything, we can just emit unreachable.
- // This will be a dataflow error if we can reach here.
- B.createUnreachable(S);
+ auto failure = [this](SILLocation location) {
+ // If we fail to match anything, we trap. This can happen with a switch
+ // over an @objc enum, which may contain any value of its underlying type.
+ // FIXME: Even if we can't say what the invalid value was, we should at
+ // least mention that this was because of a non-exhaustive enum.
+ B.createBuiltinTrap(location);
+ B.createUnreachable(location);
};
// If the subject expression is uninhabited, we're already dead.
// Emit an unreachable in place of the switch statement.
if (S->getSubjectExpr()->getType()->isStructurallyUninhabited()) {
emitIgnoredExpr(S->getSubjectExpr());
- return failure(SILLocation(S));
+ B.createUnreachable(S);
+ return;
}
auto completionHandler = [&](PatternMatchEmission &emission,
diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp
index 15d5a37..8953613 100644
--- a/lib/SILGen/SILGenProlog.cpp
+++ b/lib/SILGen/SILGenProlog.cpp
@@ -28,8 +28,9 @@
VarLocs[selfDecl] = VarLoc::get(selfValue);
SILLocation PrologueLoc(selfDecl);
PrologueLoc.markAsPrologue();
- unsigned ArgNo = 1; // Hardcoded for destructors.
- B.createDebugValue(PrologueLoc, selfValue, {selfDecl->isLet(), ArgNo});
+ uint16_t ArgNo = 1; // Hardcoded for destructors.
+ B.createDebugValue(PrologueLoc, selfValue,
+ SILDebugVariable(selfDecl->isLet(), ArgNo));
return selfValue;
}
@@ -226,7 +227,7 @@
/// An ArrayRef that we use in our SILParameterList queue. Parameters are
/// sliced off of the front as they're emitted.
ArrayRef<SILParameterInfo> parameters;
- unsigned ArgNo = 0;
+ uint16_t ArgNo = 0;
ArgumentInitHelper(SILGenFunction &SGF, SILFunction &f)
: SGF(SGF), f(f), initB(SGF.B),
@@ -265,7 +266,8 @@
if (isa<BuiltinUnsafeValueBufferType>(objectType)) {
// FIXME: mark a debug location?
SGF.VarLocs[vd] = SILGenFunction::VarLoc::get(address);
- SGF.B.createDebugValueAddr(loc, address, {vd->isLet(), ArgNo});
+ SGF.B.createDebugValueAddr(loc, address,
+ SILDebugVariable(vd->isLet(), ArgNo));
return;
}
assert(argrv.getType().isAddress() && "expected inout to be address");
@@ -289,9 +291,11 @@
}
SGF.VarLocs[vd] = SILGenFunction::VarLoc::get(argrv.getValue());
if (argrv.getType().isAddress())
- SGF.B.createDebugValueAddr(loc, argrv.getValue(), {vd->isLet(), ArgNo});
+ SGF.B.createDebugValueAddr(loc, argrv.getValue(),
+ SILDebugVariable(vd->isLet(), ArgNo));
else
- SGF.B.createDebugValue(loc, argrv.getValue(), {vd->isLet(), ArgNo});
+ SGF.B.createDebugValue(loc, argrv.getValue(),
+ SILDebugVariable(vd->isLet(), ArgNo));
}
void emitParam(ParamDecl *PD) {
@@ -330,9 +334,11 @@
SILLocation loc(PD);
loc.markAsPrologue();
if (argrv.getType().isAddress())
- SGF.B.createDebugValueAddr(loc, argrv.getValue(), {PD->isLet(), ArgNo});
+ SGF.B.createDebugValueAddr(loc, argrv.getValue(),
+ SILDebugVariable(PD->isLet(), ArgNo));
else
- SGF.B.createDebugValue(loc, argrv.getValue(), {PD->isLet(), ArgNo});
+ SGF.B.createDebugValue(loc, argrv.getValue(),
+ SILDebugVariable(PD->isLet(), ArgNo));
}
};
} // end anonymous namespace
@@ -367,7 +373,7 @@
static void emitCaptureArguments(SILGenFunction &SGF,
AnyFunctionRef closure,
CapturedValue capture,
- unsigned ArgNo) {
+ uint16_t ArgNo) {
auto *VD = capture.getDecl();
SILLocation Loc(VD);
@@ -410,8 +416,10 @@
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(val);
if (auto *AllocStack = dyn_cast<AllocStackInst>(val))
AllocStack->setArgNo(ArgNo);
- else
- SGF.B.createDebugValue(Loc, val, {/*Constant*/true, ArgNo});
+ else {
+ SILDebugVariable DbgVar(/*Constant*/ true, ArgNo);
+ SGF.B.createDebugValue(Loc, val, DbgVar);
+ }
// TODO: Closure contexts should always be guaranteed.
if (NeedToDestroyValueAtExit && !lowering.isTrivial())
@@ -430,7 +438,8 @@
SILType::getPrimitiveObjectType(boxTy), VD);
SILValue addr = SGF.B.createProjectBox(VD, box, 0);
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(addr, box);
- SGF.B.createDebugValueAddr(Loc, addr, {/*Constant*/false, ArgNo});
+ SILDebugVariable DbgVar(/*Constant*/ false, ArgNo);
+ SGF.B.createDebugValueAddr(Loc, addr, DbgVar);
break;
}
case CaptureKind::StorageAddress: {
@@ -439,7 +448,8 @@
SILType ty = SGF.getLoweredType(type).getAddressType();
SILValue addr = SGF.F.begin()->createFunctionArgument(ty, VD);
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(addr);
- SGF.B.createDebugValueAddr(Loc, addr, {/*Constant*/true, ArgNo});
+ SILDebugVariable DbgVar(/*Constant*/ true, ArgNo);
+ SGF.B.createDebugValueAddr(Loc, addr, DbgVar);
break;
}
}
@@ -448,7 +458,7 @@
void SILGenFunction::emitProlog(AnyFunctionRef TheClosure,
ArrayRef<ParameterList*> paramPatterns,
Type resultType, bool throws) {
- unsigned ArgNo = emitProlog(paramPatterns, resultType,
+ uint16_t ArgNo = emitProlog(paramPatterns, resultType,
TheClosure.getAsDeclContext(), throws);
// Emit the capture argument variables. These are placed last because they
@@ -500,7 +510,7 @@
(void)arg;
}
-unsigned SILGenFunction::emitProlog(ArrayRef<ParameterList *> paramLists,
+uint16_t SILGenFunction::emitProlog(ArrayRef<ParameterList *> paramLists,
Type resultType, DeclContext *DC,
bool throws) {
// Create the indirect result parameters.
@@ -529,8 +539,8 @@
Loc = ACE->getLoc();
auto NativeErrorTy = SILType::getExceptionType(getASTContext());
ManagedValue Undef = emitUndef(Loc, NativeErrorTy);
- B.createDebugValue(Loc, Undef.getValue(),
- {"$error", /*Constant*/ false, ++ArgNo});
+ SILDebugVariable DbgVar("$error", /*Constant*/ false, ++ArgNo);
+ B.createDebugValue(Loc, Undef.getValue(), DbgVar);
}
return ArgNo;
diff --git a/lib/SILOptimizer/IPO/CapturePromotion.cpp b/lib/SILOptimizer/IPO/CapturePromotion.cpp
index 8b4a0ab..16fa827 100644
--- a/lib/SILOptimizer/IPO/CapturePromotion.cpp
+++ b/lib/SILOptimizer/IPO/CapturePromotion.cpp
@@ -521,7 +521,7 @@
void ClosureCloner::visitDebugValueAddrInst(DebugValueAddrInst *Inst) {
if (SILValue Val = getProjectBoxMappedVal(Inst->getOperand())) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
- getBuilder().createDebugValue(Inst->getLoc(), Val, Inst->getVarInfo());
+ getBuilder().createDebugValue(Inst->getLoc(), Val, *Inst->getVarInfo());
return;
}
SILCloner<ClosureCloner>::visitDebugValueAddrInst(Inst);
diff --git a/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp b/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp
index 44d360f..b6bc09a 100644
--- a/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp
+++ b/lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp
@@ -36,7 +36,7 @@
// This is currently unsupported because tail duplication results in
// address-type block arguments.
llvm::cl::opt<bool> EnableOptimizedAccessMarkers(
- "sil-optimized-access-markers", llvm::cl::init(false),
+ "sil-optimized-access-markers", llvm::cl::init(true),
llvm::cl::desc("Enable memory access markers during optimization passes."));
namespace {
diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.cpp b/lib/SILOptimizer/Mandatory/AddressLowering.cpp
index 4d2d128..351da23 100644
--- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp
+++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp
@@ -1221,7 +1221,8 @@
void visitDebugValueInst(DebugValueInst *debugInst) {
SILValue srcVal = debugInst->getOperand();
SILValue srcAddr = pass.valueStorageMap.getStorage(srcVal).storageAddress;
- B.createDebugValueAddr(debugInst->getLoc(), srcAddr);
+ B.createDebugValueAddr(debugInst->getLoc(), srcAddr,
+ *debugInst->getVarInfo());
pass.markDead(debugInst);
}
diff --git a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
index 4375a1e..a7d52cb 100644
--- a/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
+++ b/lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp
@@ -155,7 +155,7 @@
auto Args = PAI->getArguments();
Params = Params.drop_front(Params.size() - Args.size());
- llvm::SmallVector<std::pair<SILValue, unsigned>, 8> ArgsToHandle;
+ llvm::SmallVector<std::pair<SILValue, uint16_t>, 8> ArgsToHandle;
for (unsigned i : indices(Args)) {
SILValue Arg = Args[i];
SILParameterInfo Param = Params[i];
@@ -197,8 +197,8 @@
SILValue Arg = ArgWithIdx.first;
Builder.setInsertionPoint(PAI->getFunction()->begin()->begin());
// Create a new temporary at the beginning of a function.
- auto *Tmp = Builder.createAllocStack(PAI->getLoc(), Arg->getType(),
- {/*Constant*/ true, ArgWithIdx.second});
+ SILDebugVariable DbgVar(/*Constant*/ true, ArgWithIdx.second);
+ auto *Tmp = Builder.createAllocStack(PAI->getLoc(), Arg->getType(), DbgVar);
Builder.setInsertionPoint(PAI);
// Copy argument into this temporary.
Builder.createCopyAddr(PAI->getLoc(), Arg, Tmp,
diff --git a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp
index 7150dc4..cef6bb8 100644
--- a/lib/SILOptimizer/Transforms/SILMem2Reg.cpp
+++ b/lib/SILOptimizer/Transforms/SILMem2Reg.cpp
@@ -275,7 +275,7 @@
assert(Value && "Expected valid value");
B.setInsertionPoint(DVAI);
B.setCurrentDebugScope(DVAI->getDebugScope());
- B.createDebugValue(DVAI->getLoc(), Value, DVAI->getVarInfo());
+ B.createDebugValue(DVAI->getLoc(), Value, *DVAI->getVarInfo());
DVAI->eraseFromParent();
}
diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
index d210efb..f4e1981 100644
--- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
+++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp
@@ -3594,30 +3594,35 @@
namespace {
class SimplifyCFGPass : public SILFunctionTransform {
- bool EnableJumpThread;
-
public:
- SimplifyCFGPass(bool EnableJumpThread)
- : EnableJumpThread(EnableJumpThread) {}
-
- /// The entry point to the transformation.
void run() override {
if (SimplifyCFG(*getFunction(), PM, getOptions().VerifyAll,
- EnableJumpThread)
+ /*EnableJumpThread=*/false)
.run())
invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
}
-
};
} // end anonymous namespace
SILTransform *swift::createSimplifyCFG() {
- return new SimplifyCFGPass(false);
+ return new SimplifyCFGPass();
}
+namespace {
+class JumpThreadSimplifyCFGPass : public SILFunctionTransform {
+public:
+ void run() override {
+ if (SimplifyCFG(*getFunction(), PM, getOptions().VerifyAll,
+ /*EnableJumpThread=*/true)
+ .run())
+ invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
+ }
+};
+} // end anonymous namespace
+
SILTransform *swift::createJumpThreadSimplifyCFG() {
- return new SimplifyCFGPass(true);
+ return new JumpThreadSimplifyCFGPass();
}
//===----------------------------------------------------------------------===//
diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp
index 427a00e..e71d156 100644
--- a/lib/SILOptimizer/Utils/Devirtualize.cpp
+++ b/lib/SILOptimizer/Utils/Devirtualize.cpp
@@ -496,7 +496,8 @@
/// return true if it is possible to devirtualize, false - otherwise.
bool swift::canDevirtualizeClassMethod(FullApplySite AI,
SILType ClassOrMetatypeType,
- OptRemark::Emitter *ORE) {
+ OptRemark::Emitter *ORE,
+ bool isEffectivelyFinalMethod) {
DEBUG(llvm::dbgs() << " Trying to devirtualize : " << *AI.getInstruction());
@@ -519,6 +520,15 @@
return false;
}
+ // We need to disable the “effectively final” opt if a function is inlinable
+ if (isEffectivelyFinalMethod &&
+ F->getResilienceExpansion() == ResilienceExpansion::Minimal) {
+ DEBUG(llvm::dbgs() << " FAIL: Could not optimize function because "
+ "it is an effectively-final inlinable: "
+ << F->getName() << "\n");
+ return false;
+ }
+
// Mandatory inlining does class method devirtualization. I'm not sure if this
// is really needed, but some test rely on this.
// So even for Onone functions we have to do it if the SILStage is raw.
@@ -701,10 +711,12 @@
return std::make_pair(ResultValue, NewAI);
}
-DevirtualizationResult swift::tryDevirtualizeClassMethod(FullApplySite AI,
- SILValue ClassInstance,
- OptRemark::Emitter *ORE) {
- if (!canDevirtualizeClassMethod(AI, ClassInstance->getType(), ORE))
+DevirtualizationResult
+swift::tryDevirtualizeClassMethod(FullApplySite AI, SILValue ClassInstance,
+ OptRemark::Emitter *ORE,
+ bool isEffectivelyFinalMethod) {
+ if (!canDevirtualizeClassMethod(AI, ClassInstance->getType(), ORE,
+ isEffectivelyFinalMethod))
return std::make_pair(nullptr, FullApplySite());
return devirtualizeClassMethod(AI, ClassInstance, ORE);
}
@@ -1025,7 +1037,8 @@
auto *CD = ClassType.getClassOrBoundGenericClass();
if (isEffectivelyFinalMethod(FAS, ClassType, CD, CHA))
- return tryDevirtualizeClassMethod(FAS, Instance, ORE);
+ return tryDevirtualizeClassMethod(FAS, Instance, ORE,
+ true /*isEffectivelyFinalMethod*/);
// Try to check if the exact dynamic type of the instance is statically
// known.
@@ -1091,7 +1104,9 @@
auto *CD = ClassType.getClassOrBoundGenericClass();
if (isEffectivelyFinalMethod(AI, ClassType, CD, CHA))
- return canDevirtualizeClassMethod(AI, Instance->getType());
+ return canDevirtualizeClassMethod(AI, Instance->getType(),
+ nullptr /*ORE*/,
+ true /*isEffectivelyFinalMethod*/);
// Try to check if the exact dynamic type of the instance is statically
// known.
diff --git a/lib/SILOptimizer/Utils/GenericCloner.cpp b/lib/SILOptimizer/Utils/GenericCloner.cpp
index 51f6646..2f81eec 100644
--- a/lib/SILOptimizer/Utils/GenericCloner.cpp
+++ b/lib/SILOptimizer/Utils/GenericCloner.cpp
@@ -111,9 +111,10 @@
// Try to create a new debug_value from an existing debug_value_addr.
for (Operand *ArgUse : OrigArg->getUses()) {
if (auto *DVAI = dyn_cast<DebugValueAddrInst>(ArgUse->getUser())) {
- getBuilder().setCurrentDebugScope(remapScope(DVAI->getDebugScope()));
+ getBuilder().setCurrentDebugScope(
+ remapScope(DVAI->getDebugScope()));
getBuilder().createDebugValue(DVAI->getLoc(), NewArg,
- DVAI->getVarInfo());
+ *DVAI->getVarInfo());
getBuilder().setCurrentDebugScope(nullptr);
break;
}
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index e0b28f2..4484168 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -544,10 +544,11 @@
public:
/// \brief Build a reference to the given declaration.
- Expr *buildDeclRef(ValueDecl *decl, DeclNameLoc loc, Type openedType,
+ Expr *buildDeclRef(OverloadChoice choice, DeclNameLoc loc, Type openedType,
ConstraintLocatorBuilder locator, bool implicit,
FunctionRefKind functionRefKind,
AccessSemantics semantics) {
+ auto *decl = choice.getDecl();
// Determine the declaration selected for this overloaded reference.
auto &ctx = cs.getASTContext();
@@ -612,7 +613,7 @@
if (auto fnConv = dyn_cast<FunctionConversionExpr>(refExpr))
refExpr = fnConv->getSubExpr();
- return forceUnwrapIfExpected(refExpr, decl, locator);
+ return forceUnwrapIfExpected(refExpr, choice, locator);
}
}
}
@@ -623,7 +624,7 @@
TypeExpr::createImplicitHack(loc.getBaseNameLoc(), baseTy, ctx);
cs.cacheExprTypes(base);
- return buildMemberRef(base, openedType, SourceLoc(), decl, loc,
+ return buildMemberRef(base, openedType, SourceLoc(), choice, loc,
openedFnType->getResult(), locator, locator,
implicit, functionRefKind, semantics,
/*isDynamic=*/false);
@@ -659,7 +660,7 @@
loc, implicit, semantics, type);
cs.cacheType(declRefExpr);
declRefExpr->setFunctionRefKind(functionRefKind);
- return forceUnwrapIfExpected(declRefExpr, decl, locator);
+ return forceUnwrapIfExpected(declRefExpr, choice, locator);
}
/// Describes an opened existential that has not yet been closed.
@@ -899,11 +900,12 @@
/// \brief Build a new member reference with the given base and member.
Expr *buildMemberRef(Expr *base, Type openedFullType, SourceLoc dotLoc,
- ValueDecl *member, DeclNameLoc memberLoc,
+ OverloadChoice choice, DeclNameLoc memberLoc,
Type openedType, ConstraintLocatorBuilder locator,
ConstraintLocatorBuilder memberLocator, bool Implicit,
FunctionRefKind functionRefKind,
AccessSemantics semantics, bool isDynamic) {
+ ValueDecl *member = choice.getDecl();
auto &tc = cs.getTypeChecker();
auto &context = tc.Context;
@@ -949,7 +951,7 @@
ref->setFunctionRefKind(functionRefKind);
auto *DSBI = cs.cacheType(new (context) DotSyntaxBaseIgnoredExpr(
base, dotLoc, ref, cs.getType(ref)));
- return forceUnwrapIfExpected(DSBI, member, memberLocator);
+ return forceUnwrapIfExpected(DSBI, choice, memberLocator);
}
// The formal type of the 'self' value for the member's declaration.
@@ -1088,8 +1090,9 @@
// We also need to handle the implicitly unwrap of the result
// of the called function if that's the type checking solution
// we ended up with.
- return forceUnwrapIfExpected(ref, member, memberLocator,
- member->getAttrs().hasAttribute<OptionalAttr>());
+ return forceUnwrapIfExpected(
+ ref, choice, memberLocator,
+ member->getAttrs().hasAttribute<OptionalAttr>());
}
// For types and properties, build member references.
@@ -1115,7 +1118,7 @@
cs.setType(memberRefExpr, simplifyType(openedType));
Expr *result = memberRefExpr;
closeExistential(result, locator);
- return forceUnwrapIfExpected(result, member, memberLocator);
+ return forceUnwrapIfExpected(result, choice, memberLocator);
}
// Handle all other references.
@@ -1135,7 +1138,7 @@
ApplyExpr *apply;
if (isa<ConstructorDecl>(member)) {
// FIXME: Provide type annotation.
- ref = forceUnwrapIfExpected(ref, member, memberLocator);
+ ref = forceUnwrapIfExpected(ref, choice, memberLocator);
apply = new (context) ConstructorRefCallExpr(ref, base);
} else if (!baseIsInstance && member->isInstanceMember()) {
// Reference to an unbound instance method.
@@ -1144,11 +1147,11 @@
cs.getType(ref));
cs.cacheType(result);
closeExistential(result, locator, /*force=*/openedExistential);
- return forceUnwrapIfExpected(result, member, memberLocator);
+ return forceUnwrapIfExpected(result, choice, memberLocator);
} else {
assert((!baseIsInstance || member->isInstanceMember()) &&
"can't call a static method on an instance");
- ref = forceUnwrapIfExpected(ref, member, memberLocator);
+ ref = forceUnwrapIfExpected(ref, choice, memberLocator);
apply = new (context) DotSyntaxCallExpr(ref, dotLoc, base);
if (Implicit) {
apply->setImplicit();
@@ -1449,10 +1452,10 @@
if (selected->choice.getKind() ==
OverloadChoiceKind::DynamicMemberLookup)
locatorKind = ConstraintLocator::Member;
-
- newSubscript = forceUnwrapIfExpected(
- newSubscript, selected->choice.getDecl(),
- locator.withPathElement(locatorKind));
+
+ newSubscript =
+ forceUnwrapIfExpected(newSubscript, selected->choice,
+ locator.withPathElement(locatorKind));
}
return newSubscript;
@@ -2471,8 +2474,9 @@
}
}
- bool shouldForceUnwrapResult(Decl *decl, ConstraintLocatorBuilder locator) {
- if (!decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
+ bool shouldForceUnwrapResult(OverloadChoice choice,
+ ConstraintLocatorBuilder locator) {
+ if (!choice.isImplicitlyUnwrappedValueOrReturnValue())
return false;
auto *choiceLocator = cs.getConstraintLocator(locator.withPathElement(
@@ -2481,10 +2485,10 @@
return solution.getDisjunctionChoice(choiceLocator);
}
- Expr *forceUnwrapIfExpected(Expr *expr, Decl *decl,
+ Expr *forceUnwrapIfExpected(Expr *expr, OverloadChoice choice,
ConstraintLocatorBuilder locator,
- bool forForcedOptional =false) {
- if (!shouldForceUnwrapResult(decl, locator))
+ bool forForcedOptional = false) {
+ if (!shouldForceUnwrapResult(choice, locator))
return expr;
// Force the expression if required for the solution.
@@ -2503,12 +2507,9 @@
cs.setType(expr, varDecl->getType());
return expr;
}
-
- auto choice = selected->choice;
- auto decl = choice.getDecl();
- return buildDeclRef(decl, expr->getNameLoc(), selected->openedFullType,
- locator, expr->isImplicit(),
+ return buildDeclRef(selected->choice, expr->getNameLoc(),
+ selected->openedFullType, locator, expr->isImplicit(),
expr->getFunctionRefKind(),
expr->getAccessSemantics());
}
@@ -2539,9 +2540,8 @@
auto locator = cs.getConstraintLocator(expr);
auto selected = getOverloadChoice(locator);
auto choice = selected.choice;
- auto decl = choice.getDecl();
- return buildDeclRef(decl, expr->getNameLoc(), selected.openedFullType,
+ return buildDeclRef(choice, expr->getNameLoc(), selected.openedFullType,
locator, expr->isImplicit(),
choice.getFunctionRefKind(),
AccessSemantics::Ordinary);
@@ -2566,7 +2566,7 @@
= selected.choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
return buildMemberRef(
expr->getBase(), selected.openedFullType, expr->getDotLoc(),
- selected.choice.getDecl(), expr->getNameLoc(), selected.openedType,
+ selected.choice, expr->getNameLoc(), selected.openedType,
cs.getConstraintLocator(expr), memberLocator, expr->isImplicit(),
selected.choice.getFunctionRefKind(), expr->getAccessSemantics(),
isDynamic);
@@ -2594,7 +2594,6 @@
auto memberLocator = cs.getConstraintLocator(
expr, ConstraintLocator::UnresolvedMember);
auto selected = getOverloadChoice(memberLocator);
- auto member = selected.choice.getDecl();
// If the member came by optional unwrapping, then unwrap the base type.
if (selected.choice.getKind()
@@ -2614,7 +2613,7 @@
bool isDynamic
= selected.choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
auto result = buildMemberRef(
- base, selected.openedFullType, expr->getDotLoc(), member,
+ base, selected.openedFullType, expr->getDotLoc(), selected.choice,
expr->getNameLoc(), selected.openedType,
cs.getConstraintLocator(expr), memberLocator, expr->isImplicit(),
selected.choice.getFunctionRefKind(), AccessSemantics::Ordinary,
@@ -2651,9 +2650,10 @@
Expr *applyCtorRefExpr(Expr *expr, Expr *base, SourceLoc dotLoc,
DeclNameLoc nameLoc, bool implicit,
ConstraintLocator *ctorLocator,
- ConstructorDecl *ctor,
- FunctionRefKind functionRefKind,
- Type openedType) {
+ OverloadChoice choice,
+ FunctionRefKind functionRefKind, Type openedType) {
+
+ auto *ctor = cast<ConstructorDecl>(choice.getDecl());
// If the member is a constructor, verify that it can be legally
// referenced from this base.
@@ -2665,7 +2665,7 @@
// constructor.
if (cs.getType(base)->is<AnyMetatypeType>()) {
return buildMemberRef(
- base, openedType, dotLoc, ctor, nameLoc, cs.getType(expr),
+ base, openedType, dotLoc, choice, nameLoc, cs.getType(expr),
ConstraintLocatorBuilder(cs.getConstraintLocator(expr)),
ctorLocator, implicit, functionRefKind, AccessSemantics::Ordinary,
/*isDynamic=*/false);
@@ -2731,10 +2731,9 @@
ConstraintLocator::ConstructorMember);
if (auto selected = getOverloadChoiceIfAvailable(ctorLocator)) {
auto choice = selected->choice;
- auto *ctor = cast<ConstructorDecl>(choice.getDecl());
- return applyCtorRefExpr(expr, base, dotLoc, nameLoc, implicit,
- ctorLocator, ctor, choice.getFunctionRefKind(),
- selected->openedFullType);
+ return applyCtorRefExpr(
+ expr, base, dotLoc, nameLoc, implicit, ctorLocator, choice,
+ choice.getFunctionRefKind(), selected->openedFullType);
}
// Determine the declaration selected for this overloaded reference.
@@ -2783,11 +2782,11 @@
case OverloadChoiceKind::DeclViaDynamic: {
bool isDynamic
= selected.choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
- return buildMemberRef(
- base, selected.openedFullType, dotLoc, selected.choice.getDecl(),
- nameLoc, selected.openedType, cs.getConstraintLocator(expr),
- memberLocator, implicit, selected.choice.getFunctionRefKind(),
- AccessSemantics::Ordinary, isDynamic);
+ return buildMemberRef(base, selected.openedFullType, dotLoc,
+ selected.choice, nameLoc, selected.openedType,
+ cs.getConstraintLocator(expr), memberLocator,
+ implicit, selected.choice.getFunctionRefKind(),
+ AccessSemantics::Ordinary, isDynamic);
}
case OverloadChoiceKind::TupleIndex: {
@@ -4370,7 +4369,7 @@
baseTy = component.getComponentType();
resolvedComponents.push_back(component);
- if (shouldForceUnwrapResult(property, locator)) {
+ if (shouldForceUnwrapResult(foundDecl->choice, locator)) {
auto objectTy = getObjectType(baseTy);
auto loc = origComponent.getLoc();
component = KeyPathExpr::Component::forOptionalForce(objectTy, loc);
@@ -4451,7 +4450,7 @@
baseTy = component.getComponentType();
resolvedComponents.push_back(component);
- if (shouldForceUnwrapResult(subscript, locator)) {
+ if (shouldForceUnwrapResult(foundDecl->choice, locator)) {
auto objectTy = getObjectType(baseTy);
auto loc = origComponent.getLoc();
component = KeyPathExpr::Component::forOptionalForce(objectTy, loc);
@@ -7469,17 +7468,16 @@
// We have the constructor.
auto choice = selected->choice;
- auto decl = choice.getDecl();
// Consider the constructor decl reference expr 'implicit', but the
// constructor call expr itself has the apply's 'implicitness'.
bool isDynamic = choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
- Expr *declRef =
- buildMemberRef(fn, selected->openedFullType,
- /*dotLoc=*/SourceLoc(), decl, DeclNameLoc(fn->getEndLoc()),
- selected->openedType, locator, ctorLocator,
- /*Implicit=*/true, choice.getFunctionRefKind(),
- AccessSemantics::Ordinary, isDynamic);
+ Expr *declRef = buildMemberRef(fn, selected->openedFullType,
+ /*dotLoc=*/SourceLoc(), choice,
+ DeclNameLoc(fn->getEndLoc()),
+ selected->openedType, locator, ctorLocator,
+ /*Implicit=*/true, choice.getFunctionRefKind(),
+ AccessSemantics::Ordinary, isDynamic);
if (!declRef)
return nullptr;
declRef->setImplicit(apply->isImplicit());
@@ -8173,8 +8171,10 @@
ExprRewriter rewriter(cs, solution,
/*suppressDiagnostics=*/false);
+ auto choice =
+ OverloadChoice(openedFullType, witness, FunctionRefKind::SingleApply);
auto memberRef = rewriter.buildMemberRef(
- base, openedFullType, base->getStartLoc(), witness,
+ base, openedFullType, base->getStartLoc(), choice,
DeclNameLoc(base->getEndLoc()), openedType, dotLocator, dotLocator,
/*Implicit=*/true, FunctionRefKind::SingleApply,
AccessSemantics::Ordinary,
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index b6d248f..a421d3d 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -4640,10 +4640,12 @@
UncurriedCandidate cand = calleeInfo.candidates[0];
auto candType = baseType->getTypeOfMember(CS.DC->getParentModule(),
cand.getDecl(), nullptr);
- auto paramsType = candType->getAs<FunctionType>()->getInput();
- if (!typeCheckChildIndependently(indexExpr, paramsType,
- CTP_CallArgument, TCC_ForceRecheck))
- return true;
+ if (auto *candFunc = candType->getAs<FunctionType>()) {
+ auto paramsType = candFunc->getInput();
+ if (!typeCheckChildIndependently(
+ indexExpr, paramsType, CTP_CallArgument, TCC_ForceRecheck))
+ return true;
+ }
}
}
diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp
index 235f05f..188bb4b 100644
--- a/lib/Sema/CSSolver.cpp
+++ b/lib/Sema/CSSolver.cpp
@@ -1380,9 +1380,15 @@
}
if (TC.getLangOpts().DebugConstraintSolver) {
- auto getTypeOfExpr = [&](const Expr *E) -> Type { return getType(E); };
+ auto getTypeOfExpr = [&](const Expr *E) -> Type {
+ if (hasType(E))
+ return getType(E);
+ return Type();
+ };
auto getTypeOfTypeLoc = [&](const TypeLoc &TL) -> Type {
- return getType(TL);
+ if (hasType(TL))
+ return getType(TL);
+ return Type();
};
auto &log = getASTContext().TypeCheckerDebug->getStream();
diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp
index 7a0e1e7..62cfdfc 100644
--- a/lib/Sema/ConstraintSystem.cpp
+++ b/lib/Sema/ConstraintSystem.cpp
@@ -1957,6 +1957,23 @@
}
bool OverloadChoice::isImplicitlyUnwrappedValueOrReturnValue() const {
- return isDecl() &&
- getDecl()->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
+ if (!isDecl())
+ return false;
+
+ auto *decl = getDecl();
+ if (!decl->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>())
+ return false;
+
+ auto itfType = decl->getInterfaceType();
+ if (!itfType->getAs<AnyFunctionType>())
+ return true;
+
+ switch (getFunctionRefKind()) {
+ case FunctionRefKind::Unapplied:
+ case FunctionRefKind::Compound:
+ return false;
+ case FunctionRefKind::SingleApply:
+ case FunctionRefKind::DoubleApply:
+ return true;
+ }
}
diff --git a/lib/Sema/OverloadChoice.h b/lib/Sema/OverloadChoice.h
index 1752343..4e4afac 100644
--- a/lib/Sema/OverloadChoice.h
+++ b/lib/Sema/OverloadChoice.h
@@ -190,6 +190,7 @@
result.BaseAndDeclKind.setPointer(base);
result.DeclOrKind = value;
result.DynamicNameAndFRK.setPointer(name);
+ result.DynamicNameAndFRK.setInt(FunctionRefKind::SingleApply);
return result;
}
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index 6868372..c2e6c92 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -70,48 +70,49 @@
bool visitDeclAttribute(DeclAttribute *A) = delete;
#define IGNORED_ATTR(X) void visit##X##Attr(X##Attr *) {}
- IGNORED_ATTR(CDecl)
- IGNORED_ATTR(SILGenName)
IGNORED_ATTR(Available)
+ IGNORED_ATTR(CDecl)
+ IGNORED_ATTR(ClangImporterSynthesizedType)
IGNORED_ATTR(Convenience)
+ IGNORED_ATTR(DiscardableResult)
+ IGNORED_ATTR(DowngradeExhaustivityCheck)
+ IGNORED_ATTR(DynamicMemberLookup)
IGNORED_ATTR(Effects)
IGNORED_ATTR(Exported)
- IGNORED_ATTR(DynamicMemberLookup)
IGNORED_ATTR(FixedLayout)
+ IGNORED_ATTR(Implements)
+ IGNORED_ATTR(ImplicitlyUnwrappedOptional)
IGNORED_ATTR(Infix)
IGNORED_ATTR(Inline)
- IGNORED_ATTR(Optimize)
IGNORED_ATTR(Inlineable)
+ IGNORED_ATTR(NonObjC)
IGNORED_ATTR(NSApplicationMain)
IGNORED_ATTR(NSCopying)
- IGNORED_ATTR(NonObjC)
IGNORED_ATTR(ObjC)
IGNORED_ATTR(ObjCBridged)
IGNORED_ATTR(ObjCNonLazyRealization)
IGNORED_ATTR(ObjCRuntimeName)
- IGNORED_ATTR(RestatedObjCConformance)
+ IGNORED_ATTR(Optimize)
IGNORED_ATTR(Optional)
IGNORED_ATTR(Postfix)
IGNORED_ATTR(Prefix)
IGNORED_ATTR(RawDocComment)
IGNORED_ATTR(Required)
IGNORED_ATTR(RequiresStoredPropertyInits)
+ IGNORED_ATTR(RestatedObjCConformance)
IGNORED_ATTR(Rethrows)
IGNORED_ATTR(Semantics)
+ IGNORED_ATTR(ShowInInterface)
+ IGNORED_ATTR(SILGenName)
IGNORED_ATTR(Specialize)
+ IGNORED_ATTR(StaticInitializeObjCMetadata)
IGNORED_ATTR(SwiftNativeObjCRuntimeBase)
IGNORED_ATTR(SynthesizedProtocol)
IGNORED_ATTR(Testable)
IGNORED_ATTR(UIApplicationMain)
IGNORED_ATTR(UnsafeNoObjCTaggedPointer)
IGNORED_ATTR(Versioned)
- IGNORED_ATTR(ShowInInterface)
- IGNORED_ATTR(DiscardableResult)
- IGNORED_ATTR(Implements)
- IGNORED_ATTR(StaticInitializeObjCMetadata)
- IGNORED_ATTR(DowngradeExhaustivityCheck)
- IGNORED_ATTR(ImplicitlyUnwrappedOptional)
- IGNORED_ATTR(ClangImporterSynthesizedType)
+ IGNORED_ATTR(WeakLinked)
#undef IGNORED_ATTR
// @noreturn has been replaced with a 'Never' return type.
@@ -792,8 +793,10 @@
void visit##CLASS##Attr(CLASS##Attr *) {}
IGNORED_ATTR(Alignment)
+ IGNORED_ATTR(ClangImporterSynthesizedType)
IGNORED_ATTR(Consuming)
IGNORED_ATTR(Convenience)
+ IGNORED_ATTR(DowngradeExhaustivityCheck)
IGNORED_ATTR(Dynamic)
IGNORED_ATTR(Effects)
IGNORED_ATTR(Exported)
@@ -801,6 +804,7 @@
IGNORED_ATTR(IBDesignable)
IGNORED_ATTR(IBInspectable)
IGNORED_ATTR(IBOutlet) // checked early.
+ IGNORED_ATTR(ImplicitlyUnwrappedOptional)
IGNORED_ATTR(Indirect)
IGNORED_ATTR(Inline)
IGNORED_ATTR(Lazy) // checked early.
@@ -812,27 +816,25 @@
IGNORED_ATTR(NSManaged) // checked early.
IGNORED_ATTR(ObjC)
IGNORED_ATTR(ObjCBridged)
+ IGNORED_ATTR(ObjCMembers)
IGNORED_ATTR(ObjCNonLazyRealization)
IGNORED_ATTR(ObjCRuntimeName)
- IGNORED_ATTR(RestatedObjCConformance)
IGNORED_ATTR(Optional)
- IGNORED_ATTR(Ownership)
IGNORED_ATTR(Override)
+ IGNORED_ATTR(Ownership)
IGNORED_ATTR(RawDocComment)
- IGNORED_ATTR(Semantics)
- IGNORED_ATTR(SILGenName)
- IGNORED_ATTR(Transparent)
- IGNORED_ATTR(SynthesizedProtocol)
IGNORED_ATTR(RequiresStoredPropertyInits)
- IGNORED_ATTR(SILStored)
- IGNORED_ATTR(Testable)
- IGNORED_ATTR(WarnUnqualifiedAccess)
+ IGNORED_ATTR(RestatedObjCConformance)
+ IGNORED_ATTR(Semantics)
IGNORED_ATTR(ShowInInterface)
- IGNORED_ATTR(ObjCMembers)
+ IGNORED_ATTR(SILGenName)
+ IGNORED_ATTR(SILStored)
IGNORED_ATTR(StaticInitializeObjCMetadata)
- IGNORED_ATTR(DowngradeExhaustivityCheck)
- IGNORED_ATTR(ImplicitlyUnwrappedOptional)
- IGNORED_ATTR(ClangImporterSynthesizedType)
+ IGNORED_ATTR(SynthesizedProtocol)
+ IGNORED_ATTR(Testable)
+ IGNORED_ATTR(Transparent)
+ IGNORED_ATTR(WarnUnqualifiedAccess)
+ IGNORED_ATTR(WeakLinked)
#undef IGNORED_ATTR
void visitAvailableAttr(AvailableAttr *attr);
diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp
index cca4735..d97a6bd 100644
--- a/lib/Sema/TypeCheckConstraints.cpp
+++ b/lib/Sema/TypeCheckConstraints.cpp
@@ -2276,14 +2276,10 @@
// If we entered an initializer context, contextualize any
// auto-closures we might have created.
- if (initContext) {
+ if (initContext && !hadError) {
// Check safety of error-handling in the declaration, too.
- if (!hadError) {
- checkInitializerErrorHandling(initContext, init);
- }
-
- if (!hadError)
- (void)contextualizeInitializer(initContext, init);
+ checkInitializerErrorHandling(initContext, init);
+ (void)contextualizeInitializer(initContext, init);
}
if (hadError) {
@@ -3125,9 +3121,15 @@
}
void ConstraintSystem::dump(Expr *E) {
- auto getTypeOfExpr = [&](const Expr *E) -> Type { return getType(E); };
+ auto getTypeOfExpr = [&](const Expr *E) -> Type {
+ if (hasType(E))
+ return getType(E);
+ return Type();
+ };
auto getTypeOfTypeLoc = [&](const TypeLoc &TL) -> Type {
- return getType(TL);
+ if (hasType(TL))
+ return getType(TL);
+ return Type();
};
E->dump(getTypeOfExpr, getTypeOfTypeLoc);
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index 8a26536..5c68ce8 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -3949,9 +3949,7 @@
: TC(TC), IsFirstPass(IsFirstPass), IsSecondPass(IsSecondPass) {}
void visit(Decl *decl) {
- UnifiedStatsReporter::FrontendStatsTracer Tracer;
- if (TC.Context.Stats)
- Tracer = TC.Context.Stats->getStatsTracer("typecheck-decl", decl);
+ FrontendStatsTracer StatsTracer(TC.Context.Stats, "typecheck-decl", decl);
PrettyStackTraceDecl StackTrace("type-checking", decl);
DeclVisitor<DeclChecker>::visit(decl);
@@ -6527,6 +6525,7 @@
UNINTERESTING_ATTR(DowngradeExhaustivityCheck)
UNINTERESTING_ATTR(ImplicitlyUnwrappedOptional)
UNINTERESTING_ATTR(ClangImporterSynthesizedType)
+ UNINTERESTING_ATTR(WeakLinked)
#undef UNINTERESTING_ATTR
void visitAvailableAttr(AvailableAttr *attr) {
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 8795577..60354fd 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -21,6 +21,7 @@
#include "TypeChecker.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/StringExtras.h"
+#include "swift/Basic/Statistic.h"
#include "swift/AST/AccessScope.h"
#include "swift/AST/GenericSignatureBuilder.h"
#include "swift/AST/ASTContext.h"
@@ -3047,6 +3048,9 @@
void ConformanceChecker::checkConformance(MissingWitnessDiagnosisKind Kind) {
assert(!Conformance->isComplete() && "Conformance is already complete");
+ FrontendStatsTracer statsTracer(TC.Context.Stats, "check-conformance",
+ Conformance);
+
llvm::SaveAndRestore<bool> restoreSuppressDiagnostics(SuppressDiagnostics);
SuppressDiagnostics = false;
diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp
index d9fb64b..06a1213 100644
--- a/lib/Sema/TypeCheckStmt.cpp
+++ b/lib/Sema/TypeCheckStmt.cpp
@@ -1620,9 +1620,12 @@
}
// An inlinable constructor in a class must always be delegating,
- // unless the class is formally '@_fixed_layout'.
- if (!isDelegating &&
- ClassD->isFormallyResilient() &&
+ // unless the class is '@_fixed_layout'.
+ // Note: This is specifically not using isFormallyResilient. We relax this
+ // rule for classes in non-resilient modules so that they can have inlinable
+ // constructors, as long as those constructors don't reference private
+ // declarations.
+ if (!isDelegating && ClassD->isResilient() &&
ctor->getResilienceExpansion() == ResilienceExpansion::Minimal) {
diagnose(ctor, diag::class_designated_init_inlineable_resilient,
ClassD->getDeclaredInterfaceType(),
diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp
index b2bbe27..093e294 100644
--- a/lib/Sema/TypeChecker.cpp
+++ b/lib/Sema/TypeChecker.cpp
@@ -420,9 +420,7 @@
// but that gets tricky with synthesized function bodies.
if (AFD->isBodyTypeChecked()) continue;
- UnifiedStatsReporter::FrontendStatsTracer Tracer;
- if (TC.Context.Stats)
- Tracer = TC.Context.Stats->getStatsTracer("typecheck-fn", AFD);
+ FrontendStatsTracer StatsTracer(TC.Context.Stats, "typecheck-fn", AFD);
PrettyStackTraceDecl StackEntry("type-checking", AFD);
TC.typeCheckAbstractFunctionBody(AFD);
@@ -696,8 +694,8 @@
}
void swift::performWholeModuleTypeChecking(SourceFile &SF) {
- SharedTimer("performWholeModuleTypeChecking");
auto &Ctx = SF.getASTContext();
+ FrontendStatsTracer tracer(Ctx.Stats, "perform-whole-module-type-checking");
Ctx.diagnoseAttrsRequiringFoundation(SF);
Ctx.diagnoseObjCMethodConflicts(SF);
Ctx.diagnoseObjCUnsatisfiedOptReqConflicts(SF);
diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp
index dde20da..d29c4e7 100644
--- a/lib/Serialization/DeserializeSIL.cpp
+++ b/lib/Serialization/DeserializeSIL.cpp
@@ -413,12 +413,12 @@
GenericEnvironmentID genericEnvID;
unsigned rawLinkage, isTransparent, isSerialized, isThunk, isGlobal,
inlineStrategy, optimizationMode, effect, numSpecAttrs,
- hasQualifiedOwnership;
+ hasQualifiedOwnership, isWeakLinked;
ArrayRef<uint64_t> SemanticsIDs;
SILFunctionLayout::readRecord(scratch, rawLinkage, isTransparent, isSerialized,
isThunk, isGlobal, inlineStrategy,
- optimizationMode, effect,
- numSpecAttrs, hasQualifiedOwnership, funcTyID,
+ optimizationMode, effect, numSpecAttrs,
+ hasQualifiedOwnership, isWeakLinked, funcTyID,
genericEnvID, clangNodeOwnerID, SemanticsIDs);
if (funcTyID == 0) {
@@ -498,6 +498,7 @@
fn->setGlobalInit(isGlobal == 1);
fn->setEffectsKind((EffectsKind)effect);
fn->setOptimizationMode((OptimizationMode)optimizationMode);
+ fn->setWeakLinked(isWeakLinked);
if (clangNodeOwner)
fn->setClangNodeOwner(clangNodeOwner);
for (auto ID : SemanticsIDs) {
@@ -2405,12 +2406,12 @@
GenericEnvironmentID genericEnvID;
unsigned rawLinkage, isTransparent, isSerialized, isThunk, isGlobal,
inlineStrategy, optimizationMode, effect, numSpecAttrs,
- hasQualifiedOwnership;
+ hasQualifiedOwnership, isWeakLinked;
ArrayRef<uint64_t> SemanticsIDs;
SILFunctionLayout::readRecord(scratch, rawLinkage, isTransparent, isSerialized,
isThunk, isGlobal, inlineStrategy,
- optimizationMode, effect,
- numSpecAttrs, hasQualifiedOwnership, funcTyID,
+ optimizationMode, effect, numSpecAttrs,
+ hasQualifiedOwnership, isWeakLinked, funcTyID,
genericEnvID, clangOwnerID, SemanticsIDs);
auto linkage = fromStableSILLinkage(rawLinkage);
if (!linkage) {
diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h
index 856473f..7354894 100644
--- a/lib/Serialization/SILFormat.h
+++ b/lib/Serialization/SILFormat.h
@@ -280,6 +280,7 @@
BCFixed<2>, // side effect info.
BCVBR<8>, // number of specialize attributes
BCFixed<1>, // has qualified ownership
+ BCFixed<1>, // must be weakly referenced
TypeIDField, // SILFunctionType
GenericEnvironmentIDField,
DeclIDField, // ClangNode owner
diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp
index 4b36f95..183f218 100644
--- a/lib/Serialization/SerializeSIL.cpp
+++ b/lib/Serialization/SerializeSIL.cpp
@@ -379,8 +379,8 @@
(unsigned)F.isThunk(), (unsigned)F.isGlobalInit(),
(unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(),
(unsigned)F.getEffectsKind(),
- (unsigned)numSpecAttrs, (unsigned)F.hasQualifiedOwnership(), FnID,
- genericEnvID, clangNodeOwnerID, SemanticsIDs);
+ (unsigned)numSpecAttrs, (unsigned)F.hasQualifiedOwnership(),
+ F.isWeakLinked(), FnID, genericEnvID, clangNodeOwnerID, SemanticsIDs);
if (NoBody)
return;
diff --git a/lib/Syntax/README.md b/lib/Syntax/README.md
index 7d1e914..55d0f42 100644
--- a/lib/Syntax/README.md
+++ b/lib/Syntax/README.md
@@ -587,7 +587,7 @@
// Parse a .swift file
let currentFile = URL(fileURLWithPath: "/tmp/test.swift")
let currentFileContents = try String(contentsOf: currentFile)
-let parsed = try Syntax.parse(currentFile)
+let parsed = try SourceFileSyntax.parse(currentFile)
// Print the original file
print("\n//======== Original =========\n")
diff --git a/stdlib/public/Reflection/TypeRef.cpp b/stdlib/public/Reflection/TypeRef.cpp
index 9094596..e9cc98f 100644
--- a/stdlib/public/Reflection/TypeRef.cpp
+++ b/stdlib/public/Reflection/TypeRef.cpp
@@ -420,92 +420,22 @@
return Substitutions;
}
-namespace {
-bool isStruct(Demangle::NodePointer Node) {
- switch (Node->getKind()) {
- case Demangle::Node::Kind::Type:
- return isStruct(Node->getChild(0));
- case Demangle::Node::Kind::Structure:
- case Demangle::Node::Kind::BoundGenericStructure:
- return true;
- default:
- return false;
- }
-}
-bool isEnum(Demangle::NodePointer Node) {
- switch (Node->getKind()) {
- case Demangle::Node::Kind::Type:
- return isEnum(Node->getChild(0));
- case Demangle::Node::Kind::Enum:
- case Demangle::Node::Kind::BoundGenericEnum:
- return true;
- default:
- return false;
- }
-}
-bool isClass(Demangle::NodePointer Node) {
- switch (Node->getKind()) {
- case Demangle::Node::Kind::Type:
- return isClass(Node->getChild(0));
- case Demangle::Node::Kind::Class:
- case Demangle::Node::Kind::BoundGenericClass:
- return true;
- default:
- return false;
- }
-}
-bool isProtocol(Demangle::NodePointer Node) {
- switch (Node->getKind()) {
- case Demangle::Node::Kind::Type:
- return isProtocol(Node->getChild(0));
- case Demangle::Node::Kind::Protocol:
- return true;
- default:
- return false;
- }
-}
-
-bool isAlias(Demangle::NodePointer Node) {
- switch (Node->getKind()) {
- case Demangle::Node::Kind::Type:
- return isAlias(Node->getChild(0));
- case Demangle::Node::Kind::TypeAlias:
- return true;
- default:
- return false;
- }
-}
-} // end anonymous namespace
-
bool NominalTypeTrait::isStruct() const {
- Demangle::Demangler Dem;
- Demangle::NodePointer Demangled = Dem.demangleType(MangledName);
- return ::isStruct(Demangled);
+ return Demangle::isStruct(MangledName);
}
-bool NominalTypeTrait::isEnum() const {
- Demangle::Demangler Dem;
- Demangle::NodePointer Demangled = Dem.demangleType(MangledName);
- return ::isEnum(Demangled);
-}
+bool NominalTypeTrait::isEnum() const { return Demangle::isEnum(MangledName); }
bool NominalTypeTrait::isClass() const {
- Demangle::Demangler Dem;
- Demangle::NodePointer Demangled = Dem.demangleType(MangledName);
- return ::isClass(Demangled);
+ return Demangle::isClass(MangledName);
}
bool NominalTypeTrait::isProtocol() const {
- Demangle::Demangler Dem;
- StringRef adjustedMangledName = Demangle::dropSwiftManglingPrefix(MangledName);
- Demangle::NodePointer Demangled = Dem.demangleType(adjustedMangledName);
- return ::isProtocol(Demangled);
+ return Demangle::isProtocol(MangledName);
}
bool NominalTypeTrait::isAlias() const {
- Demangle::Demangler Dem;
- Demangle::NodePointer Demangled = Dem.demangleType(MangledName);
- return ::isAlias(Demangled);
+ return Demangle::isAlias(MangledName);
}
/// Visitor class to set the WasAbstract flag of any MetatypeTypeRefs
diff --git a/stdlib/public/SDK/AppKit/AppKit.swift b/stdlib/public/SDK/AppKit/AppKit.swift
index 9ee047b..ffb9f7d 100644
--- a/stdlib/public/SDK/AppKit/AppKit.swift
+++ b/stdlib/public/SDK/AppKit/AppKit.swift
@@ -14,6 +14,7 @@
@_exported import AppKit
extension NSCursor : _DefaultCustomPlaygroundQuickLookable {
+ @available(*, deprecated, message: "NSCursor._defaultCustomPlaygroundQuickLook will be removed in a future Swift version")
public var _defaultCustomPlaygroundQuickLook: PlaygroundQuickLook {
return .image(image)
}
@@ -24,6 +25,7 @@
}
extension NSView : _DefaultCustomPlaygroundQuickLookable {
+ @available(*, deprecated, message: "NSView._defaultCustomPlaygroundQuickLook will be removed in a future Swift version")
public var _defaultCustomPlaygroundQuickLook: PlaygroundQuickLook {
// if you set NSView.needsDisplay, you can get yourself in a recursive scenario where the same view
// could need to draw itself in order to get a QLObject for itself, which in turn if your code was
diff --git a/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift b/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift
index 7ed88df..6703ab8 100644
--- a/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift
+++ b/stdlib/public/SDK/CoreGraphics/CoreGraphics.swift
@@ -232,6 +232,7 @@
return Mirror(self, children: ["x": x, "y": y], displayStyle: .`struct`)
}
+ @available(*, deprecated, message: "CGPoint.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .point(Double(x), Double(y))
}
@@ -299,6 +300,7 @@
displayStyle: .`struct`)
}
+ @available(*, deprecated, message: "CGSize.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .size(Double(width), Double(height))
}
@@ -436,6 +438,7 @@
displayStyle: .`struct`)
}
+ @available(*, deprecated, message: "CGRect.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .rectangle(
Double(origin.x), Double(origin.y),
diff --git a/stdlib/public/SDK/Dispatch/Queue.swift b/stdlib/public/SDK/Dispatch/Queue.swift
index 36f6483..545a638 100644
--- a/stdlib/public/SDK/Dispatch/Queue.swift
+++ b/stdlib/public/SDK/Dispatch/Queue.swift
@@ -112,7 +112,7 @@
}
public class func concurrentPerform(iterations: Int, execute work: (Int) -> Void) {
- _swift_dispatch_apply_current(UInt32(iterations), work)
+ _swift_dispatch_apply_current(iterations, work)
}
public class var main: DispatchQueue {
diff --git a/stdlib/public/SDK/Foundation/Date.swift b/stdlib/public/SDK/Foundation/Date.swift
index c179f30..d11270f 100644
--- a/stdlib/public/SDK/Foundation/Date.swift
+++ b/stdlib/public/SDK/Foundation/Date.swift
@@ -280,6 +280,7 @@
return df.string(from: self)
}
+ @available(*, deprecated, message: "Date.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .text(summary)
}
diff --git a/stdlib/public/SDK/Foundation/NSDate.swift b/stdlib/public/SDK/Foundation/NSDate.swift
index a69ef73..4896e9d 100644
--- a/stdlib/public/SDK/Foundation/NSDate.swift
+++ b/stdlib/public/SDK/Foundation/NSDate.swift
@@ -21,6 +21,7 @@
return df.string(from: self as Date)
}
+ @available(*, deprecated, message: "NSDate.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .text(summary)
}
diff --git a/stdlib/public/SDK/Foundation/NSRange.swift b/stdlib/public/SDK/Foundation/NSRange.swift
index e05673e..85228fc 100644
--- a/stdlib/public/SDK/Foundation/NSRange.swift
+++ b/stdlib/public/SDK/Foundation/NSRange.swift
@@ -198,6 +198,7 @@
}
extension NSRange : CustomPlaygroundQuickLookable {
+ @available(*, deprecated, message: "NSRange.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .range(Int64(location), Int64(length))
}
diff --git a/stdlib/public/SDK/Foundation/NSString.swift b/stdlib/public/SDK/Foundation/NSString.swift
index 4a98a70..da0478b 100644
--- a/stdlib/public/SDK/Foundation/NSString.swift
+++ b/stdlib/public/SDK/Foundation/NSString.swift
@@ -113,6 +113,7 @@
}
extension NSString : CustomPlaygroundQuickLookable {
+ @available(*, deprecated, message: "NSString.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .text(self as String)
}
diff --git a/stdlib/public/SDK/Foundation/NSURL.swift b/stdlib/public/SDK/Foundation/NSURL.swift
index b62c374..6cf6522 100644
--- a/stdlib/public/SDK/Foundation/NSURL.swift
+++ b/stdlib/public/SDK/Foundation/NSURL.swift
@@ -13,6 +13,7 @@
@_exported import Foundation // Clang module
extension NSURL : CustomPlaygroundQuickLookable {
+ @available(*, deprecated, message: "NSURL.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
guard let str = absoluteString else { return .text("Unknown URL") }
return .url(str)
diff --git a/stdlib/public/SDK/Foundation/URL.swift b/stdlib/public/SDK/Foundation/URL.swift
index cf2dad3..47c2e0a 100644
--- a/stdlib/public/SDK/Foundation/URL.swift
+++ b/stdlib/public/SDK/Foundation/URL.swift
@@ -1202,6 +1202,7 @@
}
extension URL : CustomPlaygroundQuickLookable {
+ @available(*, deprecated, message: "URL.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .url(absoluteString)
}
diff --git a/stdlib/public/SDK/SpriteKit/SpriteKitQuickLooks.swift.gyb b/stdlib/public/SDK/SpriteKit/SpriteKitQuickLooks.swift.gyb
index 0cd4431..5a0893b 100644
--- a/stdlib/public/SDK/SpriteKit/SpriteKitQuickLooks.swift.gyb
+++ b/stdlib/public/SDK/SpriteKit/SpriteKitQuickLooks.swift.gyb
@@ -15,6 +15,7 @@
% for Self in ['SKShapeNode', 'SKSpriteNode', 'SKTextureAtlas', 'SKTexture']:
extension ${Self} : CustomPlaygroundQuickLookable {
+ @available(*, deprecated, message: "${Self}.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
let data = (self as AnyObject)._copyImageData?() as Data?
diff --git a/stdlib/public/SDK/UIKit/UIKit.swift b/stdlib/public/SDK/UIKit/UIKit.swift
index 9be02a5..abf0015 100644
--- a/stdlib/public/SDK/UIKit/UIKit.swift
+++ b/stdlib/public/SDK/UIKit/UIKit.swift
@@ -231,6 +231,7 @@
}
extension UIView : _DefaultCustomPlaygroundQuickLookable {
+ @available(*, deprecated, message: "UIView._defaultCustomPlaygroundQuickLook will be removed in a future Swift version")
public var _defaultCustomPlaygroundQuickLook: PlaygroundQuickLook {
if _UIViewQuickLookState.views.contains(self) {
return .view(UIImage())
diff --git a/stdlib/public/SwiftShims/DispatchOverlayShims.h b/stdlib/public/SwiftShims/DispatchOverlayShims.h
index 7cdb0d4..7c85a3a 100644
--- a/stdlib/public/SwiftShims/DispatchOverlayShims.h
+++ b/stdlib/public/SwiftShims/DispatchOverlayShims.h
@@ -2,20 +2,31 @@
//
// This source file is part of the Swift.org open source project
//
-// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
+//
+// Note that this file is used by both swift-corelibs-libdispatch and the
+// Dispatch overlay for Darwin in swift/stdlib/public/SDK/Dispatch/.
+//
+//===----------------------------------------------------------------------===//
+
#ifndef SWIFT_STDLIB_SHIMS_DISPATCHSHIMS_H
#define SWIFT_STDLIB_SHIMS_DISPATCHSHIMS_H
-@import Dispatch;
+#include <dispatch/dispatch.h>
+#ifdef __OBJC__
#define SWIFT_DISPATCH_RETURNS_RETAINED __attribute__((__ns_returns_retained__))
+#else
+#define SWIFT_DISPATCH_RETURNS_RETAINED
+#endif
+
#define SWIFT_DISPATCH_NOESCAPE __attribute__((__noescape__))
#pragma clang assume_nonnull begin
@@ -25,7 +36,12 @@
#endif
typedef void (^__swift_shims_dispatch_block_t)(void);
+
+#ifdef __OBJC__
typedef id __swift_shims_dispatch_data_t;
+#else
+typedef void *__swift_shims_dispatch_data_t;
+#endif
static inline dispatch_queue_attr_t
@@ -66,21 +82,24 @@
SWIFT_DISPATCH_SOURCE_TYPE(DATA_ADD)
SWIFT_DISPATCH_SOURCE_TYPE(DATA_OR)
SWIFT_DISPATCH_SOURCE_TYPE(DATA_REPLACE)
+SWIFT_DISPATCH_SOURCE_TYPE(READ)
+SWIFT_DISPATCH_SOURCE_TYPE(SIGNAL)
+SWIFT_DISPATCH_SOURCE_TYPE(TIMER)
+SWIFT_DISPATCH_SOURCE_TYPE(WRITE)
+
+#if __APPLE__
SWIFT_DISPATCH_SOURCE_TYPE(MACH_SEND)
SWIFT_DISPATCH_SOURCE_TYPE(MACH_RECV)
SWIFT_DISPATCH_SOURCE_TYPE(MEMORYPRESSURE)
SWIFT_DISPATCH_SOURCE_TYPE(PROC)
-SWIFT_DISPATCH_SOURCE_TYPE(READ)
-SWIFT_DISPATCH_SOURCE_TYPE(SIGNAL)
-SWIFT_DISPATCH_SOURCE_TYPE(TIMER)
SWIFT_DISPATCH_SOURCE_TYPE(VNODE)
-SWIFT_DISPATCH_SOURCE_TYPE(WRITE)
+#endif
static inline __swift_shims_dispatch_block_t
_swift_dispatch_block_create_with_qos_class(
dispatch_block_flags_t flags,
- qos_class_t qos,
+ dispatch_qos_class_t qos,
int relative_priority,
__swift_shims_dispatch_block_t _Nonnull block) {
return dispatch_block_create_with_qos_class(
@@ -158,7 +177,7 @@
static inline void _swift_dispatch_apply_current(
- unsigned int iterations,
+ size_t iterations,
void SWIFT_DISPATCH_NOESCAPE (^block)(long)) {
dispatch_apply(iterations, (dispatch_queue_t _Nonnull)0, ^(size_t i){
block((long)i);
@@ -204,6 +223,18 @@
dispatch_source_set_registration_handler(source, block);
}
+#if defined(__ANDROID__)
+extern void _dispatch_install_thread_detach_callback(dispatch_function_t cb);
+#endif
+
+static inline void _swift_dispatch_retain(dispatch_object_t object) {
+ dispatch_retain(object);
+}
+
+static inline void _swift_dispatch_release(dispatch_object_t object) {
+ dispatch_release(object);
+}
+
#ifdef __cplusplus
}} // extern "C", namespace swift
#endif
diff --git a/stdlib/public/SwiftShims/UnicodeShims.h b/stdlib/public/SwiftShims/UnicodeShims.h
index d0c2c76..5b07dc7 100644
--- a/stdlib/public/SwiftShims/UnicodeShims.h
+++ b/stdlib/public/SwiftShims/UnicodeShims.h
@@ -63,27 +63,6 @@
_swift_stdlib_ExtendedGraphemeClusterNoBoundaryRulesMatrix;
SWIFT_RUNTIME_STDLIB_INTERFACE
-SWIFT_READONLY __swift_int32_t
-_swift_stdlib_unicode_compare_utf16_utf16(const __swift_uint16_t *Left,
- __swift_int32_t LeftLength,
- const __swift_uint16_t *Right,
- __swift_int32_t RightLength);
-
-SWIFT_RUNTIME_STDLIB_INTERFACE
-SWIFT_READONLY __swift_int32_t
-_swift_stdlib_unicode_compare_utf8_utf16(const unsigned char *Left,
- __swift_int32_t LeftLength,
- const __swift_uint16_t *Right,
- __swift_int32_t RightLength);
-
-SWIFT_RUNTIME_STDLIB_INTERFACE
-SWIFT_READONLY __swift_int32_t
-_swift_stdlib_unicode_compare_utf8_utf8(const unsigned char *Left,
- __swift_int32_t LeftLength,
- const unsigned char *Right,
- __swift_int32_t RightLength);
-
-SWIFT_RUNTIME_STDLIB_INTERFACE
void *_swift_stdlib_unicodeCollationIterator_create(
const __swift_uint16_t *Str,
__swift_uint32_t Length);
@@ -109,6 +88,123 @@
__swift_uint16_t *Destination, __swift_int32_t DestinationCapacity,
const __swift_uint16_t *Source, __swift_int32_t SourceLength);
+typedef enum __swift_stdlib_UProperty {
+ __swift_stdlib_UCHAR_ALPHABETIC = 0,
+ __swift_stdlib_UCHAR_BINARY_START = __swift_stdlib_UCHAR_ALPHABETIC,
+ __swift_stdlib_UCHAR_ASCII_HEX_DIGIT = 1,
+ __swift_stdlib_UCHAR_BIDI_CONTROL = 2,
+ __swift_stdlib_UCHAR_BIDI_MIRRORED = 3,
+ __swift_stdlib_UCHAR_DASH = 4,
+ __swift_stdlib_UCHAR_DEFAULT_IGNORABLE_CODE_POINT = 5,
+ __swift_stdlib_UCHAR_DEPRECATED = 6,
+ __swift_stdlib_UCHAR_DIACRITIC = 7,
+ __swift_stdlib_UCHAR_EXTENDER = 8,
+ __swift_stdlib_UCHAR_FULL_COMPOSITION_EXCLUSION = 9,
+ __swift_stdlib_UCHAR_GRAPHEME_BASE = 10,
+ __swift_stdlib_UCHAR_GRAPHEME_EXTEND = 11,
+ __swift_stdlib_UCHAR_GRAPHEME_LINK = 12,
+ __swift_stdlib_UCHAR_HEX_DIGIT = 13,
+ __swift_stdlib_UCHAR_HYPHEN = 14,
+ __swift_stdlib_UCHAR_ID_CONTINUE = 15,
+ __swift_stdlib_UCHAR_ID_START = 16,
+ __swift_stdlib_UCHAR_IDEOGRAPHIC = 17,
+ __swift_stdlib_UCHAR_IDS_BINARY_OPERATOR = 18,
+ __swift_stdlib_UCHAR_IDS_TRINARY_OPERATOR = 19,
+ __swift_stdlib_UCHAR_JOIN_CONTROL = 20,
+ __swift_stdlib_UCHAR_LOGICAL_ORDER_EXCEPTION = 21,
+ __swift_stdlib_UCHAR_LOWERCASE = 22,
+ __swift_stdlib_UCHAR_MATH = 23,
+ __swift_stdlib_UCHAR_NONCHARACTER_CODE_POINT = 24,
+ __swift_stdlib_UCHAR_QUOTATION_MARK = 25,
+ __swift_stdlib_UCHAR_RADICAL = 26,
+ __swift_stdlib_UCHAR_SOFT_DOTTED = 27,
+ __swift_stdlib_UCHAR_TERMINAL_PUNCTUATION = 28,
+ __swift_stdlib_UCHAR_UNIFIED_IDEOGRAPH = 29,
+ __swift_stdlib_UCHAR_UPPERCASE = 30,
+ __swift_stdlib_UCHAR_WHITE_SPACE = 31,
+ __swift_stdlib_UCHAR_XID_CONTINUE = 32,
+ __swift_stdlib_UCHAR_XID_START = 33,
+ __swift_stdlib_UCHAR_CASE_SENSITIVE = 34,
+ __swift_stdlib_UCHAR_S_TERM = 35,
+ __swift_stdlib_UCHAR_VARIATION_SELECTOR = 36,
+ __swift_stdlib_UCHAR_NFD_INERT = 37,
+ __swift_stdlib_UCHAR_NFKD_INERT = 38,
+ __swift_stdlib_UCHAR_NFC_INERT = 39,
+ __swift_stdlib_UCHAR_NFKC_INERT = 40,
+ __swift_stdlib_UCHAR_SEGMENT_STARTER = 41,
+ __swift_stdlib_UCHAR_PATTERN_SYNTAX = 42,
+ __swift_stdlib_UCHAR_PATTERN_WHITE_SPACE = 43,
+ __swift_stdlib_UCHAR_POSIX_ALNUM = 44,
+ __swift_stdlib_UCHAR_POSIX_BLANK = 45,
+ __swift_stdlib_UCHAR_POSIX_GRAPH = 46,
+ __swift_stdlib_UCHAR_POSIX_PRINT = 47,
+ __swift_stdlib_UCHAR_POSIX_XDIGIT = 48,
+ __swift_stdlib_UCHAR_CASED = 49,
+ __swift_stdlib_UCHAR_CASE_IGNORABLE = 50,
+ __swift_stdlib_UCHAR_CHANGES_WHEN_LOWERCASED = 51,
+ __swift_stdlib_UCHAR_CHANGES_WHEN_UPPERCASED = 52,
+ __swift_stdlib_UCHAR_CHANGES_WHEN_TITLECASED = 53,
+ __swift_stdlib_UCHAR_CHANGES_WHEN_CASEFOLDED = 54,
+ __swift_stdlib_UCHAR_CHANGES_WHEN_CASEMAPPED = 55,
+ __swift_stdlib_UCHAR_CHANGES_WHEN_NFKC_CASEFOLDED = 56,
+ __swift_stdlib_UCHAR_EMOJI = 57,
+ __swift_stdlib_UCHAR_EMOJI_PRESENTATION = 58,
+ __swift_stdlib_UCHAR_EMOJI_MODIFIER = 59,
+ __swift_stdlib_UCHAR_EMOJI_MODIFIER_BASE = 60,
+
+ __swift_stdlib_UCHAR_BIDI_CLASS = 0x1000,
+ __swift_stdlib_UCHAR_INT_START = __swift_stdlib_UCHAR_BIDI_CLASS,
+ __swift_stdlib_UCHAR_BLOCK = 0x1001,
+ __swift_stdlib_UCHAR_CANONICAL_COMBINING_CLASS = 0x1002,
+ __swift_stdlib_UCHAR_DECOMPOSITION_TYPE = 0x1003,
+ __swift_stdlib_UCHAR_EAST_ASIAN_WIDTH = 0x1004,
+ __swift_stdlib_UCHAR_GENERAL_CATEGORY = 0x1005,
+ __swift_stdlib_UCHAR_JOINING_GROUP = 0x1006,
+ __swift_stdlib_UCHAR_JOINING_TYPE = 0x1007,
+ __swift_stdlib_UCHAR_LINE_BREAK = 0x1008,
+ __swift_stdlib_UCHAR_NUMERIC_TYPE = 0x1009,
+ __swift_stdlib_UCHAR_SCRIPT = 0x100A,
+ __swift_stdlib_UCHAR_HANGUL_SYLLABLE_TYPE = 0x100B,
+ __swift_stdlib_UCHAR_NFD_QUICK_CHECK = 0x100C,
+ __swift_stdlib_UCHAR_NFKD_QUICK_CHECK = 0x100D,
+ __swift_stdlib_UCHAR_NFC_QUICK_CHECK = 0x100E,
+ __swift_stdlib_UCHAR_NFKC_QUICK_CHECK = 0x100F,
+ __swift_stdlib_UCHAR_LEAD_CANONICAL_COMBINING_CLASS = 0x1010,
+ __swift_stdlib_UCHAR_TRAIL_CANONICAL_COMBINING_CLASS = 0x1011,
+ __swift_stdlib_UCHAR_GRAPHEME_CLUSTER_BREAK = 0x1012,
+ __swift_stdlib_UCHAR_SENTENCE_BREAK = 0x1013,
+ __swift_stdlib_UCHAR_WORD_BREAK = 0x1014,
+ __swift_stdlib_UCHAR_BIDI_PAIRED_BRACKET_TYPE = 0x1015,
+
+ __swift_stdlib_UCHAR_GENERAL_CATEGORY_MASK = 0x2000,
+ __swift_stdlib_UCHAR_MASK_START = __swift_stdlib_UCHAR_GENERAL_CATEGORY_MASK,
+
+ __swift_stdlib_UCHAR_NUMERIC_VALUE = 0x3000,
+ __swift_stdlib_UCHAR_DOUBLE_START = __swift_stdlib_UCHAR_NUMERIC_VALUE,
+
+ __swift_stdlib_UCHAR_AGE = 0x4000,
+ __swift_stdlib_UCHAR_STRING_START = __swift_stdlib_UCHAR_AGE,
+ __swift_stdlib_UCHAR_BIDI_MIRRORING_GLYPH = 0x4001,
+ __swift_stdlib_UCHAR_CASE_FOLDING = 0x4002,
+
+ __swift_stdlib_UCHAR_LOWERCASE_MAPPING = 0x4004,
+ __swift_stdlib_UCHAR_NAME = 0x4005,
+ __swift_stdlib_UCHAR_SIMPLE_CASE_FOLDING = 0x4006,
+ __swift_stdlib_UCHAR_SIMPLE_LOWERCASE_MAPPING = 0x4007,
+ __swift_stdlib_UCHAR_SIMPLE_TITLECASE_MAPPING = 0x4008,
+ __swift_stdlib_UCHAR_SIMPLE_UPPERCASE_MAPPING = 0x4009,
+ __swift_stdlib_UCHAR_TITLECASE_MAPPING = 0x400A,
+
+ __swift_stdlib_UCHAR_UPPERCASE_MAPPING = 0x400C,
+ __swift_stdlib_UCHAR_BIDI_PAIRED_BRACKET = 0x400D,
+
+ __swift_stdlib_UCHAR_SCRIPT_EXTENSIONS = 0x7000,
+ __swift_stdlib_UCHAR_OTHER_PROPERTY_START =
+ __swift_stdlib_UCHAR_SCRIPT_EXTENSIONS,
+
+ __swift_stdlib_UCHAR_INVALID_CODE = -1
+} __swift_stdlib_UProperty;
+
typedef enum __swift_stdlib_UErrorCode {
__swift_stdlib_U_USING_FALLBACK_WARNING = -128,
__swift_stdlib_U_ERROR_WARNING_START = -128,
@@ -294,6 +390,9 @@
} __swift_stdlib_UBreakIteratorType;
typedef struct __swift_stdlib_UBreakIterator __swift_stdlib_UBreakIterator;
+typedef struct __swift_stdlib_UNormalizer2 __swift_stdlib_UNormalizer2;
+typedef __swift_int8_t __swift_stdlib_UBool;
+typedef __swift_int32_t __swift_stdlib_UChar32;
#if defined(__APPLE__)
typedef __swift_uint16_t __swift_stdlib_UChar;
#else
@@ -329,6 +428,37 @@
__swift_int32_t __swift_stdlib_ubrk_following(__swift_stdlib_UBreakIterator *bi,
__swift_int32_t offset);
+SWIFT_RUNTIME_STDLIB_INTERFACE
+__swift_stdlib_UBool
+__swift_stdlib_unorm2_hasBoundaryBefore(const __swift_stdlib_UNormalizer2 *,
+ __swift_stdlib_UChar32);
+
+SWIFT_RUNTIME_STDLIB_INTERFACE
+const __swift_stdlib_UNormalizer2 *
+__swift_stdlib_unorm2_getNFCInstance(__swift_stdlib_UErrorCode *);
+
+SWIFT_RUNTIME_STDLIB_INTERFACE
+__swift_int32_t
+__swift_stdlib_unorm2_normalize(const __swift_stdlib_UNormalizer2 *,
+ const __swift_uint16_t *, __swift_int32_t,
+ __swift_uint16_t *, __swift_int32_t,
+ __swift_stdlib_UErrorCode *);
+
+SWIFT_RUNTIME_STDLIB_INTERFACE
+__swift_int32_t __swift_stdlib_unorm2_spanQuickCheckYes(
+ const __swift_stdlib_UNormalizer2 *, const __swift_stdlib_UChar *,
+ __swift_int32_t, __swift_stdlib_UErrorCode *);
+
+SWIFT_RUNTIME_STDLIB_INTERFACE
+__swift_stdlib_UBool
+ __swift_stdlib_u_hasBinaryProperty(__swift_stdlib_UChar32,
+ __swift_stdlib_UProperty);
+SWIFT_RUNTIME_STDLIB_INTERFACE
+__swift_stdlib_UBool
+ __swift_stdlib_u_isdefined(__swift_stdlib_UChar32);
+
+
+
#ifdef __cplusplus
}} // extern "C", namespace swift
#endif
diff --git a/stdlib/public/core/ArrayBufferProtocol.swift b/stdlib/public/core/ArrayBufferProtocol.swift
index db46422..3dc932e 100644
--- a/stdlib/public/core/ArrayBufferProtocol.swift
+++ b/stdlib/public/core/ArrayBufferProtocol.swift
@@ -126,7 +126,7 @@
var endIndex: Int { get }
}
-extension _ArrayBufferProtocol where Indices == CountableRange<Int>{
+extension _ArrayBufferProtocol where Indices == Range<Int>{
@_inlineable
@_versioned
@@ -142,7 +142,7 @@
let newBuffer = _ContiguousArrayBuffer<Element>(
_uninitializedCount: buffer.count, minimumCapacity: buffer.count)
buffer._copyContents(
- subRange: Range(buffer.indices),
+ subRange: buffer.indices,
initializing: newBuffer.firstElementAddress)
self = Self( _buffer: newBuffer, shiftedToStartIndex: buffer.startIndex)
}
diff --git a/stdlib/public/core/Arrays.swift.gyb b/stdlib/public/core/Arrays.swift.gyb
index 00aeab8..3810a99 100644
--- a/stdlib/public/core/Arrays.swift.gyb
+++ b/stdlib/public/core/Arrays.swift.gyb
@@ -491,8 +491,20 @@
}
extension ${Self}: RandomAccessCollection, MutableCollection {
+ /// The index type for arrays, `Int`.
+ %if Self == 'ArraySlice':
+ ///
+ /// `ArraySlice` instances are not always indexed from zero. Use `startIndex`
+ /// and `endIndex` as the bounds for any element access, instead of `0` and
+ /// `count`.
+ %end
public typealias Index = Int
+
+ /// The type that represents the indices that are valid for subscripting an
+ /// array, in ascending order.
public typealias Indices = Range<Int>
+
+ /// The type that allows iteration over an array's elements.
public typealias Iterator = IndexingIterator<${Self}>
%if Self == 'ArraySlice':
@@ -541,6 +553,11 @@
%end
}
+ /// Returns the position immediately after the given index.
+ ///
+ /// - Parameter i: A valid index of the collection. `i` must be less than
+ /// `endIndex`.
+ /// - Returns: The index immediately after `i`.
@_inlineable
public func index(after i: Int) -> Int {
// NOTE: this is a manual specialization of index movement for a Strideable
@@ -551,6 +568,10 @@
return i + 1
}
+ /// Replaces the given index with its successor.
+ ///
+ /// - Parameter i: A valid index of the collection. `i` must be less than
+ /// `endIndex`.
@_inlineable
public func formIndex(after i: inout Int) {
// NOTE: this is a manual specialization of index movement for a Strideable
@@ -561,6 +582,11 @@
i += 1
}
+ /// Returns the position immediately before the given index.
+ ///
+ /// - Parameter i: A valid index of the collection. `i` must be greater than
+ /// `startIndex`.
+ /// - Returns: The index immediately before `i`.
@_inlineable
public func index(before i: Int) -> Int {
// NOTE: this is a manual specialization of index movement for a Strideable
@@ -571,6 +597,10 @@
return i - 1
}
+ /// Replaces the given index with its predecessor.
+ ///
+ /// - Parameter i: A valid index of the collection. `i` must be greater than
+ /// `startIndex`.
@_inlineable
public func formIndex(before i: inout Int) {
// NOTE: this is a manual specialization of index movement for a Strideable
@@ -2200,7 +2230,15 @@
% for (Self, a_Self) in arrayTypes:
extension ${Self} : Equatable where Element : Equatable {
- /// Returns `true` if these arrays contain the same elements.
+ /// Returns a Boolean value indicating whether two arrays contain the same
+ /// elements in the same order.
+ ///
+ /// You can use the equal-to operator (`==`) to compare any two arrays
+ /// that store the same, `Equatable`-conforming element type.
+ ///
+ /// - Parameters:
+ /// - lhs: An array to compare.
+ /// - rhs: Another array to compare.
@_inlineable
public static func ==(lhs: ${Self}<Element>, rhs: ${Self}<Element>) -> Bool {
let lhsCount = lhs.count
@@ -2243,7 +2281,15 @@
return true
}
- /// Returns `true` if the arrays do not contain the same elements.
+ /// Returns a Boolean value indicating whether two arrays are not equal.
+ ///
+ /// Two arrays are equal if they contain the same elements in the same order.
+ /// You can use the not-equal-to operator (`!=`) to compare any two arrays
+ /// that store the same, `Equatable`-conforming element type.
+ ///
+ /// - Parameters:
+ /// - lhs: An array to compare.
+ /// - rhs: Another array to compare.
@_inlineable
public static func !=(lhs: ${Self}<Element>, rhs: ${Self}<Element>) -> Bool {
return !(lhs == rhs)
diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt
index 09d6b38..44295c2 100644
--- a/stdlib/public/core/CMakeLists.txt
+++ b/stdlib/public/core/CMakeLists.txt
@@ -88,7 +88,7 @@
Misc.swift
MutableCollection.swift
NewtypeWrapper.swift.gyb
- ObjCMirrors.swift
+ NormalizedCodeUnitIterator.swift
ObjectIdentifier.swift
Optional.swift
OptionSet.swift
@@ -100,7 +100,7 @@
RandomAccessCollection.swift
Range.swift
RangeReplaceableCollection.swift
- ReflectionLegacy.swift
+ ReflectionMirror.swift
Repeat.swift
REPL.swift
Reverse.swift
@@ -109,7 +109,7 @@
SipHash.swift.gyb
SentinelCollection.swift
Sequence.swift
- SequenceAlgorithms.swift.gyb
+ SequenceAlgorithms.swift
SequenceWrapper.swift
SetAlgebra.swift
ShadowProtocols.swift
@@ -123,6 +123,7 @@
String.swift
StringBridge.swift
StringComparable.swift
+ StringComparison.swift
StringGuts.swift
StringObject.swift
StringIndex.swift
@@ -132,6 +133,7 @@
StringStorage.swift
StringSwitch.swift
StringIndexConversions.swift
+ StringNormalization.swift
StringUnicodeScalarView.swift
StringUTF16.swift
StringUTF8.swift
@@ -170,6 +172,7 @@
CollectionOfOne.swift
ExistentialCollection.swift.gyb
Mirror.swift
+ PlaygroundDisplay.swift
CommandLine.swift
SliceBuffer.swift
Tuple.swift.gyb
diff --git a/stdlib/public/core/ClosedRange.swift b/stdlib/public/core/ClosedRange.swift
index bd75d05..d721765 100644
--- a/stdlib/public/core/ClosedRange.swift
+++ b/stdlib/public/core/ClosedRange.swift
@@ -13,7 +13,7 @@
// FIXME: swift-3-indexing-model: Generalize all tests to check both
// [Closed]Range.
-/// A closed range that forms a collection of consecutive values.
+/// An interval from a lower bound up to, and including, an upper bound.
///
/// You create a `ClosedRange` instance by using the closed range
/// operator (`...`).
@@ -23,41 +23,42 @@
/// A `ClosedRange` instance contains both its lower bound and its
/// upper bound.
///
-/// print(throughFive.contains(3)) // Prints "true"
-/// print(throughFive.contains(10)) // Prints "false"
-/// print(throughFive.contains(5)) // Prints "true"
+/// throughFive.contains(3)
+/// // true
+/// throughFive.contains(10)
+/// // false
+/// throughFive.contains(5)
+/// // true
///
/// Because a closed range includes its upper bound, a closed range whose lower
-/// bound is equal to the upper bound contains one element. Therefore, a
+/// bound is equal to the upper bound contains that value. Therefore, a
/// `ClosedRange` instance cannot represent an empty range.
///
/// let zeroInclusive = 0...0
-/// print(zeroInclusive.isEmpty)
-/// // Prints "false"
-/// print(zeroInclusive.count)
-/// // Prints "1"
+/// zeroInclusive.contains(0)
+/// // true
+/// zeroInclusive.isEmpty
+/// // false
///
-/// You can use a `for`-`in` loop or any sequence or collection method with a
-/// countable range. The elements of the range are the consecutive values from
-/// its lower bound up to, and including, its upper bound.
+/// Using a Closed Range as a Collection of Consecutive Values
+/// ----------------------------------------------------------
///
-/// for n in throughFive.suffix(3) {
+/// When a closed range uses integers as its lower and upper bounds, or any
+/// other type that conforms to the `Strideable` protocol with an integer
+/// stride, you can use that range in a `for`-`in` loop or with any sequence or
+/// collection method. The elements of the range are the consecutive values
+/// from its lower bound up to, and including, its upper bound.
+///
+/// for n in 3...5 {
/// print(n)
/// }
/// // Prints "3"
/// // Prints "4"
/// // Prints "5"
///
-/// You can create a countable range over any type that conforms to the
-/// `Strideable` protocol and uses an integer as its associated `Stride` type.
-/// By default, Swift's integer and pointer types are usable as the bounds of
-/// a countable range.
-///
/// Because floating-point types such as `Float` and `Double` are their own
/// `Stride` types, they cannot be used as the bounds of a countable range. If
-/// you need to test whether values are contained within a closed interval
-/// bound by floating-point values, see the `ClosedRange` type. If you need to
-/// iterate over consecutive floating-point values, see the
+/// you need to iterate over consecutive floating-point values, see the
/// `stride(from:through:by:)` function.
@_fixed_layout
public struct ClosedRange<Bound: Comparable> {
@@ -65,9 +66,6 @@
public let lowerBound: Bound
/// The range's upper bound.
- ///
- /// `upperBound` is always reachable from `lowerBound` by zero or
- /// more applications of `index(after:)`.
public let upperBound: Bound
/// Creates an instance with the given bounds.
@@ -294,7 +292,13 @@
@_inlineable
public func _customContainsEquatableElement(_ element: Bound) -> Bool? {
- return element >= self.lowerBound && element <= self.upperBound
+ return lowerBound <= element && element <= upperBound
+ }
+
+ @_inlineable
+ public func _customIndexOfEquatableElement(_ element: Bound) -> Index?? {
+ return lowerBound <= element && element <= upperBound
+ ? .inRange(element) : nil
}
}
diff --git a/stdlib/public/core/Collection.swift b/stdlib/public/core/Collection.swift
index 6d162cf..ea8d113 100644
--- a/stdlib/public/core/Collection.swift
+++ b/stdlib/public/core/Collection.swift
@@ -69,11 +69,11 @@
/// }
/// }
///
-/// The `CollectionOfTwo` type uses the default iterator type,
-/// `IndexingIterator`, because it doesn't define its own `makeIterator()`
-/// method or `Iterator` associated type. This example shows how a
-/// `CollectionOfTwo` instance can be created holding the values of a point,
-/// and then iterated over using a `for`-`in` loop.
+/// Because `CollectionOfTwo` doesn't define its own `makeIterator()`
+/// method or `Iterator` associated type, it uses the default iterator type,
+/// `IndexingIterator`. This example shows how a `CollectionOfTwo` instance
+/// can be created holding the values of a point, and then iterated over
+/// using a `for`-`in` loop.
///
/// let point = CollectionOfTwo(15.0, 20.0)
/// for element in point {
@@ -426,22 +426,35 @@
/// Accesses a contiguous subrange of the collection's elements.
///
- /// The accessed slice uses the same indices for the same elements as the
- /// original collection uses. Always use the slice's `startIndex` property
- /// instead of assuming that its indices start at a particular value.
- ///
- /// This example demonstrates getting a slice of an array of strings, finding
- /// the index of one of the strings in the slice, and then using that index
- /// in the original array.
+ /// For example, using a `PartialRangeFrom` range expression with an array
+ /// accesses the subrange from the start of the range expression until the
+ /// end of the array.
///
/// let streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"]
- /// let streetsSlice = streets[2 ..< streets.endIndex]
+ /// let streetsSlice = streets[2..<5]
/// print(streetsSlice)
- /// // Prints "["Channing", "Douglas", "Evarts"]"
+ /// // ["Channing", "Douglas", "Evarts"]
///
- /// let index = streetsSlice.index(of: "Evarts") // 4
- /// print(streets[index!])
- /// // Prints "Evarts"
+ /// The accessed slice uses the same indices for the same elements as the
+ /// original collection. This example searches `streetsSlice` for one of the
+ /// strings in the slice, and then uses that index in the original array.
+ ///
+ /// let index = streetsSlice.index(of: "Evarts")! // 4
+ /// print(streets[index])
+ /// // "Evarts"
+ ///
+ /// Always use the slice's `startIndex` property instead of assuming that its
+ /// indices start at a particular value. Attempting to access an element by
+ /// using an index outside the bounds of the slice may result in a runtime
+ /// error, even if that index is valid for the original collection.
+ ///
+ /// print(streetsSlice.startIndex)
+ /// // 2
+ /// print(streetsSlice[2])
+ /// // "Channing"
+ ///
+ /// print(streetsSlice[0])
+ /// // error: Index out of bounds
///
/// - Parameter bounds: A range of the collection's indices. The bounds of
/// the range must be valid indices of the collection.
@@ -1044,7 +1057,7 @@
/// Accesses a contiguous subrange of the collection's elements.
///
/// The accessed slice uses the same indices for the same elements as the
- /// original collection uses. Always use the slice's `startIndex` property
+ /// original collection. Always use the slice's `startIndex` property
/// instead of assuming that its indices start at a particular value.
///
/// This example demonstrates getting a slice of an array of strings, finding
diff --git a/stdlib/public/core/ContiguousArrayBuffer.swift b/stdlib/public/core/ContiguousArrayBuffer.swift
index 4c80709..4d77557 100644
--- a/stdlib/public/core/ContiguousArrayBuffer.swift
+++ b/stdlib/public/core/ContiguousArrayBuffer.swift
@@ -750,9 +750,13 @@
_uninitializedCount: newCapacity, minimumCapacity: 0)
p = newResult.firstElementAddress + result.capacity
remainingCapacity = newResult.capacity - result.capacity
- newResult.firstElementAddress.moveInitialize(
- from: result.firstElementAddress, count: result.capacity)
- result.count = 0
+ if !result.isEmpty {
+ // This check prevents a data race writting to _swiftEmptyArrayStorage
+ // Since count is always 0 there, this code does nothing anyway
+ newResult.firstElementAddress.moveInitialize(
+ from: result.firstElementAddress, count: result.capacity)
+ result.count = 0
+ }
(result, newResult) = (newResult, result)
}
addWithExistingCapacity(element)
diff --git a/stdlib/public/core/FixedArray.swift.gyb b/stdlib/public/core/FixedArray.swift.gyb
index ad029d3..d93dbfd 100644
--- a/stdlib/public/core/FixedArray.swift.gyb
+++ b/stdlib/public/core/FixedArray.swift.gyb
@@ -16,7 +16,7 @@
%{
# The sizes to generate code for.
- sizes = [16]
+ sizes = [2, 8, 16]
}%
% for N in sizes:
@@ -56,7 +56,7 @@
@_inlineable // FIXME(sil-serialize-all)
@_versioned // FIXME(sil-serialize-all)
- internal var count : Int {
+ internal var count: Int {
@inline(__always) get { return Int(truncatingIfNeeded: _count) }
@inline(__always) set { _count = Int8(newValue) }
}
diff --git a/stdlib/public/core/GroupInfo.json b/stdlib/public/core/GroupInfo.json
index 5270de6..db8d3a1 100644
--- a/stdlib/public/core/GroupInfo.json
+++ b/stdlib/public/core/GroupInfo.json
@@ -9,11 +9,13 @@
"Character.swift",
"CharacterUnicodeScalars.swift",
"ICU.swift",
+ "NormalizedCodeUnitIterator.swift",
"StaticString.swift",
"String.swift",
"StringBridge.swift",
"StringCharacterView.swift",
"StringComparable.swift",
+ "StringComparison.swift",
"StringObject.swift",
"StringGuts.swift",
"StringGraphemeBreaking.swift",
@@ -22,6 +24,7 @@
"StringIndexConversions.swift",
"StringInterpolation.swift",
"StringLegacy.swift",
+ "StringNormalization.swift",
"StringRangeReplaceableCollection.swift",
"StringStorage.swift",
"StringSwitch.swift",
@@ -120,9 +123,8 @@
"Dump.swift",
"Mirror.swift",
"Mirrors.swift",
- "ObjCMirrors.swift",
- "ObjectIdentifier.swift",
- "ReflectionLegacy.swift"
+ "ReflectionMirror.swift",
+ "ObjectIdentifier.swift"
],
"Math": [
"SetAlgebra.swift",
@@ -152,6 +154,9 @@
"CompilerProtocols.swift",
"ShadowProtocols.swift"
],
+ "Playground": [
+ "PlaygroundDisplay.swift"
+ ],
"Misc": [
"AnyHashable.swift",
"Interval.swift",
diff --git a/stdlib/public/core/Integers.swift.gyb b/stdlib/public/core/Integers.swift.gyb
index 04a61d8..4f69a62 100644
--- a/stdlib/public/core/Integers.swift.gyb
+++ b/stdlib/public/core/Integers.swift.gyb
@@ -1585,12 +1585,18 @@
}
extension BinaryInteger {
+ /// Creates a new value equal to zero.
@_inlineable // FIXME(sil-serialize-all)
@_transparent
public init() {
self = 0
}
+ /// Returns `-1` if this value is negative and `1` if it's positive;
+ /// otherwise, `0`.
+ ///
+ /// - Returns: The sign of this number, expressed as an integer of the same
+ /// type.
@_inlineable // FIXME(sil-serialize-all)
@_transparent
public func signum() -> Self {
@@ -1835,6 +1841,7 @@
return other - self
}
+ // FIXME(ABI): using Int as the parameter type is wrong.
/// Returns a value that is offset the specified distance from this value.
///
/// Use the `advanced(by:)` method in generic code to offset a value by a
@@ -1846,7 +1853,6 @@
///
/// - Parameter n: The distance to advance this value.
/// - Returns: A value that is offset from this value by `n`.
- // FIXME(ABI): using Int as the parameter type is wrong.
@_inlineable // FIXME(sil-serialize-all)
@_transparent
public func advanced(by n: Int) -> Int {
@@ -3000,6 +3006,7 @@
: FixedWidthInteger, ${Unsigned}Integer,
_ExpressibleByBuiltinIntegerLiteral {
+ /// A type that represents an integer literal.
public typealias IntegerLiteralType = ${Self}
diff --git a/stdlib/public/core/Mirror.swift b/stdlib/public/core/Mirror.swift
index a8aee94..4359787 100644
--- a/stdlib/public/core/Mirror.swift
+++ b/stdlib/public/core/Mirror.swift
@@ -121,9 +121,7 @@
if case let customized as CustomReflectable = subject {
self = customized.customMirror
} else {
- self = Mirror(
- legacy: _reflect(subject),
- subjectType: type(of: subject))
+ self = Mirror(internalReflecting: subject)
}
}
@@ -164,29 +162,6 @@
@_versioned // FIXME(sil-serialize-all)
internal static func _noSuperclassMirror() -> Mirror? { return nil }
- /// Returns the legacy mirror representing the part of `subject`
- /// corresponding to the superclass of `staticSubclass`.
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal static func _legacyMirror(
- _ subject: AnyObject, asClass targetSuperclass: AnyClass) -> _Mirror? {
-
- // get a legacy mirror and the most-derived type
- var cls: AnyClass = type(of: subject)
- var clsMirror = _reflect(subject)
-
- // Walk up the chain of mirrors/classes until we find staticSubclass
- while let superclass: AnyClass = _getSuperclass(cls) {
- guard let superclassMirror = clsMirror._superMirror() else { break }
-
- if superclass == targetSuperclass { return superclassMirror }
-
- clsMirror = superclassMirror
- cls = superclass
- }
- return nil
- }
-
@_semantics("optimize.sil.specialize.generic.never")
@inline(never)
@_inlineable // FIXME(sil-serialize-all)
@@ -201,14 +176,19 @@
switch ancestorRepresentation {
case .generated:
return {
- self._legacyMirror(_unsafeDowncastToAnyObject(fromAny: subject), asClass: superclass).map {
- Mirror(legacy: $0, subjectType: superclass)
- }
+ Mirror(internalReflecting: subject, subjectType: superclass)
}
case .customized(let makeAncestor):
return {
- Mirror(_unsafeDowncastToAnyObject(fromAny: subject), subjectClass: superclass,
- ancestor: makeAncestor())
+ let ancestor = makeAncestor()
+ if superclass == ancestor.subjectType
+ || ancestor._defaultDescendantRepresentation == .suppressed {
+ return ancestor
+ } else {
+ return Mirror(internalReflecting: subject,
+ subjectType: superclass,
+ customAncestor: ancestor)
+ }
}
case .suppressed:
break
@@ -503,165 +483,22 @@
}
}
-//===--- Legacy _Mirror Support -------------------------------------------===//
-extension Mirror.DisplayStyle {
- /// Construct from a legacy `_MirrorDisposition`
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal init?(legacy: _MirrorDisposition) {
- switch legacy {
- case .`struct`: self = .`struct`
- case .`class`: self = .`class`
- case .`enum`: self = .`enum`
- case .tuple: self = .tuple
- case .aggregate: return nil
- case .indexContainer: self = .collection
- case .keyContainer: self = .dictionary
- case .membershipContainer: self = .`set`
- case .container: preconditionFailure("unused!")
- case .optional: self = .optional
- case .objCObject: self = .`class`
- }
- }
-}
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-internal func _isClassSuperMirror(_ t: Any.Type) -> Bool {
-#if _runtime(_ObjC)
- return t == _ClassSuperMirror.self || t == _ObjCSuperMirror.self
-#else
- return t == _ClassSuperMirror.self
-#endif
-}
-
-extension _Mirror {
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal func _superMirror() -> _Mirror? {
- if self.count > 0 {
- let childMirror = self[0].1
- if _isClassSuperMirror(type(of: childMirror)) {
- return childMirror
- }
- }
- return nil
- }
-}
-
-/// When constructed using the legacy reflection infrastructure, the
-/// resulting `Mirror`'s `children` collection will always be
-/// upgradable to `AnyRandomAccessCollection` even if it doesn't
-/// exhibit appropriate performance. To avoid this pitfall, convert
-/// mirrors to use the new style, which only present forward
-/// traversal in general.
-internal extension Mirror {
- /// An adapter that represents a legacy `_Mirror`'s children as
- /// a `Collection` with integer `Index`. Note that the performance
- /// characteristics of the underlying `_Mirror` may not be
- /// appropriate for random access! To avoid this pitfall, convert
- /// mirrors to use the new style, which only present forward
- /// traversal in general.
- @_fixed_layout // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal struct LegacyChildren : RandomAccessCollection {
- internal typealias Indices = Range<Int>
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal init(_ oldMirror: _Mirror) {
- self._oldMirror = oldMirror
- }
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var startIndex: Int {
- return _oldMirror._superMirror() == nil ? 0 : 1
- }
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var endIndex: Int { return _oldMirror.count }
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal subscript(position: Int) -> Child {
- let (label, childMirror) = _oldMirror[position]
- return (label: label, value: childMirror.value)
- }
-
- @_versioned // FIXME(sil-serialize-all)
- internal let _oldMirror: _Mirror
- }
-
- /// Initialize for a view of `subject` as `subjectClass`.
- ///
- /// - parameter ancestor: A Mirror for a (non-strict) ancestor of
- /// `subjectClass`, to be injected into the resulting hierarchy.
- ///
- /// - parameter legacy: Either `nil`, or a legacy mirror for `subject`
- /// as `subjectClass`.
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal init(
- _ subject: AnyObject,
- subjectClass: AnyClass,
- ancestor: Mirror,
- legacy legacyMirror: _Mirror? = nil
- ) {
- if ancestor.subjectType == subjectClass
- || ancestor._defaultDescendantRepresentation == .suppressed {
- self = ancestor
- }
- else {
- let legacyMirror = legacyMirror ?? Mirror._legacyMirror(
- subject, asClass: subjectClass)!
-
- self = Mirror(
- legacy: legacyMirror,
- subjectType: subjectClass,
- makeSuperclassMirror: {
- _getSuperclass(subjectClass).map {
- Mirror(
- subject,
- subjectClass: $0,
- ancestor: ancestor,
- legacy: legacyMirror._superMirror())
- }
- })
- }
- }
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal init(
- legacy legacyMirror: _Mirror,
- subjectType: Any.Type,
- makeSuperclassMirror: (() -> Mirror?)? = nil
- ) {
- if let makeSuperclassMirror = makeSuperclassMirror {
- self._makeSuperclassMirror = makeSuperclassMirror
- }
- else if let subjectSuperclass = _getSuperclass(subjectType) {
- self._makeSuperclassMirror = {
- legacyMirror._superMirror().map {
- Mirror(legacy: $0, subjectType: subjectSuperclass) }
- }
- }
- else {
- self._makeSuperclassMirror = Mirror._noSuperclassMirror
- }
- self.subjectType = subjectType
- self.children = Children(LegacyChildren(legacyMirror))
- self.displayStyle = DisplayStyle(legacy: legacyMirror.disposition)
- self._defaultDescendantRepresentation = .generated
- }
-}
-
//===--- QuickLooks -------------------------------------------------------===//
/// The sum of types that can be used as a Quick Look representation.
+///
+/// - note: `PlaygroundQuickLook` is deprecated, and will be removed from the
+/// standard library in a future Swift release. Customizing display for in a
+/// playground is now done using the `CustomPlaygroundDisplayConvertible`
+/// protocol, which does not use the `PlaygroundQuickLook` enum. Please remove
+/// your uses of `PlaygroundQuickLook`, or conditionalize your use such that it
+/// is only present when compiling with Swift 4.0 or Swift 3.2 or earlier:
+///
+/// #if !(swift(>=4.1) || swift(>=3.3) && !swift(>=4.0))
+/// /* OK to use PlaygroundQuickLook */
+/// #endif
@_fixed_layout // FIXME(sil-serialize-all)
+@available(*, deprecated, message: "PlaygroundQuickLook will be removed in a future Swift version. For customizing how types are presented in playgrounds, use CustomPlaygroundDisplayConvertible instead.")
public enum PlaygroundQuickLook {
/// Plain text.
case text(String)
@@ -748,6 +585,7 @@
/// - Parameter subject: The instance to represent with the resulting Quick
/// Look.
@_inlineable // FIXME(sil-serialize-all)
+ @available(*, deprecated, message: "PlaygroundQuickLook will be removed in a future Swift version.")
public init(reflecting subject: Any) {
if let customized = subject as? CustomPlaygroundQuickLookable {
self = customized.customPlaygroundQuickLook
@@ -756,7 +594,7 @@
self = customized._defaultCustomPlaygroundQuickLook
}
else {
- if let q = _reflect(subject).quickLookObject {
+ if let q = Mirror.quickLookObject(subject) {
self = q
}
else {
@@ -773,6 +611,23 @@
/// with the representation supplied for your type by default, you can make it
/// conform to the `CustomPlaygroundQuickLookable` protocol and provide a
/// custom `PlaygroundQuickLook` instance.
+///
+/// - note: `CustomPlaygroundQuickLookable` is deprecated, and will be removed
+/// from the standard library in a future Swift release. Please migrate to the
+/// `CustomPlaygroundDisplayConvertible` protocol instead, or conditionalize
+/// your conformance such that it is only present when compiling with Swift 4.0
+/// or Swift 3.2 or earlier:
+///
+/// #if swift(>=4.1) || swift(>=3.3) && !swift(>=4.0)
+/// // With Swift 4.1 and later (including Swift 3.3 and later), implement
+/// // CustomPlaygroundDisplayConvertible.
+/// extension MyType: CustomPlaygroundDisplayConvertible { /*...*/ }
+/// #else
+/// // Otherwise, on Swift 4.0 and Swift 3.2 and earlier,
+/// // implement CustomPlaygroundQuickLookable.
+/// extension MyType: CustomPlaygroundQuickLookable { /*...*/ }
+/// #endif
+@available(*, deprecated, message: "CustomPlaygroundQuickLookable will be removed in a future Swift version. For customizing how types are presented in playgrounds, use CustomPlaygroundDisplayConvertible instead.")
public protocol CustomPlaygroundQuickLookable {
/// A custom playground Quick Look for this instance.
///
@@ -784,6 +639,7 @@
// A workaround for <rdar://problem/26182650>
// FIXME(ABI)#50 (Dynamic Dispatch for Class Extensions) though not if it moves out of stdlib.
+@available(*, deprecated, message: "_DefaultCustomPlaygroundQuickLookable will be removed in a future Swift version. For customizing how types are presented in playgrounds, use CustomPlaygroundDisplayConvertible instead.")
public protocol _DefaultCustomPlaygroundQuickLookable {
var _defaultCustomPlaygroundQuickLook: PlaygroundQuickLook { get }
}
diff --git a/stdlib/public/core/Mirrors.swift.gyb b/stdlib/public/core/Mirrors.swift.gyb
index a5724c5..3df3a67 100644
--- a/stdlib/public/core/Mirrors.swift.gyb
+++ b/stdlib/public/core/Mirrors.swift.gyb
@@ -48,6 +48,7 @@
extension ${Type[0]} : CustomPlaygroundQuickLookable {
/// A custom playground Quick Look for the `${Type[0]}` instance.
@_inlineable // FIXME(sil-serialize-all)
+ @available(*, deprecated, message: "${Type[0]}.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return ${Type[1]}(${Type[2]})
}
diff --git a/stdlib/public/core/NormalizedCodeUnitIterator.swift b/stdlib/public/core/NormalizedCodeUnitIterator.swift
new file mode 100644
index 0000000..cc61452
--- /dev/null
+++ b/stdlib/public/core/NormalizedCodeUnitIterator.swift
@@ -0,0 +1,270 @@
+//===--- StringNormalization.swift ----------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+internal
+struct _NormalizedCodeUnitIterator: IteratorProtocol {
+ var segmentBuffer = _FixedArray16<CodeUnit>(allZeros:())
+ var overflowBuffer: [CodeUnit]? = nil
+ var normalizationBuffer: [CodeUnit]? = nil
+ var source: _SegmentSource
+ var segmentBufferIndex = 0
+ var segmentBufferCount = 0
+ var overflowBufferIndex = 0
+ var overflowBufferCount = 0
+
+ typealias CodeUnit = UInt16
+
+ init(_ opaqueString: _UnmanagedOpaqueString, startIndex: Int = 0) {
+ source = _UnmanagedOpaqueStringSource(opaqueString, start: startIndex)
+ }
+
+ init(_ unmanagedString: _UnmanagedString<UInt16>, startIndex: Int = 0) {
+ source = _UnmanagedStringSource(unmanagedString, start: startIndex)
+ }
+
+ init(_ guts: _StringGuts, _ range: Range<Int>, startIndex: Int = 0) {
+ source = _StringGutsSource(guts, range, start: startIndex)
+ }
+
+ mutating func compare(with other: _NormalizedCodeUnitIterator) -> _Ordering {
+ var mutableOther = other
+ for cu in IteratorSequence(self) {
+ if let otherCU = mutableOther.next() {
+ let result = _lexicographicalCompare(cu, otherCU)
+ if result == .equal {
+ continue
+ } else {
+ return result
+ }
+ } else {
+ //other returned nil, we are greater
+ return .greater
+ }
+ }
+
+ //we ran out of code units, either we are equal, or only we ran out and
+ //other is greater
+ if let _ = mutableOther.next() {
+ return .less
+ } else {
+ return .equal
+ }
+ }
+
+ struct _UnmanagedOpaqueStringSource: _SegmentSource {
+ var remaining: Int {
+ return opaqueString.count - index
+ }
+ var opaqueString: _UnmanagedOpaqueString
+ var index: Int
+
+ init(_ opaqueString: _UnmanagedOpaqueString, start: Int = 0) {
+ self.opaqueString = opaqueString
+ index = start
+ }
+
+ mutating func tryFill(buffer: UnsafeMutableBufferPointer<UInt16>) -> Int? {
+ var bufferIndex = 0
+ let originalIndex = index
+ repeat {
+ guard index < opaqueString.count else {
+ break
+ }
+
+ guard bufferIndex < buffer.count else {
+ //The buffer isn't big enough for the current segment
+ index = originalIndex
+ return nil
+ }
+
+ let cu = opaqueString[index]
+ buffer[bufferIndex] = cu
+ index += 1
+ bufferIndex += 1
+ } while !opaqueString.hasNormalizationBoundary(after: index - 1)
+
+ return bufferIndex
+ }
+ }
+
+ struct _UnmanagedStringSource: _SegmentSource {
+ var remaining: Int {
+ return unmanagedString.count - index
+ }
+
+ var unmanagedString: _UnmanagedString<UInt16>
+ var index: Int
+
+ init(_ unmanagedString: _UnmanagedString<UInt16>, start: Int = 0) {
+ self.unmanagedString = unmanagedString
+ index = start
+ }
+
+ mutating func tryFill(buffer: UnsafeMutableBufferPointer<UInt16>) -> Int? {
+ var bufferIndex = 0
+ let originalIndex = index
+ repeat {
+ guard index < unmanagedString.count else {
+ break
+ }
+
+ guard bufferIndex < buffer.count else {
+ //The buffer isn't big enough for the current segment
+ index = originalIndex
+ return nil
+ }
+
+ let cu = unmanagedString[index]
+ buffer[bufferIndex] = cu
+ index += 1
+ bufferIndex += 1
+ } while unmanagedString.hasNormalizationBoundary(
+ after: index - 1,
+ count: unmanagedString.count) == false
+
+ return bufferIndex
+ }
+ }
+
+ struct _StringGutsSource: _SegmentSource {
+ var remaining: Int {
+ return range.count - index
+ }
+ var guts: _StringGuts
+ var index: Int
+ var range: Range<Int>
+
+ init(_ guts: _StringGuts, _ range: Range<Int>, start: Int = 0) {
+ self.guts = guts
+ self.range = range
+ index = range.lowerBound + start
+ }
+
+ mutating func tryFill(buffer: UnsafeMutableBufferPointer<UInt16>) -> Int? {
+ var bufferIndex = 0
+ let originalIndex = index
+ repeat {
+ guard index < range.count else {
+ break
+ }
+
+ guard bufferIndex < buffer.count else {
+ //The buffer isn't big enough for the current segment
+ index = originalIndex
+ return nil
+ }
+
+ let cu = guts[index]
+ buffer[bufferIndex] = cu
+ index += 1
+ bufferIndex += 1
+ } while !guts.hasNormalizationBoundary(after: index - 1)
+
+ return bufferIndex
+ }
+ }
+
+ mutating func next() -> CodeUnit? {
+ if segmentBufferCount == segmentBufferIndex {
+ segmentBuffer = _FixedArray16<CodeUnit>(allZeros:())
+ segmentBufferCount = 0
+ segmentBufferIndex = 0
+ }
+
+ if overflowBufferCount == overflowBufferIndex {
+ overflowBufferCount = 0
+ overflowBufferIndex = 0
+ }
+
+ if source.remaining <= 0
+ && segmentBufferCount == 0
+ && overflowBufferCount == 0 {
+ // Our source of code units to normalize is empty and our buffers from
+ // previous normalizations are also empty.
+ return nil
+ }
+
+ if segmentBufferCount == 0 && overflowBufferCount == 0 {
+ //time to fill a buffer if possible. Otherwise we are done, return nil
+ // Normalize segment, and then compare first code unit
+ var intermediateBuffer = _FixedArray16<CodeUnit>(allZeros:())
+ if overflowBuffer == nil,
+ let filled = source.tryFill(buffer: &intermediateBuffer)
+ {
+ guard let count = _tryNormalize(
+ _castOutputBuffer(&intermediateBuffer,
+ endingAt: filled),
+ into: &segmentBuffer
+ )
+ else {
+ fatalError("Output buffer was not big enough, this should not happen")
+ }
+ segmentBufferCount = count
+ } else {
+ let size = source.remaining * _Normalization._maxNFCExpansionFactor
+ if overflowBuffer == nil {
+ overflowBuffer = Array(repeating: 0, count: size)
+ normalizationBuffer = Array(repeating:0, count: size)
+ }
+
+ guard let count = normalizationBuffer!.withUnsafeMutableBufferPointer({
+ (normalizationBufferPtr) -> Int? in
+ guard let filled = source.tryFill(buffer: normalizationBufferPtr)
+ else {
+ fatalError("Invariant broken, buffer should have space")
+ }
+ return overflowBuffer!.withUnsafeMutableBufferPointer {
+ (overflowBufferPtr) -> Int? in
+ return _tryNormalize(
+ UnsafeBufferPointer( rebasing: normalizationBufferPtr[..<filled]),
+ into: overflowBufferPtr
+ )
+ }
+ }) else {
+ fatalError("Invariant broken, overflow buffer should have space")
+ }
+
+ overflowBufferCount = count
+ }
+ }
+
+ //exactly one of the buffers should have code units for us to return
+ _sanityCheck((segmentBufferCount == 0)
+ != ((overflowBuffer?.count ?? 0) == 0))
+
+ if segmentBufferIndex < segmentBufferCount {
+ let index = segmentBufferIndex
+ segmentBufferIndex += 1
+ return segmentBuffer[index]
+ } else if overflowBufferIndex < overflowBufferCount {
+ _sanityCheck(overflowBufferIndex < overflowBuffer!.count)
+ let index = overflowBufferIndex
+ overflowBufferIndex += 1
+ return overflowBuffer![index]
+ } else {
+ return nil
+ }
+ }
+}
+
+protocol _SegmentSource {
+ var remaining: Int { get }
+ mutating func tryFill(buffer: UnsafeMutableBufferPointer<UInt16>) -> Int?
+}
+
+extension _SegmentSource {
+ mutating func tryFill(
+ buffer: UnsafeMutablePointer<_Normalization._SegmentOutputBuffer>
+ ) -> Int? {
+ return tryFill(buffer: _castOutputBuffer(buffer))
+ }
+}
\ No newline at end of file
diff --git a/stdlib/public/core/PlaygroundDisplay.swift b/stdlib/public/core/PlaygroundDisplay.swift
new file mode 100644
index 0000000..ef5dd66
--- /dev/null
+++ b/stdlib/public/core/PlaygroundDisplay.swift
@@ -0,0 +1,63 @@
+//===--- PlaygroundDisplay.swift ------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+/// A type that supplies a custom description for playground logging.
+///
+/// All types have a default description for playgrounds. This protocol
+/// allows types to provide custom descriptions which are then logged in
+/// place of the original instance.
+///
+/// Playground logging can generate, at a minimum, a structured description
+/// of any type. Playground logging is also capable of generating a richer,
+/// more specialized description of core types -- for instance, the contents
+/// of a `String` are logged, as are the components of an `NSColor` or
+/// `UIColor`.
+///
+/// The current playground logging implementation logs specialized
+/// descriptions of at least the following types:
+///
+/// - `String` and `NSString`
+/// - `Int` and `UInt` (including the sized variants)
+/// - `Float` and `Double`
+/// - `Bool`
+/// - `Date` and `NSDate`
+/// - `NSAttributedString`
+/// - `NSNumber`
+/// - `NSRange`
+/// - `URL` and `NSURL`
+/// - `CGPoint`, `CGSize`, and `CGRect`
+/// - `NSColor`, `UIColor`, `CGColor`, and `CIColor`
+/// - `NSImage`, `UIImage`, `CGImage`, and `CIImage`
+/// - `NSBezierPath` and `UIBezierPath`
+/// - `NSView` and `UIView`
+///
+/// Playground logging may also be able to support specialized descriptions
+/// of other types.
+///
+/// Implementors of `CustomPlaygroundDisplayConvertible` may return a value of
+/// one of the above types to also receive a specialized log description.
+/// Implementors may also return any other type, and playground logging will
+/// generated structured logging for the returned value.
+///
+/// - note: `CustomPlaygroundDisplayConvertible` conformances chain -- that is,
+/// if `playgroundDescription` returns an instance which itself conforms to
+/// `CustomPlaygroundDisplayConvertible`, then playground logging will ask for
+/// that instance's `playgroundDescription` and so on. It is permissible for
+/// playground logging implementations to place a reasonable limit on this
+/// kind of chaining to prevent infinite loops.
+public protocol CustomPlaygroundDisplayConvertible {
+ /// Returns the custom playground description for this instance.
+ ///
+ /// If this type has value semantics, the instance returned should be
+ /// unaffected by subsequent mutations if possible.
+ var playgroundDescription: Any { get }
+}
\ No newline at end of file
diff --git a/stdlib/public/core/Policy.swift b/stdlib/public/core/Policy.swift
index 8128f8c..ce5db62 100644
--- a/stdlib/public/core/Policy.swift
+++ b/stdlib/public/core/Policy.swift
@@ -474,39 +474,44 @@
static var allZeros: Self { get }
}
-/// Calculates the union of bits sets in the two arguments and stores the result
-/// in the first argument.
-///
-/// - Parameters:
-/// - lhs: A value to update with the union of bits set in the two arguments.
-/// - rhs: Another value.
-@_inlineable // FIXME(sil-serialize-all)
-public func |= <T : _BitwiseOperations>(lhs: inout T, rhs: T) {
- lhs = lhs | rhs
-}
+extension _BitwiseOperations {
+ /// Calculates the union of bits sets in the two arguments and stores the result
+ /// in the first argument.
+ ///
+ /// - Parameters:
+ /// - lhs: A value to update with the union of bits set in the two arguments.
+ /// - rhs: Another value.
+ @_inlineable // FIXME(sil-serialize-all)
+ @available(swift, obsoleted: 4.1)
+ public static func |= (lhs: inout Self, rhs: Self) {
+ lhs = lhs | rhs
+ }
-/// Calculates the intersections of bits sets in the two arguments and stores
-/// the result in the first argument.
-///
-/// - Parameters:
-/// - lhs: A value to update with the intersections of bits set in the two
-/// arguments.
-/// - rhs: Another value.
-@_inlineable // FIXME(sil-serialize-all)
-public func &= <T : _BitwiseOperations>(lhs: inout T, rhs: T) {
- lhs = lhs & rhs
-}
+ /// Calculates the intersections of bits sets in the two arguments and stores
+ /// the result in the first argument.
+ ///
+ /// - Parameters:
+ /// - lhs: A value to update with the intersections of bits set in the two
+ /// arguments.
+ /// - rhs: Another value.
+ @_inlineable // FIXME(sil-serialize-all)
+ @available(swift, obsoleted: 4.1)
+ public static func &= (lhs: inout Self, rhs: Self) {
+ lhs = lhs & rhs
+ }
-/// Calculates the bits that are set in exactly one of the two arguments and
-/// stores the result in the first argument.
-///
-/// - Parameters:
-/// - lhs: A value to update with the bits that are set in exactly one of the
-/// two arguments.
-/// - rhs: Another value.
-@_inlineable // FIXME(sil-serialize-all)
-public func ^= <T : _BitwiseOperations>(lhs: inout T, rhs: T) {
- lhs = lhs ^ rhs
+ /// Calculates the bits that are set in exactly one of the two arguments and
+ /// stores the result in the first argument.
+ ///
+ /// - Parameters:
+ /// - lhs: A value to update with the bits that are set in exactly one of the
+ /// two arguments.
+ /// - rhs: Another value.
+ @_inlineable // FIXME(sil-serialize-all)
+ @available(swift, obsoleted: 4.1)
+ public static func ^= (lhs: inout Self, rhs: Self) {
+ lhs = lhs ^ rhs
+ }
}
//===----------------------------------------------------------------------===//
diff --git a/stdlib/public/core/Range.swift b/stdlib/public/core/Range.swift
index fbd59ba..db99681 100644
--- a/stdlib/public/core/Range.swift
+++ b/stdlib/public/core/Range.swift
@@ -80,25 +80,51 @@
}
}
-/// A half-open interval over a comparable type, from a lower bound up to, but
-/// not including, an upper bound.
+/// A half-open interval from a lower bound up to, but not including, an upper
+/// bound.
///
-/// You create `Range` instances by using the half-open range operator (`..<`).
+/// You create a `Range` instance by using the half-open range operator
+/// (`..<`).
///
/// let underFive = 0.0..<5.0
///
/// You can use a `Range` instance to quickly check if a value is contained in
/// a particular range of values. For example:
///
-/// print(underFive.contains(3.14)) // Prints "true"
-/// print(underFive.contains(6.28)) // Prints "false"
-/// print(underFive.contains(5.0)) // Prints "false"
+/// underFive.contains(3.14)
+/// // true
+/// underFive.contains(6.28)
+/// // false
+/// underFive.contains(5.0)
+/// // false
///
/// `Range` instances can represent an empty interval, unlike `ClosedRange`.
///
/// let empty = 0.0..<0.0
-/// print(empty.contains(0.0)) // Prints "false"
-/// print(empty.isEmpty) // Prints "true"
+/// empty.contains(0.0)
+/// // false
+/// empty.isEmpty
+/// // true
+///
+/// Using a Range as a Collection of Consecutive Values
+/// ----------------------------------------------------
+///
+/// When a range uses integers as its lower and upper bounds, or any other type
+/// that conforms to the `Strideable` protocol with an integer stride, you can
+/// use that range in a `for`-`in` loop or with any sequence or collection
+/// method. The elements of the range are the consecutive values from its
+/// lower bound up to, but not including, its upper bound.
+///
+/// for n in 3..<5 {
+/// print(n)
+/// }
+/// // Prints "3"
+/// // Prints "4"
+///
+/// Because floating-point types such as `Float` and `Double` are their own
+/// `Stride` types, they cannot be used as the bounds of a countable range. If
+/// you need to iterate over consecutive floating-point values, see the
+/// `stride(from:to:by:)` function.
@_fixed_layout
public struct Range<Bound : Comparable> {
/// The range's lower bound.
@@ -224,6 +250,11 @@
return lowerBound <= element && element < upperBound
}
+ @_inlineable
+ public func _customIndexOfEquatableElement(_ element: Bound) -> Index?? {
+ return lowerBound <= element && element < upperBound ? element : nil
+ }
+
/// Accesses the element at specified position.
///
/// You can subscript a collection with any valid index other than the
@@ -267,6 +298,15 @@
}
extension Range: RangeExpression {
+ /// Returns the range of indices described by this range expression within
+ /// the given collection.
+ ///
+ /// - Parameter collection: The collection to evaluate this range expression
+ /// in relation to.
+ /// - Returns: A range suitable for slicing `collection`. The returned range
+ /// is *not* guaranteed to be inside the bounds of `collection`. Callers
+ /// should apply the same preconditions to the return value as they would
+ /// to a range provided directly by the user.
@_inlineable // FIXME(sil-serialize-all)
public func relative<C: Collection>(to collection: C) -> Range<Bound>
where C.Index == Bound {
@@ -280,16 +320,16 @@
/// The bounds of the result are always limited to the bounds of `limits`.
/// For example:
///
- /// let x: Range = 0${op}20
- /// print(x.clamped(to: 10${op}1000))
- /// // Prints "10${op}20"
+ /// let x: Range = 0..<20
+ /// print(x.clamped(to: 10..<1000))
+ /// // Prints "10..<20"
///
/// If the two ranges do not overlap, the result is an empty range within the
/// bounds of `limits`.
///
- /// let y: Range = 0${op}5
- /// print(y.clamped(to: 10${op}1000))
- /// // Prints "10${op}10"
+ /// let y: Range = 0..<5
+ /// print(y.clamped(to: 10..<1000))
+ /// // Prints "10..<10"
///
/// - Parameter limits: The range to clamp the bounds of this range.
/// - Returns: A new range clamped to the bounds of `limits`.
@@ -402,7 +442,7 @@
}
}
-/// A partial half-open interval up to, and including, an upper bound.
+/// A partial interval up to, and including, an upper bound.
///
/// You create `PartialRangeThrough` instances by using the prefix closed range
/// operator (prefix `...`).
@@ -445,39 +485,40 @@
}
}
-/// A partial interval extending upward from a lower bound that forms a
-/// sequence of increasing values.
+/// A partial interval extending upward from a lower bound.
///
-/// You create `PartialRangeFrom` instances by using the postfix range
-/// operator (postfix `...`).
+/// You create `PartialRangeFrom` instances by using the postfix range operator
+/// (postfix `...`).
///
/// let atLeastFive = 5...
///
-/// You can use a countable partial range to quickly check if a value is
-/// contained in a particular range of values. For example:
+/// You can use a partial range to quickly check if a value is contained in a
+/// particular range of values. For example:
///
-/// atLeastFive.contains(4) // false
-/// atLeastFive.contains(5) // true
-/// atLeastFive.contains(6) // true
+/// atLeastFive.contains(4)
+/// // false
+/// atLeastFive.contains(5)
+/// // true
+/// atLeastFive.contains(6)
+/// // true
///
-/// You can use a countable partial range of a collection's indices to
-/// represent the range from the partial range's lower bound up to the end of
-/// the collection.
+/// You can use a partial range of a collection's indices to represent the
+/// range from the partial range's lower bound up to the end of the
+/// collection.
///
/// let numbers = [10, 20, 30, 40, 50, 60, 70]
/// print(numbers[3...])
/// // Prints "[40, 50, 60, 70]"
///
-/// You can create a countable partial range over any type that conforms to the
-/// `Strideable` protocol and uses an integer as its associated `Stride` type.
-/// By default, Swift's integer and pointer types are usable as the bounds of
-/// a countable range.
-///
/// Using a Partial Range as a Sequence
-/// ===================================
+/// -----------------------------------
///
-/// You can iterate over a countable partial range using a `for`-`in` loop, or
-/// call any sequence method that doesn't require that the sequence is finite.
+/// When a partial range uses integers as its lower and upper bounds, or any
+/// other type that conforms to the `Strideable` protocol with an integer
+/// stride, you can use that range in a `for`-`in` loop or with any sequence
+/// method that doesn't require that the sequence is finite. The elements of
+/// a partial range are the consecutive values from its lower bound continuing
+/// upward indefinitely.
///
/// func isTheMagicNumber(_ x: Int) -> Bool {
/// return x == 3
@@ -495,13 +536,13 @@
/// // "2 wasn't it..."
/// // "3 is the magic number!"
///
-/// Because a `PartialRangeFrom` sequence counts upward indefinitely,
-/// do not use one with methods that read the entire sequence before
-/// returning, such as `map(_:)`, `filter(_:)`, or `suffix(_:)`. It is safe to
-/// use operations that put an upper limit on the number of elements they
-/// access, such as `prefix(_:)` or `dropFirst(_:)`, and operations that you
-/// can guarantee will terminate, such as passing a closure you know will
-/// eventually return `true` to `first(where:)`.
+/// Because a `PartialRangeFrom` sequence counts upward indefinitely, do not
+/// use one with methods that read the entire sequence before returning, such
+/// as `map(_:)`, `filter(_:)`, or `suffix(_:)`. It is safe to use operations
+/// that put an upper limit on the number of elements they access, such as
+/// `prefix(_:)` or `dropFirst(_:)`, and operations that you can guarantee
+/// will terminate, such as passing a closure you know will eventually return
+/// `true` to `first(where:)`.
///
/// In the following example, the `asciiTable` sequence is made by zipping
/// together the characters in the `alphabet` string with a partial range
@@ -523,8 +564,8 @@
///
/// The behavior of incrementing indefinitely is determined by the type of
/// `Bound`. For example, iterating over an instance of
-/// `PartialRangeFrom<Int>` traps when the sequence's next value
-/// would be above `Int.max`.
+/// `PartialRangeFrom<Int>` traps when the sequence's next value would be
+/// above `Int.max`.
@_fixed_layout
public struct PartialRangeFrom<Bound: Comparable> {
public let lowerBound: Bound
@@ -574,8 +615,8 @@
/// Returns a half-open range that contains its lower bound but not its upper
/// bound.
///
- /// Use the half-open range operator (`..<`) to create a range of any type that
- /// conforms to the `Comparable` protocol. This example creates a
+ /// Use the half-open range operator (`..<`) to create a range of any type
+ /// that conforms to the `Comparable` protocol. This example creates a
/// `Range<Double>` from zero up to, but not including, 5.0.
///
/// let lessThanFive = 0.0..<5.0
@@ -678,18 +719,95 @@
}
}
-// FIXME: replace this with a computed var named `...` when the language makes
-// that possible.
+/// A range expression that represents the entire range of a collection.
+///
+/// You can use the unbounded range operator (`...`) to create a slice of a
+/// collection that contains all of the collection's elements. Slicing with an
+/// unbounded range is essentially a conversion of a collection instance into
+/// its slice type.
+///
+/// For example, the following code declares `levenshteinDistance(_:_:)`, a
+/// function that calculates the number of changes required to convert one
+/// string into another. `levenshteinDistance(_:_:)` uses `Substring`, a
+/// string's slice type, for its parameters.
+///
+/// func levenshteinDistance(_ s1: Substring, _ s2: Substring) -> Int {
+/// if s1.isEmpty { return s2.count }
+/// if s2.isEmpty { return s1.count }
+///
+/// let cost = s1.first == s2.first ? 0 : 1
+///
+/// return min(
+/// levenshteinDistance(s1.dropFirst(), s2) + 1,
+/// levenshteinDistance(s1, s2.dropFirst()) + 1,
+/// levenshteinDistance(s1.dropFirst(), s2.dropFirst()) + cost)
+/// }
+///
+/// To call `levenshteinDistance(_:_:)` with two strings, use an unbounded
+/// range in each string's subscript to convert it to a `Substring`.
+///
+/// let word1 = "grizzly"
+/// let word2 = "grisly"
+/// let distance = levenshteinDistance(word1[...], word2[...])
+/// // distance == 2
@_fixed_layout // FIXME(sil-serialize-all)
public enum UnboundedRange_ {
+ // FIXME: replace this with a computed var named `...` when the language makes
+ // that possible.
+
+ /// Creates an unbounded range expression.
+ ///
+ /// The unbounded range operator (`...`) is valid only within a collection's
+ /// subscript.
@_inlineable // FIXME(sil-serialize-all)
public static postfix func ... (_: UnboundedRange_) -> () {
fatalError("uncallable")
}
}
+
+/// The type of an unbounded range operator.
public typealias UnboundedRange = (UnboundedRange_)->()
extension Collection {
+ /// Accesses the contiguous subrange of the collection's elements specified
+ /// by a range expression.
+ ///
+ /// The range expression is converted to a concrete subrange relative to this
+ /// collection. For example, using a `PartialRangeFrom` range expression
+ /// with an array accesses the subrange from the start of the range
+ /// expression until the end of the array.
+ ///
+ /// let streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"]
+ /// let streetsSlice = streets[2...]
+ /// print(streetsSlice)
+ /// // ["Channing", "Douglas", "Evarts"]
+ ///
+ /// The accessed slice uses the same indices for the same elements as the
+ /// original collection uses. This example searches `streetsSlice` for one
+ /// of the strings in the slice, and then uses that index in the original
+ /// array.
+ ///
+ /// let index = streetsSlice.index(of: "Evarts") // 4
+ /// print(streets[index!])
+ /// // "Evarts"
+ ///
+ /// Always use the slice's `startIndex` property instead of assuming that its
+ /// indices start at a particular value. Attempting to access an element by
+ /// using an index outside the bounds of the slice's indices may result in a
+ /// runtime error, even if that index is valid for the original collection.
+ ///
+ /// print(streetsSlice.startIndex)
+ /// // 2
+ /// print(streetsSlice[2])
+ /// // "Channing"
+ ///
+ /// print(streetsSlice[0])
+ /// // error: Index out of bounds
+ ///
+ /// - Parameter bounds: A range of the collection's indices. The bounds of
+ /// the range must be valid indices of the collection.
+ ///
+ /// - Complexity: O(1)
@_inlineable
public subscript<R: RangeExpression>(r: R)
-> SubSequence where R.Bound == Index {
diff --git a/stdlib/public/core/ReflectionLegacy.swift b/stdlib/public/core/ReflectionLegacy.swift
deleted file mode 100644
index ce562ce..0000000
--- a/stdlib/public/core/ReflectionLegacy.swift
+++ /dev/null
@@ -1,530 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// This source file is part of the Swift.org open source project
-//
-// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
-// Licensed under Apache License v2.0 with Runtime Library Exception
-//
-// See https://swift.org/LICENSE.txt for license information
-// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-//
-//===----------------------------------------------------------------------===//
-
-/// How children of this value should be presented in the IDE.
-@_fixed_layout // FIXME(sil-serialize-all)
-public enum _MirrorDisposition {
- /// As a struct.
- case `struct`
- /// As a class.
- case `class`
- /// As an enum.
- case `enum`
- /// As a tuple.
- case tuple
- /// As a miscellaneous aggregate with a fixed set of children.
- case aggregate
- /// As a container that is accessed by index.
- case indexContainer
- /// As a container that is accessed by key.
- case keyContainer
- /// As a container that represents membership of its values.
- case membershipContainer
- /// As a miscellaneous container with a variable number of children.
- case container
- /// An Optional which can have either zero or one children.
- case optional
- /// An Objective-C object imported in Swift.
- case objCObject
-}
-
-/// The type returned by `_reflect(x)`; supplies an API for runtime
-/// reflection on `x`.
-public protocol _Mirror {
- /// The instance being reflected.
- var value: Any { get }
-
- /// Identical to `type(of: value)`.
- var valueType: Any.Type { get }
-
- /// A unique identifier for `value` if it is a class instance; `nil`
- /// otherwise.
- var objectIdentifier: ObjectIdentifier? { get }
-
- /// The count of `value`'s logical children.
- var count: Int { get }
-
- /// Get a name and mirror for the `i`th logical child.
- subscript(i: Int) -> (String, _Mirror) { get }
-
- /// A string description of `value`.
- var summary: String { get }
-
- /// A rich representation of `value` for an IDE, or `nil` if none is supplied.
- var quickLookObject: PlaygroundQuickLook? { get }
-
- /// How `value` should be presented in an IDE.
- var disposition: _MirrorDisposition { get }
-}
-
-/// Produce a mirror for any value. The runtime produces a mirror that
-/// structurally reflects values of any type.
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("swift_reflectAny")
-internal func _reflect<T>(_ x: T) -> _Mirror
-
-// -- Implementation details for the runtime's _Mirror implementation
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("swift_MagicMirrorData_summary")
-internal func _swift_MagicMirrorData_summaryImpl(
- _ metadata: Any.Type, _ result: UnsafeMutablePointer<String>
-)
-
-@_fixed_layout
-public struct _MagicMirrorData {
- @_versioned // FIXME(sil-serialize-all)
- internal let owner: Builtin.NativeObject
- @_versioned // FIXME(sil-serialize-all)
- internal let ptr: Builtin.RawPointer
- @_versioned // FIXME(sil-serialize-all)
- internal let metadata: Any.Type
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var value: Any {
- @_silgen_name("swift_MagicMirrorData_value")get
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var valueType: Any.Type {
- @_silgen_name("swift_MagicMirrorData_valueType")get
- }
-
- @_inlineable // FIXME(sil-serialize-all)
- public var objcValue: Any {
- @_silgen_name("swift_MagicMirrorData_objcValue")get
- }
- @_inlineable // FIXME(sil-serialize-all)
- public var objcValueType: Any.Type {
- @_silgen_name("swift_MagicMirrorData_objcValueType")get
- }
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var summary: String {
- let (_, result) = _withUninitializedString {
- _swift_MagicMirrorData_summaryImpl(self.metadata, $0)
- }
- return result
- }
-
- @_inlineable // FIXME(sil-serialize-all)
- public func _loadValue<T>(ofType _: T.Type) -> T {
- return Builtin.load(ptr) as T
- }
-}
-
-@_versioned
-@_fixed_layout // FIXME(sil-serialize-all)
-internal struct _OpaqueMirror : _Mirror {
- @_versioned // FIXME(sil-serialize-all)
- internal let data: _MagicMirrorData
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var value: Any { return data.value }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var valueType: Any.Type { return data.valueType }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var objectIdentifier: ObjectIdentifier? { return nil }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var count: Int { return 0 }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal subscript(i: Int) -> (String, _Mirror) {
- _preconditionFailure("no children")
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var summary: String { return data.summary }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var quickLookObject: PlaygroundQuickLook? { return nil }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var disposition: _MirrorDisposition { return .aggregate }
-}
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("swift_TupleMirror_count")
-internal func _getTupleCount(_: _MagicMirrorData) -> Int
-
-// Like the other swift_*Mirror_subscript functions declared here and
-// elsewhere, this is implemented in the runtime. The Swift CC would
-// normally require the String to be returned directly and the _Mirror
-// indirectly. However, Clang isn't currently capable of doing that
-// reliably because the size of String exceeds the normal direct-return
-// ABI rules on most platforms. Therefore, we make this function generic,
-// which has the disadvantage of passing the String type metadata as an
-// extra argument, but does force the string to be returned indirectly.
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("swift_TupleMirror_subscript")
-internal func _getTupleChild<T>(_: Int, _: _MagicMirrorData) -> (T, _Mirror)
-
-@_versioned
-@_fixed_layout // FIXME(sil-serialize-all)
-internal struct _TupleMirror : _Mirror {
- @_versioned // FIXME(sil-serialize-all)
- internal let data: _MagicMirrorData
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var value: Any { return data.value }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var valueType: Any.Type { return data.valueType }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var objectIdentifier: ObjectIdentifier? { return nil }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var count: Int {
- return _getTupleCount(data)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal subscript(i: Int) -> (String, _Mirror) {
- return _getTupleChild(i, data)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var summary: String { return "(\(count) elements)" }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var quickLookObject: PlaygroundQuickLook? { return nil }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var disposition: _MirrorDisposition { return .tuple }
-}
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("swift_StructMirror_count")
-internal func _getStructCount(_: _MagicMirrorData) -> Int
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("swift_StructMirror_subscript")
-internal func _getStructChild<T>(_: Int, _: _MagicMirrorData) -> (T, _Mirror)
-
-@_versioned
-@_fixed_layout // FIXME(sil-serialize-all)
-internal struct _StructMirror : _Mirror {
- @_versioned // FIXME(sil-serialize-all)
- internal let data: _MagicMirrorData
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var value: Any { return data.value }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var valueType: Any.Type { return data.valueType }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var objectIdentifier: ObjectIdentifier? { return nil }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var count: Int {
- return _getStructCount(data)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal subscript(i: Int) -> (String, _Mirror) {
- return _getStructChild(i, data)
- }
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var summary: String {
- return _typeName(valueType)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var quickLookObject: PlaygroundQuickLook? { return nil }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var disposition: _MirrorDisposition { return .`struct` }
-}
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("swift_EnumMirror_count")
-internal func _getEnumCount(_: _MagicMirrorData) -> Int
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("swift_EnumMirror_subscript")
-internal func _getEnumChild<T>(_: Int, _: _MagicMirrorData) -> (T, _Mirror)
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("swift_EnumMirror_caseName")
-internal func _swift_EnumMirror_caseName(
- _ data: _MagicMirrorData) -> UnsafePointer<CChar>
-
-@_versioned
-@_fixed_layout // FIXME(sil-serialize-all)
-internal struct _EnumMirror : _Mirror {
- @_versioned // FIXME(sil-serialize-all)
- internal let data: _MagicMirrorData
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var value: Any { return data.value }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var valueType: Any.Type { return data.valueType }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var objectIdentifier: ObjectIdentifier? { return nil }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var count: Int {
- return _getEnumCount(data)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var caseName: UnsafePointer<CChar> {
- return _swift_EnumMirror_caseName(data)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal subscript(i: Int) -> (String, _Mirror) {
- return _getEnumChild(i, data)
- }
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var summary: String {
- let maybeCaseName = String(validatingUTF8: self.caseName)
- let typeName = _typeName(valueType)
- if let caseName = maybeCaseName {
- return typeName + "." + caseName
- }
- return typeName
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var quickLookObject: PlaygroundQuickLook? { return nil }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var disposition: _MirrorDisposition { return .`enum` }
-}
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("swift_ClassMirror_count")
-internal func _getClassCount(_: _MagicMirrorData) -> Int
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("swift_ClassMirror_subscript")
-internal func _getClassChild<T>(_: Int, _: _MagicMirrorData) -> (T, _Mirror)
-
-#if _runtime(_ObjC)
-@_inlineable // FIXME(sil-serialize-all)
-@_silgen_name("swift_ClassMirror_quickLookObject")
-public func _swift_ClassMirror_quickLookObject(_: _MagicMirrorData) -> AnyObject
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-@_silgen_name("_swift_stdlib_NSObject_isKindOfClass")
-internal func _swift_NSObject_isImpl(_ object: AnyObject, kindOf: AnyObject) -> Bool
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-internal func _is(_ object: AnyObject, kindOf `class`: String) -> Bool {
- return _swift_NSObject_isImpl(object, kindOf: `class` as AnyObject)
-}
-
-@_inlineable // FIXME(sil-serialize-all)
-@_versioned // FIXME(sil-serialize-all)
-internal func _getClassPlaygroundQuickLook(
- _ object: AnyObject
-) -> PlaygroundQuickLook? {
- if _is(object, kindOf: "NSNumber") {
- let number: _NSNumber = unsafeBitCast(object, to: _NSNumber.self)
- switch UInt8(number.objCType[0]) {
- case UInt8(ascii: "d"):
- return .double(number.doubleValue)
- case UInt8(ascii: "f"):
- return .float(number.floatValue)
- case UInt8(ascii: "Q"):
- return .uInt(number.unsignedLongLongValue)
- default:
- return .int(number.longLongValue)
- }
- } else if _is(object, kindOf: "NSAttributedString") {
- return .attributedString(object)
- } else if _is(object, kindOf: "NSImage") ||
- _is(object, kindOf: "UIImage") ||
- _is(object, kindOf: "NSImageView") ||
- _is(object, kindOf: "UIImageView") ||
- _is(object, kindOf: "CIImage") ||
- _is(object, kindOf: "NSBitmapImageRep") {
- return .image(object)
- } else if _is(object, kindOf: "NSColor") ||
- _is(object, kindOf: "UIColor") {
- return .color(object)
- } else if _is(object, kindOf: "NSBezierPath") ||
- _is(object, kindOf: "UIBezierPath") {
- return .bezierPath(object)
- } else if _is(object, kindOf: "NSString") {
- return .text(_forceBridgeFromObjectiveC(object, String.self))
- }
-
- return .none
-}
-
-#endif
-
-@_versioned
-@_fixed_layout // FIXME(sil-serialize-all)
-internal struct _ClassMirror : _Mirror {
- @_versioned // FIXME(sil-serialize-all)
- internal let data: _MagicMirrorData
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var value: Any { return data.value }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var valueType: Any.Type { return data.valueType }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var objectIdentifier: ObjectIdentifier? {
- return data._loadValue(ofType: ObjectIdentifier.self)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var count: Int {
- return _getClassCount(data)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal subscript(i: Int) -> (String, _Mirror) {
- return _getClassChild(i, data)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var summary: String {
- return _typeName(valueType)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var quickLookObject: PlaygroundQuickLook? {
-#if _runtime(_ObjC)
- let object = _swift_ClassMirror_quickLookObject(data)
- return _getClassPlaygroundQuickLook(object)
-#else
- return nil
-#endif
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var disposition: _MirrorDisposition { return .`class` }
-}
-
-@_versioned
-@_fixed_layout // FIXME(sil-serialize-all)
-internal struct _ClassSuperMirror : _Mirror {
- @_versioned // FIXME(sil-serialize-all)
- internal let data: _MagicMirrorData
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var value: Any { return data.value }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var valueType: Any.Type { return data.valueType }
-
- // Suppress the value identifier for super mirrors.
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var objectIdentifier: ObjectIdentifier? {
- return nil
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var count: Int {
- return _getClassCount(data)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal subscript(i: Int) -> (String, _Mirror) {
- return _getClassChild(i, data)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var summary: String {
- return _typeName(data.metadata)
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var quickLookObject: PlaygroundQuickLook? { return nil }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var disposition: _MirrorDisposition { return .`class` }
-}
-
-@_versioned
-@_fixed_layout // FIXME(sil-serialize-all)
-internal struct _MetatypeMirror : _Mirror {
- @_versioned // FIXME(sil-serialize-all)
- internal let data: _MagicMirrorData
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var value: Any { return data.value }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var valueType: Any.Type { return data.valueType }
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var objectIdentifier: ObjectIdentifier? {
- return data._loadValue(ofType: ObjectIdentifier.self)
- }
-
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var count: Int {
- return 0
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal subscript(i: Int) -> (String, _Mirror) {
- _preconditionFailure("no children")
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var summary: String {
- return _typeName(data._loadValue(ofType: Any.Type.self))
- }
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var quickLookObject: PlaygroundQuickLook? { return nil }
-
- // Special disposition for types?
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned // FIXME(sil-serialize-all)
- internal var disposition: _MirrorDisposition { return .aggregate }
-}
-
diff --git a/stdlib/public/core/ReflectionMirror.swift b/stdlib/public/core/ReflectionMirror.swift
new file mode 100644
index 0000000..b115330
--- /dev/null
+++ b/stdlib/public/core/ReflectionMirror.swift
@@ -0,0 +1,182 @@
+//===----------------------------------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+@_inlineable // FIXME(sil-serialize-all)
+@_versioned // FIXME(sil-serialize-all)
+@_silgen_name("swift_reflectionMirror_normalizedType")
+internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
+
+@_inlineable // FIXME(sil-serialize-all)
+@_versioned // FIXME(sil-serialize-all)
+@_silgen_name("swift_reflectionMirror_count")
+internal func _getChildCount<T>(_: T, type: Any.Type) -> Int
+
+internal typealias NameFreeFunc = @convention(c) (UnsafePointer<CChar>?) -> Void
+
+@_inlineable // FIXME(sil-serialize-all)
+@_versioned // FIXME(sil-serialize-all)
+@_silgen_name("swift_reflectionMirror_subscript")
+internal func _getChild<T>(
+ of: T,
+ type: Any.Type,
+ index: Int,
+ outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
+ outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
+) -> Any
+
+// Returns 'c' (class), 'e' (enum), 's' (struct), 't' (tuple), or '\0' (none)
+@_inlineable // FIXME(sil-serialize-all)
+@_versioned // FIXME(sil-serialize-all)
+@_silgen_name("swift_reflectionMirror_displayStyle")
+internal func _getDisplayStyle<T>(_: T) -> CChar
+
+@_inlineable // FIXME(sil-serialize-all)
+@_versioned // FIXME(sil-serialize-all)
+internal func getChild<T>(of value: T, type: Any.Type, index: Int) -> (label: String?, value: Any) {
+ var nameC: UnsafePointer<CChar>? = nil
+ var freeFunc: NameFreeFunc? = nil
+
+ let value = _getChild(of: value, type: type, index: index, outName: &nameC, outFreeFunc: &freeFunc)
+
+ let name = nameC.flatMap({ String(validatingUTF8: $0) })
+ freeFunc?(nameC)
+ return (name, value)
+}
+
+#if _runtime(_ObjC)
+@_inlineable // FIXME(sil-serialize-all)
+@_versioned // FIXME(sil-serialize-all)
+@_silgen_name("swift_reflectionMirror_quickLookObject")
+internal func _getQuickLookObject<T>(_: T) -> AnyObject?
+
+@_inlineable // FIXME(sil-serialize-all)
+@_versioned // FIXME(sil-serialize-all)
+@_silgen_name("_swift_stdlib_NSObject_isKindOfClass")
+internal func _isImpl(_ object: AnyObject, kindOf: AnyObject) -> Bool
+
+@_inlineable // FIXME(sil-serialize-all)
+@_versioned // FIXME(sil-serialize-all)
+internal func _is(_ object: AnyObject, kindOf `class`: String) -> Bool {
+ return _isImpl(object, kindOf: `class` as AnyObject)
+}
+
+@_inlineable // FIXME(sil-serialize-all)
+@_versioned // FIXME(sil-serialize-all)
+internal func _getClassPlaygroundQuickLook(
+ _ object: AnyObject
+) -> PlaygroundQuickLook? {
+ if _is(object, kindOf: "NSNumber") {
+ let number: _NSNumber = unsafeBitCast(object, to: _NSNumber.self)
+ switch UInt8(number.objCType[0]) {
+ case UInt8(ascii: "d"):
+ return .double(number.doubleValue)
+ case UInt8(ascii: "f"):
+ return .float(number.floatValue)
+ case UInt8(ascii: "Q"):
+ return .uInt(number.unsignedLongLongValue)
+ default:
+ return .int(number.longLongValue)
+ }
+ }
+
+ if _is(object, kindOf: "NSAttributedString") {
+ return .attributedString(object)
+ }
+
+ if _is(object, kindOf: "NSImage") ||
+ _is(object, kindOf: "UIImage") ||
+ _is(object, kindOf: "NSImageView") ||
+ _is(object, kindOf: "UIImageView") ||
+ _is(object, kindOf: "CIImage") ||
+ _is(object, kindOf: "NSBitmapImageRep") {
+ return .image(object)
+ }
+
+ if _is(object, kindOf: "NSColor") ||
+ _is(object, kindOf: "UIColor") {
+ return .color(object)
+ }
+
+ if _is(object, kindOf: "NSBezierPath") ||
+ _is(object, kindOf: "UIBezierPath") {
+ return .bezierPath(object)
+ }
+
+ if _is(object, kindOf: "NSString") {
+ return .text(_forceBridgeFromObjectiveC(object, String.self))
+ }
+
+ return .none
+}
+#endif
+
+extension Mirror {
+ @_inlineable // FIXME(sil-serialize-all)
+ @_versioned
+ internal init(internalReflecting subject: Any,
+ subjectType: Any.Type? = nil,
+ customAncestor: Mirror? = nil)
+ {
+ let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
+
+ let childCount = _getChildCount(subject, type: subjectType)
+ let children = (0 ..< childCount).lazy.map({
+ getChild(of: subject, type: subjectType, index: $0)
+ })
+ self.children = Children(children)
+
+ self._makeSuperclassMirror = {
+ guard let subjectClass = subjectType as? AnyClass,
+ let superclass = _getSuperclass(subjectClass) else {
+ return nil
+ }
+
+ // Handle custom ancestors. If we've hit the custom ancestor's subject type,
+ // or descendants are suppressed, return it. Otherwise continue reflecting.
+ if let customAncestor = customAncestor {
+ if superclass == customAncestor.subjectType {
+ return customAncestor
+ }
+ if customAncestor._defaultDescendantRepresentation == .suppressed {
+ return customAncestor
+ }
+ }
+ return Mirror(internalReflecting: subject,
+ subjectType: superclass,
+ customAncestor: customAncestor)
+ }
+
+ let rawDisplayStyle = _getDisplayStyle(subject)
+ switch UnicodeScalar(Int(rawDisplayStyle)) {
+ case "c": self.displayStyle = .class
+ case "e": self.displayStyle = .enum
+ case "s": self.displayStyle = .struct
+ case "t": self.displayStyle = .tuple
+ case "\0": self.displayStyle = nil
+ default: preconditionFailure("Unknown raw display style '\(rawDisplayStyle)'")
+ }
+
+ self.subjectType = subjectType
+ self._defaultDescendantRepresentation = .generated
+ }
+
+ @_inlineable // FIXME(sil-serialize-all)
+ @_versioned
+ internal static func quickLookObject(_ subject: Any) -> PlaygroundQuickLook? {
+#if _runtime(_ObjC)
+ let object = _getQuickLookObject(subject)
+ return object.flatMap(_getClassPlaygroundQuickLook)
+#else
+ return nil
+#endif
+ }
+}
diff --git a/stdlib/public/core/RuntimeFunctionCounters.swift b/stdlib/public/core/RuntimeFunctionCounters.swift
index 3b3274f..18d99db 100644
--- a/stdlib/public/core/RuntimeFunctionCounters.swift
+++ b/stdlib/public/core/RuntimeFunctionCounters.swift
@@ -37,9 +37,7 @@
) {
// Use the structural reflection and ignore any
// custom reflectable overrides.
- let mirror = Mirror(
- legacy: _reflect(value),
- subjectType: type(of: value))
+ let mirror = Mirror(internalReflecting: value)
let id: ObjectIdentifier?
let ref: UnsafeRawPointer?
diff --git a/stdlib/public/core/SequenceAlgorithms.swift.gyb b/stdlib/public/core/SequenceAlgorithms.swift
similarity index 86%
rename from stdlib/public/core/SequenceAlgorithms.swift.gyb
rename to stdlib/public/core/SequenceAlgorithms.swift
index 5add15f..960ef8d 100644
--- a/stdlib/public/core/SequenceAlgorithms.swift.gyb
+++ b/stdlib/public/core/SequenceAlgorithms.swift
@@ -1,4 +1,4 @@
-//===--- SequenceAlgorithms.swift.gyb -------------------------*- swift -*-===//
+//===--- SequenceAlgorithms.swift -----------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
@@ -10,36 +10,6 @@
//
//===----------------------------------------------------------------------===//
-%{
-
-orderingExplanation = """\
- /// The predicate must be a *strict weak ordering* over the elements. That
- /// is, for any elements `a`, `b`, and `c`, the following conditions must
- /// hold:
- ///
- /// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
- /// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
- /// both `true`, then `areInIncreasingOrder(a, c)` is also
- /// `true`. (Transitive comparability)
- /// - Two elements are *incomparable* if neither is ordered before the other
- /// according to the predicate. If `a` and `b` are incomparable, and `b`
- /// and `c` are incomparable, then `a` and `c` are also incomparable.
- /// (Transitive incomparability)
- ///"""
-
-equivalenceExplanation = """\
- /// The predicate must be a *equivalence relation* over the elements. That
- /// is, for any elements `a`, `b`, and `c`, the following conditions must
- /// hold:
- ///
- /// - `areEquivalent(a, a)` is always `true`. (Reflexivity)
- /// - `areEquivalent(a, b)` implies `areEquivalent(b, a)`. (Symmetry)
- /// - If `areEquivalent(a, b)` and `areEquivalent(b, c)` are both `true`, then
- /// `areEquivalent(a, c)` is also `true`. (Transitivity)
- ///"""
-
-}%
-
//===----------------------------------------------------------------------===//
// enumerated()
//===----------------------------------------------------------------------===//
@@ -101,18 +71,23 @@
// min(), max()
//===----------------------------------------------------------------------===//
-% # Generate two versions: with explicit predicates and with
-% # a Comparable requirement.
-% for preds in [True, False]:
-% rethrows_ = "rethrows " if preds else ""
-
-extension Sequence ${"" if preds else "where Element : Comparable"} {
-
-% if preds:
+extension Sequence {
/// Returns the minimum element in the sequence, using the given predicate as
/// the comparison between elements.
///
-${orderingExplanation}
+ /// The predicate must be a *strict weak ordering* over the elements. That
+ /// is, for any elements `a`, `b`, and `c`, the following conditions must
+ /// hold:
+ ///
+ /// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
+ /// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
+ /// both `true`, then `areInIncreasingOrder(a, c)` is also
+ /// `true`. (Transitive comparability)
+ /// - Two elements are *incomparable* if neither is ordered before the other
+ /// according to the predicate. If `a` and `b` are incomparable, and `b`
+ /// and `c` are incomparable, then `a` and `c` are also incomparable.
+ /// (Transitive incomparability)
+ ///
/// This example shows how to use the `min(by:)` method on a
/// dictionary to find the key-value pair with the lowest value.
///
@@ -127,43 +102,35 @@
/// - Returns: The sequence's minimum element, according to
/// `areInIncreasingOrder`. If the sequence has no elements, returns
/// `nil`.
-% else:
- /// Returns the minimum element in the sequence.
- ///
- /// This example finds the smallest value in an array of height measurements.
- ///
- /// let heights = [67.5, 65.7, 64.3, 61.1, 58.5, 60.3, 64.9]
- /// let lowestHeight = heights.min()
- /// print(lowestHeight)
- /// // Prints "Optional(58.5)"
- ///
- /// - Returns: The sequence's minimum element. If the sequence has no
- /// elements, returns `nil`.
-% end
@_inlineable
@warn_unqualified_access
public func min(
-% if preds:
by areInIncreasingOrder: (Element, Element) throws -> Bool
-% end
- ) ${rethrows_}-> Element? {
+ ) rethrows -> Element? {
var it = makeIterator()
guard var result = it.next() else { return nil }
- for e in IteratorSequence(it) {
-% if preds:
+ while let e = it.next() {
if try areInIncreasingOrder(e, result) { result = e }
-% else:
- if e < result { result = e }
-% end
}
return result
}
-% if preds:
/// Returns the maximum element in the sequence, using the given predicate
/// as the comparison between elements.
///
-${orderingExplanation}
+ /// The predicate must be a *strict weak ordering* over the elements. That
+ /// is, for any elements `a`, `b`, and `c`, the following conditions must
+ /// hold:
+ ///
+ /// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
+ /// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
+ /// both `true`, then `areInIncreasingOrder(a, c)` is also
+ /// `true`. (Transitive comparability)
+ /// - Two elements are *incomparable* if neither is ordered before the other
+ /// according to the predicate. If `a` and `b` are incomparable, and `b`
+ /// and `c` are incomparable, then `a` and `c` are also incomparable.
+ /// (Transitive incomparability)
+ ///
/// This example shows how to use the `max(by:)` method on a
/// dictionary to find the key-value pair with the highest value.
///
@@ -177,7 +144,38 @@
/// otherwise, `false`.
/// - Returns: The sequence's maximum element if the sequence is not empty;
/// otherwise, `nil`.
-% else:
+ @_inlineable
+ @warn_unqualified_access
+ public func max(
+ by areInIncreasingOrder: (Element, Element) throws -> Bool
+ ) rethrows -> Element? {
+ var it = makeIterator()
+ guard var result = it.next() else { return nil }
+ while let e = it.next() {
+ if try areInIncreasingOrder(result, e) { result = e }
+ }
+ return result
+ }
+}
+
+extension Sequence where Element: Comparable {
+ /// Returns the minimum element in the sequence.
+ ///
+ /// This example finds the smallest value in an array of height measurements.
+ ///
+ /// let heights = [67.5, 65.7, 64.3, 61.1, 58.5, 60.3, 64.9]
+ /// let lowestHeight = heights.min()
+ /// print(lowestHeight)
+ /// // Prints "Optional(58.5)"
+ ///
+ /// - Returns: The sequence's minimum element. If the sequence has no
+ /// elements, returns `nil`.
+ @_inlineable
+ @warn_unqualified_access
+ public func min() -> Element? {
+ return self.min(by: <)
+ }
+
/// Returns the maximum element in the sequence.
///
/// This example finds the largest value in an array of height measurements.
@@ -189,46 +187,31 @@
///
/// - Returns: The sequence's maximum element. If the sequence has no
/// elements, returns `nil`.
-% end
@_inlineable
@warn_unqualified_access
- public func max(
-% if preds:
- by areInIncreasingOrder: (Element, Element) throws -> Bool
-% end
- ) ${rethrows_}-> Element? {
- var it = makeIterator()
- guard var result = it.next() else { return nil }
- for e in IteratorSequence(it) {
-% if preds:
- if try areInIncreasingOrder(result, e) { result = e }
-% else:
- if e > result { result = e }
-% end
- }
- return result
+ public func max() -> Element? {
+ return self.max(by: <)
}
}
-% end
-
//===----------------------------------------------------------------------===//
// starts(with:)
//===----------------------------------------------------------------------===//
-% # Generate two versions: with explicit predicates and with
-% # an Equatable requirement.
-% for preds in [True, False]:
-% rethrows_ = "rethrows " if preds else ""
-
-extension Sequence ${"" if preds else "where Element : Equatable"} {
-
-% if preds:
+extension Sequence {
/// Returns a Boolean value indicating whether the initial elements of the
/// sequence are equivalent to the elements in another sequence, using
/// the given predicate as the equivalence test.
///
-${equivalenceExplanation}
+ /// The predicate must be a *equivalence relation* over the elements. That
+ /// is, for any elements `a`, `b`, and `c`, the following conditions must
+ /// hold:
+ ///
+ /// - `areEquivalent(a, a)` is always `true`. (Reflexivity)
+ /// - `areEquivalent(a, b)` implies `areEquivalent(b, a)`. (Symmetry)
+ /// - If `areEquivalent(a, b)` and `areEquivalent(b, c)` are both `true`, then
+ /// `areEquivalent(a, c)` is also `true`. (Transitivity)
+ ///
/// - Parameters:
/// - possiblePrefix: A sequence to compare to this sequence.
/// - areEquivalent: A predicate that returns `true` if its two arguments
@@ -236,7 +219,27 @@
/// - Returns: `true` if the initial elements of the sequence are equivalent
/// to the elements of `possiblePrefix`; otherwise, `false`. If
/// `possiblePrefix` has no elements, the return value is `true`.
-% else:
+ @_inlineable
+ public func starts<PossiblePrefix: Sequence>(
+ with possiblePrefix: PossiblePrefix,
+ by areEquivalent: (Element, PossiblePrefix.Element) throws -> Bool
+ ) rethrows -> Bool {
+ var possiblePrefixIterator = possiblePrefix.makeIterator()
+ for e0 in self {
+ if let e1 = possiblePrefixIterator.next() {
+ if try !areEquivalent(e0, e1) {
+ return false
+ }
+ }
+ else {
+ return true
+ }
+ }
+ return possiblePrefixIterator.next() == nil
+ }
+}
+
+extension Sequence where Element: Equatable {
/// Returns a Boolean value indicating whether the initial elements of the
/// sequence are the same as the elements in another sequence.
///
@@ -259,61 +262,61 @@
/// - Returns: `true` if the initial elements of the sequence are the same as
/// the elements of `possiblePrefix`; otherwise, `false`. If
/// `possiblePrefix` has no elements, the return value is `true`.
-% end
@_inlineable
- public func starts<PossiblePrefix>(
- with possiblePrefix: PossiblePrefix${"," if preds else ""}
-% if preds:
- by areEquivalent: (Element, Element) throws -> Bool
-% end
- ) ${rethrows_}-> Bool
- where
- PossiblePrefix : Sequence,
- PossiblePrefix.Element == Element {
-
- var possiblePrefixIterator = possiblePrefix.makeIterator()
- for e0 in self {
- if let e1 = possiblePrefixIterator.next() {
- if ${"try !areEquivalent(e0, e1)" if preds else "e0 != e1"} {
- return false
- }
- }
- else {
- return true
- }
- }
- return possiblePrefixIterator.next() == nil
+ public func starts<PossiblePrefix: Sequence>(
+ with possiblePrefix: PossiblePrefix
+ ) -> Bool where PossiblePrefix.Element == Element {
+ return self.starts(with: possiblePrefix, by: ==)
}
}
-% end
-
//===----------------------------------------------------------------------===//
// elementsEqual()
//===----------------------------------------------------------------------===//
-% # Generate two versions: with explicit predicates and with
-% # an Equatable requirement.
-% for preds in [True, False]:
-% rethrows_ = "rethrows " if preds else ""
-
-extension Sequence ${"" if preds else "where Element : Equatable"} {
-
-% if preds:
+extension Sequence {
/// Returns a Boolean value indicating whether this sequence and another
/// sequence contain equivalent elements in the same order, using the given
/// predicate as the equivalence test.
///
/// At least one of the sequences must be finite.
///
-${equivalenceExplanation}
+ /// The predicate must be a *equivalence relation* over the elements. That
+ /// is, for any elements `a`, `b`, and `c`, the following conditions must
+ /// hold:
+ ///
+ /// - `areEquivalent(a, a)` is always `true`. (Reflexivity)
+ /// - `areEquivalent(a, b)` implies `areEquivalent(b, a)`. (Symmetry)
+ /// - If `areEquivalent(a, b)` and `areEquivalent(b, c)` are both `true`, then
+ /// `areEquivalent(a, c)` is also `true`. (Transitivity)
+ ///
/// - Parameters:
/// - other: A sequence to compare to this sequence.
/// - areEquivalent: A predicate that returns `true` if its two arguments
/// are equivalent; otherwise, `false`.
/// - Returns: `true` if this sequence and `other` contain equivalent items,
/// using `areEquivalent` as the equivalence test; otherwise, `false.`
-% else:
+ @_inlineable
+ public func elementsEqual<OtherSequence: Sequence>(
+ _ other: OtherSequence,
+ by areEquivalent: (Element, OtherSequence.Element) throws -> Bool
+ ) rethrows -> Bool {
+ var iter1 = self.makeIterator()
+ var iter2 = other.makeIterator()
+ while true {
+ switch (iter1.next(), iter2.next()) {
+ case let (e1?, e2?):
+ if try !areEquivalent(e1, e2) {
+ return false
+ }
+ case (_?, nil), (nil, _?): return false
+ case (nil, nil): return true
+ }
+ }
+ }
+}
+
+extension Sequence where Element : Equatable {
/// Returns a Boolean value indicating whether this sequence and another
/// sequence contain the same elements in the same order.
///
@@ -333,57 +336,36 @@
/// - Parameter other: A sequence to compare to this sequence.
/// - Returns: `true` if this sequence and `other` contain the same elements
/// in the same order.
-% end
@_inlineable
- public func elementsEqual<OtherSequence>(
- _ other: OtherSequence${"," if preds else ""}
-% if preds:
- by areEquivalent: (Element, OtherSequence.Element) throws -> Bool
-% end
- ) ${rethrows_}-> Bool
- where
- OtherSequence: Sequence${" {" if preds else ","}
-% if not preds:
- OtherSequence.Element == Element {
-% end
-
- var iter1 = self.makeIterator()
- var iter2 = other.makeIterator()
- while true {
- switch (iter1.next(), iter2.next()) {
- case let (e1?, e2?):
- if ${'try !areEquivalent(e1, e2)' if preds else 'e1 != e2'} {
- return false
- }
- case (_?, nil),
- (nil, _?):
- return false
- case (nil, nil):
- return true
- }
- }
+ public func elementsEqual<OtherSequence: Sequence>(
+ _ other: OtherSequence
+ ) -> Bool where OtherSequence.Element == Element {
+ return self.elementsEqual(other, by: ==)
}
}
-% end
-
//===----------------------------------------------------------------------===//
// lexicographicallyPrecedes()
//===----------------------------------------------------------------------===//
-% # Generate two versions: with explicit predicates and with
-% # Comparable requirement.
-% for preds in [True, False]:
-% rethrows_ = "rethrows " if preds else ""
-
-extension Sequence ${"" if preds else "where Element : Comparable"} {
-
-% if preds:
+extension Sequence {
/// Returns a Boolean value indicating whether the sequence precedes another
/// sequence in a lexicographical (dictionary) ordering, using the given
/// predicate to compare elements.
///
-${orderingExplanation}
+ /// The predicate must be a *strict weak ordering* over the elements. That
+ /// is, for any elements `a`, `b`, and `c`, the following conditions must
+ /// hold:
+ ///
+ /// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
+ /// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
+ /// both `true`, then `areInIncreasingOrder(a, c)` is also
+ /// `true`. (Transitive comparability)
+ /// - Two elements are *incomparable* if neither is ordered before the other
+ /// according to the predicate. If `a` and `b` are incomparable, and `b`
+ /// and `c` are incomparable, then `a` and `c` are also incomparable.
+ /// (Transitive incomparability)
+ ///
/// - Parameters:
/// - other: A sequence to compare to this sequence.
/// - areInIncreasingOrder: A predicate that returns `true` if its first
@@ -396,7 +378,34 @@
/// ordering, which has no connection to Unicode. If you are sorting
/// strings to present to the end user, use `String` APIs that perform
/// localized comparison instead.
-% else:
+ @_inlineable
+ public func lexicographicallyPrecedes<OtherSequence: Sequence>(
+ _ other: OtherSequence,
+ by areInIncreasingOrder: (Element, Element) throws -> Bool
+ ) rethrows -> Bool
+ where OtherSequence.Element == Element {
+ var iter1 = self.makeIterator()
+ var iter2 = other.makeIterator()
+ while true {
+ if let e1 = iter1.next() {
+ if let e2 = iter2.next() {
+ if try areInIncreasingOrder(e1, e2) {
+ return true
+ }
+ if try areInIncreasingOrder(e2, e1) {
+ return false
+ }
+ continue // Equivalent
+ }
+ return false
+ }
+
+ return iter2.next() != nil
+ }
+ }
+}
+
+extension Sequence where Element : Comparable {
/// Returns a Boolean value indicating whether the sequence precedes another
/// sequence in a lexicographical (dictionary) ordering, using the
/// less-than operator (`<`) to compare elements.
@@ -420,77 +429,18 @@
/// ordering, which has no connection to Unicode. If you are sorting
/// strings to present to the end user, use `String` APIs that
/// perform localized comparison.
-% end
@_inlineable
- public func lexicographicallyPrecedes<OtherSequence>(
- _ other: OtherSequence${"," if preds else ""}
-% if preds:
- by areInIncreasingOrder:
- (Element, Element) throws -> Bool
-% end
- ) ${rethrows_}-> Bool
- where
- OtherSequence : Sequence,
- OtherSequence.Element == Element {
-
- var iter1 = self.makeIterator()
- var iter2 = other.makeIterator()
- while true {
- if let e1 = iter1.next() {
- if let e2 = iter2.next() {
- if ${"try areInIncreasingOrder(e1, e2)" if preds else "e1 < e2"} {
- return true
- }
- if ${"try areInIncreasingOrder(e2, e1)" if preds else "e2 < e1"} {
- return false
- }
- continue // Equivalent
- }
- return false
- }
-
- return iter2.next() != nil
- }
+ public func lexicographicallyPrecedes<OtherSequence: Sequence>(
+ _ other: OtherSequence
+ ) -> Bool where OtherSequence.Element == Element {
+ return self.lexicographicallyPrecedes(other, by: <)
}
}
-% end
-
//===----------------------------------------------------------------------===//
// contains()
//===----------------------------------------------------------------------===//
-extension Sequence where Element : Equatable {
- /// Returns a Boolean value indicating whether the sequence contains the
- /// given element.
- ///
- /// This example checks to see whether a favorite actor is in an array
- /// storing a movie's cast.
- ///
- /// let cast = ["Vivien", "Marlon", "Kim", "Karl"]
- /// print(cast.contains("Marlon"))
- /// // Prints "true"
- /// print(cast.contains("James"))
- /// // Prints "false"
- ///
- /// - Parameter element: The element to find in the sequence.
- /// - Returns: `true` if the element was found in the sequence; otherwise,
- /// `false`.
- @_inlineable
- public func contains(_ element: Element) -> Bool {
- if let result = _customContainsEquatableElement(element) {
- return result
- }
-
- for e in self {
- if e == element {
- return true
- }
- }
- return false
- }
-}
-
extension Sequence {
/// Returns a Boolean value indicating whether the sequence contains an
/// element that satisfies the given predicate.
@@ -540,6 +490,32 @@
}
}
+extension Sequence where Element : Equatable {
+ /// Returns a Boolean value indicating whether the sequence contains the
+ /// given element.
+ ///
+ /// This example checks to see whether a favorite actor is in an array
+ /// storing a movie's cast.
+ ///
+ /// let cast = ["Vivien", "Marlon", "Kim", "Karl"]
+ /// print(cast.contains("Marlon"))
+ /// // Prints "true"
+ /// print(cast.contains("James"))
+ /// // Prints "false"
+ ///
+ /// - Parameter element: The element to find in the sequence.
+ /// - Returns: `true` if the element was found in the sequence; otherwise,
+ /// `false`.
+ @_inlineable
+ public func contains(_ element: Element) -> Bool {
+ if let result = _customContainsEquatableElement(element) {
+ return result
+ } else {
+ return self.contains { $0 == element }
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// reduce()
//===----------------------------------------------------------------------===//
@@ -741,7 +717,7 @@
/// let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
/// // [1, 2, nil, nil, 5]
///
- /// let flatMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }
+ /// let compactMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }
/// // [1, 2, 5]
///
/// - Parameter transform: A closure that accepts an element of this
diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift
index 5ed3f0e..0024ada 100644
--- a/stdlib/public/core/String.swift
+++ b/stdlib/public/core/String.swift
@@ -1366,6 +1366,10 @@
}
extension String : CustomStringConvertible {
+ /// The value of this string.
+ ///
+ /// Using this property directly is discouraged. Instead, use simple
+ /// assignment to create a new constant or variable equal to this string.
@_inlineable // FIXME(sil-serialize-all)
public var description: String {
return self
diff --git a/stdlib/public/core/StringComparable.swift b/stdlib/public/core/StringComparable.swift
index 89c2fe2..d19d61b 100644
--- a/stdlib/public/core/StringComparable.swift
+++ b/stdlib/public/core/StringComparable.swift
@@ -12,148 +12,6 @@
import SwiftShims
-#if _runtime(_ObjC)
-/// Compare two strings using the Unicode collation algorithm in the
-/// deterministic comparison mode. (The strings which are equivalent according
-/// to their NFD form are considered equal. Strings which are equivalent
-/// according to the plain Unicode collation algorithm are additionally ordered
-/// based on their NFD.)
-///
-/// See Unicode Technical Standard #10.
-///
-/// The behavior is equivalent to `NSString.compare()` with default options.
-///
-/// - returns:
-/// * an unspecified value less than zero if `lhs < rhs`,
-/// * zero if `lhs == rhs`,
-/// * an unspecified value greater than zero if `lhs > rhs`.
-@_inlineable // FIXME(sil-serialize-all)
-@_silgen_name("swift_stdlib_compareNSStringDeterministicUnicodeCollation")
-public func _stdlib_compareNSStringDeterministicUnicodeCollation(
- _ lhs: AnyObject, _ rhs: AnyObject
-) -> Int32
-
-@_inlineable // FIXME(sil-serialize-all)
-@_silgen_name("swift_stdlib_compareNSStringDeterministicUnicodeCollationPtr")
-public func _stdlib_compareNSStringDeterministicUnicodeCollationPointer(
- _ lhs: OpaquePointer, _ rhs: OpaquePointer
-) -> Int32
-#endif
-
-#if _runtime(_ObjC)
-extension _UnmanagedString where CodeUnit == UInt8 {
- /// This is consistent with Foundation, but incorrect as defined by Unicode.
- /// Unicode weights some ASCII punctuation in a different order than ASCII
- /// value. Such as:
- ///
- /// 0022 ; [*02FF.0020.0002] # QUOTATION MARK
- /// 0023 ; [*038B.0020.0002] # NUMBER SIGN
- /// 0025 ; [*038C.0020.0002] # PERCENT SIGN
- /// 0026 ; [*0389.0020.0002] # AMPERSAND
- /// 0027 ; [*02F8.0020.0002] # APOSTROPHE
- ///
- @_inlineable // FIXME(sil-serialize-all)
- @_versioned
- internal func compareASCII(to other: _UnmanagedString<UInt8>) -> Int {
- // FIXME Results should be the same across all platforms.
- if self.start == other.start {
- return (self.count &- other.count).signum()
- }
- var cmp = Int(truncatingIfNeeded:
- _stdlib_memcmp(
- self.rawStart, other.rawStart,
- Swift.min(self.count, other.count)))
- if cmp == 0 {
- cmp = self.count &- other.count
- }
- return cmp.signum()
- }
-}
-#endif
-
-extension _StringGuts {
-
- //
- // FIXME(TODO: JIRA): HACK HACK HACK: Work around for ARC :-(
- //
- @inline(never)
- @effects(readonly)
- public
- static func _compareDeterministicUnicodeCollation(
- _leftUnsafeStringGutsBitPattern leftBits: _RawBitPattern,
- _rightUnsafeStringGutsBitPattern rightBits: _RawBitPattern
- ) -> Int {
- let left = _StringGuts(rawBits: leftBits)
- let right = _StringGuts(rawBits: rightBits)
- return _compareDeterministicUnicodeCollation(
- left, 0..<left.count, to: right, 0..<right.count)
- }
- @inline(never)
- @effects(readonly)
- public
- static func _compareDeterministicUnicodeCollation(
- _leftUnsafeStringGutsBitPattern leftBits: _RawBitPattern,
- _ leftRange: Range<Int>,
- _rightUnsafeStringGutsBitPattern rightBits: _RawBitPattern,
- _ rightRange: Range<Int>
- ) -> Int {
- let left = _StringGuts(rawBits: leftBits)
- let right = _StringGuts(rawBits: rightBits)
- return _compareDeterministicUnicodeCollation(
- left, leftRange, to: right, rightRange)
- }
-
- /// Compares two slices of strings with the Unicode Collation Algorithm.
- @inline(never) // Hide the CF/ICU dependency
- @effects(readonly)
- public // @testable
- static func _compareDeterministicUnicodeCollation(
- _ left: _StringGuts, _ leftRange: Range<Int>,
- to right: _StringGuts, _ rightRange: Range<Int>) -> Int {
- // Note: this operation should be consistent with equality comparison of
- // Character.
-#if _runtime(_ObjC)
- if _fastPath(left._isContiguous && right._isContiguous) {
- let l = _NSContiguousString(_unmanaged: left, range: leftRange)
- let r = _NSContiguousString(_unmanaged: right, range: rightRange)
- return l._unsafeWithNotEscapedSelfPointerPair(r) {
- return Int(
- _stdlib_compareNSStringDeterministicUnicodeCollationPointer($0, $1))
- }
- } else {
- let l = left._ephemeralCocoaString(leftRange)
- let r = right._ephemeralCocoaString(rightRange)
- return Int(_stdlib_compareNSStringDeterministicUnicodeCollation(l, r))
- }
-#else
- switch (left.isASCII, right.isASCII) {
- case (true, false):
- let l = left._unmanagedASCIIView[leftRange]
- let r = right._unmanagedUTF16View[rightRange]
- return Int(_swift_stdlib_unicode_compare_utf8_utf16(
- l.start, Int32(l.count),
- r.start, Int32(r.count)))
- case (false, true):
- // Just invert it and recurse for this case.
- return -_compareDeterministicUnicodeCollation(
- right, rightRange, to: left, leftRange)
- case (false, false):
- let l = left._unmanagedUTF16View[leftRange]
- let r = right._unmanagedUTF16View[rightRange]
- return Int(_swift_stdlib_unicode_compare_utf16_utf16(
- l.start, Int32(l.count),
- r.start, Int32(r.count)))
- case (true, true):
- let l = left._unmanagedASCIIView[leftRange]
- let r = right._unmanagedASCIIView[rightRange]
- return Int(_swift_stdlib_unicode_compare_utf8_utf8(
- l.start, Int32(l.count),
- r.start, Int32(r.count)))
- }
-#endif
- }
-}
-
extension _StringGuts {
@inline(__always)
@_inlineable
@@ -191,6 +49,10 @@
internal static func isLess(
_ left: _StringGuts, than right: _StringGuts
) -> Bool {
+ // Bitwise equality implies string equality
+ if left._bitwiseEqualTo(right) {
+ return false
+ }
return compare(left, to: right) == -1
}
@@ -200,6 +62,10 @@
_ left: _StringGuts, _ leftRange: Range<Int>,
than right: _StringGuts, _ rightRange: Range<Int>
) -> Bool {
+ // Bitwise equality implies string equality
+ if left._bitwiseEqualTo(right) && leftRange == rightRange {
+ return false
+ }
return compare(left, leftRange, to: right, rightRange) == -1
}
@@ -211,22 +77,18 @@
) -> Int {
defer { _fixLifetime(left) }
defer { _fixLifetime(right) }
-#if _runtime(_ObjC)
- // We only want to perform this optimization on objc runtimes. Elsewhere,
- // we will make it follow the unicode collation algorithm even for ASCII.
- // This is consistent with Foundation, but incorrect as defined by Unicode.
- //
- // FIXME: String ordering should be consistent across all platforms.
+
if left.isASCII && right.isASCII {
let leftASCII = left._unmanagedASCIIView[leftRange]
let rightASCII = right._unmanagedASCIIView[rightRange]
let result = leftASCII.compareASCII(to: rightASCII)
return result
}
-#endif
- return _compareDeterministicUnicodeCollation(
- _leftUnsafeStringGutsBitPattern: left.rawBits, leftRange,
- _rightUnsafeStringGutsBitPattern: right.rawBits, rightRange)
+
+ let leftBits = left.rawBits
+ let rightBits = right.rawBits
+
+ return _compareUnicode(leftBits, leftRange, rightBits, rightRange)
}
@_inlineable
@@ -236,22 +98,18 @@
) -> Int {
defer { _fixLifetime(left) }
defer { _fixLifetime(right) }
-#if _runtime(_ObjC)
- // We only want to perform this optimization on objc runtimes. Elsewhere,
- // we will make it follow the unicode collation algorithm even for ASCII.
- // This is consistent with Foundation, but incorrect as defined by Unicode.
- //
- // FIXME: String ordering should be consistent across all platforms.
+
if left.isASCII && right.isASCII {
let leftASCII = left._unmanagedASCIIView
let rightASCII = right._unmanagedASCIIView
let result = leftASCII.compareASCII(to: rightASCII)
return result
}
-#endif
- return _compareDeterministicUnicodeCollation(
- _leftUnsafeStringGutsBitPattern: left.rawBits,
- _rightUnsafeStringGutsBitPattern: right.rawBits)
+
+ let leftBits = left.rawBits
+ let rightBits = right.rawBits
+
+ return _compareUnicode(leftBits, rightBits)
}
}
diff --git a/stdlib/public/core/StringComparison.swift b/stdlib/public/core/StringComparison.swift
new file mode 100644
index 0000000..95dbd1b
--- /dev/null
+++ b/stdlib/public/core/StringComparison.swift
@@ -0,0 +1,1196 @@
+//===----------------------------------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+import SwiftShims
+
+//HACK: This gets rid of some retains/releases that was slowing down the
+//memcmp fast path for comparing ascii strings. rdar://problem/37473470
+@inline(never) // @outlined
+@effects(readonly)
+@_versioned // @opaque
+internal
+func _compareUnicode(
+ _ lhs: _StringGuts._RawBitPattern, _ rhs: _StringGuts._RawBitPattern
+) -> Int {
+ let left = _StringGuts(rawBits: lhs)
+ let right = _StringGuts(rawBits: rhs)
+
+ if _slowPath(!left._isContiguous || !right._isContiguous) {
+ if !left._isContiguous {
+ return left._asOpaque()._compareOpaque(right).rawValue
+ } else {
+ return right._asOpaque()._compareOpaque(left).flipped.rawValue
+ }
+ }
+
+ return left._compareContiguous(right)
+}
+
+@inline(never) // @outlined
+@effects(readonly)
+@_versioned // @opaque
+internal
+func _compareUnicode(
+ _ lhs: _StringGuts._RawBitPattern, _ leftRange: Range<Int>,
+ _ rhs: _StringGuts._RawBitPattern, _ rightRange: Range<Int>
+) -> Int {
+ let left = _StringGuts(rawBits: lhs)
+ let right = _StringGuts(rawBits: rhs)
+
+ if _slowPath(!left._isContiguous || !right._isContiguous) {
+ if !left._isContiguous {
+ return left._asOpaque()[leftRange]._compareOpaque(
+ right, rightRange
+ ).rawValue
+ } else {
+ return right._asOpaque()[rightRange]._compareOpaque(
+ left, leftRange
+ ).flipped.rawValue
+ }
+ }
+
+ return left._compareContiguous(leftRange, right, rightRange)
+}
+
+//
+// Pointer casting helpers
+//
+@inline(__always)
+private func _unsafeMutableBufferPointerCast<T, U>(
+ _ ptr: UnsafeMutablePointer<T>,
+ _ count: Int,
+ to: U.Type = U.self
+) -> UnsafeMutableBufferPointer<U> {
+ return UnsafeMutableBufferPointer(
+ start: UnsafeMutableRawPointer(ptr).assumingMemoryBound(to: U.self),
+ count: count
+ )
+}
+@inline(__always)
+private func _unsafeBufferPointerCast<T, U>(
+ _ ptr: UnsafePointer<T>,
+ _ count: Int,
+ to: U.Type = U.self
+) -> UnsafeBufferPointer<U> {
+ return UnsafeBufferPointer(
+ start: UnsafeRawPointer(ptr).assumingMemoryBound(to: U.self),
+ count: count
+ )
+}
+
+internal let _leadingSurrogateBias: UInt16 = 0xd800
+internal let _trailingSurrogateBias: UInt16 = 0xdc00
+internal let _surrogateMask: UInt16 = 0xfc00
+
+@inline(__always)
+internal func _isSurrogate(_ cu: UInt16) -> Bool {
+ return _isLeadingSurrogate(cu) || _isTrailingSurrogate(cu)
+}
+
+@inline(__always)
+internal func _isLeadingSurrogate(_ cu: UInt16) -> Bool {
+ // NOTE: Specifically match against the trailing surrogate mask, as it matches
+ // more cases.
+ return cu & _surrogateMask == _leadingSurrogateBias
+}
+
+@inline(__always)
+internal func _isTrailingSurrogate(_ cu: UInt16) -> Bool {
+ return cu & _surrogateMask == _trailingSurrogateBias
+}
+@inline(__always)
+internal func _decodeSurrogatePair(
+ leading high: UInt16, trailing low: UInt16
+) -> UInt32 {
+ _sanityCheck(_isLeadingSurrogate(high) && _isTrailingSurrogate(low))
+ let hi10: UInt32 = UInt32(high) &- UInt32(_leadingSurrogateBias)
+ _sanityCheck(hi10 < 1<<10, "I said high 10. Not high, like, 20 or something")
+ let lo10: UInt32 = UInt32(low) &- UInt32(_trailingSurrogateBias)
+ _sanityCheck(lo10 < 1<<10, "I said low 10. Not low, like, 20 or something")
+
+ return ((hi10 &<< 10) | lo10) &+ 0x1_00_00
+}
+
+internal func _hasNormalizationBoundary(before cu: UInt16) -> Bool {
+ guard !_isSurrogate(cu) else { return false }
+ return UnicodeScalar(_unchecked: UInt32(cu))._hasNormalizationBoundaryBefore
+}
+
+//
+// Pointer casting helpers
+//
+internal func _castOutputBuffer(
+ _ ptr: UnsafeMutablePointer<_Normalization._SegmentOutputBuffer>,
+ endingAt endIdx: Int = _Normalization._SegmentOutputBuffer.capacity
+) -> UnsafeMutableBufferPointer<UInt16> {
+ let bufPtr: UnsafeMutableBufferPointer<UInt16> =
+ _unsafeMutableBufferPointerCast(
+ ptr, _Normalization._SegmentOutputBuffer.capacity)
+ return UnsafeMutableBufferPointer<UInt16>(rebasing: bufPtr[..<endIdx])
+}
+internal func _castOutputBuffer(
+ _ ptr: UnsafePointer<_Normalization._SegmentOutputBuffer>,
+ endingAt endIdx: Int = _Normalization._SegmentOutputBuffer.capacity
+) -> UnsafeBufferPointer<UInt16> {
+ let bufPtr: UnsafeBufferPointer<UInt16> =
+ _unsafeBufferPointerCast(
+ ptr, _Normalization._SegmentOutputBuffer.capacity)
+ return UnsafeBufferPointer<UInt16>(rebasing: bufPtr[..<endIdx])
+}
+
+extension _FixedArray16 where T == UInt16 {
+ mutating func fill(from other: _UnmanagedString<T>) {
+ _sanityCheck(other.count < _FixedArray16<T>.capacity,
+ "out of bounds fill")
+ for i in 0..<other.count {
+ self[i] = other[i]
+ }
+ }
+}
+
+@_versioned internal
+enum _Ordering: Int, Equatable {
+ case less = -1
+ case equal = 0
+ case greater = 1
+
+ @_versioned internal
+ var flipped: _Ordering {
+ switch self {
+ case .less: return .greater
+ case .equal: return .equal
+ case .greater: return .less
+ }
+ }
+
+ @inline(__always)
+ @_versioned internal
+ init(signedNotation int: Int) {
+ self = int < 0 ? .less : int == 0 ? .equal : .greater
+ }
+}
+
+extension _UnmanagedString where CodeUnit == UInt8 {
+ // TODO: These should be SIMD-ized
+ internal func _findDiffIdx(_ other: _UnmanagedString<UInt16>) -> Int {
+ let count = Swift.min(self.count, other.count)
+ for idx in 0..<count {
+ guard UInt16(self[idx]) == other[idx] else {
+ return idx
+ }
+ }
+ return count
+ }
+}
+
+internal func _findDiffIdx(
+ _ left: UnsafeBufferPointer<UInt8>,
+ _ right: UnsafeBufferPointer<UInt16>
+) -> Int {
+ let count = Swift.min(left.count, right.count)
+ for idx in 0..<count {
+ guard UInt16(left[idx]) == right[idx] else {
+ return idx
+ }
+ }
+ return count
+}
+
+internal func _findDiffIdx<CodeUnit>(
+ _ left: UnsafeBufferPointer<CodeUnit>,
+ _ right: UnsafeBufferPointer<CodeUnit>
+) -> Int where CodeUnit : FixedWidthInteger & UnsignedInteger {
+ let count = Swift.min(left.count, right.count)
+ for idx in 0..<count {
+ guard left[idx] == right[idx] else {
+ return idx
+ }
+ }
+ return count
+}
+
+extension _UnmanagedString where CodeUnit : FixedWidthInteger & UnsignedInteger {
+ internal func _findDiffIdx<CodeUnit>(
+ _ other: _UnmanagedString<CodeUnit>
+ ) -> Int {
+ let count = Swift.min(self.count, other.count)
+ for idx in 0..<count {
+ guard self[idx] == other[idx] else {
+ return idx
+ }
+ }
+ return count
+ }
+}
+
+extension _UnmanagedOpaqueString {
+ internal func _findDiffIdx(_ other: _StringGuts, _ otherRange: Range<Int>
+ ) -> Int {
+ let count = Swift.min(self.count, otherRange.count)
+ for idx in 0..<count {
+ guard self[idx] == other[idx + otherRange.lowerBound] else {
+ return idx
+ }
+ }
+ return count
+ }
+}
+
+internal func _lexicographicalCompare(_ lhs: Int, _ rhs: Int) -> _Ordering {
+ // TODO: inspect code quality
+ return lhs < rhs ? .less : (lhs > rhs ? .greater : .equal)
+}
+
+internal func _lexicographicalCompare(
+ _ lhs: UInt16, _ rhs: UInt16
+) -> _Ordering {
+ return lhs < rhs ? .less : (lhs > rhs ? .greater : .equal)
+}
+
+internal func _lexicographicalCompare(
+ _ leftHS: UnsafeBufferPointer<UInt16>,
+ _ rightHS: UnsafeBufferPointer<UInt16>
+) -> _Ordering {
+ let count = Swift.min(leftHS.count, rightHS.count)
+
+ let idx = _findDiffIdx(leftHS, rightHS)
+ guard idx < count else {
+ return _lexicographicalCompare(leftHS.count, rightHS.count)
+ }
+ let leftHSPtr = leftHS.baseAddress._unsafelyUnwrappedUnchecked
+ let rightHSPtr = rightHS.baseAddress._unsafelyUnwrappedUnchecked
+ return _lexicographicalCompare(leftHSPtr[idx], rightHSPtr[idx])
+}
+
+internal func _lexicographicalCompare(
+ _ leftHS: UnsafeBufferPointer<UInt8>,
+ _ rightHS: UnsafeBufferPointer<UInt16>
+) -> _Ordering {
+ let count = Swift.min(leftHS.count, rightHS.count)
+
+ let idx = _findDiffIdx(leftHS, rightHS)
+ guard idx < count else {
+ return _lexicographicalCompare(leftHS.count, rightHS.count)
+ }
+ let leftHSPtr = leftHS.baseAddress._unsafelyUnwrappedUnchecked
+ let rightHSPtr = rightHS.baseAddress._unsafelyUnwrappedUnchecked
+ return _lexicographicalCompare(UInt16(leftHSPtr[idx]), rightHSPtr[idx])
+}
+@inline(__always)
+internal func _lexicographicalCompare(
+ _ leftHS: UnsafePointer<_Normalization._SegmentOutputBuffer>,
+ leftCount: Int,
+ _ rightHS: UnsafePointer<_Normalization._SegmentOutputBuffer>,
+ rightCount: Int
+) -> _Ordering {
+ return _lexicographicalCompare(
+ _castOutputBuffer(leftHS, endingAt: leftCount),
+ _castOutputBuffer(rightHS, endingAt: rightCount))
+}
+@inline(__always)
+internal func _lexicographicalCompare(
+ _ leftHS: Array<UInt16>,
+ _ rightHS: Array<UInt16>
+) -> _Ordering {
+ return leftHS.withUnsafeBufferPointer { leftPtr in
+ return rightHS.withUnsafeBufferPointer { rightPtr in
+ return _lexicographicalCompare(leftPtr, rightPtr)
+ }
+ }
+}
+
+internal func _parseRawScalar(
+ _ buf: UnsafeMutablePointer<_Normalization._SegmentOutputBuffer>,
+ startingFrom idx: Int = 0
+) -> (UnicodeScalar, scalarEndIndex: Int) {
+ return Swift._parseRawScalar(buffer: _castOutputBuffer(buf), startingFrom: idx)
+}
+
+internal func _parseRawScalar(
+ buffer buf: UnsafeBufferPointer<UInt16>,
+ startingFrom idx: Int = 0
+) -> (UnicodeScalar, scalarEndIndex: Int) {
+ let ptr = buf.baseAddress._unsafelyUnwrappedUnchecked
+ _sanityCheck(idx >= 0 && idx < buf.count, "out of bounds index")
+ let cu: UInt16 = ptr[idx]
+ if _slowPath(idx+1 == buf.count) {
+ return (UnicodeScalar(_unchecked: UInt32(cu)), idx+1)
+ }
+ guard _isLeadingSurrogate(cu) else {
+ return (UnicodeScalar(_unchecked: UInt32(cu)), idx+1)
+ }
+ let nextCu: UInt16 = ptr[idx+1]
+ guard _isTrailingSurrogate(nextCu) else {
+ // Invalid surrogate pair: just return the invalid value
+ return (UnicodeScalar(_unchecked: UInt32(cu)), idx+1)
+ }
+
+ // Decode
+ let value: UInt32 = _decodeSurrogatePair(leading: cu, trailing: nextCu)
+ _sanityCheck(Int32(exactly: value) != nil, "top bit shouldn't be set")
+ return (UnicodeScalar(_unchecked: value), idx+2)
+}
+
+extension _UnmanagedOpaqueString {
+ internal func _parseRawScalar(
+ startingFrom idx: Int = 0
+ ) -> (UnicodeScalar, scalarEndIndex: Int) {
+ var buffer = _FixedArray2<UInt16>(allZeros:())
+ if idx+1 < self.count {
+ buffer[0] = self[idx]
+ buffer[1] = self[idx+1]
+
+ let bufferPointer = _unsafeBufferPointerCast(
+ &buffer, 2, to: UInt16.self
+ )
+ return Swift._parseRawScalar(buffer: bufferPointer, startingFrom: 0)
+ } else {
+ buffer[0] = self[idx]
+
+ let bufferPointer = _unsafeBufferPointerCast(
+ &buffer, 1, to: UInt16.self
+ )
+ return Swift._parseRawScalar(buffer: bufferPointer, startingFrom: 0)
+ }
+ }
+}
+
+extension _UnmanagedString where CodeUnit == UInt16 {
+ internal func _parseRawScalar(
+ startingFrom idx: Int = 0
+ ) -> (UnicodeScalar, scalarEndIndex: Int) {
+ _sanityCheck(idx >= 0 && idx < self.count, "out of bounds index")
+ let cu = self[idx]
+ if _slowPath(idx+1 == self.count) {
+ return (UnicodeScalar(_unchecked: UInt32(cu)), idx+1)
+ }
+ guard _isLeadingSurrogate(cu) else {
+ return (UnicodeScalar(_unchecked: UInt32(cu)), idx+1)
+ }
+ let nextCu = self[idx+1]
+ guard _isTrailingSurrogate(nextCu) else {
+ // Invalid surrogate pair: just return the invalid value
+ return (UnicodeScalar(_unchecked: UInt32(cu)), idx+1)
+ }
+
+ // Decode
+ let value: UInt32 = _decodeSurrogatePair(leading: cu, trailing: nextCu)
+ _sanityCheck(Int32(exactly: value) != nil, "top bit shouldn't be set")
+ return (UnicodeScalar(_unchecked: value), idx+2)
+ }
+
+ internal func _reverseParseRawScalar(
+ endingAt idx: Int // one-past-the-end
+ ) -> (UnicodeScalar, scalarStartIndex: Int) {
+ _sanityCheck(idx > 0 && idx <= self.count, "out of bounds end index")
+
+ // Corner case: leading un-paired surrogate
+ if _slowPath(idx == 1) {
+ return (UnicodeScalar(_unchecked: UInt32(self[0])), 0)
+ }
+
+ let cu = self[idx-1]
+ guard _isTrailingSurrogate(cu) else {
+ return (UnicodeScalar(_unchecked: UInt32(cu)), idx-1)
+ }
+ let priorCU = self[idx-2]
+ guard _isLeadingSurrogate(priorCU) else {
+ return (UnicodeScalar(_unchecked: UInt32(cu)), idx-1)
+ }
+
+ // Decode
+ let value: UInt32 = _decodeSurrogatePair(leading: priorCU, trailing: cu)
+ _sanityCheck(Int32(exactly: value) != nil, "top bit shouldn't be set")
+ return (UnicodeScalar(_unchecked: value), idx-2)
+ }
+
+ internal func _tryNormalize(
+ into outputBuffer: UnsafeMutablePointer<_Normalization._SegmentOutputBuffer>
+ ) -> Int? {
+ return self._tryNormalize(into: _castOutputBuffer(outputBuffer))
+ }
+
+ internal func _tryNormalize(
+ into outputBuffer: UnsafeMutableBufferPointer<UInt16>
+ ) -> Int? {
+ var err = __swift_stdlib_U_ZERO_ERROR
+ let count = __swift_stdlib_unorm2_normalize(
+ _Normalization._nfcNormalizer,
+ self.start,
+ numericCast(self.count),
+ outputBuffer.baseAddress._unsafelyUnwrappedUnchecked,
+ numericCast(outputBuffer.count),
+ &err
+ )
+ guard err.isSuccess else {
+ // The output buffer needs to grow
+ return nil
+ }
+ return numericCast(count)
+ }
+
+ internal func _slowNormalize() -> [UInt16] {
+ _sanityCheck(self.count > 0, "called on empty string")
+
+ let canary = self.count * _Normalization._maxNFCExpansionFactor
+ var count = self.count
+ while true {
+ var result = Array<UInt16>(repeating: 0, count: count)
+ if let length = result.withUnsafeMutableBufferPointer({ (bufPtr) -> Int? in
+ return self._tryNormalize(into: bufPtr)
+ }) {
+ result.removeLast(count - length)
+ return result
+ }
+ // Otherwise, we need to grow
+ guard count <= canary else {
+ fatalError("Invariant broken: Max decomposition factor insufficient")
+ }
+ count *= 2
+ }
+ }
+}
+
+internal func _tryNormalize(
+ _ input: UnsafeBufferPointer<UInt16>,
+ into outputBuffer: UnsafeMutablePointer<_Normalization._SegmentOutputBuffer>
+) -> Int? {
+ return _tryNormalize(input, into: _castOutputBuffer(outputBuffer))
+}
+internal func _tryNormalize(
+ _ input: UnsafeBufferPointer<UInt16>,
+ into outputBuffer: UnsafeMutableBufferPointer<UInt16>
+) -> Int? {
+ var err = __swift_stdlib_U_ZERO_ERROR
+ let count = __swift_stdlib_unorm2_normalize(
+ _Normalization._nfcNormalizer,
+ input.baseAddress._unsafelyUnwrappedUnchecked,
+ numericCast(input.count),
+ outputBuffer.baseAddress._unsafelyUnwrappedUnchecked,
+ numericCast(outputBuffer.count),
+ &err
+ )
+ guard err.isSuccess else {
+ // The output buffer needs to grow
+ return nil
+ }
+ return numericCast(count)
+}
+
+extension _UnmanagedString where CodeUnit == UInt8 {
+ @_inlineable // FIXME(sil-serialize-all)
+ @_versioned
+ internal func compareASCII(to other: _UnmanagedString<UInt8>) -> Int {
+ // FIXME Results should be the same across all platforms.
+ if self.start == other.start {
+ return (self.count &- other.count).signum()
+ }
+ var cmp = Int(truncatingIfNeeded:
+ _stdlib_memcmp(
+ self.rawStart, other.rawStart,
+ Swift.min(self.count, other.count)))
+ if cmp == 0 {
+ cmp = self.count &- other.count
+ }
+ return cmp.signum()
+ }
+}
+
+public extension _StringGuts {
+ @inline(__always)
+ public
+ func _compareContiguous(_ other: _StringGuts) -> Int {
+ _sanityCheck(self._isContiguous && other._isContiguous)
+ switch (self.isASCII, other.isASCII) {
+ case (true, true):
+ fatalError("Should have hit the ascii comp in StringComparable.compare()")
+ case (true, false):
+ return self._unmanagedASCIIView._compareStringsPreLoop(
+ other: other._unmanagedUTF16View
+ ).rawValue
+ case (false, true):
+ // Same compare, just invert result
+ return other._unmanagedASCIIView._compareStringsPreLoop(
+ other: self._unmanagedUTF16View
+ ).flipped.rawValue
+ case (false, false):
+ return self._unmanagedUTF16View._compareStringsPreLoop(
+ other: other._unmanagedUTF16View
+ ).rawValue
+ }
+ }
+
+ @inline(__always)
+ public
+ func _compareContiguous(
+ _ selfRange: Range<Int>,
+ _ other: _StringGuts,
+ _ otherRange: Range<Int>
+ ) -> Int {
+ _sanityCheck(self._isContiguous && other._isContiguous)
+ switch (self.isASCII, other.isASCII) {
+ case (true, true):
+ fatalError("Should have hit the ascii comp in StringComparable.compare()")
+ case (true, false):
+ return self._unmanagedASCIIView[selfRange]._compareStringsPreLoop(
+ other: other._unmanagedUTF16View[otherRange]
+ ).rawValue
+ case (false, true):
+ // Same compare, just invert result
+ return other._unmanagedASCIIView[otherRange]._compareStringsPreLoop(
+ other: self._unmanagedUTF16View[selfRange]
+ ).flipped.rawValue
+ case (false, false):
+ return self._unmanagedUTF16View[selfRange]._compareStringsPreLoop(
+ other: other._unmanagedUTF16View[otherRange]
+ ).rawValue
+ }
+ }
+}
+
+extension _UnmanagedOpaqueString {
+ @inline(never) // @outlined
+ @_versioned
+ internal
+ func _compareOpaque(_ other: _StringGuts) -> _Ordering {
+ return self._compareOpaque(other, 0..<other.count)
+ }
+
+ @inline(never) // @outlined
+ @_versioned
+ internal
+ func _compareOpaque(
+ _ other: _StringGuts, _ otherRange: Range<Int>
+ ) -> _Ordering {
+ //
+ // Do a fast Latiny comparison loop; bail if that proves insufficient.
+ //
+ // The vast majority of the time, seemingly-non-contiguous Strings are
+ // really ASCII strings that were bridged improperly. E.g., unknown nul-
+ // termination of an all-ASCII file loaded by String.init(contentsOfFile:).
+ //
+
+ let selfCount = self.count
+ let otherCount = otherRange.count
+ let count = Swift.min(selfCount, otherCount)
+ let idx = self._findDiffIdx(other, otherRange)
+ if idx == count {
+ return _lexicographicalCompare(selfCount, otherCount)
+ }
+
+ let selfCU = self[idx]
+ let otherCU = other[idx + otherRange.lowerBound]
+
+ //
+ // Fast path: if one is ASCII, we can often compare the code units directly.
+ //
+ let selfIsASCII = selfCU <= 0x7F
+ let otherIsASCII = otherCU <= 0x7F
+
+ let selfIsSingleSegmentScalar =
+ self.hasNormalizationBoundary(after: idx)
+ && _hasNormalizationBoundary(before: selfCU)
+ let otherIsSingleSegmentScalar =
+ other.hasNormalizationBoundary(after: idx)
+ && _hasNormalizationBoundary(before: otherCU)
+
+ if _fastPath(selfIsASCII || otherIsASCII) {
+ _sanityCheck(idx < selfCount && idx < otherCount,
+ "Should be caught by check against min-count")
+ // Check if next CU is <0x300, or if we're in a
+ // "_isNormalizedSuperASCII" case. 99.9% of the time, we're here because
+ // the non-contig string is ASCII. We never want to hit the pathological
+ // path for those.
+
+ if selfIsASCII && otherIsASCII {
+ if selfIsSingleSegmentScalar && otherIsSingleSegmentScalar {
+ return _lexicographicalCompare(selfCU, otherCU)
+ }
+
+ return self._compareOpaquePathological(
+ other, otherRange, startingFrom: Swift.max(0, idx-1))
+ }
+
+ if selfIsASCII && selfIsSingleSegmentScalar
+ && self._parseRawScalar(startingFrom: idx).0._isNormalizedSuperASCII {
+ return .less
+ } else if otherIsASCII && otherIsSingleSegmentScalar
+ && self._parseRawScalar(startingFrom: idx).0._isNormalizedSuperASCII {
+ return .greater
+ }
+ }
+
+ return self._compareOpaquePathological(
+ other, otherRange, startingFrom: Swift.max(0, idx-1)
+ )
+ }
+
+ @inline(never)
+ func _compareOpaquePathological(
+ _ other: _StringGuts, _ otherRange: Range<Int>,
+ startingFrom: Int
+ ) -> _Ordering {
+ // Compare by pulling in a segment at a time, normalizing then comparing
+ // individual code units
+ var selfIterator = _NormalizedCodeUnitIterator(self, startIndex: startingFrom)
+ return selfIterator.compare(with:
+ _NormalizedCodeUnitIterator(other, otherRange, startIndex: startingFrom)
+ )
+ }
+}
+
+extension UnicodeScalar {
+ internal func _normalize(
+ into outputBuffer: UnsafeMutablePointer<_Normalization._SegmentOutputBuffer>
+ ) -> Int {
+ // Implementation: Perform the normalization on an input buffer and output
+ // buffer.
+ func impl(
+ _ input: UnsafeMutablePointer<_FixedArray2<UInt16>>,
+ count: Int,
+ into output: UnsafeMutablePointer<_Normalization._SegmentOutputBuffer>
+ ) -> Int {
+ let inputBuffer = _unsafeBufferPointerCast(
+ input, count, to: UInt16.self
+ )
+ let outputBuffer = _unsafeMutableBufferPointerCast(
+ output, _FixedArray8<UInt16>.capacity, to: UInt16.self
+ )
+ return _tryNormalize(
+ inputBuffer, into: outputBuffer
+ )._unsafelyUnwrappedUnchecked
+ }
+
+ var inBuffer = _FixedArray2<UInt16>(allZeros:())
+ var inLength = 0
+ for cu in self.utf16 {
+ inBuffer[inLength] = cu
+ inLength += 1
+ }
+
+ return impl(&inBuffer, count: inLength, into: outputBuffer)
+ }
+
+ static internal let maxValue = 0x0010_FFFF
+}
+
+private struct _UnicodeScalarExceptions {
+ fileprivate let _multiSegmentExpanders: Set<UInt32>
+ fileprivate let _normalizedASCIIStarter: Array<UInt32>
+
+ @inline(__always)
+ init() {
+ var msExpanders = Set<UInt32>()
+ msExpanders.reserveCapacity(16)
+ var normalizedASCIIStarter = Array<UInt32>()
+ normalizedASCIIStarter.reserveCapacity(8)
+
+ for rawValue in 0..<UnicodeScalar.maxValue {
+ guard let scalar = UnicodeScalar(rawValue) else { continue }
+
+ // Fast path: skip unassigned code points
+ guard scalar._isDefined else { continue }
+
+ // Fast path: skip unless QC_FCD=no
+ if _fastPath(!scalar._hasFullCompExclusion) {
+ continue
+ }
+
+ var outBuffer = _Normalization._SegmentOutputBuffer(allZeros:())
+ let length = scalar._normalize(into: &outBuffer)
+
+ // See if this normalized to have an ASCII starter
+ if _slowPath(outBuffer[0] <= 0x7F) {
+ normalizedASCIIStarter.append(scalar.value)
+ }
+
+ // See if this normalizes to multiple segments
+ var i = 0
+ while i < length {
+ let (innerScalar, nextI) = _parseRawScalar(&outBuffer, startingFrom: i)
+ if _slowPath(i != 0 && innerScalar._hasNormalizationBoundaryBefore) {
+ guard innerScalar._hasNormalizationBoundaryBefore else {
+ fatalError(
+ "Unicode invariant violated: non-starter multi-segment expander")
+ }
+ msExpanders.insert(scalar.value)
+ break
+ }
+ i = nextI
+ }
+ }
+
+ self._multiSegmentExpanders = msExpanders
+ self._normalizedASCIIStarter = normalizedASCIIStarter
+ }
+}
+private let _unicodeScalarExceptions: _UnicodeScalarExceptions = {
+ return _UnicodeScalarExceptions()
+}()
+
+extension UnicodeScalar {
+ // Multi-Segment Expanders - Unicode defines "expanding canonical
+ // decompositions", where even in NFC a single scalar expands to multiple
+ // scalars. A small subset (currently 12 scalars circa Unicode 10) of these
+ // will expand into multiple normalization segments, breaking any kind of
+ // segment-by- segment logic or processing even under NFC. These are a subset
+ // of what is identified by the UCD as "composition exclusion" scalars. Since
+ // we don't have access to a UCD (available only at runtime), we go through
+ // ICU which lumps those and even more as "Full Composition Exclusions". Of
+ // the many full composition exclusions, this set (created once at runtime as
+ // this can change with Unicode version) tracks just those that can expand
+ // into multiple normalization segments.
+ internal var _isMultiSegmentExpander: Bool {
+ return _unicodeScalarExceptions._multiSegmentExpanders.contains(self.value)
+ }
+
+ // Whether, post-normalization, this scalar definitely compares greater than
+ // any ASCII scalar. This is true for all super-ASCII scalars that are not
+ // ASCII Normalized Starters.
+ //
+ // ASCII Normalized Starters - A handful of scalars normalize to have ASCII
+ // starters, e.g. Greek question mark ";". As of Unicode 10 there are 3 (all
+ // from Unicode 1.1 originally) and more are unlikely. But, there could be
+ // more in future versions, so determine at runtime.
+ internal var _isNormalizedSuperASCII: Bool {
+ if _slowPath(
+ _unicodeScalarExceptions._normalizedASCIIStarter.contains(self.value)
+ ) {
+ return false
+ }
+ return self.value > 0x7F
+ }
+}
+
+extension _UnmanagedString where CodeUnit == UInt8 {
+ @_versioned
+ internal func _compareStringsPreLoop(
+ other: _UnmanagedString<UInt16>
+ ) -> _Ordering {
+ let count = Swift.min(self.count, other.count)
+
+ //
+ // Fast scan until we find a difference
+ //
+ let idx = self._findDiffIdx(other)
+ guard idx < count else {
+ return _lexicographicalCompare(self.count, other.count)
+ }
+ let otherCU = other[idx]
+
+ //
+ // Fast path: if other is super-ASCII post-normalization, we must be less. If
+ // other is ASCII and a single-scalar segment, we have our answer.
+ //
+ if otherCU > 0x7F {
+ if _fastPath(
+ other._parseRawScalar(startingFrom: idx).0._isNormalizedSuperASCII
+ ) {
+ return .less
+ }
+ } else {
+ let selfASCIIChar = UInt16(self[idx])
+ _sanityCheck(selfASCIIChar != otherCU, "should be different")
+ if idx+1 == other.count {
+ return _lexicographicalCompare(selfASCIIChar, otherCU)
+ }
+ if _fastPath(other.hasNormalizationBoundary(after: idx, count: other.count)) {
+ return _lexicographicalCompare(selfASCIIChar, otherCU)
+ }
+ }
+
+ //
+ // Otherwise, need to normalize the segment and then compare
+ //
+ let selfASCIIChar = UInt16(self[idx])
+ return _compareStringsPostSuffix(
+ selfASCIIChar: selfASCIIChar, otherUTF16: other[idx...]
+ )
+ }
+}
+
+extension _StringGuts {
+ func hasNormalizationBoundary(after index: Int) -> Bool {
+ let nextIndex = index + 1
+ if nextIndex >= self.count {
+ return true
+ }
+
+ let nextCU = self[nextIndex]
+ return _hasNormalizationBoundary(before: nextCU)
+ }
+}
+
+extension _UnmanagedOpaqueString {
+ func hasNormalizationBoundary(after index: Int) -> Bool {
+ let nextIndex = index + 1
+ if nextIndex >= self.count {
+ return true
+ }
+
+ let nextCU = self[nextIndex]
+ return _hasNormalizationBoundary(before: nextCU)
+ }
+}
+
+extension _UnmanagedString where CodeUnit == UInt16 {
+ func hasNormalizationBoundary(after index: Int, count: Int) -> Bool {
+ let nextIndex = index + 1
+ if nextIndex >= count {
+ return true
+ }
+
+ let nextCU = self[nextIndex]
+ return _hasNormalizationBoundary(before: nextCU)
+ }
+}
+
+private func _compareStringsPostSuffix(
+ selfASCIIChar: UInt16,
+ otherUTF16: _UnmanagedString<UInt16>
+) -> _Ordering {
+ let otherCU = otherUTF16[0]
+ _sanityCheck(otherCU <= 0x7F, "should be ASCII, otherwise no need to call")
+
+ let segmentEndIdx = otherUTF16._findNormalizationSegmentEnd(startingFrom: 0)
+ let segment = otherUTF16[..<segmentEndIdx]
+
+ // Fast path: If prenormal, we're done.
+ if _Normalization._prenormalQuickCheckYes(segment) {
+ return _lexicographicalCompare(selfASCIIChar, otherCU)
+ }
+
+ // Normalize segment, and then compare first code unit
+ var outputBuffer = _Normalization._SegmentOutputBuffer(allZeros:())
+ if _fastPath(
+ segment._tryNormalize(into: &outputBuffer) != nil
+ ) {
+ return _lexicographicalCompare(selfASCIIChar, outputBuffer[0])
+ }
+ return _lexicographicalCompare(selfASCIIChar, segment._slowNormalize()[0])
+}
+
+extension _UnmanagedString where CodeUnit == UInt16 {
+ //
+ // Find the end of the normalization segment
+ //
+ internal func _findNormalizationSegmentEnd(startingFrom idx: Int) -> Int {
+ let count = self.count
+ _sanityCheck(idx < count, "out of bounds")
+
+ // Normalization boundaries are best queried before known starters. Advance
+ // past one scalar first.
+ var (_, segmentEndIdx) = self._parseRawScalar(startingFrom: idx)
+ while segmentEndIdx < count {
+ let (scalar, nextIdx) = self._parseRawScalar(startingFrom: segmentEndIdx)
+ if scalar._hasNormalizationBoundaryBefore {
+ break
+ }
+ segmentEndIdx = nextIdx
+ }
+ return segmentEndIdx
+ }
+
+ internal func _findNormalizationSegmentStart(
+ endingAt idx: Int // one-past-the-end
+ ) -> Int {
+ var idx = idx
+ let count = self.count
+ _sanityCheck(idx > 0 && idx <= count, "out of bounds")
+
+ while idx > 0 {
+ let (scalar, priorIdx) = _reverseParseRawScalar(endingAt: idx)
+ idx = priorIdx
+ if scalar._hasNormalizationBoundaryBefore {
+ break
+ }
+ }
+ return idx
+ }
+
+ internal func _findNormalizationSegment(spanning idx: Int) -> (Int, Int) {
+ var idx = idx
+
+ // Corner case: if we're sub-surrogate, back up
+ if _slowPath(
+ idx > 0
+ && _isTrailingSurrogate(self[idx])
+ && _isLeadingSurrogate(self[idx-1])
+ ) {
+ idx -= 1
+ }
+ let segmentEnd = self._findNormalizationSegmentEnd(startingFrom: idx)
+
+ // Find the start
+ if _slowPath(idx == 0) {
+ return (0, segmentEnd)
+ }
+
+ // Check current scalar
+ if self._parseRawScalar(startingFrom: idx).0._hasNormalizationBoundaryBefore {
+ return (idx, segmentEnd)
+ }
+
+ // Reverse parse until we found the segment start
+ let segmentStart = self._findNormalizationSegmentStart(endingAt: idx)
+
+ return (segmentStart, segmentEnd)
+ }
+
+ // Wether the segment identified by `idx` is prenormal.
+ //
+ // Scalar values below 0x300 are special: normalization segments containing only
+ // one such scalar are trivially prenormal under NFC. Most Latin-derived scripts
+ // can be represented entirely by <0x300 scalar values, meaning that many user
+ // strings satisfy this prenormal check. We call sub-0x300 scalars "Latiny" (not
+ // official terminology).
+ //
+ // The check is effectively:
+ // 1) Whether the current scalar <0x300, AND
+ // 2) Whether the current scalar comprises the entire segment
+ //
+ internal func _isLatinyPrenormal(idx: Int
+ ) -> Bool {
+ _sanityCheck(idx < self.count, "out of bounds")
+
+ let cu = self[idx]
+ if _slowPath(cu >= 0x300) {
+ return false
+ }
+ if _slowPath(idx+1 == self.count) {
+ return true
+ }
+
+ let nextCU = self[idx+1]
+ return nextCU < 0x300 || _hasNormalizationBoundary(before: nextCU)
+ }
+
+ @_versioned
+ internal
+ func _compareStringsPreLoop(
+ other: _UnmanagedString<UInt16>
+ ) -> _Ordering {
+ let count = Swift.min(self.count, other.count)
+
+ //
+ // Fast scan until we find a diff
+ //
+ let idx = _findDiffIdx(other)
+ guard idx < count else {
+ return _lexicographicalCompare(self.count, other.count)
+ }
+ let selfCU = self[idx]
+ let otherCU = other[idx]
+
+ //
+ // Fast path: sub-0x300 single-scalar segments can be compared directly
+ //
+ if _fastPath(
+ _isLatinyPrenormal(idx: idx)
+ && other._isLatinyPrenormal(idx: idx)
+ ) {
+ return _lexicographicalCompare(selfCU, otherCU)
+ }
+
+ return self._compareStringsSuffix(other: other, randomIndex: idx)
+ }
+
+ //Is the shorter of the two parameters a prefix of the other parameter?
+ private func shorterPrefixesOther(
+ _ other: _UnmanagedString<UInt16>
+ ) -> Bool {
+ if self.count == other.count {
+ return false
+ }
+
+ let minimumLength = Swift.min(self.count, other.count)
+ for i in 0..<minimumLength {
+ if self[i] != other[i] {
+ return false
+ }
+ }
+ return true
+ }
+
+ private func _compareStringsSuffix(
+ other: _UnmanagedString<UInt16>,
+ randomIndex: Int
+ ) -> _Ordering {
+ let count = Swift.min(self.count, other.count)
+ let selfCU = self[randomIndex]
+ let otherCU = other[randomIndex]
+ _sanityCheck(randomIndex >= 0 && randomIndex < count, "out of bounds")
+ _sanityCheck(selfCU != otherCU, "should be called at a point of difference")
+
+ //
+ // Find the segment surrounding the random index passed in. This may involve
+ // some back tracking to the nearest normalization boundary. Once we've
+ // identified the segment, we can normalize and continue comparision.
+ //
+ // NOTE: We need to back-track for both self and other. Even though prefixes
+ // are binary equal, the point of difference might be at the start of a new
+ // segment for one and in the middle of the prior segment for the other. In
+ // which case, we will want to effectively compare the two consecutive
+ // segments together.
+ //
+ let (selfSegmentStartIdx, selfSegmentEndIdx) =
+ self._findNormalizationSegment(spanning: randomIndex)
+ let (otherSegmentStartIdx, otherSegmentEndIdx) =
+ other._findNormalizationSegment(spanning: randomIndex)
+ let comparisonStartIdx = Swift.min(selfSegmentStartIdx, otherSegmentStartIdx)
+
+
+ //
+ // Fast path: if both are prenormal, we have our answer
+ //
+ let selfSegment = self[comparisonStartIdx..<selfSegmentEndIdx]
+ let otherSegment = other[comparisonStartIdx..<otherSegmentEndIdx]
+ let selfSegmentPrenormal = _Normalization._prenormalQuickCheckYes(selfSegment)
+ let otherSegmentPrenormal = _Normalization._prenormalQuickCheckYes(
+ otherSegment)
+ if selfSegmentPrenormal && otherSegmentPrenormal {
+ return _lexicographicalCompare(selfCU, otherCU)
+ }
+
+ //
+ // Pathological case: multi-segment expanders ruin segment-by-segment
+ // processing.
+ //
+ // NOTE: Multi-segment expanders are (at least up til Unicode 10) always the
+ // beginning of a normalization segment (i.e. they are starters). This is very
+ // unlikely to change in the future, as new non-starter scalars that normalize
+ // to pre-existing scalars would have to produce a starter. We validate this
+ // fact on constructing our MultiSegmentExpander set, so we can rely on it
+ // here.
+ //
+ if _slowPath(
+ selfSegment._parseRawScalar().0._isMultiSegmentExpander
+ || otherSegment._parseRawScalar().0._isMultiSegmentExpander
+ ) {
+ return self[comparisonStartIdx...]._compareStringsPathological(
+ other: other[comparisonStartIdx...]
+ )
+ }
+
+ //
+ // Normalize segments and compare. If they still differ, we have our answer.
+ //
+ var selfOutputBuffer = _Normalization._SegmentOutputBuffer(allZeros:())
+ var otherOutputBuffer = _Normalization._SegmentOutputBuffer(allZeros:())
+ let selfSegmentLengthOpt: Int?
+ let otherSegmentLengthOpt: Int?
+ if selfSegmentPrenormal {
+ selfOutputBuffer.fill(from: selfSegment)
+ selfSegmentLengthOpt = selfSegment.count
+ } else {
+ selfSegmentLengthOpt = selfSegment._tryNormalize(into: &selfOutputBuffer)
+ }
+ if otherSegmentPrenormal {
+ otherOutputBuffer.fill(from: otherSegment)
+ otherSegmentLengthOpt = otherSegment.count
+ } else {
+ otherSegmentLengthOpt = otherSegment._tryNormalize(into: &otherOutputBuffer)
+ }
+
+ if _slowPath(selfSegmentLengthOpt == nil || otherSegmentLengthOpt == nil) {
+ // If we couldn't normalize a segment into a generously large stack buffer,
+ // we have a pathological String.
+ return self[comparisonStartIdx...]._compareStringsPathological(
+ other: other[comparisonStartIdx...]
+ )
+ }
+ let selfLength = selfSegmentLengthOpt._unsafelyUnwrappedUnchecked
+ let otherLength = otherSegmentLengthOpt._unsafelyUnwrappedUnchecked
+
+ if Swift.shorterPrefixesOther(
+ &selfOutputBuffer, selfLength,
+ &otherOutputBuffer, otherLength)
+ {
+ let selfSlice = self[selfSegmentEndIdx...]
+ let otherSlice = other[otherSegmentEndIdx...]
+ return selfSlice._compareStringsPathological(other: otherSlice)
+ }
+
+ let comp = _lexicographicalCompare(
+ &selfOutputBuffer, leftCount: selfLength,
+ &otherOutputBuffer, rightCount: otherLength)
+ if _fastPath(comp != .equal) {
+ return comp
+ }
+
+ //
+ // If they compare equal after normalization, we may have equal strings that
+ // differ in form, e.g. NFC vs NFD strings. Or, we may have strings that
+ // differ in form that also will differ later on. Either way, segment-by-
+ // segment processing incurs significant overhead. We'd rather do larger
+ // chunks of work at a time (e.g. ~1KB of text at a time). For now, we eagerly
+ // process the entire strings, as chunking properly without guarantees of
+ // normality is tricky (and expensive at times as well).
+ //
+ // NOTE: We could add a chunking path. It is hard to do correctly, because
+ // Unicode. It's especially hard to test, because Unicode. It's hard to ensure
+ // lasting correctness, because Unicode. (Also, sometimes it's impossible, but
+ // that's what _compareStringsPathological is for.) However, it helps for very
+ // long strings that differ in the middle. We might want this one day... but
+ // not today.
+ //
+ // TODO: An additional (or even repeated) reapplying of the algorithm,
+ // including the binary diff scan, could greatly benefit strings that only
+ // sparsely differ in normality (penalizing strings that densely differ in
+ // normality). This would add complexity, but with compelling data could be an
+ // alternative to chunking.
+ //
+ return self[selfSegmentEndIdx...]._compareStringsPathological(
+ other: other[otherSegmentEndIdx...]
+ )
+ }
+
+ private func _compareStringsPathological(
+ other: _UnmanagedString<UInt16>
+ ) -> _Ordering {
+ var selfIterator = _NormalizedCodeUnitIterator(self)
+ return selfIterator.compare(with:
+ _NormalizedCodeUnitIterator(other)
+ )
+ }
+}
+
+private func shorterPrefixesOther(
+ _ selfBuffer: UnsafePointer<_Normalization._SegmentOutputBuffer>,
+ _ selfLength: Int,
+ _ otherBuffer: UnsafePointer<_Normalization._SegmentOutputBuffer>,
+ _ otherLength: Int
+) -> Bool {
+ return shorterPrefixesOther(
+ _castOutputBuffer(selfBuffer, endingAt: selfLength),
+ _castOutputBuffer(otherBuffer, endingAt: otherLength)
+ )
+}
+
+//Is the shorter of the two parameters a prefix of the other parameter?
+private func shorterPrefixesOther(
+ _ selfBuffer: UnsafeBufferPointer<UInt16>,
+ _ otherBuffer: UnsafeBufferPointer<UInt16>
+) -> Bool {
+ if selfBuffer.count == otherBuffer.count {
+ return false
+ }
+
+ let minimumLength = Swift.min(selfBuffer.count, otherBuffer.count)
+ for i in 0..<minimumLength {
+ if selfBuffer[i] != otherBuffer[i] {
+ return false
+ }
+ }
+ return true
+}
+
diff --git a/stdlib/public/core/StringNormalization.swift b/stdlib/public/core/StringNormalization.swift
new file mode 100644
index 0000000..4567407
--- /dev/null
+++ b/stdlib/public/core/StringNormalization.swift
@@ -0,0 +1,120 @@
+//===--- StringNormalization.swift ----------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+import SwiftShims
+
+// A namespace for various heuristics
+//
+internal enum _Normalization {
+ // ICU's NFC unorm2 instance
+ internal static var _nfcNormalizer: OpaquePointer = {
+ var err = __swift_stdlib_U_ZERO_ERROR
+ let normalizer = __swift_stdlib_unorm2_getNFCInstance(&err)
+ guard err.isSuccess else {
+ // This shouldn't be possible unless some deep (unrecoverable) system
+ // invariants are violated
+ fatalError("Unable to talk to ICU")
+ }
+ return normalizer
+ }()
+
+ // Whether this buffer of code units satisfies the quickCheck=YES property for
+ // normality checking under NFC.
+ //
+ // ICU provides a quickCheck, which may yield "YES", "NO", or "MAYBE". YES
+ // means that the string was determined to definitely be normal under NFC. In
+ // practice, the majority of Strings have this property. Checking for YES is
+ // considerably faster than trying to distinguish between NO and MAYBE.
+ internal static func _prenormalQuickCheckYes(
+ _ buffer: UnsafeBufferPointer<UInt16>
+ ) -> Bool {
+ var err = __swift_stdlib_U_ZERO_ERROR
+ let length = __swift_stdlib_unorm2_spanQuickCheckYes(
+ _Normalization._nfcNormalizer,
+ buffer.baseAddress._unsafelyUnwrappedUnchecked,
+ Int32(buffer.count),
+ &err)
+
+ guard err.isSuccess else {
+ // This shouldn't be possible unless some deep (unrecoverable) system
+ // invariants are violated
+ fatalError("Unable to talk to ICU")
+ }
+ return length == buffer.count
+ }
+ internal static func _prenormalQuickCheckYes(
+ _ string: _UnmanagedString<UInt16>
+ ) -> Bool {
+ var err = __swift_stdlib_U_ZERO_ERROR
+ let length = __swift_stdlib_unorm2_spanQuickCheckYes(
+ _Normalization._nfcNormalizer,
+ string.start,
+ Int32(string.count),
+ &err)
+
+ guard err.isSuccess else {
+ // This shouldn't be possible unless some deep (unrecoverable) system
+ // invariants are violated
+ fatalError("Unable to talk to ICU")
+ }
+ return length == string.count
+ }
+}
+
+extension UnicodeScalar {
+ // Normalization boundary - a place in a string where everything left of the
+ // boundary can be normalized independently from everything right of the
+ // boundary. The concatenation of each result is the same as if the entire
+ // string had been normalized as a whole.
+ //
+ // Normalization segment - a sequence of code units between two normalization
+ // boundaries (without any boundaries in the middle). Note that normalization
+ // segments can, as a process of normalization, expand, contract, and even
+ // produce new sub-segments.
+
+ // Whether this scalar value always has a normalization boundary before it.
+ internal var _hasNormalizationBoundaryBefore: Bool {
+ _sanityCheck(Int32(exactly: self.value) != nil, "top bit shouldn't be set")
+ let value = Int32(bitPattern: self.value)
+ return 0 != __swift_stdlib_unorm2_hasBoundaryBefore(
+ _Normalization._nfcNormalizer, value)
+ }
+
+ // Whether the supported version of Unicode has assigned a code point to this
+ // value.
+ internal var _isDefined: Bool {
+ return __swift_stdlib_u_isdefined(Int32(self.value)) != 0
+ }
+
+ // A property tracked in ICU regarding the scalar's potential non-normality;
+ // this is equivalent to whether quickCheck=NO. A subset of such scalars may
+ // expand under NFC normalization, and a subset of those may expand into
+ // multiple segments.
+ internal var _hasFullCompExclusion: Bool {
+ _sanityCheck(Int32(exactly: self.value) != nil, "top bit shouldn't be set")
+ let value = Int32(bitPattern: self.value)
+ let prop = __swift_stdlib_UCHAR_FULL_COMPOSITION_EXCLUSION
+ return __swift_stdlib_u_hasBinaryProperty(value, prop) != 0
+ }
+}
+
+extension _Normalization {
+ // When normalized in NFC, some segments may expand in size (e.g. some non-BMP
+ // musical notes). This expansion is capped by the maximum expansion factor of
+ // the normal form. For NFC, that is 3x.
+ internal static let _maxNFCExpansionFactor = 3
+
+ // A small output buffer to use for normalizing a single normalization
+ // segment. Fits all but pathological arbitrary-length segments (i.e. zalgo-
+ // segments)
+ internal typealias _SegmentOutputBuffer = _FixedArray16<UInt16>
+}
diff --git a/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb b/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb
index 74f29fe0..0e7903d 100644
--- a/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb
+++ b/stdlib/public/core/StringRangeReplaceableCollection.swift.gyb
@@ -574,13 +574,6 @@
}
extension Collection {
- @_inlineable // FIXME(sil-serialize-all)
- public func compactMap(
- _ transform: (Element) throws -> String?
- ) rethrows -> [String] {
- return try _compactMap(transform)
- }
-
@available(swift, deprecated: 4.1, renamed: "compactMap(_:)",
message: "Please use compactMap(_:) for the case where closure returns an optional value")
@inline(__always)
diff --git a/stdlib/public/core/StringUTF16.swift b/stdlib/public/core/StringUTF16.swift
index 5921f2d..25e4a3d 100644
--- a/stdlib/public/core/StringUTF16.swift
+++ b/stdlib/public/core/StringUTF16.swift
@@ -447,6 +447,7 @@
extension String.UTF16View : CustomPlaygroundQuickLookable {
@_inlineable // FIXME(sil-serialize-all)
+ @available(*, deprecated, message: "UTF16View.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .text(description)
}
diff --git a/stdlib/public/core/StringUTF8.swift b/stdlib/public/core/StringUTF8.swift
index 74105d9..b192ca3 100644
--- a/stdlib/public/core/StringUTF8.swift
+++ b/stdlib/public/core/StringUTF8.swift
@@ -634,6 +634,7 @@
extension String.UTF8View : CustomPlaygroundQuickLookable {
@_inlineable // FIXME(sil-serialize-all)
+ @available(*, deprecated, message: "UTF8View.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .text(description)
}
diff --git a/stdlib/public/core/StringUnicodeScalarView.swift b/stdlib/public/core/StringUnicodeScalarView.swift
index fed94a6..9d02b3b 100644
--- a/stdlib/public/core/StringUnicodeScalarView.swift
+++ b/stdlib/public/core/StringUnicodeScalarView.swift
@@ -544,6 +544,7 @@
extension String.UnicodeScalarView : CustomPlaygroundQuickLookable {
@_inlineable // FIXME(sil-serialize-all)
+ @available(*, deprecated, message: "UnicodeScalarView.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .text(description)
}
diff --git a/stdlib/public/core/Substring.swift.gyb b/stdlib/public/core/Substring.swift.gyb
index 4b02cb3..22e36a8 100644
--- a/stdlib/public/core/Substring.swift.gyb
+++ b/stdlib/public/core/Substring.swift.gyb
@@ -338,6 +338,7 @@
extension Substring : CustomPlaygroundQuickLookable {
@_inlineable // FIXME(sil-serialize-all)
+ @available(*, deprecated, message: "Substring.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return String(self).customPlaygroundQuickLook
}
@@ -472,10 +473,6 @@
///
/// - Complexity: O(1)
@_inlineable // FIXME(sil-serialize-all)
- % if property == 'characters':
- @available(swift, deprecated: 3.2, message:
- "Please use String or Substring directly")
- % end
public init(_ content: ${View}) {
self = content._wholeString[content.startIndex..<content.endIndex]
}
diff --git a/stdlib/public/core/SwiftNativeNSArray.swift b/stdlib/public/core/SwiftNativeNSArray.swift
index 4c181d5..a0cf41a 100644
--- a/stdlib/public/core/SwiftNativeNSArray.swift
+++ b/stdlib/public/core/SwiftNativeNSArray.swift
@@ -48,7 +48,7 @@
@_inlineable // FIXME(sil-serialize-all)
@_versioned // FIXME(sil-serialize-all)
- internal override init() {}
+ @nonobjc internal override init() {}
@_inlineable // FIXME(sil-serialize-all)
@_versioned // FIXME(sil-serialize-all)
diff --git a/stdlib/public/core/UnmanagedString.swift b/stdlib/public/core/UnmanagedString.swift
index db0c5ef..11512d3 100644
--- a/stdlib/public/core/UnmanagedString.swift
+++ b/stdlib/public/core/UnmanagedString.swift
@@ -173,6 +173,36 @@
start: start + offsetRange.lowerBound,
count: offsetRange.count)
}
+
+ @_inlineable // FIXME(sil-serialize-all)
+ @_versioned // FIXME(sil-serialize-all)
+ internal subscript(offsetRange: PartialRangeFrom<Int>) -> SubSequence {
+ _sanityCheck(offsetRange.lowerBound >= 0)
+ return _UnmanagedString(
+ start: start + offsetRange.lowerBound,
+ count: self.count - offsetRange.lowerBound
+ )
+ }
+
+ @_inlineable // FIXME(sil-serialize-all)
+ @_versioned // FIXME(sil-serialize-all)
+ internal subscript(offsetRange: PartialRangeUpTo<Int>) -> SubSequence {
+ _sanityCheck(offsetRange.upperBound <= count)
+ return _UnmanagedString(
+ start: start,
+ count: offsetRange.upperBound
+ )
+ }
+
+ @_inlineable // FIXME(sil-serialize-all)
+ @_versioned // FIXME(sil-serialize-all)
+ internal subscript(offsetRange: PartialRangeThrough<Int>) -> SubSequence {
+ _sanityCheck(offsetRange.upperBound < count)
+ return _UnmanagedString(
+ start: start,
+ count: offsetRange.upperBound + 1
+ )
+ }
@_inlineable // FIXME(sil-serialize-all)
@_versioned // FIXME(sil-serialize-all)
diff --git a/stdlib/public/core/UnsafePointer.swift.gyb b/stdlib/public/core/UnsafePointer.swift.gyb
index e6ff2a1..05ae11e 100644
--- a/stdlib/public/core/UnsafePointer.swift.gyb
+++ b/stdlib/public/core/UnsafePointer.swift.gyb
@@ -1004,6 +1004,7 @@
}
@_inlineable // FIXME(sil-serialize-all)
+ @available(*, deprecated, message: "${Self}.customPlaygroundQuickLook will be removed in a future Swift version")
public var customPlaygroundQuickLook: PlaygroundQuickLook {
return .text(summary)
}
diff --git a/stdlib/public/core/UnsafeRawPointer.swift.gyb b/stdlib/public/core/UnsafeRawPointer.swift.gyb
index 4a3e4aa..5d0259c 100644
--- a/stdlib/public/core/UnsafeRawPointer.swift.gyb
+++ b/stdlib/public/core/UnsafeRawPointer.swift.gyb
@@ -996,6 +996,7 @@
extension Unsafe${Mutable}RawPointer : CustomPlaygroundQuickLookable {
@_inlineable // FIXME(sil-serialize-all)
@_versioned // FIXME(sil-serialize-all)
+ @available(*, deprecated, message: "Unsafe${Mutable}RawPointer.customPlaygroundQuickLook will be removed in a future Swift version")
internal var summary: String {
let selfType = "${Self}"
let ptrValue = UInt64(
diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt
index e9c1ee8..52bab17 100644
--- a/stdlib/public/runtime/CMakeLists.txt
+++ b/stdlib/public/runtime/CMakeLists.txt
@@ -30,7 +30,7 @@
ErrorObject.mm
SwiftObject.mm
SwiftValue.mm
- Reflection.mm
+ ReflectionMirror.mm
"${SWIFT_SOURCE_DIR}/lib/Demangling/OldRemangler.cpp"
"${SWIFT_SOURCE_DIR}/lib/Demangling/Remangler.cpp"
"${SWIFT_SOURCE_DIR}/lib/Demangling/TypeDecoder.cpp"
diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp
index 11d2a72..72c3269 100644
--- a/stdlib/public/runtime/Casting.cpp
+++ b/stdlib/public/runtime/Casting.cpp
@@ -638,7 +638,7 @@
/******************************************************************************/
/// Nominal type descriptor for Swift.AnyHashable.
-extern "C" const TypeContextDescriptor STRUCT_TYPE_DESCR_SYM(s11AnyHashable);
+extern "C" const StructDescriptor STRUCT_TYPE_DESCR_SYM(s11AnyHashable);
static bool isAnyHashableType(const StructMetadata *type) {
return type->getDescription() == &STRUCT_TYPE_DESCR_SYM(s11AnyHashable);
@@ -2117,13 +2117,13 @@
/******************************************************************************/
/// Nominal type descriptor for Swift.Array.
-extern "C" const TypeContextDescriptor NOMINAL_TYPE_DESCR_SYM(Sa);
+extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(Sa);
/// Nominal type descriptor for Swift.Dictionary.
-extern "C" const TypeContextDescriptor STRUCT_TYPE_DESCR_SYM(s10Dictionary);
+extern "C" const StructDescriptor STRUCT_TYPE_DESCR_SYM(s10Dictionary);
/// Nominal type descriptor for Swift.Set.
-extern "C" const TypeContextDescriptor STRUCT_TYPE_DESCR_SYM(s3Set);
+extern "C" const StructDescriptor STRUCT_TYPE_DESCR_SYM(s3Set);
// internal func _arrayDownCastIndirect<SourceValue, TargetValue>(
// _ source: UnsafePointer<Array<SourceValue>>,
diff --git a/stdlib/public/runtime/Demangle.cpp b/stdlib/public/runtime/Demangle.cpp
index 11b11de..8130e69 100644
--- a/stdlib/public/runtime/Demangle.cpp
+++ b/stdlib/public/runtime/Demangle.cpp
@@ -12,6 +12,7 @@
#include "swift/Basic/Range.h"
#include "swift/Runtime/Metadata.h"
+#include "swift/Runtime/Portability.h"
#include "swift/Strings.h"
#include "Private.h"
@@ -634,3 +635,47 @@
// Not a type.
return nullptr;
}
+
+// NB: This function is not used directly in the Swift codebase, but is
+// exported for Xcode support and is used by the sanitizers. Please coordinate
+// before changing.
+char *swift_demangle(const char *mangledName,
+ size_t mangledNameLength,
+ char *outputBuffer,
+ size_t *outputBufferSize,
+ uint32_t flags) {
+ if (flags != 0) {
+ swift::fatalError(0, "Only 'flags' value of '0' is currently supported.");
+ }
+ if (outputBuffer != nullptr && outputBufferSize == nullptr) {
+ swift::fatalError(0, "'outputBuffer' is passed but the size is 'nullptr'.");
+ }
+
+ // Check if we are dealing with Swift mangled name, otherwise, don't try
+ // to demangle and send indication to the user.
+ if (!Demangle::isSwiftSymbol(mangledName))
+ return nullptr; // Not a mangled name
+
+ // Demangle the name.
+ auto options = Demangle::DemangleOptions();
+ options.DisplayDebuggerGeneratedModule = false;
+ auto result =
+ Demangle::demangleSymbolAsString(mangledName,
+ mangledNameLength,
+ options);
+
+ // If the output buffer is not provided, malloc memory ourselves.
+ if (outputBuffer == nullptr || *outputBufferSize == 0) {
+ return strdup(result.c_str());
+ }
+
+ // Indicate a failure if the result does not fit and will be truncated
+ // and set the required outputBufferSize.
+ if (*outputBufferSize < result.length() + 1) {
+ *outputBufferSize = result.length() + 1;
+ }
+
+ // Copy into the provided buffer.
+ _swift_strlcpy(outputBuffer, result.c_str(), *outputBufferSize);
+ return outputBuffer;
+}
diff --git a/stdlib/public/runtime/Enum.cpp b/stdlib/public/runtime/Enum.cpp
index e69e47f..409e168 100644
--- a/stdlib/public/runtime/Enum.cpp
+++ b/stdlib/public/runtime/Enum.cpp
@@ -184,7 +184,7 @@
// The total size includes space for the tag.
unsigned totalSize = payloadSize + getNumTagBytes(payloadSize,
- enumType->Description->Enum.getNumEmptyCases(),
+ enumType->getDescription()->getNumEmptyCases(),
numPayloads);
auto vwtable = getMutableVWTableForInit(enumType, layoutFlags);
@@ -296,7 +296,7 @@
const EnumMetadata *enumType,
unsigned whichCase) {
auto layout = getMultiPayloadLayout(enumType);
- unsigned numPayloads = enumType->Description->Enum.getNumPayloadCases();
+ unsigned numPayloads = enumType->getDescription()->getNumPayloadCases();
if (whichCase < numPayloads) {
// For a payload case, store the tag after the payload area.
storeMultiPayloadTag(value, layout, whichCase);
@@ -322,7 +322,7 @@
swift::swift_getEnumCaseMultiPayload(const OpaqueValue *value,
const EnumMetadata *enumType) {
auto layout = getMultiPayloadLayout(enumType);
- unsigned numPayloads = enumType->Description->Enum.getNumPayloadCases();
+ unsigned numPayloads = enumType->getDescription()->getNumPayloadCases();
unsigned tag = loadMultiPayloadTag(value, layout);
if (tag < numPayloads) {
diff --git a/stdlib/public/runtime/ErrorDefaultImpls.cpp b/stdlib/public/runtime/ErrorDefaultImpls.cpp
index bc46f3b..5163c4d 100644
--- a/stdlib/public/runtime/ErrorDefaultImpls.cpp
+++ b/stdlib/public/runtime/ErrorDefaultImpls.cpp
@@ -32,7 +32,7 @@
// Enum tags use negative values for payload cases, so adjust code to be
// in the range [0, num-cases).
result = T->vw_getEnumTag(error) +
- T->getTypeContextDescriptor()->Enum.getNumPayloadCases();
+ cast<EnumMetadata>(T)->getDescription()->getNumPayloadCases();
break;
case MetadataKind::Class:
diff --git a/stdlib/public/runtime/ImageInspection.h b/stdlib/public/runtime/ImageInspection.h
index 021bebb..1d64e31 100644
--- a/stdlib/public/runtime/ImageInspection.h
+++ b/stdlib/public/runtime/ImageInspection.h
@@ -44,12 +44,18 @@
/// Load the metadata from the image necessary to find a type by name.
void initializeTypeMetadataRecordLookup();
+/// Load the metadata from the image necessary to find field types
+/// based on the nominal type name.
+void initializeTypeFieldLookup();
+
// Callbacks to register metadata from an image to the runtime.
- void addImageProtocolsBlockCallback(const void *start, uintptr_t size);
+void addImageProtocolsBlockCallback(const void *start, uintptr_t size);
void addImageProtocolConformanceBlockCallback(const void *start,
uintptr_t size);
void addImageTypeMetadataRecordBlockCallback(const void *start,
uintptr_t size);
+void addImageTypeFieldDescriptorBlockCallback(const void *start,
+ uintptr_t size);
int lookupSymbol(const void *address, SymbolInfo *info);
diff --git a/stdlib/public/runtime/ImageInspectionELF.cpp b/stdlib/public/runtime/ImageInspectionELF.cpp
index 00b2346..16064ab 100644
--- a/stdlib/public/runtime/ImageInspectionELF.cpp
+++ b/stdlib/public/runtime/ImageInspectionELF.cpp
@@ -86,6 +86,20 @@
}
}
+void swift::initializeTypeFieldLookup() {
+ const swift::MetadataSections *sections = registered;
+ while (true) {
+ const swift::MetadataSections::Range &fields = sections->swift5_fieldmd;
+ if (fields.length)
+ addImageTypeFieldDescriptorBlockCallback(
+ reinterpret_cast<void *>(fields.start), fields.length);
+
+ if (sections->next == registered)
+ break;
+ sections = sections->next;
+ }
+}
+
// As ELF images are loaded, ImageInspectionInit:sectionDataInit() will call
// addNewDSOImage() with an address in the image that can later be used via
// dladdr() to dlopen() the image after the appropriate initialize*Lookup()
diff --git a/stdlib/public/runtime/ImageInspectionMachO.cpp b/stdlib/public/runtime/ImageInspectionMachO.cpp
index 6d490f0..c7d556c 100644
--- a/stdlib/public/runtime/ImageInspectionMachO.cpp
+++ b/stdlib/public/runtime/ImageInspectionMachO.cpp
@@ -38,6 +38,9 @@
/// The Mach-O section name for the section containing type references.
/// This lives within SEG_TEXT.
constexpr const char TypeMetadataRecordSection[] = "__swift5_types";
+/// The Mach-O section name for the section containing type field references.
+/// This lives within SEG_TEXT.
+constexpr const char TypeFieldRecordSection[] = "__swift5_fieldmd";
template<const char *SECTION_NAME,
void CONSUME_BLOCK(const void *start, uintptr_t size)>
@@ -82,6 +85,12 @@
}
+void swift::initializeTypeFieldLookup() {
+ _dyld_register_func_for_add_image(
+ addImageCallback<TypeFieldRecordSection,
+ addImageTypeFieldDescriptorBlockCallback>);
+}
+
int swift::lookupSymbol(const void *address, SymbolInfo *info) {
Dl_info dlinfo;
if (dladdr(address, &dlinfo) == 0) {
diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp
index cbc8393..f363392 100644
--- a/stdlib/public/runtime/Metadata.cpp
+++ b/stdlib/public/runtime/Metadata.cpp
@@ -1516,12 +1516,12 @@
}
// Copy the field offsets.
- if (description->Class.hasFieldOffsetVector()) {
+ if (description->hasFieldOffsetVector()) {
unsigned fieldOffsetVector =
- description->Class.getFieldOffsetVectorOffset(ancestor);
+ description->getFieldOffsetVectorOffset(ancestor);
memcpy(classWords + fieldOffsetVector,
superWords + fieldOffsetVector,
- description->Class.NumFields * sizeof(uintptr_t));
+ description->NumFields * sizeof(uintptr_t));
}
ancestor = ancestor->SuperClass;
}
diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp
index bab6072..f03716c 100644
--- a/stdlib/public/runtime/MetadataLookup.cpp
+++ b/stdlib/public/runtime/MetadataLookup.cpp
@@ -18,6 +18,7 @@
#include "swift/Basic/Lazy.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Demangling/TypeDecoder.h"
+#include "swift/Reflection/Records.h"
#include "swift/Runtime/Casting.h"
#include "swift/Runtime/Concurrent.h"
#include "swift/Runtime/HeapObject.h"
@@ -33,9 +34,11 @@
#include "ImageInspection.h"
#include <functional>
#include <vector>
+#include <list>
using namespace swift;
using namespace Demangle;
+using namespace reflection;
#if SWIFT_OBJC_INTEROP
#include <objc/runtime.h>
@@ -43,6 +46,24 @@
#include <objc/objc.h>
#endif
+/// Produce a Demangler value suitable for resolving runtime type metadata
+/// strings.
+static Demangler getDemanglerForRuntimeTypeResolution() {
+ Demangler dem;
+ // Resolve symbolic references to type contexts into the absolute address of
+ // the type context descriptor, so that if we see a symbolic reference in the
+ // mangled name we can immediately find the associated metadata.
+ dem.setSymbolicReferenceResolver([&](int32_t offset,
+ const void *base) -> NodePointer {
+ auto absolute_addr = (uintptr_t)detail::applyRelativeOffset(base, offset);
+ auto reference = dem.createNode(Node::Kind::SymbolicReference, absolute_addr);
+ auto type = dem.createNode(Node::Kind::Type);
+ type->addChild(reference, dem);
+ return type;
+ });
+ return dem;
+}
+
#pragma mark Nominal type descriptor cache
// Type Metadata Cache.
@@ -136,8 +157,16 @@
Demangle::NodePointer node) {
if (node->getKind() == Demangle::Node::Kind::Type)
node = node->getChild(0);
-
+
while (context) {
+ // We can directly match symbolic references to the current context.
+ if (node && node->getKind() == Demangle::Node::Kind::SymbolicReference) {
+ if (equalContexts(context, reinterpret_cast<const ContextDescriptor *>(
+ node->getIndex()))) {
+ return true;
+ }
+ }
+
switch (context->getKind()) {
case ContextDescriptorKind::Module: {
auto module = cast<ModuleContextDescriptor>(context);
@@ -181,10 +210,16 @@
if (!(flags & (uint16_t)TypeContextDescriptorFlags::IsCTypedef))
return false;
break;
+
default:
return false;
}
- if (!node->getChild(1)->getText().equals(type->Name.get()))
+
+ auto nameNode = node->getChild(1);
+ if (nameNode->getKind() == Demangle::Node::Kind::PrivateDeclName)
+ return false;
+
+ if (nameNode->getText() != type->Name.get())
return false;
node = node->getChild(0);
@@ -233,9 +268,12 @@
auto &T = TypeMetadataRecords.get();
// If we have a symbolic reference to a context, resolve it immediately.
- if (node->getKind() == Node::Kind::SymbolicReference)
+ NodePointer symbolicNode = node;
+ if (symbolicNode->getKind() == Node::Kind::Type)
+ symbolicNode = symbolicNode->getChild(0);
+ if (symbolicNode->getKind() == Node::Kind::SymbolicReference)
return cast<TypeContextDescriptor>(
- (const ContextDescriptor *)node->getIndex());
+ (const ContextDescriptor *)symbolicNode->getIndex());
auto mangledName = Demangle::mangleNode(node);
@@ -282,11 +320,9 @@
public:
ProtocolDescriptorCacheEntry(const llvm::StringRef name,
const ProtocolDescriptor *description)
- : Name(name.str()), Description(description) {}
+ : Name(name.str()), Description(description) {}
- const ProtocolDescriptor *getDescription() {
- return Description;
- }
+ const ProtocolDescriptor *getDescription() { return Description; }
int compareWithKey(llvm::StringRef aName) const {
return aName.compare(Name);
@@ -388,6 +424,97 @@
return foundProtocol;
}
+#pragma mark Type field descriptor cache
+namespace {
+struct FieldDescriptorCacheEntry {
+private:
+ const Metadata *Type;
+ const FieldDescriptor *Description;
+
+public:
+ FieldDescriptorCacheEntry(const Metadata *type,
+ const FieldDescriptor *description)
+ : Type(type), Description(description) {}
+
+ const FieldDescriptor *getDescription() { return Description; }
+
+ int compareWithKey(const Metadata *other) const {
+ auto a = (uintptr_t)Type;
+ auto b = (uintptr_t)other;
+ return a == b ? 0 : (a < b ? -1 : 1);
+ }
+
+ template <class... Args>
+ static size_t getExtraAllocationSize(Args &&... ignored) {
+ return 0;
+ }
+};
+
+class StaticFieldSection {
+ const void *Begin;
+ const void *End;
+
+public:
+ StaticFieldSection(const void *begin, const void *end)
+ : Begin(begin), End(end) {}
+
+ FieldDescriptorIterator begin() const {
+ return FieldDescriptorIterator(Begin, End);
+ }
+
+ FieldDescriptorIterator end() const {
+ return FieldDescriptorIterator(End, End);
+ }
+};
+
+class DynamicFieldSection {
+ const FieldDescriptor **Begin;
+ const FieldDescriptor **End;
+
+public:
+ DynamicFieldSection(const FieldDescriptor **fields, size_t size)
+ : Begin(fields), End(fields + size) {}
+
+ const FieldDescriptor **begin() { return Begin; }
+
+ const FieldDescriptor **end() const { return End; }
+};
+
+struct FieldCacheState {
+ ConcurrentMap<FieldDescriptorCacheEntry> FieldCache;
+
+ Mutex SectionsLock;
+ std::vector<StaticFieldSection> StaticSections;
+ std::vector<DynamicFieldSection> DynamicSections;
+
+ FieldCacheState() {
+ StaticSections.reserve(16);
+ DynamicSections.reserve(8);
+ initializeTypeFieldLookup();
+ }
+};
+
+static Lazy<FieldCacheState> FieldCache;
+} // namespace
+
+void swift::swift_registerFieldDescriptors(const FieldDescriptor **records,
+ size_t size) {
+ auto &cache = FieldCache.get();
+ ScopedLock guard(cache.SectionsLock);
+ cache.DynamicSections.push_back({records, size});
+}
+
+void swift::addImageTypeFieldDescriptorBlockCallback(const void *recordsBegin,
+ uintptr_t size) {
+ auto sectionBytes = reinterpret_cast<const char *>(recordsBegin);
+ auto recordsEnd = reinterpret_cast<const void *>(sectionBytes + size);
+
+ // Field cache should always be sufficiently initialized by this point.
+ auto &cache = FieldCache.unsafeGetAlreadyInitialized();
+ ScopedLock guard(cache.SectionsLock);
+ cache.StaticSections.push_back({recordsBegin, recordsEnd});
+}
+
#pragma mark Metadata lookup via mangled name
#if SWIFT_OBJC_INTEROP
@@ -841,7 +968,7 @@
TypeInfo
swift::_getTypeByMangledName(StringRef typeName,
SubstGenericParameterFn substGenericParam) {
- Demangler demangler;
+ auto demangler = getDemanglerForRuntimeTypeResolution();
NodePointer node;
// Check whether this is the convenience syntax "ModuleName.ClassName".
@@ -851,21 +978,11 @@
return llvm::StringRef::npos;
if (typeName.find('.', dotPos + 1) != llvm::StringRef::npos)
return llvm::StringRef::npos;
- if (typeName.find('$') != llvm::StringRef::npos)
+ if (typeName.find('\1') != llvm::StringRef::npos)
return llvm::StringRef::npos;
return dotPos;
};
- // Resolve symbolic references to type contexts into the absolute address of
- // the type context descriptor, so that if we see a symbolic reference in the
- // mangled name we can immediately find the associated metadata.
- demangler.setSymbolicReferenceResolver(
- [&](int32_t offset, const void *base) -> NodePointer {
- auto absolute_addr = (uintptr_t)detail::applyRelativeOffset(base, offset);
- return demangler.createNode(Node::Kind::SymbolicReference,
- absolute_addr);
- });
-
auto dotPos = getDotPosForConvenienceSyntax();
if (dotPos != llvm::StringRef::npos) {
// Form a demangle tree for this class.
@@ -873,7 +990,7 @@
NodePointer moduleNode = demangler.createNode(Node::Kind::Module,
typeName.substr(0, dotPos));
NodePointer nameNode = demangler.createNode(Node::Kind::Identifier,
- typeName.substr(dotPos + 1));
+ typeName.substr(dotPos + 1));
classNode->addChild(moduleNode, demangler);
classNode->addChild(nameNode, demangler);
@@ -929,3 +1046,104 @@
return flatSubstitutions[flatIndex];
});
}
+
+void swift::swift_getFieldAt(
+ const Metadata *base, unsigned index,
+ std::function<void(llvm::StringRef name, FieldType fieldInfo)>
+ callback) {
+ auto *baseDesc = base->getTypeContextDescriptor();
+ if (!baseDesc)
+ return;
+
+ auto getFieldAt = [&](const FieldDescriptor &descriptor) {
+ auto &field = descriptor.getFields()[index];
+ auto name = field.getFieldName(0);
+
+ // Enum cases don't always have types.
+ if (!field.hasMangledTypeName()) {
+ callback(name, FieldType().withIndirect(field.isIndirectCase()));
+ return;
+ }
+
+ std::vector<const ContextDescriptor *> descriptorPath;
+ {
+ const auto *parent = reinterpret_cast<
+ const ContextDescriptor *>(baseDesc);
+ while (parent) {
+ if (parent->isGeneric())
+ descriptorPath.push_back(parent);
+
+ parent = parent->Parent.get();
+ }
+ }
+
+ auto typeInfo = _getTypeByMangledName(
+ field.getMangledTypeName(0),
+ [&](unsigned depth, unsigned index) -> const Metadata * {
+ if (depth >= descriptorPath.size())
+ return nullptr;
+
+ unsigned currentDepth = 0;
+ unsigned flatIndex = index;
+ const ContextDescriptor *currentContext = descriptorPath.back();
+
+ for (const auto *context : llvm::reverse(descriptorPath)) {
+ if (currentDepth >= depth)
+ break;
+
+ flatIndex += context->getNumGenericParams();
+ currentContext = context;
+ ++currentDepth;
+ }
+
+ if (index >= currentContext->getNumGenericParams())
+ return nullptr;
+
+ return base->getGenericArgs()[flatIndex];
+ });
+
+ callback(name, FieldType()
+ .withType(typeInfo)
+ .withIndirect(field.isIndirectCase())
+ .withWeak(typeInfo.isWeak()));
+
+ };
+
+ auto dem = getDemanglerForRuntimeTypeResolution();
+ auto &cache = FieldCache.get();
+ auto isRequestedDescriptor = [&](const FieldDescriptor &descriptor) {
+ assert(descriptor.hasMangledTypeName());
+ auto mangledName = descriptor.getMangledTypeName(0);
+
+ if (!_contextDescriptorMatchesMangling(baseDesc,
+ dem.demangleType(mangledName)))
+ return false;
+
+ cache.FieldCache.getOrInsert(base, &descriptor);
+ getFieldAt(descriptor);
+ return true;
+ };
+
+
+ // Fast path: If we already have field descriptor cached.
+ if (auto Value = cache.FieldCache.find(base)) {
+ getFieldAt(*Value->getDescription());
+ return;
+ }
+
+ ScopedLock guard(cache.SectionsLock);
+ // Otherwise let's try to find it in one of the sections.
+ for (auto §ion : cache.DynamicSections) {
+ for (const auto *descriptor : section) {
+ if (isRequestedDescriptor(*descriptor))
+ return;
+ }
+ }
+
+ for (const auto §ion : cache.StaticSections) {
+ for (auto &descriptor : section) {
+ if (isRequestedDescriptor(descriptor))
+ return;
+ }
+ }
+}
diff --git a/stdlib/public/runtime/Reflection.mm b/stdlib/public/runtime/Reflection.mm
deleted file mode 100644
index 699696c..0000000
--- a/stdlib/public/runtime/Reflection.mm
+++ /dev/null
@@ -1,1240 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// This source file is part of the Swift.org open source project
-//
-// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
-// Licensed under Apache License v2.0 with Runtime Library Exception
-//
-// See https://swift.org/LICENSE.txt for license information
-// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-//
-//===----------------------------------------------------------------------===//
-
-#include "swift/Runtime/Reflection.h"
-#include "swift/Runtime/Casting.h"
-#include "swift/Runtime/Config.h"
-#include "swift/Runtime/HeapObject.h"
-#include "swift/Runtime/Metadata.h"
-#include "swift/Runtime/Enum.h"
-#include "swift/Runtime/Unreachable.h"
-#include "swift/Demangling/Demangle.h"
-#include "swift/Runtime/Debug.h"
-#include "swift/Runtime/Portability.h"
-#include "Private.h"
-#include "WeakReference.h"
-#include "llvm/Support/Compiler.h"
-#include <cassert>
-#include <cinttypes>
-#include <cstdio>
-#include <cstring>
-#include <new>
-#include <string>
-#include <tuple>
-
-#if SWIFT_OBJC_INTEROP
-#include "swift/Runtime/ObjCBridge.h"
-#include <Foundation/Foundation.h>
-#include <objc/objc.h>
-#include <objc/runtime.h>
-#endif
-
-using namespace swift;
-
-#if SWIFT_OBJC_INTEROP
-// Declare the debugQuickLookObject selector.
-@interface DeclareSelectors
-
-- (id)debugQuickLookObject;
-@end
-
-// mangled Swift._SwiftObject
-#define SwiftObject _TtCs12_SwiftObject
-@class SwiftObject;
-#endif
-
-namespace {
-
-/// The layout of Any.
-using Any = OpaqueExistentialContainer;
-
-// Swift assumes Any is returned in memory.
-// Use AnyReturn to guarantee that even on architectures
-// where Any would be returned in registers.
-struct AnyReturn {
- Any any;
- AnyReturn(Any a) : any(a) { }
- operator Any() { return any; }
- ~AnyReturn() { }
-};
-
-struct MagicMirrorData;
-
-struct String;
-
-SWIFT_CC(swift)
-extern "C" void swift_stringFromUTF8InRawMemory(String *out,
- const char *start,
- intptr_t len);
-
-struct String {
- // Keep the details of String's implementation opaque to the runtime.
- const void *x = nullptr;
- const void *y = nullptr;
-#if __POINTER_WIDTH__ == 32
- const void *z = nullptr;
-#endif
-
- /// Keep String trivial on the C++ side so we can control its instantiation.
- String() = default;
-
- /// Wrap a string literal in a swift String.
- template<size_t N>
- explicit String(const char (&s)[N]) {
- swift_stringFromUTF8InRawMemory(this, s, N-1);
- }
-
- /// Copy an ASCII string into a swift String on the heap.
- explicit String(const char *ptr, size_t size) {
- swift_stringFromUTF8InRawMemory(this, ptr, size);
- }
-
- explicit String(const char *ptr)
- : String(ptr, strlen(ptr))
- {}
-
-#if SWIFT_OBJC_INTEROP
- explicit String(NSString *s)
- // FIXME: Use the usual NSString bridging entry point.
- : String([s UTF8String])
- {}
-#endif
-};
-
-/// A Mirror witness table for use by MagicMirror.
-struct MirrorWitnessTable;
-
-// This structure needs to mirror _MagicMirrorData in the stdlib.
-struct MagicMirrorData {
- /// The owner pointer for the buffer the value lives in. For class values
- /// this is the class instance itself. The mirror owns a strong reference to
- /// this object.
- HeapObject *Owner;
- /// The pointer to the value. The mirror does not own the referenced value.
- const OpaqueValue *Value;
- /// The type metadata for the referenced value. For an ObjC witness, this is
- /// the ObjC class.
- const Metadata *Type;
-};
-static_assert(sizeof(MagicMirrorData) == sizeof(ValueBuffer),
- "MagicMirrorData doesn't exactly fill a ValueBuffer");
-
-/// A magic implementation of Mirror that can use runtime metadata to walk an
-/// arbitrary object.
-///
-/// This type is layout-compatible with a Swift existential container for the
-/// _Mirror protocol.
-class MagicMirror {
-public:
- // The data for the mirror.
- MagicMirrorData Data;
-
- // The existential header.
- const Metadata *Self;
- const MirrorWitnessTable *MirrorWitness;
-
- MagicMirror() = default;
-
- /// Build a new MagicMirror for type T by taking ownership of the referenced
- /// value.
- MagicMirror(OpaqueValue *value, const Metadata *T, bool take);
-
- /// Build a new MagicMirror for type T, sharing ownership with an existing
- /// heap object, which is retained.
- MagicMirror(HeapObject *owner, const OpaqueValue *value, const Metadata *T);
-};
-
-static_assert(alignof(MagicMirror) == alignof(Mirror),
- "MagicMirror layout does not match existential container");
-static_assert(sizeof(MagicMirror) == sizeof(Mirror),
- "MagicMirror layout does not match existential container");
-static_assert(offsetof(MagicMirror, Data) == offsetof(OpaqueExistentialContainer, Buffer),
- "MagicMirror layout does not match existential container");
-static_assert(offsetof(MagicMirror, Self) == offsetof(OpaqueExistentialContainer, Type),
- "MagicMirror layout does not match existential container");
-static_assert(offsetof(MagicMirror, MirrorWitness) ==
- offsetof(Mirror, MirrorWitness),
- "MagicMirror layout does not match existential container");
-
-// -- Build an Any from an arbitrary value unowned-referenced by a mirror.
-
-// We intentionally use a non-POD return type with these entry points to give
-// them an indirect return ABI for compatibility with Swift.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
-
-// struct _MagicMirrorData {
-// internal var value: Any {
-// @_silgen_name("swift_MagicMirrorData_value")get
-// }
-// }
-//
-// Since this is a method, owner is passed in at +0.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-AnyReturn swift_MagicMirrorData_value(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- Any result;
-
- result.Type = type;
- auto *opaqueValueAddr = type->allocateBoxForExistentialIn(&result.Buffer);
- type->vw_initializeWithCopy(opaqueValueAddr,
- const_cast<OpaqueValue *>(value));
-
- return AnyReturn(result);
-}
-
-// struct _MagicMirrorData {
-// internal var valueType: Any.Type {
-// @_silgen_name("swift_MagicMirrorData_valueType")get
-// }
-// }
-//
-// Since this is a method, owner is passed in at +0.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-const Metadata *swift_MagicMirrorData_valueType(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- return swift_getDynamicType(const_cast<OpaqueValue*>(value), type,
- /*existential metatype*/ true);
-}
-
-#if SWIFT_OBJC_INTEROP
-
-// struct _MagicMirrorData {
-// public var objcValue: Any {
-// @_silgen_name("swift_MagicMirrorData_objcValue")get
-// }
-// }
-//
-// Since this is a method, owner is at +0.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-AnyReturn swift_MagicMirrorData_objcValue(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- Any result;
-
- void *object = *reinterpret_cast<void * const *>(value);
- auto isa = _swift_getClass(object);
- result.Type = swift_getObjCClassMetadata(isa);
- swift_unknownRetain(object);
- *reinterpret_cast<void **>(&result.Buffer) = object;
- return AnyReturn(result);
-}
-#endif
-
-#pragma clang diagnostic pop
-
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-const char *swift_OpaqueSummary(const Metadata *T) {
- switch (T->getKind()) {
- case MetadataKind::Class:
- case MetadataKind::Struct:
- case MetadataKind::Enum:
- case MetadataKind::Optional:
- case MetadataKind::Metatype:
- return nullptr;
- case MetadataKind::Opaque:
- return "(Opaque Value)";
- case MetadataKind::Tuple:
- return "(Tuple)";
- case MetadataKind::Function:
- return "(Function)";
- case MetadataKind::Existential:
- return "(Existential)";
- case MetadataKind::ObjCClassWrapper:
- return "(Objective-C Class Wrapper)";
- case MetadataKind::ExistentialMetatype:
- return "(Existential Metatype)";
- case MetadataKind::ForeignClass:
- return "(Foreign Class)";
- case MetadataKind::HeapLocalVariable:
- return "(Heap Local Variable)";
- case MetadataKind::HeapGenericLocalVariable:
- return "(Heap Generic Local Variable)";
- case MetadataKind::ErrorObject:
- return "(ErrorType Object)";
- }
-
- swift_runtime_unreachable("Unhandled MetadataKind in switch.");
-}
-
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-void swift_MagicMirrorData_summary(const Metadata *T, String *result) {
- switch (T->getKind()) {
- case MetadataKind::Class:
- new (result) String("(Class)");
- break;
- case MetadataKind::Struct:
- new (result) String("(Struct)");
- break;
- case MetadataKind::Enum:
- case MetadataKind::Optional:
- new (result) String("(Enum Value)");
- break;
- case MetadataKind::Opaque:
- new (result) String("(Opaque Value)");
- break;
- case MetadataKind::Tuple:
- new (result) String("(Tuple)");
- break;
- case MetadataKind::Function:
- new (result) String("(Function)");
- break;
- case MetadataKind::Existential:
- new (result) String("(Existential)");
- break;
- case MetadataKind::Metatype:
- new (result) String("(Metatype)");
- break;
- case MetadataKind::ObjCClassWrapper:
- new (result) String("(Objective-C Class Wrapper)");
- break;
- case MetadataKind::ExistentialMetatype:
- new (result) String("(ExistentialMetatype)");
- break;
- case MetadataKind::ForeignClass:
- new (result) String("(Foreign Class)");
- break;
- case MetadataKind::HeapLocalVariable:
- new (result) String("(Heap Local Variable)");
- break;
- case MetadataKind::HeapGenericLocalVariable:
- new (result) String("(Heap Generic Local Variable)");
- break;
- case MetadataKind::ErrorObject:
- new (result) String("(Error Object)");
- break;
- }
-}
-
-// struct _MagicMirrorData {
-// public var objcValueType: Any.Type {
-// @_silgen_name("swift_MagicMirrorData_objcValueType")get
-// }
-// }
-//
-// This is a method, so owner is at +0.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-const Metadata *swift_MagicMirrorData_objcValueType(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- void *object = *reinterpret_cast<void * const *>(value);
- auto isa = _swift_getClass(object);
- return getMetadataForClass(isa);
-}
-
-static std::tuple<const Metadata *, const OpaqueValue *>
-unwrapExistential(const Metadata *T, const OpaqueValue *Value) {
- // If the value is an existential container, look through it to reflect the
- // contained value.
- // TODO: Should look through existential metatypes too, but it doesn't
- // really matter yet since we don't have any special mirror behavior for
- // concrete metatypes yet.
- while (T->getKind() == MetadataKind::Existential) {
- auto existential
- = static_cast<const ExistentialTypeMetadata *>(T);
-
- // Unwrap the existential container.
- T = existential->getDynamicType(Value);
- Value = existential->projectValue(Value);
-
- // Existential containers can end up nested in some cases due to generic
- // abstraction barriers. Repeat in case we have a nested existential.
- }
- return std::make_tuple(T, Value);
-}
-
-/// Produce a mirror for any value, like swift_reflectAny, but do not consume
-/// the value, so we can produce a mirror for a subobject of a value already
-/// owned by a mirror.
-///
-/// \param owner passed at +1, consumed.
-/// \param value passed unowned.
-static Mirror reflect(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *T) {
- const Metadata *mirrorType;
- const OpaqueValue *mirrorValue;
- std::tie(mirrorType, mirrorValue) = unwrapExistential(T, value);
-
-#ifdef SWIFT_RUNTIME_ENABLE_GUARANTEED_NORMAL_ARGUMENTS
- swift_retain(owner);
-#endif
-
- // Use MagicMirror.
- // Consumes 'owner'.
- Mirror result;
- ::new (&result) MagicMirror(owner, mirrorValue, mirrorType);
- return result;
-}
-
-// -- Tuple destructuring.
-
-// internal func _getTupleCount(_: _MagicMirrorData) -> Int
-//
-// This is a free standing function, not a method.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-intptr_t swift_TupleMirror_count(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- auto Tuple = static_cast<const TupleTypeMetadata *>(type);
- SWIFT_CC_PLUSONE_GUARD(swift_release(owner));
- return Tuple->NumElements;
-}
-
-/// internal func _getTupleChild<T>(_: Int, _: _MagicMirrorData) -> (T, _Mirror)
-///
-/// This is a free standing function, not a method.
-///
-/// \param owner passed at +1, consumed.
-/// \param value passed unowned.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-void swift_TupleMirror_subscript(String *outString,
- Mirror *outMirror,
- intptr_t i,
- HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- auto Tuple = static_cast<const TupleTypeMetadata *>(type);
-
- if (i < 0 || (size_t)i > Tuple->NumElements)
- swift::crash("Swift mirror subscript bounds check failure");
-
- // Determine whether there is a label.
- bool hasLabel = false;
- if (const char *labels = Tuple->Labels) {
- const char *space = strchr(labels, ' ');
- for (intptr_t j = 0; j != i && space; ++j) {
- labels = space + 1;
- space = strchr(labels, ' ');
- }
-
- // If we have a label, create it.
- if (labels && space && labels != space) {
- new (outString) String(labels, space - labels);
- hasLabel = true;
- }
- }
-
- if (!hasLabel) {
- // The name is the stringized element number '.0'.
- char buf[32];
- snprintf(buf, sizeof(buf), ".%" PRIdPTR, i);
- new (outString) String(buf, strlen(buf));
- }
-
- // Get a Mirror for the nth element.
- auto &elt = Tuple->getElement(i);
- auto bytes = reinterpret_cast<const char*>(value);
- auto eltData = reinterpret_cast<const OpaqueValue *>(bytes + elt.Offset);
-
- // Since 'owner' is consumed, when we have a +0 convention, we must retain
- // owner first.
- SWIFT_CC_PLUSZERO_GUARD(swift_retain(owner));
-
- // 'owner' is consumed by this call.
- new (outMirror) Mirror(reflect(owner, eltData, elt.Type));
-}
-
-// Get a field name from a doubly-null-terminated list.
-static const char *getFieldName(const char *fieldNames, size_t i) {
- const char *fieldName = fieldNames;
- for (size_t j = 0; j < i; ++j) {
- size_t len = strlen(fieldName);
- assert(len != 0);
- fieldName += len + 1;
- }
-
- return fieldName;
-}
-
-
-static bool loadSpecialReferenceStorage(HeapObject *owner,
- OpaqueValue *fieldData,
- const FieldType fieldType,
- Mirror *outMirror) {
- // isWeak() implies a reference type via Sema.
- if (!fieldType.isWeak())
- return false;
-
- auto type = fieldType.getType();
- assert(type->getKind() == MetadataKind::Optional);
-
- auto weakField = reinterpret_cast<WeakReference *>(fieldData);
- auto strongValue = swift_unknownWeakLoadStrong(weakField);
-
- // Now that we have a strong reference, we need to create a temporary buffer
- // from which to copy the whole value, which might be a native class-bound
- // existential, which means we also need to copy n witness tables, for
- // however many protocols are in the protocol composition. For example, if we
- // are copying a:
- // weak var myWeakProperty : (Protocol1 & Protocol2)?
- // then we need to copy three values:
- // - the instance
- // - the witness table for Protocol1
- // - the witness table for Protocol2
-
- auto weakContainer =
- reinterpret_cast<WeakClassExistentialContainer *>(fieldData);
-
- // Create a temporary existential where we can put the strong reference.
- // The allocateBuffer value witness requires a ValueBuffer to own the
- // allocated storage.
- ValueBuffer temporaryBuffer;
-
- auto temporaryValue = reinterpret_cast<ClassExistentialContainer *>(
- type->allocateBufferIn(&temporaryBuffer));
-
- // Now copy the entire value out of the parent, which will include the
- // witness tables.
- temporaryValue->Value = strongValue;
- auto valueWitnessesSize = type->getValueWitnesses()->getSize() -
- sizeof(WeakClassExistentialContainer);
- memcpy(temporaryValue->getWitnessTables(), weakContainer->getWitnessTables(),
- valueWitnessesSize);
-
- // This MagicMirror constructor creates a box to hold the loaded reference
- // value, which becomes the new owner for the value.
- new (outMirror) MagicMirror(reinterpret_cast<OpaqueValue *>(temporaryValue),
- type, /*take*/ true);
-
- type->deallocateBufferIn(&temporaryBuffer);
-
-#ifndef SWIFT_RUNTIME_ENABLE_GUARANTEED_NORMAL_ARGUMENTS
- // swift_StructMirror_subscript and swift_ClassMirror_subscript
- // requires that the owner be consumed. Since we have the new heap box as the
- // owner now, we need to release the old owner to maintain the contract.
- if (owner->metadata->isAnyClass())
- swift_unknownRelease(owner);
- else
- swift_release(owner);
-#endif
-
- return true;
-}
-
-// -- Struct destructuring.
-
-// internal func _getStructCount(_: _MagicMirrorData) -> Int
-//
-// This is a free standing function, not a method.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-intptr_t swift_StructMirror_count(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- auto Struct = static_cast<const StructMetadata *>(type);
- SWIFT_CC_PLUSONE_GUARD(swift_release(owner));
- return Struct->Description->Struct.NumFields;
-}
-
-// internal func _getStructChild<T>(_: Int, _: _MagicMirrorData) -> (T, _Mirror)
-//
-// This is a free standing function, not a method.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-void swift_StructMirror_subscript(String *outString,
- Mirror *outMirror,
- intptr_t i,
- HeapObject *owner,
- OpaqueValue *value,
- const Metadata *type) {
- auto Struct = static_cast<const StructMetadata *>(type);
-
- if (i < 0 || (size_t)i > Struct->Description->Struct.NumFields)
- swift::crash("Swift mirror subscript bounds check failure");
-
- // Load the type and offset from their respective vectors.
- auto fieldType = Struct->getFieldTypes()[i];
- auto fieldOffset = Struct->getFieldOffsets()[i];
-
- auto bytes = reinterpret_cast<char*>(value);
- auto fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
-
- new (outString) String(getFieldName(Struct->Description->Struct.FieldNames, i));
-
- // 'owner' is consumed by this call.
- SWIFT_CC_PLUSZERO_GUARD(swift_unknownRetain(owner));
-
- assert(!fieldType.isIndirect() && "indirect struct fields not implemented");
-
- // This only consumed owner if we succeed.
- if (loadSpecialReferenceStorage(owner, fieldData, fieldType, outMirror))
- return;
-
- new (outMirror) Mirror(reflect(owner, fieldData, fieldType.getType()));
-}
-
-// -- Enum destructuring.
-
-static bool isEnumReflectable(const Metadata *type) {
- const auto Enum = static_cast<const EnumMetadata *>(type);
- const auto &Description = Enum->Description->Enum;
-
- // No metadata for C and @objc enums yet
- if (Description.CaseNames == nullptr)
- return false;
-
- return true;
-}
-
-static void getEnumMirrorInfo(const OpaqueValue *value,
- const Metadata *type,
- unsigned *tagPtr,
- const Metadata **payloadTypePtr,
- bool *indirectPtr) {
- const auto Enum = static_cast<const EnumMetadata *>(type);
- const auto &Description = Enum->Description->Enum;
-
- unsigned payloadCases = Description.getNumPayloadCases();
-
- // 'tag' is in the range [-ElementsWithPayload..ElementsWithNoPayload-1].
- int tag = type->vw_getEnumTag(value);
-
- // Convert resilient tag index to fragile tag index.
- tag += payloadCases;
-
- const Metadata *payloadType = nullptr;
- bool indirect = false;
-
- if (static_cast<unsigned>(tag) < payloadCases) {
- auto payload = Description.GetCaseTypes(type)[tag];
- payloadType = payload.getType();
- indirect = payload.isIndirect();
- }
-
- if (tagPtr)
- *tagPtr = tag;
- if (payloadTypePtr)
- *payloadTypePtr = payloadType;
- if (indirectPtr)
- *indirectPtr = indirect;
-}
-
-// internal func _swift_EnumMirror_caseName(
-// _ data: _MagicMirrorData) -> UnsafePointer<CChar>
-//
-// This is a free standing function.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-const char *swift_EnumMirror_caseName(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- if (!isEnumReflectable(type)) {
- SWIFT_CC_PLUSONE_GUARD(swift_release(owner));
- return nullptr;
- }
-
- const auto Enum = static_cast<const EnumMetadata *>(type);
- const auto &Description = Enum->Description->Enum;
-
- unsigned tag;
- getEnumMirrorInfo(value, type, &tag, nullptr, nullptr);
-
- SWIFT_CC_PLUSONE_GUARD(swift_release(owner));
-
- return getFieldName(Description.CaseNames, tag);
-}
-
-// internal func _getEnumCaseName<T>(_ value: T) -> UnsafePointer<CChar>?
-//
-// This is a free standing function, not a method.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-const char *swift_EnumCaseName(OpaqueValue *value, const Metadata *type) {
- // Build a magic mirror. Unconditionally destroy the value at the end.
- const Metadata *mirrorType;
- const OpaqueValue *cMirrorValue;
- std::tie(mirrorType, cMirrorValue) = unwrapExistential(type, value);
-
- OpaqueValue *mirrorValue = const_cast<OpaqueValue*>(cMirrorValue);
- Mirror mirror;
-
- bool take = false;
- SWIFT_CC_PLUSONE_GUARD(take = (mirrorValue == value));
-
- ::new (&mirror) MagicMirror(mirrorValue, mirrorType, take);
-
- MagicMirror *theMirror = reinterpret_cast<MagicMirror *>(&mirror);
- MagicMirrorData data = theMirror->Data;
- const char *result = swift_EnumMirror_caseName(data.Owner, data.Value, data.Type);
-
- // Destroy the whole original value if we couldn't take it.
- if (!take)
- type->vw_destroy(value);
-
- return result;
-}
-
-// internal func _getEnumCount(_: _MagicMirrorData) -> Int
-//
-// This is a free standing function, not a method.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-intptr_t swift_EnumMirror_count(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- if (!isEnumReflectable(type)) {
- SWIFT_CC_PLUSONE_GUARD(swift_release(owner));
- return 0;
- }
-
- const Metadata *payloadType;
- getEnumMirrorInfo(value, type, nullptr, &payloadType, nullptr);
- SWIFT_CC_PLUSONE_GUARD(swift_release(owner));
- return (payloadType != nullptr) ? 1 : 0;
-}
-
-// internal func _getEnumChild<T>(_: Int, _: _MagicMirrorData) -> (T, _Mirror)
-//
-// This is a free standing function, not a method.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-void swift_EnumMirror_subscript(String *outString,
- Mirror *outMirror,
- intptr_t i,
- HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- const auto Enum = static_cast<const EnumMetadata *>(type);
- const auto &Description = Enum->Description->Enum;
-
- unsigned tag;
- const Metadata *payloadType;
- bool indirect;
-
- getEnumMirrorInfo(value, type, &tag, &payloadType, &indirect);
-
- // Copy the enum payload into a box
- const Metadata *boxType = (indirect ? &METADATA_SYM(Bo).base : payloadType);
- BoxPair pair = swift_allocBox(boxType);
-
- type->vw_destructiveProjectEnumData(const_cast<OpaqueValue *>(value));
- boxType->vw_initializeWithCopy(pair.buffer, const_cast<OpaqueValue *>(value));
- type->vw_destructiveInjectEnumTag(const_cast<OpaqueValue *>(value),
- (int) (tag - Description.getNumPayloadCases()));
-
- SWIFT_CC_PLUSONE_GUARD(swift_release(owner));
-
- owner = pair.object;
- value = pair.buffer;
-
- // If the payload is indirect, we need to jump through the box to get it.
- if (indirect) {
- owner = *reinterpret_cast<HeapObject * const *>(value);
- value = swift_projectBox(const_cast<HeapObject *>(owner));
- swift_retain(owner);
- swift_release(pair.object);
- }
-
- new (outString) String(getFieldName(Description.CaseNames, tag));
- new (outMirror) Mirror(reflect(owner, value, payloadType));
-}
-
-// -- Class destructuring.
-static Mirror getMirrorForSuperclass(const ClassMetadata *sup,
- HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type);
-
-// internal func _getClassCount(_: _MagicMirrorData) -> Int
-//
-// This is a free standing function, not a method.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-intptr_t swift_ClassMirror_count(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- auto Clas = static_cast<const ClassMetadata*>(type);
- SWIFT_CC_PLUSONE_GUARD(swift_release(owner));
- auto count = Clas->getDescription()->Class.NumFields;
-
- // If the class has a superclass, the superclass instance is treated as the
- // first child.
- if (classHasSuperclass(Clas))
- count += 1;
-
- return count;
-}
-
-/// internal func _getClassChild<T>(_: Int, _: _MagicMirrorData) -> (T, _Mirror)
-///
-/// This is a free standing function, not a method.
-///
-/// \param owner passed at +1, consumed.
-/// \param value passed unowned.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-void swift_ClassMirror_subscript(String *outString,
- Mirror *outMirror,
- intptr_t i,
- HeapObject *owner,
- OpaqueValue *value,
- const Metadata *type) {
- auto Clas = static_cast<const ClassMetadata*>(type);
-
- if (classHasSuperclass(Clas)) {
- // If the class has a superclass, the superclass instance is treated as the
- // first child.
- if (i == 0) {
- // FIXME: Put superclass name here
- new (outString) String("super");
- new (outMirror) Mirror(
- getMirrorForSuperclass(Clas->SuperClass, owner, value, type));
- return;
- }
- --i;
- }
-
- if (i < 0 || (size_t)i > Clas->getDescription()->Class.NumFields)
- swift::crash("Swift mirror subscript bounds check failure");
-
- // Load the type and offset from their respective vectors.
- auto fieldType = Clas->getFieldTypes()[i];
- assert(!fieldType.isIndirect()
- && "class indirect properties not implemented");
-
- // FIXME: If the class has ObjC heritage, get the field offset using the ObjC
- // metadata, because we don't update the field offsets in the face of
- // resilient base classes.
- uintptr_t fieldOffset;
- if (usesNativeSwiftReferenceCounting(Clas)) {
- fieldOffset = Clas->getFieldOffsets()[i];
- } else {
-#if SWIFT_OBJC_INTEROP
- Ivar *ivars = class_copyIvarList((Class)Clas, nullptr);
- fieldOffset = ivar_getOffset(ivars[i]);
- free(ivars);
-#else
- swift::crash("Object appears to be Objective-C, but no runtime.");
-#endif
- }
-
- auto bytes = *reinterpret_cast<char * const *>(value);
- auto fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
-
- new (outString) String(getFieldName(Clas->getDescription()->Class.FieldNames,
- i));
-
- if (loadSpecialReferenceStorage(owner, fieldData, fieldType, outMirror))
- return;
-
- // 'owner' is consumed by this call.
- new (outMirror) Mirror(reflect(owner, fieldData, fieldType.getType()));
-}
-
-// -- Mirror witnesses for ObjC classes.
-
-#if SWIFT_OBJC_INTEROP
-
-extern "C" const Metadata METADATA_SYM(Sb); // Bool
-extern "C" const Metadata METADATA_SYM(Si); // Int
-extern "C" const Metadata METADATA_SYM(Su); // UInt
-extern "C" const Metadata METADATA_SYM(Sf); // Float
-extern "C" const Metadata METADATA_SYM(Sd); // Double
-extern "C" const Metadata STRUCT_METADATA_SYM(s4Int8);
-extern "C" const Metadata STRUCT_METADATA_SYM(s5Int16);
-extern "C" const Metadata STRUCT_METADATA_SYM(s5Int32);
-extern "C" const Metadata STRUCT_METADATA_SYM(s5Int64);
-extern "C" const Metadata STRUCT_METADATA_SYM(s5UInt8);
-extern "C" const Metadata STRUCT_METADATA_SYM(s6UInt16);
-extern "C" const Metadata STRUCT_METADATA_SYM(s6UInt32);
-extern "C" const Metadata STRUCT_METADATA_SYM(s6UInt64);
-
-/// \param owner passed at +1, consumed.
-/// \param value passed unowned.
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-intptr_t swift_ObjCMirror_count(HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- auto isa = (const ClassMetadata *)type;
-
- unsigned count = 0;
- // ObjC makes no guarantees about the state of ivars, so we can't safely
- // introspect them in the general case.
-
- // The superobject counts as a child.
- if (isa->SuperClass)
- count += 1;
-
-#ifndef SWIFT_RUNTIME_ENABLE_GUARANTEED_NORMAL_ARGUMENTS
- swift_release(owner);
-#endif
- return count;
-}
-
-static Mirror ObjC_getMirrorForSuperclass(Class sup,
- HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type);
-
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-void swift_ObjCMirror_subscript(String *outString,
- Mirror *outMirror,
- intptr_t i,
- HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- auto isa = (Class)type;
-
- // If there's a superclass, it becomes the first child.
- if (auto sup = class_getSuperclass(isa)) {
- if (i == 0) {
- const char *supName = class_getName(sup);
- new (outString) String(supName, strlen(supName));
- new (outMirror) Mirror(
- ObjC_getMirrorForSuperclass(sup, owner, value, type));
- return;
- }
- --i;
- }
- // ObjC makes no guarantees about the state of ivars, so we can't safely
- // introspect them in the general case.
- abort();
-}
-
-SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
-id
-swift_ClassMirror_quickLookObject(HeapObject *owner, const OpaqueValue *value,
- const Metadata *type) {
- id object = [*reinterpret_cast<const id *>(value) retain];
- SWIFT_CC_PLUSONE_GUARD(swift_release(owner));
- if ([object respondsToSelector:@selector(debugQuickLookObject)]) {
- id quickLookObject = [object debugQuickLookObject];
- [quickLookObject retain];
- [object release];
- return quickLookObject;
- }
-
- return object;
-}
-
-#endif
-
-// -- MagicMirror implementation.
-
-#define MIRROR_CONFORMANCE_SYM(Mirror, Subst) \
- MANGLE_SYM(Mirror##Vs01_##Subst##0sWP)
-#define OBJC_MIRROR_CONFORMANCE_SYM() \
- MANGLE_SYM(s11_ObjCMirrorVs7_MirrorsWP)
-
-// Addresses of the type metadata and Mirror witness tables for the primitive
-// mirrors.
-typedef const Metadata *(*MetadataFn)();
-
-extern "C" Metadata *STRUCT_MD_ACCESSOR_SYM(s13_OpaqueMirror)();
-static constexpr auto &OpaqueMirrorMetadata = STRUCT_MD_ACCESSOR_SYM(s13_OpaqueMirror);
-
-extern "C" const MirrorWitnessTable MIRROR_CONFORMANCE_SYM(s13_OpaqueMirror, B);
-static constexpr auto &OpaqueMirrorWitnessTable = MIRROR_CONFORMANCE_SYM(s13_OpaqueMirror, B);
-
-extern "C" Metadata *STRUCT_MD_ACCESSOR_SYM(s12_TupleMirror)();
-static constexpr auto &TupleMirrorMetadata = STRUCT_MD_ACCESSOR_SYM(s12_TupleMirror);
-
-extern "C" const MirrorWitnessTable MIRROR_CONFORMANCE_SYM(s12_TupleMirror, B);
-static constexpr auto &TupleMirrorWitnessTable = MIRROR_CONFORMANCE_SYM(s12_TupleMirror, B);
-
-extern "C" Metadata *STRUCT_MD_ACCESSOR_SYM(s13_StructMirror)();
-static constexpr auto &StructMirrorMetadata = STRUCT_MD_ACCESSOR_SYM(s13_StructMirror);
-
-extern "C" const MirrorWitnessTable MIRROR_CONFORMANCE_SYM(s13_StructMirror, B);
-static constexpr auto &StructMirrorWitnessTable = MIRROR_CONFORMANCE_SYM(s13_StructMirror, B);
-
-extern "C" Metadata *STRUCT_MD_ACCESSOR_SYM(s11_EnumMirror)();
-static constexpr auto &EnumMirrorMetadata = STRUCT_MD_ACCESSOR_SYM(s11_EnumMirror);
-
-extern "C" const MirrorWitnessTable MIRROR_CONFORMANCE_SYM(s11_EnumMirror, B);
-static constexpr auto &EnumMirrorWitnessTable = MIRROR_CONFORMANCE_SYM(s11_EnumMirror, B);
-
-extern "C" Metadata *STRUCT_MD_ACCESSOR_SYM(s12_ClassMirror)();
-static constexpr auto &ClassMirrorMetadata = STRUCT_MD_ACCESSOR_SYM(s12_ClassMirror);
-
-extern "C" const MirrorWitnessTable MIRROR_CONFORMANCE_SYM(s12_ClassMirror, B);
-static constexpr auto &ClassMirrorWitnessTable = MIRROR_CONFORMANCE_SYM(s12_ClassMirror, B);
-
-extern "C" Metadata *STRUCT_MD_ACCESSOR_SYM(s17_ClassSuperMirror)();
-static constexpr auto &ClassSuperMirrorMetadata = STRUCT_MD_ACCESSOR_SYM(s17_ClassSuperMirror);
-
-extern "C" const MirrorWitnessTable MIRROR_CONFORMANCE_SYM(s17_ClassSuperMirror, C);
-static constexpr auto &ClassSuperMirrorWitnessTable = MIRROR_CONFORMANCE_SYM(s17_ClassSuperMirror, C);
-
-extern "C" Metadata *STRUCT_MD_ACCESSOR_SYM(s15_MetatypeMirror)();
-static constexpr auto &MetatypeMirrorMetadata = STRUCT_MD_ACCESSOR_SYM(s15_MetatypeMirror);
-
-extern "C" const MirrorWitnessTable MIRROR_CONFORMANCE_SYM(s15_MetatypeMirror, B);
-static constexpr auto &MetatypeMirrorWitnessTable = MIRROR_CONFORMANCE_SYM(s15_MetatypeMirror, B);
-
-#if SWIFT_OBJC_INTEROP
-extern "C" Metadata *STRUCT_MD_ACCESSOR_SYM(s11_ObjCMirror)();
-static constexpr auto &ObjCMirrorMetadata = STRUCT_MD_ACCESSOR_SYM(s11_ObjCMirror);
-
-extern "C" const MirrorWitnessTable OBJC_MIRROR_CONFORMANCE_SYM();
-static constexpr auto &ObjCMirrorWitnessTable = OBJC_MIRROR_CONFORMANCE_SYM();
-
-extern "C" Metadata *STRUCT_MD_ACCESSOR_SYM(s16_ObjCSuperMirror)();
-static constexpr auto &ObjCSuperMirrorMetadata = STRUCT_MD_ACCESSOR_SYM(s16_ObjCSuperMirror);
-
-extern "C" const MirrorWitnessTable MIRROR_CONFORMANCE_SYM(s16_ObjCSuperMirror, C);
-static constexpr auto &ObjCSuperMirrorWitnessTable = MIRROR_CONFORMANCE_SYM(s16_ObjCSuperMirror, C);
-#endif
-
-/// \param owner passed at +1, consumed.
-/// \param value passed unowned.
-static Mirror getMirrorForSuperclass(const ClassMetadata *sup,
- HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
-#if SWIFT_OBJC_INTEROP
- // If the superclass is natively ObjC, cut over to the ObjC mirror
- // implementation.
- if (!sup->isTypeMetadata())
- return ObjC_getMirrorForSuperclass((Class)sup, owner, value, type);
-#endif
-
- Mirror resultBuf;
- MagicMirror *result = ::new (&resultBuf) MagicMirror;
-
- SWIFT_CC_PLUSZERO_GUARD(swift_retain(owner));
-
- result->Self = ClassSuperMirrorMetadata();
- result->MirrorWitness = &ClassSuperMirrorWitnessTable;
- result->Data.Owner = owner;
- result->Data.Type = sup;
- result->Data.Value = value;
-
- return resultBuf;
-}
-
-#if SWIFT_OBJC_INTEROP
-/// \param owner passed at +1, consumed.
-/// \param value passed unowned.
-static Mirror ObjC_getMirrorForSuperclass(Class sup,
- HeapObject *owner,
- const OpaqueValue *value,
- const Metadata *type) {
- Mirror resultBuf;
- MagicMirror *result = ::new (&resultBuf) MagicMirror;
-
- SWIFT_CC_PLUSZERO_GUARD(swift_retain(owner));
-
- result->Self = ObjCSuperMirrorMetadata();
- result->MirrorWitness = &ObjCSuperMirrorWitnessTable;
- result->Data.Owner = owner;
- result->Data.Type = reinterpret_cast<ClassMetadata*>(sup);
- result->Data.Value = value;
- return resultBuf;
-}
-#endif
-
-// (type being mirrored, mirror type, mirror witness)
-using MirrorTriple
- = std::tuple<const Metadata *, const Metadata *, const MirrorWitnessTable *>;
-
-static MirrorTriple
-getImplementationForClass(const OpaqueValue *Value) {
- // Get the runtime type of the object.
- const void *obj = *reinterpret_cast<const void * const *>(Value);
- auto isa = _swift_getClass(obj);
-
- // Look through artificial subclasses.
- while (isa->isTypeMetadata() && isa->isArtificialSubclass()) {
- isa = isa->SuperClass;
- }
-
-#if SWIFT_OBJC_INTEROP
- // If this is a pure ObjC class, reflect it using ObjC's runtime facilities.
- if (!isa->isTypeMetadata())
- return {isa, ObjCMirrorMetadata(), &ObjCMirrorWitnessTable};
-#endif
-
- // Otherwise, use the native Swift facilities.
- return std::make_tuple(
- isa, ClassMirrorMetadata(), &ClassMirrorWitnessTable);
-}
-
-/// Get the magic mirror witnesses appropriate to a particular type.
-static MirrorTriple
-getImplementationForType(const Metadata *T, const OpaqueValue *Value) {
- switch (T->getKind()) {
- case MetadataKind::Tuple:
- return std::make_tuple(
- T, TupleMirrorMetadata(), &TupleMirrorWitnessTable);
-
- case MetadataKind::Struct:
- return std::make_tuple(
- T, StructMirrorMetadata(), &StructMirrorWitnessTable);
-
- case MetadataKind::Enum:
- case MetadataKind::Optional:
- return std::make_tuple(
- T, EnumMirrorMetadata(), &EnumMirrorWitnessTable);
-
- case MetadataKind::ObjCClassWrapper:
- case MetadataKind::ForeignClass:
- case MetadataKind::Class: {
- return getImplementationForClass(Value);
- }
-
- case MetadataKind::Metatype:
- case MetadataKind::ExistentialMetatype: {
- return std::make_tuple(T, MetatypeMirrorMetadata(),
- &MetatypeMirrorWitnessTable);
- }
-
- case MetadataKind::Opaque: {
-#if SWIFT_OBJC_INTEROP
- // If this is the Builtin.UnknownObject type, use the dynamic type of the
- // object reference.
- if (T == &METADATA_SYM(BO).base) {
- return getImplementationForClass(Value);
- }
-#endif
- // If this is the Builtin.NativeObject type, and the heap object is a
- // class instance, use the dynamic type of the object reference.
- if (T == &METADATA_SYM(Bo).base) {
- const HeapObject *obj
- = *reinterpret_cast<const HeapObject * const*>(Value);
- if (obj->metadata->getKind() == MetadataKind::Class)
- return getImplementationForClass(Value);
- }
- LLVM_FALLTHROUGH;
- }
-
- /// TODO: Implement specialized mirror witnesses for all kinds.
- case MetadataKind::Function:
- case MetadataKind::Existential:
- return std::make_tuple(
- T, OpaqueMirrorMetadata(), &OpaqueMirrorWitnessTable);
-
- // Types can't have these kinds.
- case MetadataKind::HeapLocalVariable:
- case MetadataKind::HeapGenericLocalVariable:
- case MetadataKind::ErrorObject:
- swift::crash("Swift mirror lookup failure");
- }
-
- swift_runtime_unreachable("Unhandled MetadataKind in switch.");
-}
-
-/// MagicMirror ownership-taking whole-value constructor.
-///
-/// \param owner passed at +1, consumed.
-MagicMirror::MagicMirror(OpaqueValue *value, const Metadata *T,
- bool take) {
- // Put value types into a box so we can take stable interior pointers.
- // TODO: Specialize behavior here. If the value is a swift-refcounted class
- // we don't need to put it in a box to point into it.
- BoxPair box = swift_allocBox(T);
-
- if (take)
- T->vw_initializeWithTake(box.buffer, value);
- else
- T->vw_initializeWithCopy(box.buffer, value);
- std::tie(T, Self, MirrorWitness) = getImplementationForType(T, box.buffer);
-
- Data = {box.object, box.buffer, T};
-}
-
-/// MagicMirror ownership-sharing subvalue constructor.
-///
-/// \param owner passed at +1, consumed.
-MagicMirror::MagicMirror(HeapObject *owner,
- const OpaqueValue *value, const Metadata *T) {
- std::tie(T, Self, MirrorWitness) = getImplementationForType(T, value);
- Data = {owner, value, T};
-}
-
-} // end anonymous namespace
-
-/// func reflect<T>(x: T) -> Mirror
-///
-/// Produce a mirror for any value. The runtime produces a mirror that
-/// structurally reflects values of any type.
-///
-/// This function consumes 'value', following Swift's +1 convention for "in"
-/// arguments.
-SWIFT_CC(swift)
-MirrorReturn swift::swift_reflectAny(OpaqueValue *value, const Metadata *T) {
- const Metadata *mirrorType;
- const OpaqueValue *cMirrorValue;
- std::tie(mirrorType, cMirrorValue) = unwrapExistential(T, value);
-
- OpaqueValue *mirrorValue = const_cast<OpaqueValue*>(cMirrorValue);
-
- // Use MagicMirror.
- Mirror result;
- // Take the value, unless we projected a subvalue from it. We don't want to
- // deal with partial value deinitialization.
- bool take = false;
- SWIFT_CC_PLUSONE_GUARD(take = (mirrorValue == value));
- ::new (&result) MagicMirror(mirrorValue, mirrorType, take);
-
- // Destroy the whole original value if we couldn't take it.
- if (!take) {
- T->vw_destroy(value);
- }
- return MirrorReturn(result);
-}
-
-// NB: This function is not used directly in the Swift codebase, but is
-// exported for Xcode support and is used by the sanitizers. Please coordinate
-// before changing.
-//
-/// Demangles a Swift symbol name.
-///
-/// \param mangledName is the symbol name that needs to be demangled.
-/// \param mangledNameLength is the length of the string that should be
-/// demangled.
-/// \param outputBuffer is the user provided buffer where the demangled name
-/// will be placed. If nullptr, a new buffer will be malloced. In that case,
-/// the user of this API is responsible for freeing the returned buffer.
-/// \param outputBufferSize is the size of the output buffer. If the demangled
-/// name does not fit into the outputBuffer, the output will be truncated and
-/// the size will be updated, indicating how large the buffer should be.
-/// \param flags can be used to select the demangling style. TODO: We should
-//// define what these will be.
-/// \returns the demangled name. Returns nullptr if the input String is not a
-/// Swift mangled name.
-SWIFT_RUNTIME_EXPORT
-char *swift_demangle(const char *mangledName,
- size_t mangledNameLength,
- char *outputBuffer,
- size_t *outputBufferSize,
- uint32_t flags) {
- if (flags != 0) {
- swift::fatalError(0, "Only 'flags' value of '0' is currently supported.");
- }
- if (outputBuffer != nullptr && outputBufferSize == nullptr) {
- swift::fatalError(0, "'outputBuffer' is passed but the size is 'nullptr'.");
- }
-
- // Check if we are dealing with Swift mangled name, otherwise, don't try
- // to demangle and send indication to the user.
- if (!Demangle::isSwiftSymbol(mangledName))
- return nullptr; // Not a mangled name
-
- // Demangle the name.
- auto options = Demangle::DemangleOptions();
- options.DisplayDebuggerGeneratedModule = false;
- auto result =
- Demangle::demangleSymbolAsString(mangledName,
- mangledNameLength,
- options);
-
- // If the output buffer is not provided, malloc memory ourselves.
- if (outputBuffer == nullptr || *outputBufferSize == 0) {
- return strdup(result.c_str());
- }
-
- // Indicate a failure if the result does not fit and will be truncated
- // and set the required outputBufferSize.
- if (*outputBufferSize < result.length() + 1) {
- *outputBufferSize = result.length() + 1;
- }
-
- // Copy into the provided buffer.
- _swift_strlcpy(outputBuffer, result.c_str(), *outputBufferSize);
- return outputBuffer;
-}
diff --git a/stdlib/public/runtime/ReflectionMirror.mm b/stdlib/public/runtime/ReflectionMirror.mm
new file mode 100644
index 0000000..8910654
--- /dev/null
+++ b/stdlib/public/runtime/ReflectionMirror.mm
@@ -0,0 +1,712 @@
+//===----------------------------------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#include "swift/Runtime/Reflection.h"
+#include "swift/Runtime/Casting.h"
+#include "swift/Runtime/Config.h"
+#include "swift/Runtime/HeapObject.h"
+#include "swift/Runtime/Metadata.h"
+#include "swift/Runtime/Enum.h"
+#include "swift/Runtime/Unreachable.h"
+#include "swift/Demangling/Demangle.h"
+#include "swift/Runtime/Debug.h"
+#include "swift/Runtime/Portability.h"
+#include "Private.h"
+#include "WeakReference.h"
+#include "llvm/Support/Compiler.h"
+#include <cassert>
+#include <cinttypes>
+#include <cstdio>
+#include <cstring>
+#include <new>
+#include <string>
+#include <tuple>
+
+#if SWIFT_OBJC_INTEROP
+#include "swift/Runtime/ObjCBridge.h"
+#include "SwiftObject.h"
+#include <Foundation/Foundation.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+#endif
+
+using namespace swift;
+
+#if SWIFT_OBJC_INTEROP
+// Declare the debugQuickLookObject selector.
+@interface DeclareSelectors
+- (id)debugQuickLookObject;
+@end
+#endif
+
+namespace {
+
+/// The layout of Any.
+using Any = OpaqueExistentialContainer;
+
+// Swift assumes Any is returned in memory.
+// Use AnyReturn to guarantee that even on architectures
+// where Any would be returned in registers.
+struct AnyReturn {
+ Any any;
+ AnyReturn(Any a) : any(a) { }
+ operator Any() { return any; }
+ ~AnyReturn() { }
+};
+
+static std::tuple<const Metadata *, OpaqueValue *>
+unwrapExistential(const Metadata *T, OpaqueValue *Value) {
+ // If the value is an existential container, look through it to reflect the
+ // contained value.
+ // TODO: Should look through existential metatypes too, but it doesn't
+ // really matter yet since we don't have any special mirror behavior for
+ // concrete metatypes yet.
+ while (T->getKind() == MetadataKind::Existential) {
+ auto *existential
+ = static_cast<const ExistentialTypeMetadata *>(T);
+
+ // Unwrap the existential container.
+ T = existential->getDynamicType(Value);
+ Value = existential->projectValue(Value);
+
+ // Existential containers can end up nested in some cases due to generic
+ // abstraction barriers. Repeat in case we have a nested existential.
+ }
+ return std::make_tuple(T, Value);
+}
+
+static bool loadSpecialReferenceStorage(OpaqueValue *fieldData,
+ const FieldType fieldType,
+ Any *outValue) {
+ // isWeak() implies a reference type via Sema.
+ if (!fieldType.isWeak())
+ return false;
+
+ auto type = fieldType.getType();
+ assert(type->getKind() == MetadataKind::Optional);
+
+ auto *weakField = reinterpret_cast<WeakReference *>(fieldData);
+ auto *strongValue = swift_unknownWeakLoadStrong(weakField);
+
+ // Now that we have a strong reference, we need to create a temporary buffer
+ // from which to copy the whole value, which might be a native class-bound
+ // existential, which means we also need to copy n witness tables, for
+ // however many protocols are in the protocol composition. For example, if we
+ // are copying a:
+ // weak var myWeakProperty : (Protocol1 & Protocol2)?
+ // then we need to copy three values:
+ // - the instance
+ // - the witness table for Protocol1
+ // - the witness table for Protocol2
+
+ auto *weakContainer =
+ reinterpret_cast<WeakClassExistentialContainer *>(fieldData);
+
+ // Create a temporary existential where we can put the strong reference.
+ // The allocateBuffer value witness requires a ValueBuffer to own the
+ // allocated storage.
+ ValueBuffer temporaryBuffer;
+
+ auto *temporaryValue = reinterpret_cast<ClassExistentialContainer *>(
+ type->allocateBufferIn(&temporaryBuffer));
+
+ // Now copy the entire value out of the parent, which will include the
+ // witness tables.
+ temporaryValue->Value = strongValue;
+ auto valueWitnessesSize = type->getValueWitnesses()->getSize() -
+ sizeof(WeakClassExistentialContainer);
+ memcpy(temporaryValue->getWitnessTables(), weakContainer->getWitnessTables(),
+ valueWitnessesSize);
+
+ outValue->Type = type;
+ auto *opaqueValueAddr = type->allocateBoxForExistentialIn(&outValue->Buffer);
+ type->vw_initializeWithCopy(opaqueValueAddr,
+ reinterpret_cast<OpaqueValue *>(temporaryValue));
+
+ type->deallocateBufferIn(&temporaryBuffer);
+
+ return true;
+}
+
+
+// Abstract base class for reflection implementations.
+struct ReflectionMirrorImpl {
+ const Metadata *type;
+ OpaqueValue *value;
+
+ virtual char displayStyle() = 0;
+ virtual intptr_t count() = 0;
+ virtual AnyReturn subscript(intptr_t index, const char **outName,
+ void (**outFreeFunc)(const char *)) = 0;
+ virtual const char *enumCaseName() { return nullptr; }
+
+#if SWIFT_OBJC_INTEROP
+ virtual id quickLookObject() { return nil; }
+#endif
+
+ virtual ~ReflectionMirrorImpl() {}
+};
+
+
+// Implementation for tuples.
+struct TupleImpl : ReflectionMirrorImpl {
+ char displayStyle() {
+ return 't';
+ }
+
+ intptr_t count() {
+ auto *Tuple = static_cast<const TupleTypeMetadata *>(type);
+ return Tuple->NumElements;
+ }
+
+ AnyReturn subscript(intptr_t i, const char **outName,
+ void (**outFreeFunc)(const char *)) {
+ auto *Tuple = static_cast<const TupleTypeMetadata *>(type);
+
+ if (i < 0 || (size_t)i > Tuple->NumElements)
+ swift::crash("Swift mirror subscript bounds check failure");
+
+ // Determine whether there is a label.
+ bool hasLabel = false;
+ if (const char *labels = Tuple->Labels) {
+ const char *space = strchr(labels, ' ');
+ for (intptr_t j = 0; j != i && space; ++j) {
+ labels = space + 1;
+ space = strchr(labels, ' ');
+ }
+
+ // If we have a label, create it.
+ if (labels && space && labels != space) {
+ *outName = strndup(labels, space - labels);
+ hasLabel = true;
+ }
+ }
+
+ if (!hasLabel) {
+ // The name is the stringized element number '.0'.
+ char *str;
+ asprintf(&str, ".%" PRIdPTR, i);
+ *outName = str;
+ }
+
+ *outFreeFunc = [](const char *str) { free(const_cast<char *>(str)); };
+
+ // Get the nth element.
+ auto &elt = Tuple->getElement(i);
+ auto *bytes = reinterpret_cast<const char *>(value);
+ auto *eltData = reinterpret_cast<const OpaqueValue *>(bytes + elt.Offset);
+
+ Any result;
+
+ result.Type = elt.Type;
+ auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
+ result.Type->vw_initializeWithCopy(opaqueValueAddr,
+ const_cast<OpaqueValue *>(eltData));
+
+ return AnyReturn(result);
+ }
+};
+
+
+// Implementation for structs.
+struct StructImpl : ReflectionMirrorImpl {
+ char displayStyle() {
+ return 's';
+ }
+
+ intptr_t count() {
+ auto *Struct = static_cast<const StructMetadata *>(type);
+ return Struct->getDescription()->NumFields;
+ }
+
+ AnyReturn subscript(intptr_t i, const char **outName,
+ void (**outFreeFunc)(const char *)) {
+ auto *Struct = static_cast<const StructMetadata *>(type);
+
+ if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)
+ swift::crash("Swift mirror subscript bounds check failure");
+
+ // Load the offset from its respective vector.
+ auto fieldOffset = Struct->getFieldOffsets()[i];
+
+ Any result;
+
+ swift_getFieldAt(type, i, [&](llvm::StringRef name, FieldType fieldInfo) {
+ assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
+
+ *outName = name.data();
+ *outFreeFunc = nullptr;
+
+ auto *bytes = reinterpret_cast<char*>(value);
+ auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
+
+ bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result);
+ if (!didLoad) {
+ result.Type = fieldInfo.getType();
+ auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
+ result.Type->vw_initializeWithCopy(opaqueValueAddr,
+ const_cast<OpaqueValue *>(fieldData));
+ }
+ });
+
+ return AnyReturn(result);
+ }
+};
+
+
+// Implementation for enums.
+struct EnumImpl : ReflectionMirrorImpl {
+ bool isReflectable() {
+ const auto *Enum = static_cast<const EnumMetadata *>(type);
+ const auto &Description = Enum->getDescription();
+ return Description->IsReflectable;
+ }
+
+ const char *getInfo(unsigned *tagPtr = nullptr,
+ const Metadata **payloadTypePtr = nullptr,
+ bool *indirectPtr = nullptr) {
+ const auto *Enum = static_cast<const EnumMetadata *>(type);
+ const auto &Description = Enum->getDescription();;
+
+ unsigned payloadCases = Description->getNumPayloadCases();
+
+ // 'tag' is in the range [-ElementsWithPayload..ElementsWithNoPayload-1].
+ int tag = type->vw_getEnumTag(value);
+
+ // Convert resilient tag index to fragile tag index.
+ tag += payloadCases;
+
+ const Metadata *payloadType = nullptr;
+ bool indirect = false;
+
+ const char *caseName = nullptr;
+ swift_getFieldAt(type, tag, [&](llvm::StringRef name, FieldType info) {
+ caseName = name.data();
+ payloadType = info.getType();
+ indirect = info.isIndirect();
+ });
+
+ if (tagPtr)
+ *tagPtr = tag;
+ if (payloadTypePtr)
+ *payloadTypePtr = payloadType;
+ if (indirectPtr)
+ *indirectPtr = indirect;
+
+ return caseName;
+ }
+
+ char displayStyle() {
+ return 'e';
+ }
+
+ intptr_t count() {
+ if (!isReflectable()) {
+ return 0;
+ }
+
+ const Metadata *payloadType;
+ getInfo(nullptr, &payloadType, nullptr);
+ return (payloadType != nullptr) ? 1 : 0;
+ }
+
+ AnyReturn subscript(intptr_t i, const char **outName,
+ void (**outFreeFunc)(const char *)) {
+ const auto *Enum = static_cast<const EnumMetadata *>(type);
+ const auto &Description = Enum->getDescription();
+
+ unsigned tag;
+ const Metadata *payloadType;
+ bool indirect;
+
+ auto *caseName = getInfo(&tag, &payloadType, &indirect);
+
+ // Copy the enum payload into a box
+ const Metadata *boxType = (indirect ? &METADATA_SYM(Bo).base : payloadType);
+ BoxPair pair = swift_allocBox(boxType);
+
+ type->vw_destructiveProjectEnumData(const_cast<OpaqueValue *>(value));
+ boxType->vw_initializeWithCopy(pair.buffer, const_cast<OpaqueValue *>(value));
+ type->vw_destructiveInjectEnumTag(const_cast<OpaqueValue *>(value),
+ (int) (tag - Description->getNumPayloadCases()));
+
+ value = pair.buffer;
+
+ // If the payload is indirect, we need to jump through the box to get it.
+ if (indirect) {
+ const HeapObject *owner = *reinterpret_cast<HeapObject * const *>(value);
+ value = swift_projectBox(const_cast<HeapObject *>(owner));
+ }
+
+ *outName = caseName;
+ *outFreeFunc = nullptr;
+
+ Any result;
+
+ result.Type = payloadType;
+ auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
+ result.Type->vw_initializeWithCopy(opaqueValueAddr,
+ const_cast<OpaqueValue *>(value));
+
+ swift_release(pair.object);
+ return AnyReturn(result);
+ }
+
+ const char *enumCaseName() {
+ if (!isReflectable()) {
+ return nullptr;
+ }
+
+ return getInfo();
+ }
+};
+
+
+// Implementation for classes.
+struct ClassImpl : ReflectionMirrorImpl {
+ char displayStyle() {
+ return 'c';
+ }
+
+ intptr_t count() {
+ auto *Clas = static_cast<const ClassMetadata*>(type);
+ auto count = Clas->getDescription()->NumFields;
+
+ return count;
+ }
+
+ AnyReturn subscript(intptr_t i, const char **outName,
+ void (**outFreeFunc)(const char *)) {
+ auto *Clas = static_cast<const ClassMetadata*>(type);
+
+ if (i < 0 || (size_t)i > Clas->getDescription()->NumFields)
+ swift::crash("Swift mirror subscript bounds check failure");
+
+ // FIXME: If the class has ObjC heritage, get the field offset using the ObjC
+ // metadata, because we don't update the field offsets in the face of
+ // resilient base classes.
+ uintptr_t fieldOffset;
+ if (usesNativeSwiftReferenceCounting(Clas)) {
+ fieldOffset = Clas->getFieldOffsets()[i];
+ } else {
+ #if SWIFT_OBJC_INTEROP
+ Ivar *ivars = class_copyIvarList((Class)Clas, nullptr);
+ fieldOffset = ivar_getOffset(ivars[i]);
+ free(ivars);
+ #else
+ swift::crash("Object appears to be Objective-C, but no runtime.");
+ #endif
+ }
+
+ Any result;
+
+ swift_getFieldAt(type, i, [&](llvm::StringRef name, FieldType fieldInfo) {
+ assert(!fieldInfo.isIndirect() && "class indirect properties not implemented");
+
+ auto *bytes = *reinterpret_cast<char * const *>(value);
+ auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
+
+ *outName = name.data();
+ *outFreeFunc = nullptr;
+
+ bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result);
+ if (!didLoad) {
+ result.Type = fieldInfo.getType();
+ auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
+ result.Type->vw_initializeWithCopy(opaqueValueAddr,
+ const_cast<OpaqueValue *>(fieldData));
+ }
+ });
+
+ return AnyReturn(result);
+ }
+
+#if SWIFT_OBJC_INTEROP
+ id quickLookObject() {
+ id object = [*reinterpret_cast<const id *>(value) retain];
+ if ([object respondsToSelector:@selector(debugQuickLookObject)]) {
+ id quickLookObject = [object debugQuickLookObject];
+ [quickLookObject retain];
+ [object release];
+ return quickLookObject;
+ }
+
+ return object;
+ }
+#endif
+};
+
+
+#if SWIFT_OBJC_INTEROP
+// Implementation for ObjC classes.
+struct ObjCClassImpl : ClassImpl {
+ intptr_t count() {
+ // ObjC makes no guarantees about the state of ivars, so we can't safely
+ // introspect them in the general case.
+ return 0;
+ }
+
+ AnyReturn subscript(intptr_t i, const char **outName,
+ void (**outFreeFunc)(const char *)) {
+ swift::crash("Cannot get children of Objective-C objects.");
+ }
+};
+#endif
+
+
+// Implementation for metatypes.
+struct MetatypeImpl : ReflectionMirrorImpl {
+ char displayStyle() {
+ return '\0';
+ }
+
+ intptr_t count() {
+ return 0;
+ }
+
+ AnyReturn subscript(intptr_t i, const char **outName,
+ void (**outFreeFunc)(const char *)) {
+ swift::crash("Metatypes have no children.");
+ }
+};
+
+
+// Implementation for opaque types.
+struct OpaqueImpl : ReflectionMirrorImpl {
+ char displayStyle() {
+ return '\0';
+ }
+
+ intptr_t count() {
+ return 0;
+ }
+
+ AnyReturn subscript(intptr_t i, const char **outName,
+ void (**outFreeFunc)(const char *)) {
+ swift::crash("Opaque types have no children.");
+ }
+};
+
+
+template<typename F>
+auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
+ const F &f) -> decltype(f(nullptr))
+{
+ const Metadata *type;
+ OpaqueValue *value;
+ std::tie(type, value) = unwrapExistential(T, passedValue);
+
+ if (passedType != nullptr) {
+ type = passedType;
+ }
+
+ auto call = [&](ReflectionMirrorImpl *impl) {
+ impl->type = type;
+ impl->value = value;
+ auto result = f(impl);
+ SWIFT_CC_PLUSONE_GUARD(T->vw_destroy(passedValue));
+ return result;
+ };
+
+ auto callClass = [&] {
+ if (passedType == nullptr) {
+ // Get the runtime type of the object.
+ const void *obj = *reinterpret_cast<const void * const *>(value);
+ auto isa = _swift_getClass(obj);
+
+ // Look through artificial subclasses.
+ while (isa->isTypeMetadata() && isa->isArtificialSubclass()) {
+ isa = isa->SuperClass;
+ }
+ passedType = isa;
+ }
+
+ #if SWIFT_OBJC_INTEROP
+ // If this is a pure ObjC class, reflect it using ObjC's runtime facilities.
+ // ForeignClass (e.g. CF classes) manifests as a NULL class object.
+ auto *classObject = passedType->getClassObject();
+ if (classObject == nullptr || !classObject->isTypeMetadata()) {
+ ObjCClassImpl impl;
+ return call(&impl);
+ }
+ #endif
+
+ // Otherwise, use the native Swift facilities.
+ ClassImpl impl;
+ return call(&impl);
+ };
+
+ switch (type->getKind()) {
+ case MetadataKind::Tuple: {
+ TupleImpl impl;
+ return call(&impl);
+ }
+
+ case MetadataKind::Struct: {
+ StructImpl impl;
+ return call(&impl);
+ }
+
+
+ case MetadataKind::Enum:
+ case MetadataKind::Optional: {
+ EnumImpl impl;
+ return call(&impl);
+ }
+
+ case MetadataKind::ObjCClassWrapper:
+ case MetadataKind::ForeignClass:
+ case MetadataKind::Class: {
+ return callClass();
+ }
+
+ case MetadataKind::Metatype:
+ case MetadataKind::ExistentialMetatype: {
+ MetatypeImpl impl;
+ return call(&impl);
+ }
+
+ case MetadataKind::Opaque: {
+#if SWIFT_OBJC_INTEROP
+ // If this is the Builtin.UnknownObject type, use the dynamic type of the
+ // object reference.
+ if (type == &METADATA_SYM(BO).base) {
+ return callClass();
+ }
+#endif
+ // If this is the Builtin.NativeObject type, and the heap object is a
+ // class instance, use the dynamic type of the object reference.
+ if (type == &METADATA_SYM(Bo).base) {
+ const HeapObject *obj
+ = *reinterpret_cast<const HeapObject * const*>(value);
+ if (obj->metadata->getKind() == MetadataKind::Class) {
+ return callClass();
+ }
+ }
+ LLVM_FALLTHROUGH;
+ }
+
+ /// TODO: Implement specialized mirror witnesses for all kinds.
+ case MetadataKind::Function:
+ case MetadataKind::Existential: {
+ OpaqueImpl impl;
+ return call(&impl);
+ }
+
+ // Types can't have these kinds.
+ case MetadataKind::HeapLocalVariable:
+ case MetadataKind::HeapGenericLocalVariable:
+ case MetadataKind::ErrorObject:
+ swift::crash("Swift mirror lookup failure");
+ }
+
+ swift_runtime_unreachable("Unhandled MetadataKind in switch.");
+}
+
+} // end anonymous namespace
+
+
+// func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
+SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
+const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value,
+ const Metadata *type,
+ const Metadata *T) {
+ return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; });
+}
+
+// func _getChildCount<T>(_: T, type: Any.Type) -> Int
+SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
+intptr_t swift_reflectionMirror_count(OpaqueValue *value,
+ const Metadata *type,
+ const Metadata *T) {
+ return call(value, T, type, [](ReflectionMirrorImpl *impl) {
+ return impl->count();
+ });
+}
+
+// We intentionally use a non-POD return type with this entry point to give
+// it an indirect return ABI for compatibility with Swift.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
+// func _getChild<T>(
+// of: T,
+// type: Any.Type,
+// index: Int,
+// outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
+// outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
+// ) -> Any
+SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
+AnyReturn swift_reflectionMirror_subscript(OpaqueValue *value, const Metadata *type,
+ intptr_t index,
+ const char **outName,
+ void (**outFreeFunc)(const char *),
+ const Metadata *T) {
+ return call(value, T, type, [&](ReflectionMirrorImpl *impl) {
+ return impl->subscript(index, outName, outFreeFunc);
+ });
+}
+#pragma clang diagnostic pop
+
+// func _getDisplayStyle<T>(_: T) -> CChar
+SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
+char swift_reflectionMirror_displayStyle(OpaqueValue *value, const Metadata *T) {
+ return call(value, T, nullptr, [](ReflectionMirrorImpl *impl) { return impl->displayStyle(); });
+}
+
+// func _getEnumCaseName<T>(_ value: T) -> UnsafePointer<CChar>?
+SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
+const char *swift_EnumCaseName(OpaqueValue *value, const Metadata *T) {
+ return call(value, T, nullptr, [](ReflectionMirrorImpl *impl) { return impl->enumCaseName(); });
+}
+
+// func _opaqueSummary(_ metadata: Any.Type) -> UnsafePointer<CChar>?
+SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
+const char *swift_OpaqueSummary(const Metadata *T) {
+ switch (T->getKind()) {
+ case MetadataKind::Class:
+ case MetadataKind::Struct:
+ case MetadataKind::Enum:
+ case MetadataKind::Optional:
+ case MetadataKind::Metatype:
+ return nullptr;
+ case MetadataKind::Opaque:
+ return "(Opaque Value)";
+ case MetadataKind::Tuple:
+ return "(Tuple)";
+ case MetadataKind::Function:
+ return "(Function)";
+ case MetadataKind::Existential:
+ return "(Existential)";
+ case MetadataKind::ObjCClassWrapper:
+ return "(Objective-C Class Wrapper)";
+ case MetadataKind::ExistentialMetatype:
+ return "(Existential Metatype)";
+ case MetadataKind::ForeignClass:
+ return "(Foreign Class)";
+ case MetadataKind::HeapLocalVariable:
+ return "(Heap Local Variable)";
+ case MetadataKind::HeapGenericLocalVariable:
+ return "(Heap Generic Local Variable)";
+ case MetadataKind::ErrorObject:
+ return "(ErrorType Object)";
+ }
+
+ swift_runtime_unreachable("Unhandled MetadataKind in switch.");
+}
+
+#if SWIFT_OBJC_INTEROP
+// func _getQuickLookObject<T>(_: T) -> AnyObject?
+SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
+id swift_reflectionMirror_quickLookObject(OpaqueValue *value, const Metadata *T) {
+ return call(value, T, nullptr, [](ReflectionMirrorImpl *impl) { return impl->quickLookObject(); });
+}
+#endif
diff --git a/stdlib/public/stubs/GlobalObjects.cpp b/stdlib/public/stubs/GlobalObjects.cpp
index 6c5b30d..436b03e 100644
--- a/stdlib/public/stubs/GlobalObjects.cpp
+++ b/stdlib/public/stubs/GlobalObjects.cpp
@@ -129,8 +129,13 @@
namespace llvm { namespace hashing { namespace detail {
// An extern variable expected by LLVM's hashing templates. We don't link any
- // LLVM libs into the runtime, so define this here.
- size_t fixed_seed_override = 0;
+ // LLVM libs into the runtime, so define it as a weak symbol.
+ //
+ // Systems that compile this code into a dynamic library will do so with
+ // hidden visibility, making this all internal to the dynamic library.
+ // Systems that statically link the Swift runtime into applications (e.g. on
+ // Linux) need this to handle the case when the app already uses LLVM.
+ size_t LLVM_ATTRIBUTE_WEAK fixed_seed_override = 0;
} // namespace detail
} // namespace hashing
} // namespace llvm
diff --git a/stdlib/public/stubs/UnicodeNormalization.cpp b/stdlib/public/stubs/UnicodeNormalization.cpp
index d31c3e9..6dd98e2 100644
--- a/stdlib/public/stubs/UnicodeNormalization.cpp
+++ b/stdlib/public/stubs/UnicodeNormalization.cpp
@@ -22,17 +22,34 @@
// Declare a few external functions to avoid a dependency on ICU headers.
extern "C" {
+
+// Types
typedef struct UBreakIterator UBreakIterator;
+typedef struct UBreakIterator UNormalizer2;
typedef enum UBreakIteratorType {} UBreakIteratorType;
typedef enum UErrorCode {} UErrorCode;
typedef uint16_t UChar;
+typedef int32_t UChar32;
+typedef int8_t UBool;
+typedef swift::__swift_stdlib_UProperty UProperty;
+// Grapheme breaking APIs
void ubrk_close(UBreakIterator *);
UBreakIterator *ubrk_open(UBreakIteratorType, const char *, const UChar *,
int32_t, UErrorCode *);
int32_t ubrk_preceding(UBreakIterator *, int32_t);
int32_t ubrk_following(UBreakIterator *, int32_t);
void ubrk_setText(UBreakIterator *, const UChar *, int32_t, UErrorCode *);
+
+// Comparison, normalization, and character property APIs
+int32_t unorm2_spanQuickCheckYes(const UNormalizer2 *, const UChar *, int32_t,
+ UErrorCode *);
+int32_t unorm2_normalize(const UNormalizer2 *, const UChar *, int32_t, UChar *,
+ int32_t, UErrorCode *);
+const UNormalizer2 *unorm2_getNFCInstance(UErrorCode *);
+UBool unorm2_hasBoundaryBefore(const UNormalizer2 *norm2, UChar32 c);
+UBool u_hasBinaryProperty(UChar32, UProperty);
+UBool u_isdefined(UChar32);
}
#else
@@ -45,6 +62,7 @@
#include <unicode/ucoleitr.h>
#include <unicode/uiter.h>
#include <unicode/ubrk.h>
+#include <unicode/uchar.h>
#pragma clang diagnostic pop
@@ -137,76 +155,6 @@
ASCIICollation(const ASCIICollation &) = delete;
};
-/// Compares the strings via the Unicode Collation Algorithm on the root locale.
-/// Results are the usual string comparison results:
-/// <0 the left string is less than the right string.
-/// ==0 the strings are equal according to their collation.
-/// >0 the left string is greater than the right string.
-int32_t
-swift::_swift_stdlib_unicode_compare_utf16_utf16(const uint16_t *LeftString,
- int32_t LeftLength,
- const uint16_t *RightString,
- int32_t RightLength) {
- // ICU UChar type is platform dependent. In Cygwin, it is defined
- // as wchar_t which size is 2. It seems that the underlying binary
- // representation is same with swift utf16 representation.
- // On Clang 4.0 under a recent Linux, ICU uses the built-in char16_t type.
- return ucol_strcoll(GetRootCollator(),
- reinterpret_cast<const UChar *>(LeftString), LeftLength,
- reinterpret_cast<const UChar *>(RightString), RightLength);
-}
-
-/// Compares the strings via the Unicode Collation Algorithm on the root locale.
-/// Results are the usual string comparison results:
-/// <0 the left string is less than the right string.
-/// ==0 the strings are equal according to their collation.
-/// >0 the left string is greater than the right string.
-int32_t
-swift::_swift_stdlib_unicode_compare_utf8_utf16(const unsigned char *LeftString,
- int32_t LeftLength,
- const uint16_t *RightString,
- int32_t RightLength) {
- UCharIterator LeftIterator;
- UCharIterator RightIterator;
- UErrorCode ErrorCode = U_ZERO_ERROR;
-
- uiter_setUTF8(&LeftIterator, reinterpret_cast<const char *>(LeftString), LeftLength);
- uiter_setString(&RightIterator, reinterpret_cast<const UChar *>(RightString),
- RightLength);
-
- uint32_t Diff = ucol_strcollIter(GetRootCollator(),
- &LeftIterator, &RightIterator, &ErrorCode);
- if (U_FAILURE(ErrorCode)) {
- swift::crash("ucol_strcollIter: Unexpected error doing utf8<->utf16 string comparison.");
- }
- return Diff;
-}
-
-/// Compares the strings via the Unicode Collation Algorithm on the root locale.
-/// Results are the usual string comparison results:
-/// <0 the left string is less than the right string.
-/// ==0 the strings are equal according to their collation.
-/// >0 the left string is greater than the right string.
-int32_t
-swift::_swift_stdlib_unicode_compare_utf8_utf8(const unsigned char *LeftString,
- int32_t LeftLength,
- const unsigned char *RightString,
- int32_t RightLength) {
- UCharIterator LeftIterator;
- UCharIterator RightIterator;
- UErrorCode ErrorCode = U_ZERO_ERROR;
-
- uiter_setUTF8(&LeftIterator, reinterpret_cast<const char *>(LeftString), LeftLength);
- uiter_setUTF8(&RightIterator, reinterpret_cast<const char *>(RightString), RightLength);
-
- uint32_t Diff = ucol_strcollIter(GetRootCollator(),
- &LeftIterator, &RightIterator, &ErrorCode);
- if (U_FAILURE(ErrorCode)) {
- swift::crash("ucol_strcollIter: Unexpected error doing utf8<->utf8 string comparison.");
- }
- return Diff;
-}
-
void *swift::_swift_stdlib_unicodeCollationIterator_create(
const __swift_uint16_t *Str, __swift_uint32_t Length) {
UErrorCode ErrorCode = U_ZERO_ERROR;
@@ -225,7 +173,8 @@
auto Result = ucol_next(
static_cast<UCollationElements *>(CollationIterator), &ErrorCode);
if (U_FAILURE(ErrorCode)) {
- swift::crash("_swift_stdlib_unicodeCollationIterator_next: ucol_next() failed.");
+ swift::crash(
+ "_swift_stdlib_unicodeCollationIterator_next: ucol_next() failed.");
}
*HitEnd = (Result == UCOL_NULLORDER);
return Result;
@@ -328,6 +277,44 @@
textLength, ptr_cast<UErrorCode>(status));
}
+swift::__swift_stdlib_UBool swift::__swift_stdlib_unorm2_hasBoundaryBefore(
+ const __swift_stdlib_UNormalizer2 *ptr, __swift_stdlib_UChar32 char32) {
+ return unorm2_hasBoundaryBefore(ptr_cast<UNormalizer2>(ptr), char32);
+}
+const swift::__swift_stdlib_UNormalizer2 *
+swift::__swift_stdlib_unorm2_getNFCInstance(__swift_stdlib_UErrorCode *err) {
+ return ptr_cast<__swift_stdlib_UNormalizer2>(
+ unorm2_getNFCInstance(ptr_cast<UErrorCode>(err)));
+}
+
+int32_t swift::__swift_stdlib_unorm2_normalize(
+ const __swift_stdlib_UNormalizer2 *norm, const __swift_uint16_t *src,
+ __swift_int32_t len, __swift_uint16_t *dst, __swift_int32_t capacity,
+ __swift_stdlib_UErrorCode *err) {
+ return unorm2_normalize(ptr_cast<UNormalizer2>(norm), src, len, dst, capacity,
+ ptr_cast<UErrorCode>(err));
+}
+
+__swift_int32_t swift::__swift_stdlib_unorm2_spanQuickCheckYes(
+ const __swift_stdlib_UNormalizer2 *norm, const __swift_stdlib_UChar *ptr,
+ __swift_int32_t len, __swift_stdlib_UErrorCode *err) {
+ return unorm2_spanQuickCheckYes(ptr_cast<UNormalizer2>(norm),
+ ptr_cast<UChar>(ptr), len,
+ ptr_cast<UErrorCode>(err));
+}
+
+swift::__swift_stdlib_UBool
+swift::__swift_stdlib_u_hasBinaryProperty(__swift_stdlib_UChar32 c,
+ __swift_stdlib_UProperty p) {
+ return u_hasBinaryProperty(c, static_cast<UProperty>(p));
+}
+
+swift::__swift_stdlib_UBool
+swift::__swift_stdlib_u_isdefined(UChar32 c) {
+ return u_isdefined(c);
+}
+
+
// Force an autolink with ICU
#if defined(__MACH__)
asm(".linker_option \"-licucore\"\n");
diff --git a/test/ClangImporter/Inputs/attr-objc_subclassing_restricted.h b/test/ClangImporter/Inputs/attr-objc_subclassing_restricted.h
new file mode 100644
index 0000000..acdd65b
--- /dev/null
+++ b/test/ClangImporter/Inputs/attr-objc_subclassing_restricted.h
@@ -0,0 +1,6 @@
+// This file is meant to be used with the mock SDK.
+#import <Foundation.h>
+
+__attribute__((objc_subclassing_restricted))
+@interface Restricted: NSObject
+@end
diff --git a/test/ClangImporter/attr-objc_subclassing_restricted.swift b/test/ClangImporter/attr-objc_subclassing_restricted.swift
new file mode 100644
index 0000000..dd9b4ac
--- /dev/null
+++ b/test/ClangImporter/attr-objc_subclassing_restricted.swift
@@ -0,0 +1,9 @@
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -import-objc-header %S/Inputs/attr-objc_subclassing_restricted.h %s -swift-version 5 -verify
+
+// No errors in Swift 3 and 4 modes.
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -import-objc-header %S/Inputs/attr-objc_subclassing_restricted.h %s -swift-version 4
+
+// REQUIRES: objc_interop
+
+class Sub: Restricted { // expected-error {{cannot inherit from non-open class 'Restricted' outside of its defining module}}
+}
diff --git a/test/ClangImporter/private_frameworks_modules.swift b/test/ClangImporter/private_frameworks_modules.swift
index 079dba2..bf8f5a4 100644
--- a/test/ClangImporter/private_frameworks_modules.swift
+++ b/test/ClangImporter/private_frameworks_modules.swift
@@ -1,8 +1,7 @@
-// REQUIRES: rdar37618912
// RUN: %empty-directory(%t)
-// RUN: %target-swift-frontend -typecheck -F %S/Inputs/frameworks -DOLD -verify %s -Xcc -Wno-private-module
-// RUN: %target-swift-frontend -typecheck -F %S/Inputs/frameworks -DNEW -verify %s -Xcc -Wno-private-module
+// RUN: %target-swift-frontend -typecheck -F %S/Inputs/frameworks -DOLD -verify %s -Xcc -w
+// RUN: %target-swift-frontend -typecheck -F %S/Inputs/frameworks -DNEW -verify %s -Xcc -w
import PrivateAsSubmodule.Private
diff --git a/test/Constraints/iuo.swift b/test/Constraints/iuo.swift
index b483b4f..a4b0731 100644
--- a/test/Constraints/iuo.swift
+++ b/test/Constraints/iuo.swift
@@ -167,3 +167,14 @@
let _: (Bool) -> T? = id(T.iuoResultStatic as (Bool) -> T?)
let _: T! = id(T.iuoResultStatic(true))
}
+
+class rdar37241550 {
+ public init(blah: Float) { fatalError() }
+ public convenience init() { fatalError() }
+ public convenience init!(with void: ()) { fatalError() }
+
+ static func f(_ fn: () -> rdar37241550) {}
+ static func test() {
+ f(rdar37241550.init) // no error, the failable init is not applicable
+ }
+}
diff --git a/test/DebugInfo/arg-debug_value.swift b/test/DebugInfo/arg-debug_value.swift
deleted file mode 100644
index 7573dcb..0000000
--- a/test/DebugInfo/arg-debug_value.swift
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s
-
-// Verify that arguments described by debug_value intrinsics are only
-// emitted once.
-var g: Int64 = 1
-
-class Foo {
- var x: Int64
- // CHECK: define {{.*}}$S4main3FooCACycfc
- // CHECK: entry:
- // CHECK: call void @llvm.dbg.value(metadata %T4main3FooC* %0
- // CHECK: ret %T4main3FooC* %0
- init () { x = g; g += 1 }
-}
diff --git a/test/DebugInfo/fnptr.swift b/test/DebugInfo/fnptr.swift
index 30a23aa..83c7ee9 100644
--- a/test/DebugInfo/fnptr.swift
+++ b/test/DebugInfo/fnptr.swift
@@ -4,9 +4,7 @@
// CHECK-DAG: ![[SINODE:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Int64",{{.*}} identifier: [[SI:.*]])
// CHECK-DAG: ![[SFNODE:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Float",{{.*}} identifier: [[SF:.*]])
// CHECK-DAG: ![[VOIDNODE:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$SytD",{{.*}} identifier: [[VOID:.*]])
-func bar() {
- print("bar()", terminator: "")
-}
+func bar() {}
func baz(_ i: Float) -> Int64 { return 0; }
func barz(_ i: Float, _ j: Float) -> Int64 { return 0; }
func main() -> Int64 {
diff --git a/test/DebugInfo/local-vars.swift.gyb b/test/DebugInfo/local-vars.swift.gyb
index 973bd3a..b8e5320 100644
--- a/test/DebugInfo/local-vars.swift.gyb
+++ b/test/DebugInfo/local-vars.swift.gyb
@@ -23,26 +23,98 @@
let j : Int32 = 2
}
+public struct SLarge {
+ var tuple : (Int64, Int64, Int64, Int64, Int64, Int64, Int64, Int64)
+}
+
+public enum ENoPayload {
+ case one
+ case two
+}
+
+public enum ESinglePayload : Int {
+ case one = 1
+ case two = 2
+}
+
+public enum EMultiPayload {
+ case int(Int)
+ indirect case recursive(EMultiPayload)
+ case string(String)
+}
+
+public protocol Proto {
+ func f()
+}
+
+func nop() {}
func use<T>(_ x: T) {}
func variable_use<T>(_ x: inout T) {}
-% def derive_name((type, val)):
-% return (type.replace('<', '_').replace(' ', '_').replace(',', '_')
-% .replace('?', '_').replace('>', '_')
-% .replace('[', '_').replace(']', '_'), type, val)
-% for name, type, val in map(derive_name,
-% [("UInt64", "64"), ("UInt32", "32"), ("Int64", "64"), ("Int32", "32"),
-% ("Int", "42"), ("UInt", "42"), ("C", "C(42)"), ("String", '"string"'),
-% ("Dictionary<UInt64, String>", '[1:"entry"]'),
-% ("Float", "2.71"), ("Double", "3.14"), ("[UInt64]", "[1, 2, 3]"),
-% ("S", "S()")]):
+%{
+type_initializer_map = [
+ #// Basic types.
+ ("UInt64", "64"), ("UInt32", "32"), ("Int64", "64"), ("Int32", "32"),
+ ("Int", "42"), ("UInt", "42"),
+ ("Float", "2.71"), ("Double", "3.14"),
+ #// Sugared types and strings.
+ ("String", '"string"'),
+ ("[UInt64]", "[1, 2, 3]"),
+ ("Dictionary<UInt64, String>", '[1:"entry"]'),
+ #// Classes, structs, tuples.
+ ("(Int, C)", "(42, C(42))"),
+ ("C", "C(42)"),
+ ("S", "S()"),
+ ("SLarge", "SLarge(tuple: (1,2,3,4,5,6,7,8))"),
+ #// Enums.
+ ("ENoPayload", ".two"),
+ ("ESinglePayload", ".two"),
+ ("EMultiPayload", ".recursive(.string(\"string\"))"),
+ #// Existentials.
+ ("T", "self.t"),
+ ("U", "self.u"),
+ #// Functions.
+ ("(() -> ())", "nop")
+ ]
+import re
+def derive_name((type, val)):
+ return (re.sub(r'[<> ,\.\?\(\)\[\]-]', '_', type), type, val)
+
+for name, type, val in map(derive_name, type_initializer_map):
+ generic = (type in ['T', 'U'])
+}%
+% if generic:
+public class ContextA_${name}<T, U : Proto> {
+ let t : T
+ let u : U
+ init(_ t: T, _ u: U) { self.t = t; self.u = u; }
+% end
+
public func constant_${name}() -> ${type} {
let v : ${type} = ${val}
// CHECK: !DILocalVariable(name: "v",{{.*}} line: [[@LINE-1]]
// DWARF: DW_TAG_subprogram
- // DWARF: DW_AT_name {{.*}}constant_${name}
+ // DWARF-LABEL: DW_AT_name {{.*}}constant_${name}
// DWARF-NOT: DW_TAG_subprogram
+% if generic:
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("self")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+% end
// DWARF: DW_TAG_variable
// DWARF-NOT: DW_TAG
// DWARF: {{(DW_AT_location)|(DW_AT_const_value)}}
@@ -55,8 +127,26 @@
var v : ${type} = ${val}
// CHECK: !DILocalVariable(name: "v",{{.*}} line: [[@LINE-1]]
// DWARF: DW_TAG_subprogram
- // DWARF: DW_AT_name {{.*}}constvar_${name}
+ // DWARF-LABEL: DW_AT_name {{.*}}constvar_${name}
// DWARF-NOT: DW_TAG_subprogram
+% if generic:
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("self")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+% end
// DWARF: DW_TAG_variable
// DWARF-NOT: DW_TAG
// DWARF: {{(DW_AT_location)|(DW_AT_const_value)}}
@@ -69,8 +159,26 @@
let v : ${type} = constant_${name}()
// CHECK: !DILocalVariable(name: "v",{{.*}} line: [[@LINE-1]]
// DWARF: DW_TAG_subprogram
- // DWARF: DW_AT_name {{.*}}let_${name}
+ // DWARF-LABEL: DW_AT_name {{.*}}let_${name}
// DWARF-NOT: DW_TAG_subprogram
+% if generic:
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("self")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+% end
// DWARF: DW_TAG_variable
// DWARF-NOT: DW_TAG
// DWARF: {{(DW_AT_location)|(DW_AT_const_value)}}
@@ -79,6 +187,40 @@
use(v)
}
+public func case_let_${name}() {
+ switch constant_${name}() {
+ case let v:
+ // CHECK: !DILocalVariable(name: "v",{{.*}} line: [[@LINE-1]]
+ use(v)
+ }
+ // DWARF: DW_TAG_subprogram
+ // DWARF-LABEL: DW_AT_name {{.*}}let_${name}
+ // DWARF-NOT: DW_TAG_subprogram
+% if generic:
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("self")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+% end
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: {{(DW_AT_location)|(DW_AT_const_value)}}
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("v")
+}
+
public func optional_${name}() -> ${type}? {
return constant_${name}();
}
@@ -87,8 +229,26 @@
let opt : ${type}? = optional_${name}()
// CHECK: !DILocalVariable(name: "opt",{{.*}} line: [[@LINE-1]]
// DWARF: DW_TAG_subprogram
- // DWARF: DW_AT_name {{.*}}guard_let_${name}
+ // DWARF-LABEL: DW_AT_name {{.*}}guard_let_${name}
// DWARF-NOT: DW_TAG_subprogram
+% if generic:
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("self")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+% end
// DWARF: DW_TAG_variable
// DWARF-NOT: DW_TAG
// DWARF: DW_AT_location
@@ -113,8 +273,26 @@
var v : ${type} = constant_${name}()
// CHECK: !DILocalVariable(name: "v",{{.*}} line: [[@LINE-1]]
// DWARF: DW_TAG_subprogram
- // DWARF: DW_AT_name {{.*}}var_${name}
+ // DWARF-LABEL: DW_AT_name {{.*}}var_${name}
// DWARF-NOT: DW_TAG_subprogram
+% if generic:
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("self")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+% end
// DWARF: DW_TAG_variable
// DWARF-NOT: DW_TAG
// DWARF: DW_AT_location
@@ -126,25 +304,163 @@
public func arg_${name}(_ v: ${type}) {
// CHECK: !DILocalVariable(name: "v",{{.*}} line: [[@LINE-1]]
// DWARF: DW_TAG_subprogram
- // DWARF: DW_AT_name {{.*}}arg_${name}
+ // DWARF-LABEL: DW_AT_name {{.*}}arg_${name}
// DWARF-NOT: DW_TAG_subprogram
// DWARF: DW_TAG_formal_parameter
// DWARF-NOT: DW_TAG
// DWARF: DW_AT_location
// DWARF-NOT: DW_TAG
// DWARF: DW_AT_name {{.*}}"v"
+% if generic:
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("self")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF: DW_AT_artificial
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+% end
use(v)
}
public func arg_inout_${name}(_ v: inout ${type}) {
// CHECK: !DILocalVariable(name: "v",{{.*}} line: [[@LINE-1]]
// DWARF: DW_TAG_subprogram
- // DWARF: DW_AT_name {{.*}}arg_inout_${name}
+ // DWARF-LABEL: DW_AT_name {{.*}}arg_inout_${name}
// DWARF-NOT: DW_TAG_subprogram
// DWARF: DW_TAG_formal_parameter
// DWARF-NOT: DW_TAG
// DWARF: DW_AT_location
// DWARF-NOT: DW_TAG
// DWARF: DW_AT_name {{.*}}"v"
+% if generic:
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("self")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+% end
variable_use(&v)
}
+
+public func arg_tuple_${name}(_ v: (${type}, ${type})) {
+ let (_, y) = v
+ // CHECK: !DILocalVariable(name: "y",{{.*}} line: [[@LINE-1]]
+ // DWARF: DW_TAG_subprogram
+ // DWARF-LABEL: DW_AT_name {{.*}}arg_tuple_${name}
+ // DWARF-NOT: DW_TAG_subprogram
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_location
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name {{.*}}"v"
+% if generic:
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("self")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+ // FIMXE-DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF: DW_AT_artificial
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+% end
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_location
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name {{.*}}"y"
+ use(y)
+}
+
+public func closure_capture_${name}() {
+ let v : ${type} = constant_${name}();
+ // CHECK: !DILocalVariable(name: "v",{{.*}} line: [[@LINE-1]]
+ use({ () -> ${type} in v }())
+ // DWARF: DW_TAG_subprogram
+ // DWARF-LABEL: DW_AT_name {{.*}}closure_capture_${name}
+ // DWARF: DW_TAG_subprogram
+ // DWARF: DW_AT_linkage_name {{.*}}closure_capture_${name}
+ // DWARF-NOT: DW_AT_name {{.*}}closure_capture_${name}
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_location
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name {{.*}}"v"
+% if generic:
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+% end
+}
+
+public func closure_capture_byref_${name}() {
+ var v : ${type} = constant_${name}();
+ // CHECK: !DILocalVariable(name: "v",{{.*}} line: [[@LINE-1]]
+ { () -> () in v = ${val} }()
+ use(v)
+ // DWARF: DW_TAG_subprogram
+ // DWARF-LABEL: DW_AT_name {{.*}}closure_capture_byref_${name}
+ // DWARF: DW_TAG_subprogram
+ // DWARF: DW_AT_linkage_name {{.*}}closure_capture_byref_${name}
+ // DWARF-NOT: DW_AT_name {{.*}}closure_capture_byref_${name}
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_location
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name {{.*}}"v"
+% if generic:
+ // DWARF: DW_TAG_formal_parameter
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("self")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF: DW_AT_artificial
+ // DWARF: DW_TAG_variable
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_name ("$swift.type.{{T|U}}")
+ // DWARF-NOT: DW_TAG
+ // DWARF: DW_AT_artificial
+% end
+}
+
+% if generic:
+} // End of Context_${name}.
+% end
diff --git a/test/Driver/batch_mode.swift b/test/Driver/batch_mode.swift
new file mode 100644
index 0000000..2bbf0ab
--- /dev/null
+++ b/test/Driver/batch_mode.swift
@@ -0,0 +1,64 @@
+// RUN: %empty-directory(%t)
+// RUN: touch %t/file-01.swift %t/file-02.swift %t/file-03.swift %t/file-04.swift %t/file-05.swift
+// RUN: touch %t/file-06.swift %t/file-07.swift %t/file-08.swift %t/file-09.swift %t/file-10.swift
+// RUN: touch %t/file-11.swift %t/file-12.swift %t/file-13.swift %t/file-14.swift %t/file-15.swift
+// RUN: touch %t/file-16.swift %t/file-17.swift %t/file-18.swift %t/file-19.swift %t/file-20.swift
+// RUN: touch %t/file-21.swift %t/file-22.swift %t/file-23.swift %t/file-24.swift %t/file-25.swift
+// RUN: touch %t/file-26.swift %t/file-27.swift %t/file-28.swift %t/file-29.swift %t/file-30.swift
+//
+// RUN: %swiftc_driver -enable-batch-mode -driver-show-job-lifecycle -driver-skip-execution -j 4 %t/file-01.swift %t/file-02.swift %t/file-03.swift %t/file-04.swift %t/file-05.swift %t/file-06.swift %t/file-07.swift %t/file-08.swift %t/file-09.swift %t/file-10.swift %t/file-11.swift %t/file-12.swift %t/file-13.swift %t/file-14.swift %t/file-15.swift %t/file-16.swift %t/file-17.swift %t/file-18.swift %t/file-19.swift %t/file-20.swift %t/file-21.swift %t/file-22.swift %t/file-23.swift %t/file-24.swift %t/file-25.swift %t/file-26.swift %t/file-27.swift %t/file-28.swift %t/file-29.swift %t/file-30.swift | %FileCheck %s -check-prefix=SEED0
+//
+// RUN: %swiftc_driver -enable-batch-mode -driver-show-job-lifecycle -driver-skip-execution -j 4 -driver-batch-seed 1 %t/file-01.swift %t/file-02.swift %t/file-03.swift %t/file-04.swift %t/file-05.swift %t/file-06.swift %t/file-07.swift %t/file-08.swift %t/file-09.swift %t/file-10.swift %t/file-11.swift %t/file-12.swift %t/file-13.swift %t/file-14.swift %t/file-15.swift %t/file-16.swift %t/file-17.swift %t/file-18.swift %t/file-19.swift %t/file-20.swift %t/file-21.swift %t/file-22.swift %t/file-23.swift %t/file-24.swift %t/file-25.swift %t/file-26.swift %t/file-27.swift %t/file-28.swift %t/file-29.swift %t/file-30.swift | %FileCheck %s -check-prefix=SEED1
+//
+// RUN: %swiftc_driver -enable-batch-mode -driver-show-job-lifecycle -driver-skip-execution -j 4 -driver-batch-seed 2 %t/file-01.swift %t/file-02.swift %t/file-03.swift %t/file-04.swift %t/file-05.swift %t/file-06.swift %t/file-07.swift %t/file-08.swift %t/file-09.swift %t/file-10.swift %t/file-11.swift %t/file-12.swift %t/file-13.swift %t/file-14.swift %t/file-15.swift %t/file-16.swift %t/file-17.swift %t/file-18.swift %t/file-19.swift %t/file-20.swift %t/file-21.swift %t/file-22.swift %t/file-23.swift %t/file-24.swift %t/file-25.swift %t/file-26.swift %t/file-27.swift %t/file-28.swift %t/file-29.swift %t/file-30.swift | %FileCheck %s -check-prefix=SEED2
+//
+// 30 files / 4 batches => 2 batches of 8 jobs + 2 batches of 7 jobs
+//
+// SEED0: Found 30 batchable jobs
+// SEED0: Forming into 4 batches
+// SEED0: Adding {compile: {{file-01-.*}} <= file-01.swift} to batch 0
+// SEED0: Adding {compile: {{file-02-.*}} <= file-02.swift} to batch 0
+// SEED0: Adding {compile: {{file-09-.*}} <= file-09.swift} to batch 1
+// SEED0: Adding {compile: {{file-10-.*}} <= file-10.swift} to batch 1
+// SEED0: Adding {compile: {{file-19-.*}} <= file-19.swift} to batch 2
+// SEED0: Adding {compile: {{file-20-.*}} <= file-20.swift} to batch 2
+// SEED0: Adding {compile: {{file-29-.*}} <= file-29.swift} to batch 3
+// SEED0: Adding {compile: {{file-30-.*}} <= file-30.swift} to batch 3
+// SEED0: Forming batch job from 8 constituents
+// SEED0: Forming batch job from 8 constituents
+// SEED0: Forming batch job from 7 constituents
+// SEED0: Forming batch job from 7 constituents
+// SEED0: Adding batch job to task queue: {compile: file-01{{.*}} file-02{{.*}} file-03{{.*}} ... 5 more <= file-01.swift file-02.swift file-03.swift ... 5 more}
+// SEED0: Adding batch job to task queue: {compile: file-09{{.*}} file-10{{.*}} file-11{{.*}} ... 5 more <= file-09.swift file-10.swift file-11.swift ... 5 more}
+// SEED0: Adding batch job to task queue: {compile: file-17{{.*}} file-18{{.*}} file-19{{.*}} ... 4 more <= file-17.swift file-18.swift file-19.swift ... 4 more}
+// SEED0: Adding batch job to task queue: {compile: file-24{{.*}} file-25{{.*}} file-26{{.*}} ... 4 more <= file-24.swift file-25.swift file-26.swift ... 4 more}
+//
+// SEED1: Found 30 batchable jobs
+// SEED1: Forming into 4 batches
+// SEED1: Adding {compile: file-{{.*}} <= file-{{.*}}.swift} to batch 0
+// SEED1: Adding {compile: file-{{.*}} <= file-{{.*}}.swift} to batch 1
+// SEED1: Adding {compile: file-{{.*}} <= file-{{.*}}.swift} to batch 2
+// SEED1: Adding {compile: file-{{.*}} <= file-{{.*}}.swift} to batch 3
+// SEED1: Forming batch job from 8 constituents
+// SEED1: Forming batch job from 8 constituents
+// SEED1: Forming batch job from 7 constituents
+// SEED1: Forming batch job from 7 constituents
+// SEED1-NOT: Adding batch job to task queue: {compile: file-01{{.*}} file-02{{.*}} file-03{{.*}} ... 5 more <= file-01.swift file-02.swift file-03.swift ... 5 more }
+// SEED1: Added to TaskQueue: {compile: {{.*}} <= {{file-[0-3][2-9].swift .*}}}
+// SEED1: Added to TaskQueue: {compile: {{.*}} <= {{.*}}}
+// SEED1: Added to TaskQueue: {compile: {{.*}} <= {{.*}}}
+//
+// SEED2: Found 30 batchable jobs
+// SEED2: Forming into 4 batches
+// SEED2: Adding {compile: file-{{.*}} <= file-{{.*}}.swift} to batch 0
+// SEED2: Adding {compile: file-{{.*}} <= file-{{.*}}.swift} to batch 1
+// SEED2: Adding {compile: file-{{.*}} <= file-{{.*}}.swift} to batch 2
+// SEED2: Adding {compile: file-{{.*}} <= file-{{.*}}.swift} to batch 3
+// SEED2: Forming batch job from 8 constituents
+// SEED2: Forming batch job from 8 constituents
+// SEED2: Forming batch job from 7 constituents
+// SEED2: Forming batch job from 7 constituents
+// SEED2-NOT: Adding batch job to task queue: {compile: file-01{{.*}} file-02{{.*}} file-03{{.*}} ... 5 more <= file-01.swift file-02.swift file-03.swift ... 5 more }
+// SEED2: Added to TaskQueue: {compile: {{.*}} <= {{file-[0-3][2-9].swift .*}}}
+// SEED2: Added to TaskQueue: {compile: {{.*}} <= {{.*}}}
+// SEED2: Added to TaskQueue: {compile: {{.*}} <= {{.*}}}
diff --git a/test/Driver/working-directory.swift b/test/Driver/working-directory.swift
new file mode 100644
index 0000000..5c8d895
--- /dev/null
+++ b/test/Driver/working-directory.swift
@@ -0,0 +1,96 @@
+// RUN: %empty-directory(%t)
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c main.swift | %FileCheck %s -check-prefix=INPUT
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c %S/Inputs/main.swift | %FileCheck %s -check-prefix=INPUT
+// INPUT: SOURCE_DIR/test/Driver/Inputs/main.swift
+
+// Relative -working-directory...
+// RUN: cd %S && %swiftc_driver -driver-print-jobs -working-directory Inputs -c %S/Inputs/main.swift | %FileCheck %s -check-prefix=INPUT
+
+// -working-directory=
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory=%S/Inputs -c %S/Inputs/main.swift | %FileCheck %s -check-prefix=INPUT
+
+// In another driver mode.
+// RUN: cd %t && %swift_driver -driver-print-jobs -working-directory %S/Inputs -F. | %FileCheck %s -check-prefix=REPL
+// RUN: cd %t && %swift_driver -driver-print-jobs -deprecated-integrated-repl -working-directory %S/Inputs -F. | %FileCheck %s -check-prefix=REPL
+// REPL: -F SOURCE_DIR/test/Driver/Inputs/.
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory=%S/Inputs -c -module-name m main.swift lib.swift | %FileCheck %s -check-prefix=MULTI_INPUT
+// MULTI_INPUT: SOURCE_DIR/test/Driver/Inputs/main.swift
+// MULTI_INPUT-SAME: SOURCE_DIR/test/Driver/Inputs/lib.swift
+
+// Using --
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory=%S/Inputs -c -module-name m -- main.swift lib.swift | %FileCheck %s -check-prefix=MULTI_INPUT
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c %s -F . | %FileCheck %s -check-prefix=SEARCH_PATH
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c %s -F. | %FileCheck %s -check-prefix=SEARCH_PATH
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c %s -F=. | %FileCheck %s -check-prefix=SEARCH_PATH
+// SEARCH_PATH: -F SOURCE_DIR/test/Driver/Inputs/.
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -emit-executable %s -L . | %FileCheck %s -check-prefix=L_PATH
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -emit-executable %s -L. | %FileCheck %s -check-prefix=L_PATH
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -emit-executable %s -L=. | %FileCheck %s -check-prefix=L_PATH
+// L_PATH: -L SOURCE_DIR/test/Driver/Inputs/.
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c %s -disable-bridging-pch -import-objc-header bridging-header.h | %FileCheck %s -check-prefix=OBJC_HEADER1
+// OBJC_HEADER1: -import-objc-header SOURCE_DIR/test/Driver/Inputs/bridging-header.h
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c %s -enable-bridging-pch -import-objc-header bridging-header.h | %FileCheck %s -check-prefix=OBJC_HEADER2
+// OBJC_HEADER2: SOURCE_DIR/test/Driver/Inputs/bridging-header.h {{.*}}-emit-pch
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c %s -o main.o | %FileCheck %s -check-prefix=OUTPUT_OBJ
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c %s -o %S/Inputs/main.o | %FileCheck %s -check-prefix=OUTPUT_OBJ
+// OUTPUT_OBJ: -o SOURCE_DIR/test/Driver/Inputs/main.o
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c %s -module-cache-path mcp | %FileCheck %s -check-prefix=ARG_IS_PATH
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c %s -module-cache-path %S/Inputs/mcp | %FileCheck %s -check-prefix=ARG_IS_PATH
+// ARG_IS_PATH: -module-cache-path SOURCE_DIR/test/Driver/Inputs/mcp
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -emit-executable %s -o main | %FileCheck %s -check-prefix=OUTPUT_EXE
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -emit-executable %s -o %S/Inputs/main | %FileCheck %s -check-prefix=OUTPUT_EXE
+// OUTPUT_EXE: -o SOURCE_DIR/test/Driver/Inputs/main
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -emit-ir %s -o - | %FileCheck %s -check-prefix=OUTPUT_STDOUT
+// OUTPUT_STDOUT: -o -
+
+// RUN: echo "{\"main.swift\": {\"object\": \"main-modified.o\"}}" > %t/ofmo.json
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c main.swift -output-file-map %t/ofmo.json | %FileCheck %s -check-prefix=OUTPUT_FILE_MAP_1
+// OUTPUT_FILE_MAP_1: -o SOURCE_DIR/test/Driver/Inputs/main-modified.o
+
+// -output-file-map itself
+// RUN: echo "{\"main.swift\": {\"object\": \"main-modified.o\"}}" > %t/ofmo2.json
+// RUN: touch %t/main.swift
+// RUN: cd %S && %swiftc_driver -driver-print-jobs -working-directory %t -c main.swift -output-file-map ofmo2.json | %FileCheck %s -check-prefix=OUTPUT_FILE_MAP_2
+// -output-file-map= is an alias for -output-file-map
+// RUN: cd %S && %swiftc_driver -driver-print-jobs -working-directory %t -c main.swift -output-file-map=ofmo2.json | %FileCheck %s -check-prefix=OUTPUT_FILE_MAP_2
+// OUTPUT_FILE_MAP_2: BUILD_DIR{{.*}}main-modified.o
+
+// RUN: %empty-directory(%t/sub)
+// RUN: echo "{\"\": {\"swift-dependencies\": \"br.swiftdeps\"}}" > %t/sub/ofmo.json
+// RUN: touch %t/sub/a.swift %t/sub/b.swift
+// RUN: cd %t && %swiftc_driver -incremental -working-directory %t/sub -emit-dependencies -c -module-name ab a.swift b.swift -output-file-map=%t/sub/ofmo.json
+// RUN: ls %t/sub/br.swiftdeps
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -Xcc -working-directory -Xcc %t -c %s | %FileCheck %s -check-prefix=CLANG
+// CLANG: -Xcc -working-directory -Xcc SOURCE_DIR
+// CLANG-SAME: -Xcc -working-directory -Xcc BUILD_DIR
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -c main.swift | %FileCheck %s -check-prefix=OUTPUT_IMPLICIT_OBJ
+// OUTPUT_IMPLICIT_OBJ: -o SOURCE_DIR/test/Driver/Inputs/main.o
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -emit-module main.swift | %FileCheck %s -check-prefix=OUTPUT_IMPLICIT_MODULE
+// OUTPUT_IMPLICIT_MODULE: -emit-module-doc-path SOURCE_DIR/test/Driver/Inputs/main.swiftdoc
+// OUTPUT_IMPLICIT_MODULE-SAME: -o SOURCE_DIR/test/Driver/Inputs/main.swiftmodule
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -emit-executable main.swift | %FileCheck %s -check-prefix=OUTPUT_IMPLICIT_EXE
+// OUTPUT_IMPLICIT_EXE: -o SOURCE_DIR/test/Driver/Inputs/main
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -emit-module -emit-executable main.swift | %FileCheck %s -check-prefix=OUTPUT_IMPLICIT_EXE_AND_MODULE
+// OUTPUT_IMPLICIT_EXE_AND_MODULE: -emit-module-doc-path SOURCE_DIR/test/Driver/Inputs/main.swiftdoc
+// OUTPUT_IMPLICIT_EXE_AND_MODULE-SAME: -o SOURCE_DIR/test/Driver/Inputs/main.swiftmodule
+// OUTPUT_IMPLICIT_EXE_AND_MODULE: -o SOURCE_DIR/test/Driver/Inputs/main
+
+// RUN: cd %t && %swiftc_driver -driver-print-jobs -working-directory %S/Inputs -emit-module -emit-executable main.swift -o not_main | %FileCheck %s -check-prefix=OUTPUT_IMPLICIT_EXPLICIT
+// OUTPUT_IMPLICIT_EXPLICIT: -emit-module-doc-path SOURCE_DIR/test/Driver/Inputs/not_main.swiftdoc
+// OUTPUT_IMPLICIT_EXPLICIT-SAME: -o SOURCE_DIR/test/Driver/Inputs/not_main.swiftmodule
+// OUTPUT_IMPLICIT_EXPLICIT: -o SOURCE_DIR/test/Driver/Inputs/not_main
diff --git a/test/IDE/coloring_configs.swift b/test/IDE/coloring_configs.swift
index 7c8dfb3..6bd6393 100644
--- a/test/IDE/coloring_configs.swift
+++ b/test/IDE/coloring_configs.swift
@@ -316,3 +316,10 @@
func foo3() {}
// CHECK: <kw>func</kw> foo3() {}
}
+
+// CHECK: <#kw>#error</#kw>(<str>"Error"</str>)
+#error("Error")
+// CHECK: <#kw>#warning</#kw>(<str>"Warning"</str>)
+#warning("Warning")
+// CHECK: <#kw>#sourceLocation</#kw>(file: <str>"x"</str>, line: <int>1</int>)
+#sourceLocation(file: "x", line: 1)
diff --git a/test/IRGen/Inputs/weak_import_native_helper.swift b/test/IRGen/Inputs/weak_import_native_helper.swift
new file mode 100644
index 0000000..6e6c557
--- /dev/null
+++ b/test/IRGen/Inputs/weak_import_native_helper.swift
@@ -0,0 +1,105 @@
+@_weakLinked
+public func fn() {}
+
+@_weakLinked
+public var globalStored = 0
+
+@_weakLinked
+public var globalComputed: Int {
+ get { return 1 }
+ set {}
+}
+
+public struct S {
+ @_weakLinked
+ public func fn() {}
+
+ @_weakLinked
+ public var storedProp = 0
+
+ @_weakLinked
+ public var computedProp: Int {
+ get { return 1 }
+ set {}
+ }
+
+ @_weakLinked
+ public init() {}
+
+ @_weakLinked
+ public subscript(_: Int) -> Int {
+ get { return 1 }
+ set {}
+ }
+}
+
+public enum E {
+ case strong
+
+ @_weakLinked
+ case weak
+
+ case strongAssoc(Int)
+
+ @_weakLinked
+ case weakAssoc(Int)
+}
+
+open class C {
+ @_weakLinked
+ open func fn() {}
+
+ @_weakLinked
+ open var storedProp = 0
+
+ @_weakLinked
+ open var computedProp: Int {
+ get { return 1 }
+ set {}
+ }
+
+ @_weakLinked
+ public init() {}
+
+ @_weakLinked
+ open subscript(_: Int) -> Int {
+ get { return 1 }
+ set {}
+ }
+}
+
+public protocol P {
+ @_weakLinked
+ func fn()
+
+ @_weakLinked
+ var prop: Int { get set }
+
+ @_weakLinked
+ init()
+
+ @_weakLinked
+ subscript(_: Int) -> Int { get set }
+}
+
+@_weakLinked
+public struct WeakS {}
+
+@_weakLinked
+public enum WeakE {}
+
+@_weakLinked
+open class WeakC {}
+
+@_weakLinked
+public protocol WeakP {}
+
+
+@_weakLinked
+public struct GenericS<T> {}
+
+@_weakLinked
+public enum GenericE<T> {}
+
+@_weakLinked
+open class GenericC<T> {}
diff --git a/test/IRGen/big_types_corner_cases.swift b/test/IRGen/big_types_corner_cases.swift
index dfa3983..7dfb3eb 100644
--- a/test/IRGen/big_types_corner_cases.swift
+++ b/test/IRGen/big_types_corner_cases.swift
@@ -95,8 +95,6 @@
}
// CHECK-LABEL: define{{( protected)?}} hidden swiftcc void @"$S22big_types_corner_cases8BigClassC03useE6Struct0aH0yAA0eH0V_tF"(%T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}), %T22big_types_corner_cases8BigClassC* swiftself)
-// CHECK: getelementptr inbounds %T22big_types_corner_cases8BigClassC, %T22big_types_corner_cases8BigClassC*
-// CHECK: call void @"$SSqWy
// CHECK: [[BITCAST:%.*]] = bitcast i8* {{.*}} to void (%T22big_types_corner_cases9BigStructV*, %swift.refcounted*)*
// CHECK: call swiftcc void [[BITCAST]](%T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}) %0, %swift.refcounted* swiftself
// CHECK: ret void
@@ -212,6 +210,12 @@
// CHECK: [[CALL2:%.*]] = call i8** @"$SSayy22big_types_corner_cases9BigStructVcSgGSayxGs10CollectionsWl
// CHECK: call swiftcc void @"$Ss10CollectionPsE5index5where5IndexQzSgSb7ElementQzKXE_tKF"(%TSq.{{.*}}* noalias nocapture sret {{.*}}, i8* bitcast (i1 (%T22big_types_corner_cases9BigStructVytIegir_Sg*, %swift.refcounted*, %swift.error**)* @"$S22big_types_corner_cases9BigStructVIegy_SgSbs5Error_pIgxdzo_ACytIegir_SgSbsAE_pIegidzo_TRTA" to i8*), %swift.opaque* {{.*}}, %swift.type* [[CALL1]], i8** [[CALL2]], %swift.opaque* noalias nocapture swiftself
// CHECK: ret void
+
+// CHECK-LABEL: define{{( protected)?}} hidden swiftcc void @"$S22big_types_corner_cases7TestBigC5test2yyF"(%T22big_types_corner_cases7TestBigC* swiftself)
+// CHECK: [[CALL1:%.*]] = call %swift.type* @"$SSaySS2ID_y22big_types_corner_cases9BigStructVcSg7handlertGMa"
+// CHECK: [[CALL2:%.*]] = call i8** @"$SSaySS2ID_y22big_types_corner_cases9BigStructVcSg7handlertGSayxGs10CollectionsWl"
+// CHECK: call swiftcc void @"$Ss10CollectionPss16IndexingIteratorVyxG0C0RtzrlE04makeC0AEyF"(%Ts16IndexingIteratorV* noalias nocapture sret {{.*}}, %swift.type* [[CALL1]], i8** [[CALL2]], %swift.opaque* noalias nocapture swiftself {{.*}})
+// CHECK: ret void
class TestBig {
typealias Handler = (BigStruct) -> Void
@@ -219,4 +223,13 @@
let arr = [Handler?]()
let d = arr.index(where: { _ in true })
}
+
+ func test2() {
+ let arr: [(ID: String, handler: Handler?)] = []
+ for (_, handler) in arr {
+ takeClosure {
+ handler?(BigStruct())
+ }
+ }
+ }
}
diff --git a/test/IRGen/bitcast_different_size.sil b/test/IRGen/bitcast_different_size.sil
index 0ae508a..d3f3c85 100644
--- a/test/IRGen/bitcast_different_size.sil
+++ b/test/IRGen/bitcast_different_size.sil
@@ -1,4 +1,5 @@
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir %s -verify | %FileCheck %s
+// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir -O %s -verify | %FileCheck %s --check-prefix=OPT
// REQUIRES: CPU=i386 || CPU=x86_64
@@ -8,6 +9,11 @@
// CHECK-LABEL: define{{( protected)?}} swiftcc i64 @bitcast_different_size1
+// OPT-LABEL: define{{.*}}@bitcast_different_size1(i32)
+// OPT: tail call void asm sideeffect "", "n"(i32 0) #2
+// OPT-NEXT: tail call void @llvm.trap()
+// OPT-NEXT: unreachable
+
sil @bitcast_different_size1 : $@convention(thin) (Int32) -> Int64 {
entry(%i : $Int32):
// CHECK: ret {{.*}}undef
diff --git a/test/IRGen/cf.sil b/test/IRGen/cf.sil
index d52805c..f9cd361 100644
--- a/test/IRGen/cf.sil
+++ b/test/IRGen/cf.sil
@@ -30,7 +30,6 @@
// -- is imported C typedef, is class, is nonunique
// CHECK-64-SAME: <i32 0x1000_0010>
// CHECK-64-SAME: [[MUTABLE_REFRIGERATOR_NAME]]
-// CHECK-64-SAME: @get_field_types_CCMutableRefrigerator
// CHECK-64: @"$SSo24CCMutableRefrigeratorRefaN" = linkonce_odr hidden global <{ {{.*}} }> <{
// CHECK-64-SAME: @initialize_metadata_CCMutableRefrigerator
diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift
index 1e0453f..a274a5b 100644
--- a/test/IRGen/class_resilience.swift
+++ b/test/IRGen/class_resilience.swift
@@ -27,7 +27,6 @@
// CHECK: @"$S16class_resilience30ClassWithIndirectResilientEnumC5colors5Int32VvpWvd" = hidden constant [[INT]] {{12|24}}
// CHECK: [[RESILIENTCHILD_NAME:@.*]] = private constant [15 x i8] c"ResilientChild\00"
-// CHECK: [[RESILIENTCHILD_FIELDS:@.*]] = private constant [7 x i8] c"field\00\00"
// CHECK: @"$S16class_resilience14ResilientChildCMn" = {{(protected )?}}constant <{{.*}}> <{
// -- flags: class, unique, has vtable, has resilient superclass
@@ -38,8 +37,6 @@
// CHECK-SAME: i32 1,
// -- field offset vector offset
// CHECK-SAME: i32 3,
-// -- field names,
-// CHECK-SAME: [7 x i8]* [[RESILIENTCHILD_FIELDS]]
// CHECK-SAME: }>
// CHECK: @"$S16class_resilience14ResilientChildCMo" = {{(protected )?}}global [[INT]] 0
diff --git a/test/IRGen/dllimport.swift b/test/IRGen/dllimport.swift
index ee44b05..c24285c 100644
--- a/test/IRGen/dllimport.swift
+++ b/test/IRGen/dllimport.swift
@@ -40,8 +40,6 @@
// CHECK-NO-OPT-DAG: declare dllimport void @swift_deallocObject(%swift.refcounted*, i32, i32)
// CHECK-NO-OPT-DAG: declare dllimport void @swift_release(%swift.refcounted*)
// CHECK-NO-OPT-DAG: declare dllimport %swift.refcounted* @swift_retain(%swift.refcounted* returned)
-// CHECK-NO-OPT-DAG: declare dllimport i8* @swift_slowAlloc(i32, i32) #2
-// CHECK-NO-OPT-DAG: declare dllimport void @swift_slowDealloc(i8*, i32, i32) #2
// CHECK-NO-OPT-DAG: @"$S9dllexport1cCN" = external dllimport global %swift.type
// CHECK-NO-OPT-DAG: @"$S9dllexport1pMp" = external dllimport global %swift.protocol
// CHECK-NO-OPT-DAG: @"$SytN" = external dllimport global %swift.full_type
@@ -55,8 +53,6 @@
// CHECK-OPT-DAG: @"$SBoWV" = external dllimport global i8*
// CHECK-OPT-DAG: @"$S9dllexport1cCN" = external dllimport global %swift.type
// CHECK-OPT-DAG: @"$S9dllexport1pMp" = external dllimport global %swift.protocol
-// CHECK-OPT-DAG: declare dllimport i8* @swift_slowAlloc(i32, i32) local_unnamed_addr
-// CHECK-OPT-DAG: declare dllimport void @swift_slowDealloc(i8*, i32, i32) local_unnamed_addr
// CHECK-OPT-DAG: declare dllimport swiftcc i8* @"$S9dllexport2ciAA1cCvau"()
// CHECK-OPT-DAG: declare dllimport %swift.type* @"$S9dllexport1cCMa"()
// CHECK-OPT-DAG: declare dllimport void @swift_deallocClassInstance(%swift.refcounted*, i32, i32)
diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil
index bfbda2b..42b7aed 100644
--- a/test/IRGen/enum.sil
+++ b/test/IRGen/enum.sil
@@ -104,7 +104,6 @@
// The witness table pattern includes extra inhabitant witness
// implementations which are used if the instance has extra inhabitants.
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
-// CHECK: [[DYNAMICSINGLETON_FIELD_NAMES:@.*]] = private constant [7 x i8] c"value\00\00"
// CHECK: @"$S4enum16DynamicSingletonOWV" =
// CHECK-SAME: i8* null
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$S4enum16DynamicSingletonOwxs" to i8*)
@@ -117,11 +116,7 @@
// CHECK-SAME: i32 1,
// -- No empty cases
// CHECK-SAME: i32 0,
-// -- Case names
-// CHECK-SAME: [[DYNAMICSINGLETON_FIELD_NAMES]]
// -- Case type accessor
-// CHECK-SAME: @get_field_types_DynamicSingleton
-// -- generic argument offset
// CHECK-SAME: i32 2,
// -- generic parameters, requirements, key, extra
// CHECK-SAME: i32 1, i32 0, i32 1, i32 0
diff --git a/test/IRGen/enum_value_semantics.sil b/test/IRGen/enum_value_semantics.sil
index ff2167e..d98da2e 100644
--- a/test/IRGen/enum_value_semantics.sil
+++ b/test/IRGen/enum_value_semantics.sil
@@ -162,8 +162,6 @@
// CHECK: i64 2,
// CHECK: {{.*}}* @"$S20enum_value_semantics18GenericFixedLayoutOMn"
// CHECK: i{{32|64}} 0
-// CHECK: %swift.type* null,
-// CHECK: %swift.type** null
// CHECK: }>
sil @single_payload_nontrivial_copy_destroy : $(@owned SinglePayloadNontrivial) -> () {
diff --git a/test/IRGen/field_type_vectors.sil b/test/IRGen/field_type_vectors.sil
index 90d2f77..d4b1129 100644
--- a/test/IRGen/field_type_vectors.sil
+++ b/test/IRGen/field_type_vectors.sil
@@ -5,13 +5,11 @@
import Swift
// CHECK-LABEL: @"$S18field_type_vectors3FooVMn" = hidden constant
-// CHECK: %swift.type** (%swift.type*)* [[FOO_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
struct Foo {
var x: Int
}
// CHECK-LABEL: @"$S18field_type_vectors3BarVMn" = hidden constant
-// CHECK: %swift.type** (%swift.type*)* [[BAR_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
// CHECK-LABEL: @"$S18field_type_vectors3BarVMP" = internal global
// -- There should be 1 word between the field type vector slot, with type %swift.type**,
// and the address point
@@ -21,7 +19,6 @@
}
// CHECK-LABEL: @"$S18field_type_vectors3BasVMn" = hidden constant
-// CHECK: %swift.type** (%swift.type*)* [[BAS_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
// CHECK-LABEL: @"$S18field_type_vectors3BasVMP" = internal global
// -- There should be 1 word between the field type vector slot, with type %swift.type**,
// and the address point
@@ -32,7 +29,6 @@
}
// CHECK-LABEL: @"$S18field_type_vectors3ZimCMn" = hidden constant
-// CHECK: %swift.type** (%swift.type*)* [[ZIM_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
// CHECK-LABEL: @"$S18field_type_vectors3ZimCMP" = internal global
// -- There should be 1 word between the field type vector slot, with type %swift.type**,
// and the address point
@@ -47,7 +43,6 @@
sil @_TFC18field_type_vectors3ZimcU___fMGS0_Q_Q0__FT_GS0_Q_Q0__ : $@convention(method) <T, U> (@owned Zim<T, U>) -> @owned Zim<T, U>
// CHECK-LABEL: @"$S18field_type_vectors4ZangCMn" = hidden constant
-// CHECK: %swift.type** (%swift.type*)* [[ZANG_TYPES_ACCESSOR:@[A-Za-z0-9_]*]]
// CHECK-LABEL: @"$S18field_type_vectors4ZangCMP" = internal global
// -- There should be 1 word between the field type vector slot, with type %swift.type**,
// and the address point
@@ -70,41 +65,3 @@
}
}
sil_vtable StorageQualified {}
-
-// CHECK: [[FOO_TYPE_VECTOR_SLOT:@.*Foo.*]] = private global %swift.type** null
-
-// CHECK: define{{( protected)?}} private %swift.type** [[FOO_TYPES_ACCESSOR]](%swift.type* %Foo)
-// CHECK: [[EXISTING:%.*]] = load %swift.type**, %swift.type*** [[FOO_TYPE_VECTOR_SLOT]]
-// CHECK: [[IS_NULL:%.*]] = icmp eq %swift.type** [[EXISTING]], null
-// CHECK: br i1 [[IS_NULL]], label %[[BUILD_FIELD_TYPES:.*]], label %[[DONE:.*]]
-// CHECK: [[BUILD_FIELD_TYPES]]:
-// CHECK: store {{.*}} @"$SSiN"
-// CHECK: cmpxchg {{.*}} [[FOO_TYPE_VECTOR_SLOT]]
-
-// CHECK: define{{( protected)?}} private %swift.type** [[BAR_TYPES_ACCESSOR]](%swift.type* %"Bar<T>")
-// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Bar<T>" to %swift.type***
-// CHECK: [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i64 -2
-// CHECK: load %swift.type**, %swift.type*** [[SLOT]], align 8
-// CHECK: br
-// CHECK-NOT: load %swift.type*,
-// CHECK: store {{.*}} @"$SSiN"
-
-
-// CHECK: define{{( protected)?}} private %swift.type** [[BAS_TYPES_ACCESSOR]](%swift.type* %"Bas<T, U>")
-// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Bas<T, U>" to %swift.type***
-// CHECK: [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i64 -2
-// CHECK: load %swift.type**, %swift.type*** [[SLOT]], align 8
-// CHECK: br
-// CHECK: store {{.*}} @"$S18field_type_vectors3FooVMf"
-// CHECK: call %swift.type* @"$S18field_type_vectors3BarVMa"(%swift.type* %T)
-
-// CHECK: define{{( protected)?}} private %swift.type** [[ZIM_TYPES_ACCESSOR]](%swift.type* %"Zim<T, U>")
-// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Zim<T, U>" to %swift.type***
-// CHECK: [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i64 -3
-// CHECK: load %swift.type**, %swift.type*** [[SLOT]], align 8
-
-// CHECK: define{{( protected)?}} private %swift.type** [[ZANG_TYPES_ACCESSOR]](%swift.type* %"Zang<V>")
-// CHECK: [[T0:%.*]] = bitcast %swift.type* %"Zang<V>" to %swift.type***
-// CHECK: [[SLOT:%.*]] = getelementptr inbounds %swift.type**, %swift.type*** [[T0]], i64 -3
-// CHECK: load %swift.type**, %swift.type*** [[SLOT]], align 8
-
diff --git a/test/IRGen/generic_classes.sil b/test/IRGen/generic_classes.sil
index 1dde5f5..3f0c58d 100644
--- a/test/IRGen/generic_classes.sil
+++ b/test/IRGen/generic_classes.sil
@@ -13,7 +13,6 @@
// -- offset of RootGeneric<T>.x
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[ROOTGENERIC_NAME:@.*]] = private constant [12 x i8] c"RootGeneric\00"
-// CHECK: [[ROOTGENERIC_FIELDS:@.*]] = private constant [7 x i8] c"x\00y\00z\00\00"
// CHECK-LABEL: @"$S15generic_classes11RootGenericCMn" =
// -- flags: class, generic, unique, has vtable
@@ -24,8 +23,6 @@
// CHECK-SAME: i32 3,
// -- field offset vector offset
// CHECK-SAME: i32 15,
-// -- field names
-// CHECK-SAME: [7 x i8]* [[ROOTGENERIC_FIELDS]]
// -- generic parameter vector offset
// CHECK-SAME: i32 10,
// -- generic parameters, requirements, key arguments, extra arguments
@@ -63,8 +60,6 @@
// CHECK-SAME: i32 3,
// -- -- field offset vector offset
// CHECK-SAME: i32 11,
-// -- field names
-// CHECK-SAME: [7 x i8]* [[ROOTGENERIC_FIELDS]]
// CHECK-SAME: }>
// CHECK: @"$S15generic_classes14RootNonGenericCMf" = internal global <{ {{.*}} }> <{
diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil
index c8d4fea..cadee5d 100644
--- a/test/IRGen/generic_structs.sil
+++ b/test/IRGen/generic_structs.sil
@@ -20,7 +20,6 @@
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[SINGLEDYNAMIC_NAME:@.*]] = private constant [14 x i8] c"SingleDynamic\00"
-// CHECK: [[SINGLEDYNAMIC_FIELDS:@.*]] = private constant [3 x i8] c"x\00\00"
// CHECK: @"$S15generic_structs13SingleDynamicVMn" = hidden constant
// -- flags: struct, unique, generic
// CHECK-SAME: <i32 0x0000_00D1>
@@ -30,8 +29,6 @@
// CHECK-SAME: i32 1,
// -- field offset vector offset
// CHECK-SAME: i32 3,
-// -- field names
-// CHECK-SAME: [3 x i8]* [[SINGLEDYNAMIC_FIELDS]]
// -- generic parameter vector offset
// CHECK-SAME: i32 2,
// -- generic params, requirements, key args, extra args
@@ -53,7 +50,6 @@
// -- Nominal type descriptor for generic struct with protocol requirements
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[DYNAMICWITHREQUIREMENTS_NAME:@.*]] = private constant [24 x i8] c"DynamicWithRequirements\00"
-// CHECK: [[DYNAMICWITHREQUIREMENTS_FIELDS:@.*]] = private constant [5 x i8] c"x\00y\00\00"
// CHECK: @"$S15generic_structs23DynamicWithRequirementsVMn" = hidden constant <{ {{.*}} i32 }> <{
// -- flags: struct, unique, generic
// CHECK-SAME: <i32 0x0000_00D1>
@@ -63,8 +59,6 @@
// CHECK-SAME: i32 2,
// -- field offset vector offset
// CHECK-SAME: i32 6,
-// -- field names
-// CHECK-SAME: [5 x i8]* [[DYNAMICWITHREQUIREMENTS_FIELDS]]
// -- generic parameter vector offset
// CHECK-SAME: i32 2,
// -- generic params, requirements, key args, extra args
diff --git a/test/IRGen/indirect_enum.sil b/test/IRGen/indirect_enum.sil
index 115a27a..8487e0b 100644
--- a/test/IRGen/indirect_enum.sil
+++ b/test/IRGen/indirect_enum.sil
@@ -5,39 +5,21 @@
// CHECK-64: @"$S13indirect_enum5TreeAOWV" = internal constant {{.*}} i8* inttoptr ([[WORD:i64]] 8 to i8*), i8* inttoptr (i64 2162695 to i8*), i8* inttoptr (i64 8 to i8*)
// CHECK-32: @"$S13indirect_enum5TreeAOWV" = internal constant {{.*}} i8* inttoptr ([[WORD:i32]] 4 to i8*), i8* inttoptr (i32 2162691 to i8*), i8* inttoptr (i32 4 to i8*)
-// CHECK-LABEL: define{{( protected)?}} private %swift.type** @get_field_types_TreeA
-// -- Leaf(T)
-// CHECK: [[BITS:%.*]] = ptrtoint %swift.type* %T to [[WORD]]
-// CHECK: [[INDIRECT_FLAG:%.*]] = or [[WORD]] [[BITS]], 1
-// -- Branch(TreeA, TreeA)
-// CHECK: [[TUPLE:%.*]] = call %swift.type* @swift_getTupleTypeMetadata2
-// CHECK: [[BITS:%.*]] = ptrtoint %swift.type* [[TUPLE]]
-// CHECK: [[INDIRECT_FLAG:%.*]] = or [[WORD]] [[BITS]], 1
+// CHECK-NOT: define{{( protected)?}} private %swift.type** @get_field_types_TreeA
indirect enum TreeA<T> {
case Nil
case Leaf(T)
case Branch(left: TreeA<T>, right: TreeA<T>)
}
-// CHECK-LABEL: define{{( protected)?}} private %swift.type** @get_field_types_TreeB
-// -- Leaf(T)
-// CHECK-NOT: ptrtoint %swift.type* %T
-// -- Branch(TreeA, TreeA)
-// CHECK: [[TUPLE:%.*]] = call %swift.type* @swift_getTupleTypeMetadata2
-// CHECK: [[BITS:%.*]] = ptrtoint %swift.type* [[TUPLE]]
-// CHECK: [[INDIRECT_FLAG:%.*]] = or [[WORD]] [[BITS]], 1
+// CHECK-NOT: define{{( protected)?}} private %swift.type** @get_field_types_TreeB
enum TreeB<T> {
case Nil
case Leaf(T)
indirect case Branch(left: TreeB<T>, right: TreeB<T>)
}
-// CHECK-LABEL: define{{( protected)?}} private %swift.type** @get_field_types_Foo
-// -- Foo(Int)
-// CHECK-64: (i64 or (i64 ptrtoint (%swift.type* @"$SSiN" {{.*}}), [[WORD]] 1)
-// CHECK-32: (i32 or (i32 ptrtoint (%swift.type* @"$SSiN" {{.*}}), [[WORD]] 1)
-// -- Bar(T)
-// CHECK-NOT: ptrtoint %swift.type* %T
+// CHECK-NOT: define{{( protected)?}} private %swift.type** @get_field_types_Foo
enum Foo<T> {
indirect case Foo(Int)
case Bar(T)
diff --git a/test/IRGen/objc_enum_multi_file.swift b/test/IRGen/objc_enum_multi_file.swift
index 99099e5..da7123b 100644
--- a/test/IRGen/objc_enum_multi_file.swift
+++ b/test/IRGen/objc_enum_multi_file.swift
@@ -16,9 +16,6 @@
// CHECK-DAG: i32 0, label %[[CASE_A:.+]]
// CHECK: ]
- // CHECK: <label>:[[DEFAULT]]
- // CHECK-NEXT: unreachable
-
switch x {
// CHECK: <label>:[[CASE_B]]
// CHECK-NEXT: br label %[[FINAL:.+]]
@@ -36,6 +33,10 @@
return 10
}
+ // CHECK: <label>:[[DEFAULT]]
+ // CHECK-NEXT: call void @llvm.trap()
+ // CHECK-NEXT: unreachable
+
// CHECK: <label>:[[FINAL]]
// CHECK: %[[RETVAL:.+]] = phi i32 [ 10, %[[CASE_A]] ], [ 15, %[[CASE_C]] ], [ 11, %[[CASE_B]] ]
// CHECK: ret i32 %[[RETVAL]]
@@ -49,9 +50,6 @@
// CHECK-DAG: i32 5, label %[[CASE_A:.+]]
// CHECK: ]
- // CHECK: <label>:[[DEFAULT]]
- // CHECK-NEXT: unreachable
-
switch x {
// CHECK: <label>:[[CASE_B]]
// CHECK-NEXT: br label %[[FINAL:.+]]
@@ -69,6 +67,10 @@
return 10
}
+ // CHECK: <label>:[[DEFAULT]]
+ // CHECK-NEXT: call void @llvm.trap()
+ // CHECK-NEXT: unreachable
+
// CHECK: <label>:[[FINAL]]
// CHECK: %[[RETVAL:.+]] = phi i32 [ 10, %[[CASE_A]] ], [ 15, %[[CASE_C]] ], [ 11, %[[CASE_B]] ]
// CHECK: ret i32 %[[RETVAL]]
diff --git a/test/IRGen/weak_import.swift b/test/IRGen/weak_import_clang.swift
similarity index 100%
rename from test/IRGen/weak_import.swift
rename to test/IRGen/weak_import_clang.swift
diff --git a/test/IRGen/weak_import_native.sil b/test/IRGen/weak_import_native.sil
new file mode 100644
index 0000000..664aa95
--- /dev/null
+++ b/test/IRGen/weak_import_native.sil
@@ -0,0 +1,23 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s
+
+sil_stage canonical
+
+// CHECK-DAG: define{{( protected)?}} swiftcc void @weakButDefined() {{#[0-9]+}} {
+sil public [_weakLinked] @weakButDefined : $@convention(thin) () -> () {
+ %unit = tuple()
+ return %unit : $()
+}
+
+// CHECK-DAG: declare extern_weak swiftcc void @weakExternal()
+sil public_external [_weakLinked] @weakExternal : $@convention(thin) () -> ()
+
+sil [_weakLinked] @testWeak : $@convention(thin) () -> () {
+ %weakButDefined = function_ref @weakButDefined : $@convention(thin) () -> ()
+ %wbdResult = apply %weakButDefined() : $@convention(thin) () -> ()
+ %weakExternal = function_ref @weakExternal : $@convention(thin) () -> ()
+ %weResult = apply %weakExternal() : $@convention(thin) () -> ()
+ %unit = tuple()
+ return %unit : $()
+}
+
diff --git a/test/IRGen/weak_import_native.swift b/test/IRGen/weak_import_native.swift
new file mode 100644
index 0000000..3b186b7
--- /dev/null
+++ b/test/IRGen/weak_import_native.swift
@@ -0,0 +1,163 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module -emit-module-path %t/weak_import_native_helper.swiftmodule %S/Inputs/weak_import_native_helper.swift -enable-resilience
+//
+// RUN: %target-swift-frontend -primary-file %s -I %t -emit-ir | %FileCheck %s
+
+import weak_import_native_helper
+
+func testTopLevel() {
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper2fnyyF"()
+ fn()
+
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper12globalStoredSivg"
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper12globalStoredSivs"
+ let x = globalStored
+ globalStored = x
+ globalStored += 1
+
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper14globalComputedSivg"
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper14globalComputedSivs"
+ let y = globalComputed
+ globalComputed = y
+ globalComputed += 1
+}
+
+func testStruct() {
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1SVACycfC"
+ var s = S()
+
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1SV2fnyyF"
+ s.fn()
+
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1SV10storedPropSivg"
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1SV10storedPropSivs"
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1SV10storedPropSivm"
+ let x = s.storedProp
+ s.storedProp = x
+ s.storedProp += 1
+
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1SV12computedPropSivg"
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1SV12computedPropSivs"
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1SV12computedPropSivm"
+ let y = s.computedProp
+ s.computedProp = y
+ s.computedProp += 1
+
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1SVyS2icig"
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1SVyS2icis"
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1SVyS2icim"
+ let z = s[0]
+ s[0] = z
+ s[0] += 1
+}
+
+func testEnum() {
+ // FIXME: We're still referencing tags directly.
+ _ = E.strong
+ _ = E.weak
+ _ = E.strongAssoc(0)
+ _ = E.weakAssoc(0)
+}
+
+func testClass() {
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1CCACycfC"
+ let c = C()
+
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1CC2fnyyFTj"
+ c.fn()
+
+ // FIXME: vtable dispatch functions for accessors should also be weak
+
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1CC10storedPropSivgTj"
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1CC10storedPropSivsTj"
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1CC10storedPropSivmTj"
+ let x = c.storedProp
+ c.storedProp = x
+ c.storedProp += 1
+
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1CC12computedPropSivgTj"
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1CC12computedPropSivsTj"
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1CC12computedPropSivmTj"
+ let y = c.computedProp
+ c.computedProp = y
+ c.computedProp += 1
+
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1CCyS2icigTj"
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1CCyS2icisTj"
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1CCyS2icimTj"
+ let z = c[0]
+ c[0] = z
+ c[0] += 1
+}
+
+class Sub : C {
+ deinit {
+ // This is correctly a strong symbol reference; the class is not declared
+ // weak.
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1CCfd"
+ }
+}
+
+func testProtocolExistential(_ p: P) {
+ var mutP = p
+
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1PP2fnyyFTj"
+ p.fn()
+
+ // FIXME: witness table dispatch functions for accessors should also be weak
+
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1PP4propSivgTj"
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1PP4propSivsTj"
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1PP4propSivmTj"
+ let x = p.prop
+ mutP.prop = x
+ mutP.prop += 1
+
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1PPyS2icigTj"
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1PPyS2icisTj"
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper1PPyS2icimTj"
+ let z = p[0]
+ mutP[0] = z
+ mutP[0] += 1
+}
+
+func testProtocolGeneric<Impl: P>(_ type: Impl.Type) {
+ // CHECK-DAG: declare extern_weak {{.+}} @"$S25weak_import_native_helper1PPxycfCTj"
+ var mutP = type.init()
+
+ mutP.fn()
+
+ let x = mutP.prop
+ mutP.prop = x
+ mutP.prop += 1
+
+ let z = mutP[0]
+ mutP[0] = z
+ mutP[0] += 1
+}
+
+func testWeakTypes() -> [Any.Type] {
+ // FIXME: These should be weak.
+ // CHECK-DAG: declare %swift.type* @"$S25weak_import_native_helper5WeakSVMa"()
+ // CHECK-DAG: declare %swift.type* @"$S25weak_import_native_helper5WeakEOMa"()
+ // CHECK-DAG: declare %swift.type* @"$S25weak_import_native_helper5WeakCCMa"()
+ // CHECK-DAG: @"$S25weak_import_native_helper5WeakPMp" = extern_weak global %swift.protocol
+ // CHECK-DAG: declare %swift.type* @"$S25weak_import_native_helper8GenericSVMa"
+ // CHECK-DAG: declare %swift.type* @"$S25weak_import_native_helper8GenericEOMa"
+ // CHECK-DAG: declare %swift.type* @"$S25weak_import_native_helper8GenericCCMa"
+ return [WeakS.self, WeakE.self, WeakC.self, WeakP.self, GenericS<Int>.self, GenericE<Int>.self, GenericC<Int>.self]
+}
+
+class WeakSub: WeakC {
+ deinit {
+ // FIXME: This should be weak.
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper5WeakCCfd"
+ }
+}
+
+class WeakGenericSub: GenericC<Int> {
+ deinit {
+ // FIXME: This should be weak.
+ // CHECK-DAG: declare swiftcc {{.+}} @"$S25weak_import_native_helper8GenericCCfd"
+ }
+}
diff --git a/test/Interpreter/Inputs/enum-nonexhaustivity.h b/test/Interpreter/Inputs/enum-nonexhaustivity.h
new file mode 100644
index 0000000..2bfc08a
--- /dev/null
+++ b/test/Interpreter/Inputs/enum-nonexhaustivity.h
@@ -0,0 +1,25 @@
+enum NonExhaustiveEnum {
+ NonExhaustiveEnumA = 0,
+ NonExhaustiveEnumB = 1,
+ NonExhaustiveEnumC = 2,
+} __attribute__((enum_extensibility(open)));
+
+enum NonExhaustiveEnum getExpectedValue(void) {
+ return NonExhaustiveEnumB;
+}
+enum NonExhaustiveEnum getUnexpectedValue(void) {
+ return (enum NonExhaustiveEnum)3;
+}
+
+enum LyingExhaustiveEnum {
+ LyingExhaustiveEnumA = 0,
+ LyingExhaustiveEnumB = 1,
+ LyingExhaustiveEnumC = 2,
+} __attribute__((enum_extensibility(closed)));
+
+enum LyingExhaustiveEnum getExpectedLiarValue(void) {
+ return LyingExhaustiveEnumB;
+}
+enum LyingExhaustiveEnum getUnexpectedLiarValue(void) {
+ return (enum LyingExhaustiveEnum)3;
+}
diff --git a/test/Interpreter/enum-nonexhaustivity.swift b/test/Interpreter/enum-nonexhaustivity.swift
new file mode 100644
index 0000000..f3e52de
--- /dev/null
+++ b/test/Interpreter/enum-nonexhaustivity.swift
@@ -0,0 +1,250 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-build-swift %s -Onone -o %t/main -import-objc-header %S/Inputs/enum-nonexhaustivity.h -Xfrontend -disable-objc-attr-requires-foundation-module
+// RUN: %target-run %t/main
+// RUN: %target-build-swift %s -O -o %t/main -import-objc-header %S/Inputs/enum-nonexhaustivity.h -Xfrontend -disable-objc-attr-requires-foundation-module
+// RUN: %target-run %t/main
+// RUN: %target-build-swift %s -Ounchecked -o %t/main -import-objc-header %S/Inputs/enum-nonexhaustivity.h -Xfrontend -disable-objc-attr-requires-foundation-module
+// RUN: %target-run %t/main
+// REQUIRES: executable_test
+
+import StdlibUnittest
+
+var EnumTestSuite = TestSuite("Enums")
+
+EnumTestSuite.test("PlainOldSwitch/NonExhaustive") {
+ var gotCorrectValue = false
+ switch getExpectedValue() {
+ case .A, .C:
+ expectUnreachable()
+ case .B:
+ gotCorrectValue = true
+ }
+ expectTrue(gotCorrectValue)
+}
+
+EnumTestSuite.test("TrapOnUnexpected/NonExhaustive") {
+ expectCrashLater()
+ switch getUnexpectedValue() {
+ case .A, .C:
+ expectUnreachable()
+ case .B:
+ expectUnreachable()
+ }
+ expectUnreachable()
+}
+
+EnumTestSuite.test("TrapOnUnexpectedNested/NonExhaustive") {
+ expectCrashLater()
+ switch (getExpectedValue(), getUnexpectedValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (_, .B):
+ expectUnreachable()
+ case (_, .A), (_, .C):
+ expectUnreachable()
+ }
+ expectUnreachable()
+}
+
+EnumTestSuite.test("TrapOnUnexpectedNested2/NonExhaustive") {
+ expectCrashLater()
+ switch (getUnexpectedValue(), getExpectedValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (.B, _):
+ expectUnreachable()
+ case (.A, _), (.C, _):
+ expectUnreachable()
+ }
+ expectUnreachable()
+}
+
+EnumTestSuite.test("UnexpectedOkayNested/NonExhaustive") {
+ var gotCorrectValue = false
+ switch (getExpectedValue(), getUnexpectedValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (.B, _):
+ gotCorrectValue = true
+ case (.A, _), (.C, _):
+ expectUnreachable()
+ }
+ expectTrue(gotCorrectValue)
+}
+
+EnumTestSuite.test("UnexpectedOkayNested2/NonExhaustive") {
+ var gotCorrectValue = false
+ switch (getUnexpectedValue(), getExpectedValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (_, .B):
+ gotCorrectValue = true
+ case (_, .A), (_, .C):
+ expectUnreachable()
+ }
+ expectTrue(gotCorrectValue)
+}
+
+
+EnumTestSuite.test("PlainOldSwitch/LyingExhaustive") {
+ var gotCorrectValue = false
+ switch getExpectedLiarValue() {
+ case .A, .C:
+ expectUnreachable()
+ case .B:
+ gotCorrectValue = true
+ }
+ expectTrue(gotCorrectValue)
+}
+
+EnumTestSuite.test("TrapOnUnexpected/LyingExhaustive") {
+ expectCrashLater()
+ switch getUnexpectedLiarValue() {
+ case .A, .C:
+ expectUnreachable()
+ case .B:
+ expectUnreachable()
+ }
+ expectUnreachable()
+}
+
+EnumTestSuite.test("TrapOnUnexpectedNested/LyingExhaustive") {
+ expectCrashLater()
+ switch (getExpectedLiarValue(), getUnexpectedLiarValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (_, .B):
+ expectUnreachable()
+ case (_, .A), (_, .C):
+ expectUnreachable()
+ }
+ expectUnreachable()
+}
+
+EnumTestSuite.test("TrapOnUnexpectedNested2/LyingExhaustive") {
+ expectCrashLater()
+ switch (getUnexpectedLiarValue(), getExpectedLiarValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (.B, _):
+ expectUnreachable()
+ case (.A, _), (.C, _):
+ expectUnreachable()
+ }
+ expectUnreachable()
+}
+
+EnumTestSuite.test("UnexpectedOkayNested/LyingExhaustive") {
+ var gotCorrectValue = false
+ switch (getExpectedLiarValue(), getUnexpectedLiarValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (.B, _):
+ gotCorrectValue = true
+ case (.A, _), (.C, _):
+ expectUnreachable()
+ }
+ expectTrue(gotCorrectValue)
+}
+
+EnumTestSuite.test("UnexpectedOkayNested2/LyingExhaustive") {
+ var gotCorrectValue = false
+ switch (getUnexpectedLiarValue(), getExpectedLiarValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (_, .B):
+ gotCorrectValue = true
+ case (_, .A), (_, .C):
+ expectUnreachable()
+ }
+ expectTrue(gotCorrectValue)
+}
+
+
+@objc enum SwiftEnum : Int32 {
+ case A, B, C
+
+ @inline(never) static func getExpectedValue() -> SwiftEnum {
+ return .B
+ }
+ @inline(never) static func getUnexpectedValue() -> SwiftEnum {
+ return unsafeBitCast(42 as Int32, to: SwiftEnum.self)
+ }
+}
+
+EnumTestSuite.test("PlainOldSwitch/SwiftExhaustive") {
+ var gotCorrectValue = false
+ switch SwiftEnum.getExpectedValue() {
+ case .A, .C:
+ expectUnreachable()
+ case .B:
+ gotCorrectValue = true
+ }
+ expectTrue(gotCorrectValue)
+}
+
+EnumTestSuite.test("TrapOnUnexpected/SwiftExhaustive") {
+ expectCrashLater()
+ switch SwiftEnum.getUnexpectedValue() {
+ case .A, .C:
+ expectUnreachable()
+ case .B:
+ expectUnreachable()
+ }
+ expectUnreachable()
+}
+
+EnumTestSuite.test("TrapOnUnexpectedNested/SwiftExhaustive") {
+ expectCrashLater()
+ switch (SwiftEnum.getExpectedValue(), SwiftEnum.getUnexpectedValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (_, .B):
+ expectUnreachable()
+ case (_, .A), (_, .C):
+ expectUnreachable()
+ }
+ expectUnreachable()
+}
+
+EnumTestSuite.test("TrapOnUnexpectedNested2/SwiftExhaustive") {
+ expectCrashLater()
+ switch (SwiftEnum.getUnexpectedValue(), SwiftEnum.getExpectedValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (.B, _):
+ expectUnreachable()
+ case (.A, _), (.C, _):
+ expectUnreachable()
+ }
+ expectUnreachable()
+}
+
+EnumTestSuite.test("UnexpectedOkayNested/SwiftExhaustive") {
+ var gotCorrectValue = false
+ switch (SwiftEnum.getExpectedValue(), SwiftEnum.getUnexpectedValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (.B, _):
+ gotCorrectValue = true
+ case (.A, _), (.C, _):
+ expectUnreachable()
+ }
+ expectTrue(gotCorrectValue)
+}
+
+EnumTestSuite.test("UnexpectedOkayNested2/SwiftExhaustive") {
+ var gotCorrectValue = false
+ switch (SwiftEnum.getUnexpectedValue(), SwiftEnum.getExpectedValue()) {
+ case (.A, .A), (.C, .C):
+ expectUnreachable()
+ case (_, .B):
+ gotCorrectValue = true
+ case (_, .A), (_, .C):
+ expectUnreachable()
+ }
+ expectTrue(gotCorrectValue)
+}
+
+
+runAllTests()
diff --git a/test/Misc/stats_dir_profiler.swift b/test/Misc/stats_dir_profiler.swift
new file mode 100644
index 0000000..59a7cb6
--- /dev/null
+++ b/test/Misc/stats_dir_profiler.swift
@@ -0,0 +1,30 @@
+// RUN: %empty-directory(%t)
+// RUN: %empty-directory(%t/stats-events)
+// RUN: %empty-directory(%t/stats-entities)
+// RUN: %target-swiftc_driver -o %t/main -module-name main -stats-output-dir %t/stats-events %s -profile-stats-events
+// RUN: %target-swiftc_driver -o %t/main -module-name main -stats-output-dir %t/stats-entities %s -profile-stats-entities
+// RUN: %FileCheck -check-prefix=EVENTS -input-file %t/stats-events/*.dir/Time.User.events %s
+// RUN: %FileCheck -check-prefix=ENTITIES -input-file %t/stats-entities/*.dir/Time.User.entities %s
+
+// EVENTS: {{perform-sema;.*;typecheck-decl [0-9]+}}
+// ENTITIES: {{perform-sema;.*;typecheck-fn bar\(\);typecheck-decl <pattern binding> [0-9]+}}
+
+public func foo() {
+ print("hello")
+}
+
+protocol Proto {
+ func bar() -> Int;
+}
+
+class Bar {
+ typealias T = Int
+}
+
+extension Bar : Proto {
+ func bar() -> T {
+ let x = 1
+ let y = Int(1.0)
+ return x + y
+ }
+}
diff --git a/test/Misc/stats_dir_tracer.swift b/test/Misc/stats_dir_tracer.swift
index a80d9b8..254a68e 100644
--- a/test/Misc/stats_dir_tracer.swift
+++ b/test/Misc/stats_dir_tracer.swift
@@ -2,8 +2,26 @@
// RUN: %target-swiftc_driver -o %t/main -module-name main -stats-output-dir %t %s -trace-stats-events
// RUN: %FileCheck -input-file %t/*.csv %s
-// CHECK: {{"Sema.NumTypesDeserialized"}}
+// CHECK: {{[0-9]+,[0-9]+,"exit","lookup-direct","Sema.NominalTypeLookupDirectCount",[0-9]+,[0-9]+,"Proto","\[.*stats_dir_tracer.swift:13:1 - line:15:1\]"}}
+// CHECK: {{[0-9]+,[0-9]+,"exit","typecheck-fn","Sema.NumTypesDeserialized",[0-9]+,[0-9]+,"foo\(\)","\[.*stats_dir_tracer.swift:9:8 - line:11:1\]"}}
+// CHECK: {{[0-9]+,[0-9]+,"exit","typecheck-decl","Sema.NumConstraintScopes",[0-9]+,[0-9]+,"<pattern binding>","\[.*stats_dir_tracer.swift:23:5 - line:23:13\]"}}
public func foo() {
print("hello")
}
+
+protocol Proto {
+ func bar() -> Int;
+}
+
+class Bar {
+ typealias T = Int
+}
+
+extension Bar : Proto {
+ func bar() -> T {
+ let x = 1
+ let y = Int(1.0)
+ return x + y
+ }
+}
diff --git a/test/SIL/ownership-verifier/leaks.sil b/test/SIL/ownership-verifier/leaks.sil
new file mode 100644
index 0000000..83f2f8e
--- /dev/null
+++ b/test/SIL/ownership-verifier/leaks.sil
@@ -0,0 +1,71 @@
+// RUN: %target-sil-opt -module-name Swift -sil-ownership-verifier-enable-testing -enable-sil-ownership -enable-sil-verify-all=0 %s -o /dev/null 2>&1 | %FileCheck %s
+// REQUIRES: asserts
+
+// This file is meant to contain dataflow tests that are true leaks. It is
+// intended to test both that we are failing and that we are emitting
+// appropriate error messages.
+
+//////////////////
+// Declarations //
+//////////////////
+
+sil_stage canonical
+
+import Builtin
+
+///////////
+// Tests //
+///////////
+
+// CHECK-LABEL: Function: 'owned_never_consumed'
+// CHECK: Error! Found a leaked owned value that was never consumed.
+// CHECK: Value: %1 = copy_value %0 : $Builtin.NativeObject
+sil @owned_never_consumed : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
+bb0(%0 : @guaranteed $Builtin.NativeObject):
+ %1 = copy_value %0 : $Builtin.NativeObject
+ %9999 = tuple()
+ return %9999 : $()
+}
+
+// CHECK-LABEL: Function: 'owned_leaks_along_one_path'
+// CHECK: Error! Found a leak due to a consuming post-dominance failure!
+// CHECK: Value: %0 = argument of bb0 : $Builtin.NativeObject
+// CHECK: Post Dominating Failure Blocks:
+// CHECK: bb1
+sil @owned_leaks_along_one_path : $@convention(thin) (@owned Builtin.NativeObject) -> () {
+bb0(%0 : @owned $Builtin.NativeObject):
+ cond_br undef, bb1, bb2
+
+bb1:
+ br bb3
+
+bb2:
+ destroy_value %0 : $Builtin.NativeObject
+ br bb3
+
+bb3:
+ %9999 = tuple()
+ return %9999 : $()
+}
+
+// Make sure that we report the leak at the phi.
+// CHECK-LABEL: Function: 'owned_leaks_with_phi'
+// CHECK: Error! Found a leaked owned value that was never consumed.
+// CHECK: Value: %6 = argument of bb4 : $Builtin.NativeObject
+sil @owned_leaks_with_phi : $@convention(thin) (@owned Builtin.NativeObject) -> () {
+bb0(%0 : @owned $Builtin.NativeObject):
+ br bb1(%0 : $Builtin.NativeObject)
+
+bb1(%1 : @owned $Builtin.NativeObject):
+ cond_br undef, bb3, bb2
+
+bb2:
+ br bb4(%1 : $Builtin.NativeObject)
+
+bb3:
+ br bb1(%1 : $Builtin.NativeObject)
+
+bb4(%2 : @owned $Builtin.NativeObject):
+ %9999 = tuple()
+ return %9999 : $()
+}
diff --git a/test/SILGen/downgrade_exhaustivity_swift3.swift b/test/SILGen/downgrade_exhaustivity_swift3.swift
index 9fb20d8..84e5682 100644
--- a/test/SILGen/downgrade_exhaustivity_swift3.swift
+++ b/test/SILGen/downgrade_exhaustivity_swift3.swift
@@ -18,6 +18,7 @@
case .hat:
break
// CHECK: [[DEFAULT_CASE]]({{%.*}} : @trivial $Downgradable):
+ // CHECK-NEXT: builtin "int_trap"()
// CHECK-NEXT: unreachable
}
@@ -33,14 +34,17 @@
case (.hat, .hat):
break
// CHECK: [[TUPLE_DEFAULT_CASE_2]]({{%.*}} : @trivial $Downgradable):
+ // CHECK-NEXT: builtin "int_trap"()
// CHECK-NEXT: unreachable
// CHECK: switch_enum [[Y]] : $Downgradable, case #Downgradable.spoon!enumelt: {{bb[0-9]+}}, case #Downgradable.hat!enumelt: {{bb[0-9]+}}, default [[TUPLE_DEFAULT_CASE_3:bb[0-9]+]]
// CHECK: [[TUPLE_DEFAULT_CASE_3]]({{%.*}} : @trivial $Downgradable):
+ // CHECK-NEXT: builtin "int_trap"()
// CHECK-NEXT: unreachable
// CHECK: [[TUPLE_DEFAULT_CASE_1]]({{%.*}} : @trivial $Downgradable):
+ // CHECK-NEXT: builtin "int_trap"()
// CHECK-NEXT: unreachable
}
diff --git a/test/SILGen/enum_resilience.swift b/test/SILGen/enum_resilience.swift
index 2c51b8d..dbebe9c 100644
--- a/test/SILGen/enum_resilience.swift
+++ b/test/SILGen/enum_resilience.swift
@@ -31,6 +31,7 @@
// CHECK-NEXT: dealloc_stack [[BOX]]
// CHECK-NEXT: br bb6
// CHECK: bb5:
+// CHECK-NEXT: builtin "int_trap"()
// CHECK-NEXT: unreachable
// CHECK: bb6:
// CHECK-NEXT: destroy_addr %0
diff --git a/test/SILOptimizer/abcopts.sil b/test/SILOptimizer/abcopts.sil
index fb2f530..d528145 100644
--- a/test/SILOptimizer/abcopts.sil
+++ b/test/SILOptimizer/abcopts.sil
@@ -1,5 +1,5 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -loop-rotate -dce -simplify-cfg -abcopts -enable-abcopts=1 %s | %FileCheck %s
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -loop-rotate -dce -simplify-cfg -abcopts -dce -enable-abcopts -enable-abc-hoisting %s | %FileCheck %s --check-prefix=HOIST
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -loop-rotate -dce -jumpthread-simplify-cfg -abcopts -enable-abcopts=1 %s | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -loop-rotate -dce -jumpthread-simplify-cfg -abcopts -dce -enable-abcopts -enable-abc-hoisting %s | %FileCheck %s --check-prefix=HOIST
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -abcopts %s | %FileCheck %s --check-prefix=RANGECHECK
sil_stage canonical
diff --git a/test/SILOptimizer/access_marker_elim.sil b/test/SILOptimizer/access_marker_elim.sil
index d59c48e..95d7b32 100644
--- a/test/SILOptimizer/access_marker_elim.sil
+++ b/test/SILOptimizer/access_marker_elim.sil
@@ -1,4 +1,5 @@
-// RUN: %target-sil-opt -enforce-exclusivity=checked -emit-sorted-sil -access-marker-elim %s | %FileCheck %s
+// RUN: %target-sil-opt -enforce-exclusivity=unchecked -emit-sorted-sil -access-marker-elim %s | %FileCheck %s --check-prefix=UNCHECKED
+// RUN: %target-sil-opt -enforce-exclusivity=checked -emit-sorted-sil -access-marker-elim %s | %FileCheck %s --check-prefix=CHECKED
sil_stage raw
@@ -11,21 +12,40 @@
init(i: Int)
}
-// CHECK-LABEL: sil hidden [noinline] @f010_initS : $@convention(thin) () -> @owned S {
-// CHECK: bb0:
-// CHECK: %[[BOX:.*]] = alloc_box ${ var S }, var, name "s"
-// CHECK: %[[ADDRS:.*]] = project_box %[[BOX]] : ${ var S }, 0
-// CHECK: %[[NUM:.*]] = integer_literal $Builtin.Int64, 1
-// CHECK-NOT: begin_access
-// CHECK: %[[ADDRI:.*]] = struct_element_addr %[[ADDRS]] : $*S, #S.i
-// CHECK: assign %[[NUM]] to %[[ADDRI]] : $*Builtin.Int64
-// CHECK-NOT: end_access
-// CHECK-NOT: begin_access
-// CHECK: %[[VALS:.*]] = load [trivial] %[[ADDRS]] : $*S
-// CHECK-NOT: end_access
-// CHECK: destroy_value %[[BOX]] : ${ var S }
-// CHECK: return %[[VALS]] : $S
-// CHECK-LABEL: } // end sil function 'f010_initS'
+// [unknown] markers are treated like [dynamic] markers by AccessMarkerElimination.
+// We don't remove them for -enforce-exclusivity=checked
+
+// UNCHECKED-LABEL: sil hidden [noinline] @f010_initS : $@convention(thin) () -> @owned S {
+// UNCHECKED: bb0:
+// UNCHECKED: [[BOX:%.*]] = alloc_box ${ var S }, var, name "s"
+// UNCHECKED: [[ADDRS:%.*]] = project_box [[BOX]] : ${ var S }, 0
+// UNCHECKED: [[NUM:%.*]] = integer_literal $Builtin.Int64, 1
+// UNCHECKED-NOT: begin_access
+// UNCHECKED: [[ADDRI:%.*]] = struct_element_addr [[ADDRS]] : $*S, #S.i
+// UNCHECKED: assign [[NUM]] to [[ADDRI]] : $*Builtin.Int64
+// UNCHECKED-NOT: end_access
+// UNCHECKED-NOT: begin_access
+// UNCHECKED: [[VALS:%.*]] = load [trivial] [[ADDRS]] : $*S
+// UNCHECKED-NOT: end_access
+// UNCHECKED: destroy_value [[BOX]] : ${ var S }
+// UNCHECKED: return [[VALS]] : $S
+// UNCHECKED-LABEL: } // end sil function 'f010_initS'
+//
+// CHECKED-LABEL: sil hidden [noinline] @f010_initS : $@convention(thin) () -> @owned S {
+// CHECKED: bb0:
+// CHECKED: [[BOX:%.*]] = alloc_box ${ var S }, var, name "s"
+// CHECKED: [[ADDRS:%.*]] = project_box [[BOX]] : ${ var S }, 0
+// CHECKED: [[NUM:%.*]] = integer_literal $Builtin.Int64, 1
+// CHECKED: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[ADDRS]]
+// CHECKED: [[ADDRI:%.*]] = struct_element_addr [[ACCESS]] : $*S, #S.i
+// CHECKED: assign [[NUM]] to [[ADDRI]] : $*Builtin.Int64
+// CHECKED: end_access [[ACCESS]]
+// CHECKED: [[ACCESS:%.*]] = begin_access [read] [unknown] [[ADDRS]]
+// CHECKED: [[VALS:%.*]] = load [trivial] [[ACCESS]] : $*S
+// CHECKED: end_access [[ACCESS]]
+// CHECKED: destroy_value [[BOX]] : ${ var S }
+// CHECKED: return [[VALS]] : $S
+// CHECKED-LABEL: } // end sil function 'f010_initS'
sil hidden [noinline] @f010_initS : $@convention(thin) () -> @owned S {
bb0:
%0 = alloc_box ${ var S }, var, name "s"
@@ -46,14 +66,27 @@
// And since inactive elimination currently eliminates all dynamic markers,
// they are gone from the output.
//
-// CHECK-LABEL: sil hidden @f020_boxArg : $@convention(thin) (@owned { var Builtin.Int64 }) -> () {
-// CHECK: bb0(%0 : ${ var Builtin.Int64 }):
-// CHECK: [[ADR:%.*]] = project_box %0 : ${ var Builtin.Int64 }, 0
-// CHECK: [[VAL:%.*]] = integer_literal $Builtin.Int64, 42
-// CHECK: store [[VAL]] to [trivial] [[ADR]] : $*Builtin.Int64
-// CHECK: destroy_value %0 : ${ var Builtin.Int64 }
-// CHECK: return %{{.*}} : $()
-// CHECK-LABEL: } // end sil function 'f020_boxArg'
+// UNCHECKED-LABEL: sil hidden @f020_boxArg : $@convention(thin) (@owned { var Builtin.Int64 }) -> () {
+// UNCHECKED: bb0(%0 : ${ var Builtin.Int64 }):
+// UNCHECKED: [[ADR:%.*]] = project_box %0 : ${ var Builtin.Int64 }, 0
+// UNCHECKED: [[VAL:%.*]] = integer_literal $Builtin.Int64, 42
+// UNCHECKED-NOT: begin_access
+// UNCHECKED: store [[VAL]] to [trivial] [[ADR]] : $*Builtin.Int64
+// UNCHECKED-NOT: end_access
+// UNCHECKED: destroy_value %0 : ${ var Builtin.Int64 }
+// UNCHECKED: return %{{.*}} : $()
+// UNCHECKED-LABEL: } // end sil function 'f020_boxArg'
+//
+// CHECKED-LABEL: sil hidden @f020_boxArg : $@convention(thin) (@owned { var Builtin.Int64 }) -> () {
+// CHECKED: bb0(%0 : ${ var Builtin.Int64 }):
+// CHECKED: [[ADR:%.*]] = project_box %0 : ${ var Builtin.Int64 }, 0
+// CHECKED: [[VAL:%.*]] = integer_literal $Builtin.Int64, 42
+// CHECKED: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[ADR]]
+// CHECKED: store [[VAL]] to [trivial] [[ACCESS]] : $*Builtin.Int64
+// CHECKED: end_access [[ACCESS]]
+// CHECKED: destroy_value %0 : ${ var Builtin.Int64 }
+// CHECKED: return %{{.*}} : $()
+// CHECKED-LABEL: } // end sil function 'f020_boxArg'
sil hidden @f020_boxArg : $@convention(thin) (@owned { var Builtin.Int64 }) -> () {
bb0(%0 : ${ var Builtin.Int64 }):
%1 = project_box %0 : ${ var Builtin.Int64 }, 0
diff --git a/test/SILOptimizer/canonicalize_switch_enum.sil b/test/SILOptimizer/canonicalize_switch_enum.sil
index 4212051..4ac63d1 100644
--- a/test/SILOptimizer/canonicalize_switch_enum.sil
+++ b/test/SILOptimizer/canonicalize_switch_enum.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
import Builtin
import Swift
diff --git a/test/SILOptimizer/devirt_access_serialized.sil b/test/SILOptimizer/devirt_access_serialized.sil
new file mode 100644
index 0000000..73c50bf
--- /dev/null
+++ b/test/SILOptimizer/devirt_access_serialized.sil
@@ -0,0 +1,57 @@
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -devirtualizer | %FileCheck %s
+
+sil_stage canonical
+
+import Builtin
+import Swift
+import SwiftShims
+
+class X
+{
+ private func ping() -> Int
+ @objc deinit
+ init()
+}
+
+class Y : X
+{
+ @objc deinit
+ override init()
+}
+
+sil [serialized] @_TFC14devirt_access21X4pingfS0_FT_Si : $@convention(method) (@guaranteed X) -> Int
+sil public_external [transparent] @_TFSi33_convertFromBuiltinIntegerLiteralfMSiFBi2048_Si : $@convention(thin) (Builtin.Int2048, @thin Int.Type) -> Int
+sil @_TFC14devirt_access21Xd : $@convention(method) (@guaranteed X) -> @owned Builtin.NativeObject
+sil @_TFC14devirt_access21XD : $@convention(method) (@guaranteed X) -> ()
+sil @_TFC14devirt_access21XcfMS0_FT_S0_ : $@convention(method) (@owned X) -> @owned X
+sil @_TFC14devirt_access21XCfMS0_FT_S0_ : $@convention(thin) (@thick X.Type) -> @owned X
+sil @_TFC14devirt_access21Yd : $@convention(method) (@guaranteed Y) -> @owned Builtin.NativeObject
+sil @_TFC14devirt_access21YD : $@convention(method) (@guaranteed Y) -> ()
+sil @_TFC14devirt_access21YcfMS0_FT_S0_ : $@convention(method) (@owned Y) -> @owned Y
+sil @_TFC14devirt_access21YCfMS0_FT_S0_ : $@convention(thin) (@thick Y.Type) -> @owned Y
+
+//CHECK-LABEL: sil @Case
+//CHECK-NOT: function_ref @_TFC14devirt_access21X4pingfS0_FT_Si
+//CHECK: class_method
+//CHECK: apply
+//CHECK: return
+sil @Case : $@convention(thin) (@owned Y) -> Int {
+bb0(%0 : $Y):
+ debug_value %0 : $Y, let, name "a" // id: %1
+ strong_retain %0 : $Y // id: %2
+ %3 = upcast %0 : $Y to $X // users: %4, %5
+ %4 = class_method %3 : $X, #X.ping!1 : (X) -> () -> Int, $@convention(method) (@guaranteed X) -> Int // user: %5
+ %5 = apply %4(%3) : $@convention(method) (@guaranteed X) -> Int // user: %7
+ strong_release %0 : $Y // id: %6
+ return %5 : $Int // id: %7
+}
+
+sil_vtable X {
+ #X.ping!1: @_TFC14devirt_access21X4pingfS0_FT_Si // devirt_access2.X.ping (devirt_access2.X)() -> Swift.Int
+ #X.init!initializer.1: @_TFC14devirt_access21XcfMS0_FT_S0_ // devirt_access2.X.init (devirt_access2.X.Type)() -> devirt_access2.X
+}
+
+sil_vtable Y {
+ #X.ping!1: @_TFC14devirt_access21X4pingfS0_FT_Si // devirt_access2.X.ping (devirt_access2.X)() -> Swift.Int
+ #X.init!initializer.1: @_TFC14devirt_access21YcfMS0_FT_S0_ // devirt_access2.Y.init (devirt_access2.Y.Type)() -> devirt_access2.Y
+}
diff --git a/test/SILOptimizer/devirt_jump_thread.sil b/test/SILOptimizer/devirt_jump_thread.sil
index c740bda..8ffd2de 100644
--- a/test/SILOptimizer/devirt_jump_thread.sil
+++ b/test/SILOptimizer/devirt_jump_thread.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg -cse | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -jumpthread-simplify-cfg -cse | %FileCheck %s
// Check that jump-threading works for sequences of checked_cast_br instructions produced by the devirtualizer.
// This allows for simplifications of code like e.g. f.foo() + f.foo()
diff --git a/test/SILOptimizer/devirt_jump_thread_crasher.sil b/test/SILOptimizer/devirt_jump_thread_crasher.sil
index bd50bf2..d9365a2 100644
--- a/test/SILOptimizer/devirt_jump_thread_crasher.sil
+++ b/test/SILOptimizer/devirt_jump_thread_crasher.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
// REQUIRES: objc_interop
// FIXME: this test relies on standard library implementation details that are
diff --git a/test/SILOptimizer/enum_jump_thread.sil b/test/SILOptimizer/enum_jump_thread.sil
index 1fc652c..6c780ee 100644
--- a/test/SILOptimizer/enum_jump_thread.sil
+++ b/test/SILOptimizer/enum_jump_thread.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg -cse | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -jumpthread-simplify-cfg -cse | %FileCheck %s
// Test if jump-threading is done to combine two enum instructions
// into a single block.
diff --git a/test/SILOptimizer/opened_archetype_operands_tracking.sil b/test/SILOptimizer/opened_archetype_operands_tracking.sil
index 35d49f0..3332211 100644
--- a/test/SILOptimizer/opened_archetype_operands_tracking.sil
+++ b/test/SILOptimizer/opened_archetype_operands_tracking.sil
@@ -1,5 +1,5 @@
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -sil-inline-generics -enable-sil-verify-all %s -O | %FileCheck %s
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -simplify-cfg -enable-sil-verify-all %s -O | %FileCheck --check-prefix=CHECK-SIMPLIFY-CFG %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -jumpthread-simplify-cfg -enable-sil-verify-all %s -O | %FileCheck --check-prefix=CHECK-SIMPLIFY-CFG %s
// Check some corner cases related to tracking of opened archetypes.
// For example, the compiler used to crash compiling the "process" function (rdar://28024272)
diff --git a/test/SILOptimizer/sil_combine_enum_addr.sil b/test/SILOptimizer/sil_combine_enum_addr.sil
index 828da98..12b70cc 100644
--- a/test/SILOptimizer/sil_combine_enum_addr.sil
+++ b/test/SILOptimizer/sil_combine_enum_addr.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -sil-combine -simplify-cfg | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -sil-combine -jumpthread-simplify-cfg | %FileCheck %s
sil_stage canonical
diff --git a/test/SILOptimizer/simplify_cfg.sil b/test/SILOptimizer/simplify_cfg.sil
index f10a84e..36d4efa 100644
--- a/test/SILOptimizer/simplify_cfg.sil
+++ b/test/SILOptimizer/simplify_cfg.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
// FIXME: Update for select_enum change.
import Builtin
diff --git a/test/SILOptimizer/simplify_cfg_and_combine.sil b/test/SILOptimizer/simplify_cfg_and_combine.sil
index 1ab018b..b157736 100644
--- a/test/SILOptimizer/simplify_cfg_and_combine.sil
+++ b/test/SILOptimizer/simplify_cfg_and_combine.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg -sil-combine -simplify-cfg -sil-combine | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -jumpthread-simplify-cfg -sil-combine -jumpthread-simplify-cfg -sil-combine | %FileCheck %s
// These require both SimplifyCFG and SILCombine
diff --git a/test/SILOptimizer/simplify_cfg_args.sil b/test/SILOptimizer/simplify_cfg_args.sil
index 956d4bd..8267444 100644
--- a/test/SILOptimizer/simplify_cfg_args.sil
+++ b/test/SILOptimizer/simplify_cfg_args.sil
@@ -1,5 +1,5 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -late-codemotion -simplify-cfg | %FileCheck %s --check-prefix=CHECK_WITH_CODEMOTION
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -late-codemotion -jumpthread-simplify-cfg | %FileCheck %s --check-prefix=CHECK_WITH_CODEMOTION
sil_stage raw
diff --git a/test/SILOptimizer/simplify_cfg_jump_thread_crash.sil b/test/SILOptimizer/simplify_cfg_jump_thread_crash.sil
index c38ac1d..f6f87ec 100644
--- a/test/SILOptimizer/simplify_cfg_jump_thread_crash.sil
+++ b/test/SILOptimizer/simplify_cfg_jump_thread_crash.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
sil_stage canonical
diff --git a/test/SILOptimizer/simplify_cfg_opaque.sil b/test/SILOptimizer/simplify_cfg_opaque.sil
index 082f6c5..96e4df3 100644
--- a/test/SILOptimizer/simplify_cfg_opaque.sil
+++ b/test/SILOptimizer/simplify_cfg_opaque.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -enable-sil-opaque-values -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s
+// RUN: %target-sil-opt -enable-sil-opaque-values -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
sil_stage canonical
diff --git a/test/SILOptimizer/simplify_cfg_select_enum.sil b/test/SILOptimizer/simplify_cfg_select_enum.sil
index d9c0fe5..b38a219 100644
--- a/test/SILOptimizer/simplify_cfg_select_enum.sil
+++ b/test/SILOptimizer/simplify_cfg_select_enum.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
// Two select_enum instructions must not be considered as the same "condition",
// even if they have the same enum operand.
diff --git a/test/SILOptimizer/simplify_cfg_unique_values.sil b/test/SILOptimizer/simplify_cfg_unique_values.sil
index e7aa1f9..62ebf14 100644
--- a/test/SILOptimizer/simplify_cfg_unique_values.sil
+++ b/test/SILOptimizer/simplify_cfg_unique_values.sil
@@ -1,4 +1,4 @@
-// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -simplify-cfg | %FileCheck %s
+// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -jumpthread-simplify-cfg | %FileCheck %s
sil_stage canonical
diff --git a/test/SILOptimizer/string_switch.swift b/test/SILOptimizer/string_switch.swift
index 933c78d..2c0beef 100644
--- a/test/SILOptimizer/string_switch.swift
+++ b/test/SILOptimizer/string_switch.swift
@@ -1,6 +1,7 @@
// RUN: %target-build-swift -O %s -module-name=test -Xllvm -sil-disable-pass=FunctionSignatureOpts -o %t.out
// RUN: %target-build-swift -O %s -module-name=test -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil | %FileCheck %s
// RUN: %target-run %t.out
+// REQUIRES: swift_stdlib_no_asserts,optimized_stdlib
// UNSUPPORTED: nonatomic_rc
import StdlibUnittest
diff --git a/test/SourceKit/CodeComplete/complete_working_directory.swift b/test/SourceKit/CodeComplete/complete_working_directory.swift
new file mode 100644
index 0000000..44ec9e0
--- /dev/null
+++ b/test/SourceKit/CodeComplete/complete_working_directory.swift
@@ -0,0 +1,8 @@
+import Foo
+
+// REQUIRES: objc_interop
+
+// RUN: %sourcekitd-test -req=complete.open -pos=2:1 -req-opts=hidelowpriority=0 %s -- %s -F libIDE-mock-sdk -working-directory %S/../Inputs | %FileCheck %s
+// RUN: %sourcekitd-test -req=complete.open -pos=2:1 -req-opts=hidelowpriority=0 %s -- %s -Xcc -F -Xcc libIDE-mock-sdk -working-directory %S/../Inputs | %FileCheck %s
+
+// CHECK: fooFunc
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-pound-keyword.swift b/test/SourceKit/SyntaxMapData/syntaxmap-pound-keyword.swift
index 9d72fb3..7ab6cfb 100644
--- a/test/SourceKit/SyntaxMapData/syntaxmap-pound-keyword.swift
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-pound-keyword.swift
@@ -8,3 +8,11 @@
if #available(iOS 9.0, *) {}
+#if false
+#error("Error")
+#elseif true
+#warning("Warning")
+#else
+#sourceLocation(file: "here.swift", line:100)
+#sourceLocation()
+#endif
diff --git a/test/SourceKit/SyntaxMapData/syntaxmap-pound-keyword.swift.response b/test/SourceKit/SyntaxMapData/syntaxmap-pound-keyword.swift.response
index d4aae63..9baa46a 100644
--- a/test/SourceKit/SyntaxMapData/syntaxmap-pound-keyword.swift.response
+++ b/test/SourceKit/SyntaxMapData/syntaxmap-pound-keyword.swift.response
@@ -1,6 +1,6 @@
{
key.offset: 0,
- key.length: 206,
+ key.length: 342,
key.diagnostic_stage: source.diagnostic.stage.swift.parse,
key.syntaxmap: [
{
@@ -92,6 +92,86 @@
key.kind: source.lang.swift.syntaxtype.number,
key.offset: 194,
key.length: 3
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.buildconfig.keyword,
+ key.offset: 206,
+ key.length: 3
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.keyword,
+ key.offset: 210,
+ key.length: 5
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.pounddirective.keyword,
+ key.offset: 216,
+ key.length: 6
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.string,
+ key.offset: 223,
+ key.length: 7
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.buildconfig.keyword,
+ key.offset: 232,
+ key.length: 7
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.keyword,
+ key.offset: 240,
+ key.length: 4
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.pounddirective.keyword,
+ key.offset: 245,
+ key.length: 8
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.string,
+ key.offset: 254,
+ key.length: 9
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.buildconfig.keyword,
+ key.offset: 265,
+ key.length: 5
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.pounddirective.keyword,
+ key.offset: 271,
+ key.length: 15
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.identifier,
+ key.offset: 287,
+ key.length: 4
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.string,
+ key.offset: 293,
+ key.length: 12
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.identifier,
+ key.offset: 307,
+ key.length: 4
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.number,
+ key.offset: 312,
+ key.length: 3
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.pounddirective.keyword,
+ key.offset: 317,
+ key.length: 15
+ },
+ {
+ key.kind: source.lang.swift.syntaxtype.buildconfig.keyword,
+ key.offset: 335,
+ key.length: 6
}
]
}
diff --git a/test/api-digester/Inputs/APINotesLeft/APINotesTest.h b/test/api-digester/Inputs/APINotesLeft/APINotesTest.h
index ab12619..90d5820 100644
--- a/test/api-digester/Inputs/APINotesLeft/APINotesTest.h
+++ b/test/api-digester/Inputs/APINotesLeft/APINotesTest.h
@@ -10,3 +10,9 @@
+(void) plusPrint;
-(int) getPropertyA;
@end
+
+@protocol ObjcProt
+ -(void) ProtMemberFunc;
+ -(void) ProtMemberFunc2;
+ -(void) ProtMemberFunc3;
+@end
diff --git a/test/api-digester/Inputs/APINotesRight/APINotesTest.h b/test/api-digester/Inputs/APINotesRight/APINotesTest.h
index a20dc5d..a500614 100644
--- a/test/api-digester/Inputs/APINotesRight/APINotesTest.h
+++ b/test/api-digester/Inputs/APINotesRight/APINotesTest.h
@@ -10,3 +10,7 @@
+(void) plusPrint;
@property int PropertyA;
@end
+
+@protocol ObjcProt
+ -(void) ProtMemberFunc;
+@end
diff --git a/test/api-digester/Outputs/apinotes-diags.txt b/test/api-digester/Outputs/apinotes-diags.txt
new file mode 100644
index 0000000..9cd3b42
--- /dev/null
+++ b/test/api-digester/Outputs/apinotes-diags.txt
@@ -0,0 +1,15 @@
+
+/* Removed Decls */
+APINotesTest(APINotesTest.h): Var OldType.oldMember has been removed
+APINotesTest(APINotesTest.h): Func ObjcProt.protMemberFunc2() has been removed
+APINotesTest(APINotesTest.h): Func ObjcProt.protMemberFunc3() has been removed
+APINotesTest(APINotesTest.h): Func SwiftTypeWithMethodLeft.getPropertyA() has been removed
+
+/* Moved Decls */
+
+/* Renamed Decls */
+APINotesTest(APINotesTest.h): Protocol SwiftTypeWithMethodLeft has been renamed to Protocol SwiftTypeWithMethodRight
+
+/* Type Changes */
+
+/* Decl Attribute changes */
diff --git a/test/api-digester/apinotes-diags.swift b/test/api-digester/apinotes-diags.swift
new file mode 100644
index 0000000..e6f22c2
--- /dev/null
+++ b/test/api-digester/apinotes-diags.swift
@@ -0,0 +1,8 @@
+// REQUIRES: OS=macosx
+// RUN: %empty-directory(%t.mod)
+// RUN: %empty-directory(%t.sdk)
+// RUN: %empty-directory(%t.module-cache)
+// RUN: %api-digester -dump-sdk -module APINotesTest -o %t.dump1.json -module-cache-path %t.module-cache -sdk %t.sdk -swift-version 3 -I %S/Inputs/APINotesLeft
+// RUN: %api-digester -dump-sdk -module APINotesTest -o %t.dump2.json -module-cache-path %t.module-cache -sdk %t.sdk -swift-version 3 -I %S/Inputs/APINotesRight
+// RUN: %api-digester -diagnose-sdk -print-module -input-paths %t.dump1.json -input-paths %t.dump2.json > %t.result
+// RUN: diff -u %S/Outputs/apinotes-diags.txt %t.result
diff --git a/test/decl/init/resilience-cross-module.swift b/test/decl/init/resilience-cross-module.swift
new file mode 100644
index 0000000..e547759
--- /dev/null
+++ b/test/decl/init/resilience-cross-module.swift
@@ -0,0 +1,38 @@
+// RUN: %empty-directory(%t)
+
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../../Inputs/resilient_struct.swift
+// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../../Inputs/resilient_protocol.swift
+
+// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -I %t %s
+// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -enable-resilience -I %t %s
+
+// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -I %t %s
+// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -enable-resilience -I %t %s
+
+import resilient_struct
+import resilient_protocol
+
+// Size is not @_fixed_layout, so we cannot define a new designated initializer
+extension Size {
+ init(ww: Int, hh: Int) {
+ self.w = ww
+ self.h = hh // expected-error {{'let' property 'h' may not be initialized directly; use "self.init(...)" or "self = ..." instead}}
+ }
+
+ // This is OK
+ init(www: Int, hhh: Int) {
+ self.init(w: www, h: hhh)
+ }
+
+ // This is OK
+ init(other: Size) {
+ self = other
+ }
+}
+
+// Protocol extension initializers are OK too
+extension OtherResilientProtocol {
+ public init(other: Self) {
+ self = other
+ }
+}
diff --git a/test/decl/init/resilience.swift b/test/decl/init/resilience.swift
index 0133982..fba6e6d 100644
--- a/test/decl/init/resilience.swift
+++ b/test/decl/init/resilience.swift
@@ -1,34 +1,9 @@
-// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -enable-resilience %s -DRESILIENT
+// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -enable-resilience %s -DRESILIENT
-// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../../Inputs/resilient_struct.swift
-// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../../Inputs/resilient_protocol.swift
-
-// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -I %t %s
-// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -enable-resilience -I %t %s
-
-// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -I %t %s
-// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -enable-resilience -I %t %s
-
-import resilient_struct
-import resilient_protocol
-
-// Size is not @_fixed_layout, so we cannot define a new designated initializer
-extension Size {
- init(ww: Int, hh: Int) {
- self.w = ww
- self.h = hh // expected-error {{'let' property 'h' may not be initialized directly; use "self.init(...)" or "self = ..." instead}}
- }
-
- // This is OK
- init(www: Int, hhh: Int) {
- self.init(w: www, h: hhh)
- }
-
- // This is OK
- init(other: Size) {
- self = other
- }
-}
+// There should be no errors when run without resilience enabled.
+// RUN: %target-swift-frontend -typecheck -swift-version 4 %s
+// RUN: %target-swift-frontend -typecheck -swift-version 5 %s
// Animal is not @_fixed_layout, so we cannot define an @_inlineable
// designated initializer
@@ -86,10 +61,3 @@
self.init()
}
}
-
-// Protocol extension initializers are OK too
-extension OtherResilientProtocol {
- public init(other: Self) {
- self = other
- }
-}
diff --git a/test/sil-func-extractor/basic.swift b/test/sil-func-extractor/basic.swift
index b8a2d03..648238a 100644
--- a/test/sil-func-extractor/basic.swift
+++ b/test/sil-func-extractor/basic.swift
@@ -56,10 +56,8 @@
// EXTRACT-NOW-LABEL: sil [serialized] @$S5basic7VehicleC3nowSiyF : $@convention(method) (@guaranteed Vehicle) -> Int {
// EXTRACT-NOW: bb0
-// EXTRACT-NOW: ref_element_addr
-// EXTRACT-NOW-NEXT: begin_access [read] [dynamic]
-// EXTRACT-NOW-NEXT: load
-// EXTRACT-NOW-NEXT: end_access
+// EXTRACT-NOW: class_method
+// EXTRACT-NOW-NEXT: apply
// EXTRACT-NOW-NEXT: return
public struct X {
diff --git a/test/stdlib/BinaryIntegerRequirements.swift b/test/stdlib/BinaryIntegerRequirements.swift
new file mode 100644
index 0000000..f3c8a25
--- /dev/null
+++ b/test/stdlib/BinaryIntegerRequirements.swift
@@ -0,0 +1,61 @@
+// RUN: %swift -swift-version 4 -typecheck -verify %s
+
+struct MyInt: FixedWidthInteger { // expected-error {{type 'MyInt' does not conform to protocol 'BinaryInteger'}}
+ typealias IntegerLiteralType = Int
+ static let isSigned = false
+ init(integerLiteral value: Int) { fatalError() }
+ init(_truncatingBits bits: UInt) { fatalError() }
+ init<T : BinaryFloatingPoint>(_ source: T) { fatalError() }
+ init?<T : BinaryFloatingPoint>(exactly source: T) { fatalError() }
+ init<T : BinaryInteger>(_ source: T) { fatalError() }
+ init?<T : BinaryInteger>(exactly source: T) { fatalError() }
+ init<T : BinaryInteger>(truncatingIfNeeded source: T) { fatalError() }
+ init<T : BinaryInteger>(clamping source: T) { fatalError() }
+
+ let words = [UInt]()
+ let _lowWord: UInt = 0
+ static var bitWidth: Int { fatalError() }
+ var trailingZeroBitCount: Int { fatalError() }
+
+ static func /=(_ lhs: inout MyInt, _ rhs: MyInt) { fatalError() }
+ static func /(_ lhs: MyInt, _ rhs: MyInt) -> MyInt { fatalError() }
+ static func %=(_ lhs: inout MyInt, _ rhs: MyInt) { fatalError() }
+ static func %(_ lhs: MyInt, _ rhs: MyInt) -> MyInt { fatalError() }
+ static func +=(_ lhs: inout MyInt, _ rhs: MyInt) { fatalError() }
+ static func +(_ lhs: MyInt, _ rhs: MyInt) -> MyInt { fatalError() }
+ static func -=(_ lhs: inout MyInt, _ rhs: MyInt) { fatalError() }
+ static func -(_ lhs: MyInt, _ rhs: MyInt) -> MyInt { fatalError() }
+ static func *=(_ lhs: inout MyInt, _ rhs: MyInt) { fatalError() }
+ static func *(_ lhs: MyInt, _ rhs: MyInt) -> MyInt { fatalError() }
+
+ static func ==(_ lhs: MyInt, _ rhs: MyInt) -> Bool { fatalError() }
+ static func <(_ lhs: MyInt, _ rhs: MyInt) -> Bool { fatalError() }
+
+ static prefix func ~ (_ x: MyInt) -> MyInt { fatalError() }
+
+ static func >><RHS: BinaryInteger>(_ lhs: MyInt, _ rhs: RHS) -> MyInt { fatalError() }
+
+ static func >>=<RHS: BinaryInteger>(_ lhs: inout MyInt, _ rhs: RHS) { fatalError() }
+ static func <<<RHS: BinaryInteger>(_ lhs: MyInt, _ rhs: RHS) -> MyInt { fatalError() }
+ static func <<=<RHS: BinaryInteger>(_ lhs: inout MyInt, _ rhs: RHS) { fatalError() }
+
+ func quotientAndRemainder(dividingBy rhs: MyInt) -> (quotient: MyInt, remainder: MyInt) { fatalError() }
+ func signum() -> MyInt { fatalError() }
+
+ var hashValue: Int { fatalError() }
+ var byteSwapped: MyInt { fatalError() }
+ static var max: MyInt { fatalError() }
+ static var min: MyInt { fatalError() }
+ func addingReportingOverflow(_ rhs: MyInt) -> (partialValue: MyInt, overflow: Bool) { fatalError() }
+ func subtractingReportingOverflow(_ rhs: MyInt) -> (partialValue: MyInt, overflow: Bool) { fatalError() }
+ func multipliedReportingOverflow(by rhs: MyInt) -> (partialValue: MyInt, overflow: Bool) { fatalError() }
+ func dividedReportingOverflow(by rhs: MyInt) -> (partialValue: MyInt, overflow: Bool) { fatalError() }
+ func remainderReportingOverflow(dividingBy rhs: MyInt) -> (partialValue: MyInt, overflow: Bool) { fatalError() }
+ func multipliedFullWidth(by other: MyInt) -> (high: MyInt, low: Magnitude) { fatalError() }
+ func dividingFullWidth(_ dividend: (high: MyInt, low: Magnitude)) -> (quotient: MyInt, remainder: MyInt) { fatalError() }
+
+ var nonzeroBitCount: Int { fatalError() }
+ var leadingZeroBitCount: Int { fatalError() }
+
+ var magnitude: UInt { fatalError() }
+}
diff --git a/test/stdlib/CodableTests.swift b/test/stdlib/CodableTests.swift
index 626afd8..8498145 100644
--- a/test/stdlib/CodableTests.swift
+++ b/test/stdlib/CodableTests.swift
@@ -694,7 +694,7 @@
}
func test_URLComponents_Plist() {
- for (testLine, components) in urlComponentsValues {
+ for (testLine, components) in urlComponentsValues {
expectRoundTripEqualityThroughPlist(for: components, lineNumber: testLine)
}
}
diff --git a/test/stdlib/Reflection_objc.swift b/test/stdlib/Reflection_objc.swift
index e649106..28286f7 100644
--- a/test/stdlib/Reflection_objc.swift
+++ b/test/stdlib/Reflection_objc.swift
@@ -81,15 +81,15 @@
switch PlaygroundQuickLook(reflecting: "woozle wuzzle" as NSString) {
case .text("woozle wuzzle"):
print("got the expected quick look text")
-case _:
- print("got something else")
+case let x:
+ print("NSString: got something else: \(x)")
}
// CHECK-NEXT: foobar
let somesubclassofnsstring = ("foo" + "bar") as NSString
switch PlaygroundQuickLook(reflecting: somesubclassofnsstring) {
case .text(let text): print(text)
- default: print("not the expected quicklook")
+ case let x: print("not the expected quicklook: \(x)")
}
// CHECK-NEXT: got the expected quick look attributed string
@@ -98,40 +98,40 @@
case .attributedString(let astr2 as NSAttributedString)
where astr == astr2:
print("got the expected quick look attributed string")
-case _:
- print("got something else")
+case let x:
+ print("NSAttributedString: got something else: \(x)")
}
// CHECK-NEXT: got the expected quick look int
switch PlaygroundQuickLook(reflecting: Int.max as NSNumber) {
case .int(+Int64(Int.max)):
print("got the expected quick look int")
-case _:
- print("got something else")
+case let x:
+ print("NSNumber(Int.max): got something else: \(x)")
}
// CHECK-NEXT: got the expected quick look uint
switch PlaygroundQuickLook(reflecting: NSNumber(value: UInt64.max)) {
case .uInt(UInt64.max):
print("got the expected quick look uint")
-case _:
- print("got something else")
+case let x:
+ print("NSNumber(Int64.max): got something else: \(x)")
}
// CHECK-NEXT: got the expected quick look double
switch PlaygroundQuickLook(reflecting: 22.5 as NSNumber) {
case .double(22.5):
print("got the expected quick look double")
-case _:
- print("got something else")
+case let x:
+ print("NSNumber(22.5): got something else: \(x)")
}
// CHECK-NEXT: got the expected quick look float
switch PlaygroundQuickLook(reflecting: Float32(1.25)) {
case .float(1.25):
print("got the expected quick look float")
-case _:
- print("got something else")
+case let x:
+ print("NSNumber(Float32(1.25)): got something else: \(x)")
}
// CHECK-NEXT: got the expected quick look image
@@ -142,24 +142,24 @@
switch PlaygroundQuickLook(reflecting: image) {
case .image(let image2 as OSImage) where image === image2:
print("got the expected quick look image")
-case _:
- print("got something else")
+case let x:
+ print("OSImage: got something else: \(x)")
}
let color = OSColor.black
switch PlaygroundQuickLook(reflecting: color) {
case .color(let color2 as OSColor) where color === color2:
print("got the expected quick look color")
-case _:
- print("got something else")
+case let x:
+ print("OSColor: got something else: \(x)")
}
let path = OSBezierPath()
switch PlaygroundQuickLook(reflecting: path) {
case .bezierPath(let path2 as OSBezierPath) where path === path2:
print("got the expected quick look bezier path")
-case _:
- print("got something else")
+case let x:
+ print("OSBezierPath: got something else: \(x)")
}
// CHECK-LABEL: Reflecting NSArray:
diff --git a/test/stdlib/Runtime.swift.gyb b/test/stdlib/Runtime.swift.gyb
index db0053a..e386aac 100644
--- a/test/stdlib/Runtime.swift.gyb
+++ b/test/stdlib/Runtime.swift.gyb
@@ -803,9 +803,11 @@
" - a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Plus\n" +
" - a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.SE30\n" +
" ▿ a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Classic\n" +
- " - Classic: 16\n" +
+ " ▿ Classic: (1 element)\n" +
+ " - mhz: 16\n" +
" ▿ a.MultiPayloadTagBitsNonGenericEnumWithDefaultMirror.Performa\n" +
- " - Performa: 220\n"
+ " ▿ Performa: (1 element)\n" +
+ " - model: 220\n"
expectEqual(expected, output)
}
@@ -849,11 +851,13 @@
" - a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.MacPaint\n" +
" - a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.FileMaker\n" +
" ▿ a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.ClarisWorks\n" +
- " ▿ ClarisWorks: a.Floppy #0\n" +
- " - capacity: 800\n" +
+ " ▿ ClarisWorks: (1 element)\n" +
+ " ▿ floppy: a.Floppy #0\n" +
+ " - capacity: 800\n" +
" ▿ a.MultiPayloadSpareBitsNonGenericEnumWithDefaultMirror.HyperCard\n" +
- " ▿ HyperCard: a.CDROM #1\n" +
- " - capacity: 600\n"
+ " ▿ HyperCard: (1 element)\n" +
+ " ▿ cdrom: a.CDROM #1\n" +
+ " - capacity: 600\n"
expectEqual(expected, output)
}
@@ -885,9 +889,11 @@
" - a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.MacPaint\n" +
" - a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.FileMaker\n" +
" ▿ a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.ClarisWorks\n" +
- " - ClarisWorks: true\n" +
+ " ▿ ClarisWorks: (1 element)\n" +
+ " - floppy: true\n" +
" ▿ a.MultiPayloadTagBitsSmallNonGenericEnumWithDefaultMirror.HyperCard\n" +
- " - HyperCard: false\n"
+ " ▿ HyperCard: (1 element)\n" +
+ " - cdrom: false\n"
expectEqual(expected, output)
}
@@ -920,9 +926,11 @@
" - a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.IIe\n" +
" - a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.IIgs\n" +
" ▿ a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.Centris\n" +
- " - Centris: 4096\n" +
+ " ▿ Centris: (1 element)\n" +
+ " - ram: 4096\n" +
" ▿ a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.Quadra\n" +
- " - Quadra: \"160MB\"\n" +
+ " ▿ Quadra: (1 element)\n" +
+ " - hdd: \"160MB\"\n" +
" - a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.PowerBook170\n" +
" - a.MultiPayloadGenericEnumWithDefaultMirror<Swift.Int, Swift.String>.PowerBookDuo220\n"
diff --git a/test/stdlib/RuntimeObjC.swift b/test/stdlib/RuntimeObjC.swift
index 64060aa..795fefb 100644
--- a/test/stdlib/RuntimeObjC.swift
+++ b/test/stdlib/RuntimeObjC.swift
@@ -470,34 +470,6 @@
}
}
-RuntimeFoundationWrappers.test(
- "_stdlib_compareNSStringDeterministicUnicodeCollation/NoLeak"
-) {
- nsStringCanaryCount = 0
- autoreleasepool {
- let a = NSStringCanary()
- let b = NSStringCanary()
- expectEqual(2, nsStringCanaryCount)
- _stdlib_compareNSStringDeterministicUnicodeCollation(a, b)
- }
- expectEqual(0, nsStringCanaryCount)
-}
-
-RuntimeFoundationWrappers.test(
- "_stdlib_compareNSStringDeterministicUnicodeCollationPtr/NoLeak"
-) {
- nsStringCanaryCount = 0
- autoreleasepool {
- let a = NSStringCanary()
- let b = NSStringCanary()
- expectEqual(2, nsStringCanaryCount)
- let ptrA = unsafeBitCast(a, to: OpaquePointer.self)
- let ptrB = unsafeBitCast(b, to: OpaquePointer.self)
- _stdlib_compareNSStringDeterministicUnicodeCollationPointer(ptrA, ptrB)
- }
- expectEqual(0, nsStringCanaryCount)
-}
-
RuntimeFoundationWrappers.test("_stdlib_NSStringHashValue/NoLeak") {
nsStringCanaryCount = 0
autoreleasepool {
diff --git a/test/stdlib/StringAPI.swift b/test/stdlib/StringAPI.swift
index a51a686..6c7662e 100644
--- a/test/stdlib/StringAPI.swift
+++ b/test/stdlib/StringAPI.swift
@@ -92,7 +92,7 @@
ComparisonTest(.eq, "\u{212b}", "A\u{30a}"),
ComparisonTest(.eq, "\u{212b}", "\u{c5}"),
ComparisonTest(.eq, "A\u{30a}", "\u{c5}"),
- ComparisonTest(.lt, "A\u{30a}", "a"),
+ ComparisonTest(.gt, "A\u{30a}", "a"),
ComparisonTest(.lt, "A", "A\u{30a}"),
// U+2126 OHM SIGN
@@ -176,25 +176,7 @@
// Mark the test cases that are expected to fail in checkStringComparison
-let comparisonTests = tests.map {
- (test: ComparisonTest) -> ComparisonTest in
- switch (test.expectedUnicodeCollation, test.lhs, test.rhs) {
- case (.gt, "t", "Tt"), (.lt, "A\u{30a}", "a"):
- return test.replacingPredicate(.nativeRuntime(
- "Comparison reversed between ICU and CFString, https://bugs.swift.org/browse/SR-530"))
-
- case (.gt, "\u{0}", ""), (.lt, "\u{0}", "\u{0}\u{0}"):
- return test.replacingPredicate(.nativeRuntime(
- "Null-related issue: https://bugs.swift.org/browse/SR-630"))
-
- case (.lt, "\u{0301}", "\u{0954}"), (.lt, "\u{0341}", "\u{0954}"):
- return test.replacingPredicate(.nativeRuntime(
- "Compares as equal with ICU"))
-
- default:
- return test
- }
-}
+let comparisonTests = tests
for test in comparisonTests {
StringTests.test("String.{Equatable,Hashable,Comparable}: line \(test.loc.line)")
diff --git a/test/stdlib/StringOrderRelation.swift b/test/stdlib/StringOrderRelation.swift
index 7df4802..b804c62 100644
--- a/test/stdlib/StringOrderRelation.swift
+++ b/test/stdlib/StringOrderRelation.swift
@@ -6,10 +6,7 @@
var StringOrderRelationTestSuite = TestSuite("StringOrderRelation")
-StringOrderRelationTestSuite.test("StringOrderRelation/ASCII/NullByte")
- .xfail(.nativeRuntime("String comparison: ICU vs. Foundation " +
- "https://bugs.swift.org/browse/SR-630"))
- .code {
+StringOrderRelationTestSuite.test("StringOrderRelation/ASCII/NullByte") {
let baseString = "a"
let nullbyteString = "a\0"
expectTrue(baseString < nullbyteString)
diff --git a/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def.gyb b/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def.gyb
index 943c524..c31b763 100644
--- a/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def.gyb
+++ b/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def.gyb
@@ -1,8 +1,7 @@
%{
# -*- mode: Python -*-
- from gyb_sourcekit_support.UIDs import UID_KEYS
- from gyb_sourcekit_support.UIDs import UID_REQUESTS
- from gyb_sourcekit_support.UIDs import UID_KINDS
+ from gyb_sourcekit_support import *
+ assert check_uid_duplication(), "Found UID duplication"
# Ignore the following admonition; it applies to the resulting .def file only
}%
//// Automatically Generated From ProtocolUIDs.def.gyb.
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp
index 0705991..1992a35 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp
@@ -704,6 +704,7 @@
case SyntaxNodeKind::TypeId:
case SyntaxNodeKind::BuildConfigKeyword:
case SyntaxNodeKind::BuildConfigId:
+ case SyntaxNodeKind::PoundDirectiveKeyword:
case SyntaxNodeKind::AttributeId:
case SyntaxNodeKind::AttributeBuiltin:
case SyntaxNodeKind::ObjectLiteral:
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp
index 1e1c052..cd50866 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp
@@ -339,6 +339,8 @@
return KindBuildConfigKeyword;
case SyntaxNodeKind::BuildConfigId:
return KindBuildConfigId;
+ case SyntaxNodeKind::PoundDirectiveKeyword:
+ return KindPoundDirectiveKeyword;
case SyntaxNodeKind::AttributeId:
return KindAttributeId;
case SyntaxNodeKind::AttributeBuiltin:
diff --git a/tools/SwiftSyntax/SyntaxNodes.swift.gyb b/tools/SwiftSyntax/SyntaxNodes.swift.gyb
index 5dd080e..1aa788f 100644
--- a/tools/SwiftSyntax/SyntaxNodes.swift.gyb
+++ b/tools/SwiftSyntax/SyntaxNodes.swift.gyb
@@ -54,19 +54,6 @@
}
}
-% for trait in TRAITS:
-public protocol ${trait.trait_name} {
-% for child in trait.children:
-% ret_type = child.type_name
-% if child.is_optional:
-% ret_type += '?'
-% end
- var ${child.swift_name}: ${ret_type} { get }
- func with${child.name}(_ newChild: ${child.type_name}?) -> Self
-% end
-}
-% end
-
% for node in SYNTAX_NODES:
% base_type = node.base_type
% if node.is_base():
@@ -75,12 +62,7 @@
% elif node.collection_element:
% pass
% else:
-% traits_list = ""
-% if node.traits:
-% traits_list = ", ".join(node.traits)
-% traits_list = traits_list + ", "
-% end
-public struct ${node.name}: ${traits_list} ${base_type}, _SyntaxBase, Hashable {
+public struct ${node.name}: ${base_type}, _SyntaxBase, Hashable {
% if node.children:
enum Cursor: Int {
% for child in node.children:
@@ -192,6 +174,31 @@
% end
% end
+% for trait in TRAITS:
+public protocol ${trait.trait_name}Syntax {
+% for child in trait.children:
+% ret_type = child.type_name
+% if child.is_optional:
+% ret_type += '?'
+% end
+ var ${child.swift_name}: ${ret_type} { get }
+ func with${child.name}(_ newChild: ${child.type_name}?) -> Self
+% end
+}
+% end
+
+% for node in SYNTAX_NODES:
+% base_type = node.base_type
+% if node.is_base():
+% pass
+% elif node.collection_element:
+% pass
+% elif node.traits:
+% traits_list = ", ".join(trait + 'Syntax' for trait in node.traits)
+extension ${node.name}: ${traits_list} {}
+% end
+% end
+
/// MARK: Convenience methods
extension StructDeclSyntax {
diff --git a/tools/driver/modulewrap_main.cpp b/tools/driver/modulewrap_main.cpp
index 52e555d..846a4e7 100644
--- a/tools/driver/modulewrap_main.cpp
+++ b/tools/driver/modulewrap_main.cpp
@@ -22,6 +22,7 @@
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/Option/Options.h"
#include "swift/Serialization/ModuleFormat.h"
+#include "swift/SIL/SILModule.h"
#include "swift/Subsystems.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Bitcode/BitstreamReader.h"
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index 07ac6dd..477671f 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -383,6 +383,7 @@
StringRef getUsr() const { return Usr; }
StringRef getLocation() const { return Location; }
StringRef getModuleName() const {return ModuleName;}
+ StringRef getHeaderName() const;
void addDeclAttribute(SDKDeclAttrKind DAKind);
ArrayRef<SDKDeclAttrKind> getDeclAttributes() const;
swift::Ownership getOwnership() const { return swift::Ownership(Ownership); }
@@ -396,6 +397,12 @@
bool isStatic() const { return IsStatic; };
};
+StringRef SDKNodeDecl::getHeaderName() const {
+ if (Location.empty())
+ return StringRef();
+ return llvm::sys::path::filename(Location.split(":").first);
+}
+
class SDKNodeRoot :public SDKNode {
/// This keeps track of all decl descendants with USRs.
llvm::StringMap<llvm::SmallSetVector<SDKNodeDecl*, 2>> DescendantDeclTable;
@@ -1540,12 +1547,12 @@
StringRef Usr = D->getUsr();
StringRef Location = D->getLocation();
StringRef ModuleName = D->getModuleName();
-
out.mapRequired(getKeyContent(Ctx, KeyKind::KK_declKind).data(), DK);
out.mapRequired(getKeyContent(Ctx, KeyKind::KK_usr).data(), Usr);
out.mapRequired(getKeyContent(Ctx, KeyKind::KK_location).data(), Location);
out.mapRequired(getKeyContent(Ctx, KeyKind::KK_moduleName).data(),
ModuleName);
+
if (auto isStatic = D->isStatic())
out.mapRequired(getKeyContent(Ctx, KeyKind::KK_static).data(), isStatic);
@@ -2665,13 +2672,24 @@
}
};
- struct DiagBase {
+ struct MetaInfo {
StringRef ModuleName;
- DiagBase(StringRef ModuleName): ModuleName(ModuleName) {}
+ StringRef HeaderName;
+ MetaInfo(const SDKNodeDecl *Node):
+ ModuleName(Node->getModuleName()), HeaderName(Node->getHeaderName()) {}
+ };
+
+ struct DiagBase {
+ MetaInfo Info;
+ DiagBase(MetaInfo Info): Info(Info) {}
virtual ~DiagBase() = default;
void outputModule() const {
- if (options::PrintModule)
- llvm::outs() << ModuleName << ": ";
+ if (options::PrintModule) {
+ llvm::outs() << Info.ModuleName;
+ if (!Info.HeaderName.empty())
+ llvm::outs() << "(" << Info.HeaderName << ")";
+ llvm::outs() << ": ";
+ }
}
virtual void output() const = 0;
};
@@ -2680,8 +2698,8 @@
DeclKind Kind;
StringRef Name;
bool IsDeprecated;
- RemovedDeclDiag(StringRef ModuleName, DeclKind Kind, StringRef Name,
- bool IsDeprecated): DiagBase(ModuleName), Kind(Kind),
+ RemovedDeclDiag(MetaInfo Info, DeclKind Kind, StringRef Name,
+ bool IsDeprecated): DiagBase(Info), Kind(Kind),
Name(Name), IsDeprecated(IsDeprecated) {}
bool operator<(RemovedDeclDiag Other) const;
void output() const override;
@@ -2693,9 +2711,9 @@
DeclKind AddedKind;
StringRef RemovedName;
StringRef AddedName;
- MovedDeclDiag(StringRef ModuleName, DeclKind RemovedKind, DeclKind AddedKind,
+ MovedDeclDiag(MetaInfo Info, DeclKind RemovedKind, DeclKind AddedKind,
StringRef RemovedName, StringRef AddedName):
- DiagBase(ModuleName), RemovedKind(RemovedKind), AddedKind(AddedKind),
+ DiagBase(Info), RemovedKind(RemovedKind), AddedKind(AddedKind),
RemovedName(RemovedName), AddedName(AddedName) {}
bool operator<(MovedDeclDiag other) const;
void output() const override;
@@ -2707,9 +2725,9 @@
DeclKind KindAfter;
StringRef NameBefore;
StringRef NameAfter;
- RenamedDeclDiag(StringRef ModuleName, DeclKind KindBefore, DeclKind KindAfter,
+ RenamedDeclDiag(MetaInfo Info, DeclKind KindBefore, DeclKind KindAfter,
StringRef NameBefore, StringRef NameAfter):
- DiagBase(ModuleName),
+ DiagBase(Info),
KindBefore(KindBefore), KindAfter(KindAfter),
NameBefore(NameBefore), NameAfter(NameAfter) {}
bool operator<(RenamedDeclDiag Other) const;
@@ -2722,12 +2740,12 @@
StringRef DeclName;
StringRef AttrBefore;
StringRef AttrAfter;
- DeclAttrDiag(StringRef ModuleName, DeclKind Kind, StringRef DeclName,
+ DeclAttrDiag(MetaInfo Info, DeclKind Kind, StringRef DeclName,
StringRef AttrBefore, StringRef AttrAfter):
- DiagBase(ModuleName), Kind(Kind), DeclName(DeclName),
+ DiagBase(Info), Kind(Kind), DeclName(DeclName),
AttrBefore(AttrBefore), AttrAfter(AttrAfter) {}
- DeclAttrDiag(StringRef ModuleName, DeclKind Kind, StringRef DeclName,
- StringRef AttrAfter): DeclAttrDiag(ModuleName, Kind, DeclName,
+ DeclAttrDiag(MetaInfo Info, DeclKind Kind, StringRef DeclName,
+ StringRef AttrAfter): DeclAttrDiag(Info, Kind, DeclName,
StringRef(), AttrAfter) {}
bool operator<(DeclAttrDiag Other) const;
@@ -2741,9 +2759,9 @@
StringRef TypeNameBefore;
StringRef TypeNameAfter;
StringRef Description;
- DeclTypeChangeDiag(StringRef ModuleName, DeclKind Kind, StringRef DeclName,
+ DeclTypeChangeDiag(MetaInfo Info, DeclKind Kind, StringRef DeclName,
StringRef TypeNameBefore, StringRef TypeNameAfter,
- StringRef Description): DiagBase(ModuleName),
+ StringRef Description): DiagBase(Info),
Kind(Kind), DeclName(DeclName), TypeNameBefore(TypeNameBefore),
TypeNameAfter(TypeNameAfter), Description(Description) {}
bool operator<(DeclTypeChangeDiag Other) const;
@@ -2888,6 +2906,7 @@
void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) {
assert(Node->isAnnotatedAs(Anno));
auto &Ctx = Node->getSDKContext();
+ MetaInfo ScreenInfo(Node);
switch(Anno) {
case NodeAnnotation::Removed: {
// If we can find a type alias decl with the same name of this type, we
@@ -2896,7 +2915,7 @@
return;
if (auto *Added = findAddedDecl(Node)) {
if (Node->getDeclKind() != DeclKind::Constructor) {
- MovedDecls.Diags.emplace_back(Node->getModuleName(),
+ MovedDecls.Diags.emplace_back(ScreenInfo,
Node->getDeclKind(),
Added->getDeclKind(),
Node->getFullyQualifiedName(),
@@ -2920,7 +2939,7 @@
}
if (FoundInSuperclass)
return;
- RemovedDecls.Diags.emplace_back(Node->getModuleName(),
+ RemovedDecls.Diags.emplace_back(ScreenInfo,
Node->getDeclKind(),
Node->getFullyQualifiedName(),
Node->isDeprecated());
@@ -2928,28 +2947,28 @@
}
case NodeAnnotation::Rename: {
auto *Count = UpdateMap.findUpdateCounterpart(Node)->getAs<SDKNodeDecl>();
- RenamedDecls.Diags.emplace_back(Node->getModuleName(),
+ RenamedDecls.Diags.emplace_back(ScreenInfo,
Node->getDeclKind(), Count->getDeclKind(),
Node->getFullyQualifiedName(),
Count->getFullyQualifiedName());
return;
}
case NodeAnnotation::NowMutating: {
- AttrChangedDecls.Diags.emplace_back(Node->getModuleName(),
+ AttrChangedDecls.Diags.emplace_back(ScreenInfo,
Node->getDeclKind(),
Node->getFullyQualifiedName(),
Ctx.buffer("mutating"));
return;
}
case NodeAnnotation::NowThrowing: {
- AttrChangedDecls.Diags.emplace_back(Node->getModuleName(),
+ AttrChangedDecls.Diags.emplace_back(ScreenInfo,
Node->getDeclKind(),
Node->getFullyQualifiedName(),
Ctx.buffer("throwing"));
return;
}
case NodeAnnotation::StaticChange: {
- AttrChangedDecls.Diags.emplace_back(Node->getModuleName(),
+ AttrChangedDecls.Diags.emplace_back(ScreenInfo,
Node->getDeclKind(),
Node->getFullyQualifiedName(),
Ctx.buffer(Node->isStatic() ? "not static" : "static"));
@@ -2967,7 +2986,7 @@
llvm_unreachable("Unhandled Ownership in switch.");
};
auto *Count = UpdateMap.findUpdateCounterpart(Node)->getAs<SDKNodeDecl>();
- AttrChangedDecls.Diags.emplace_back(Node->getModuleName(),
+ AttrChangedDecls.Diags.emplace_back(ScreenInfo,
Node->getDeclKind(),
Node->getFullyQualifiedName(),
getOwnershipDescription(Node->getOwnership()),
@@ -2991,6 +3010,7 @@
auto *Parent = dyn_cast<SDKNodeDecl>(Node->getParent());
if (!Parent || Parent->isSDKPrivate())
return;
+ MetaInfo ScreenInfo(Parent);
SDKContext &Ctx = Node->getSDKContext();
if (Node->isAnnotatedAs(NodeAnnotation::Updated)) {
auto *Count = UpdateMap.findUpdateCounterpart(Node)->getAs<SDKNodeType>();
@@ -3003,7 +3023,7 @@
SDKNodeAbstractFunc::getTypeRoleDescription(Ctx, Parent->getChildIndex(Node)) :
Ctx.buffer("declared");
if (Node->getPrintedName() != Count->getPrintedName())
- TypeChangedDecls.Diags.emplace_back(Parent->getModuleName(),
+ TypeChangedDecls.Diags.emplace_back(ScreenInfo,
Parent->getDeclKind(),
Parent->getFullyQualifiedName(),
Node->getPrintedName(),
diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp
index 3057489..b84602d 100644
--- a/tools/swift-ide-test/swift-ide-test.cpp
+++ b/tools/swift-ide-test/swift-ide-test.cpp
@@ -897,6 +897,7 @@
case SyntaxNodeKind::TypeId: Id = "type"; break;
case SyntaxNodeKind::BuildConfigKeyword: Id = "#kw"; break;
case SyntaxNodeKind::BuildConfigId: Id = "#id"; break;
+ case SyntaxNodeKind::PoundDirectiveKeyword: Id = "#kw"; break;
case SyntaxNodeKind::AttributeId: Id = "attr-id"; break;
case SyntaxNodeKind::AttributeBuiltin: Id = "attr-builtin"; break;
case SyntaxNodeKind::EditorPlaceholder: Id = "placeholder"; break;
@@ -927,6 +928,7 @@
case SyntaxNodeKind::TypeId: Col = llvm::raw_ostream::CYAN; break;
case SyntaxNodeKind::BuildConfigKeyword: Col = llvm::raw_ostream::YELLOW; break;
case SyntaxNodeKind::BuildConfigId: Col = llvm::raw_ostream::YELLOW; break;
+ case SyntaxNodeKind::PoundDirectiveKeyword: Col = llvm::raw_ostream::YELLOW; break;
case SyntaxNodeKind::AttributeId: Col = llvm::raw_ostream::CYAN; break;
case SyntaxNodeKind::AttributeBuiltin: Col = llvm::raw_ostream::MAGENTA; break;
case SyntaxNodeKind::EditorPlaceholder: Col = llvm::raw_ostream::YELLOW; break;
@@ -1611,18 +1613,21 @@
case NodeKind::Structure:
case NodeKind::Class:
case NodeKind::Enum:
+ case NodeKind::OtherNominalType:
break;
case NodeKind::BoundGenericStructure:
case NodeKind::BoundGenericClass:
case NodeKind::BoundGenericEnum:
+ case NodeKind::BoundGenericOtherNominalType:
// Base type
typeNode = node->getFirstChild();
// Nominal type
node = typeNode->getFirstChild();
assert(node->getKind() == NodeKind::Structure ||
node->getKind() == NodeKind::Class ||
- node->getKind() == NodeKind::Enum);
+ node->getKind() == NodeKind::Enum ||
+ node->getKind() == NodeKind::OtherNominalType);
break;
default:
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index 9860cd8..be88c8e 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -1,4 +1,5 @@
add_subdirectory(vim)
+add_subdirectory(lldb)
swift_install_in_component(editor-integration
FILES swift-mode.el
diff --git a/utils/build-script-impl b/utils/build-script-impl
index 54f58bc..ffc3d39 100755
--- a/utils/build-script-impl
+++ b/utils/build-script-impl
@@ -2731,22 +2731,21 @@
fi
lldb_build_dir=$(build_directory ${host} lldb)
- if [[ ! "${LLDB_TEST_SWIFT_ONLY}" ]]; then
- # Run the gtests.
- if [[ "$(uname -s)" == "Darwin" && "$(true_false ${LLDB_BUILD_WITH_XCODE})" == "TRUE" ]] ; then
- set_lldb_xcodebuild_options
- # Run the LLDB unittests (gtests).
- with_pushd ${LLDB_SOURCE_DIR} \
- call xcodebuild -scheme lldb-gtest -configuration ${LLDB_BUILD_MODE} ${lldb_xcodebuild_options[@]}
- rc=$?
- if [[ "$rc" -ne 0 ]] ; then
- >&2 echo "error: LLDB gtests failed"
- exit 1
- fi
- else
- with_pushd ${lldb_build_dir} \
- ${NINJA_BIN} check-lldb-unit
+ # Run the unittests.
+ # FIXME: The xcode build project currently doesn't know how to run the lit style tests.
+ if [[ "$(uname -s)" == "Darwin" && "$(true_false ${LLDB_BUILD_WITH_XCODE})" == "TRUE" ]] ; then
+ set_lldb_xcodebuild_options
+ # Run the LLDB unittests (gtests).
+ with_pushd ${LLDB_SOURCE_DIR} \
+ call xcodebuild -scheme lldb-gtest -configuration ${LLDB_BUILD_MODE} ${lldb_xcodebuild_options[@]}
+ rc=$?
+ if [[ "$rc" -ne 0 ]] ; then
+ >&2 echo "error: LLDB gtests failed"
+ exit 1
fi
+ else
+ with_pushd ${lldb_build_dir} \
+ ${NINJA_BIN} check-lldb-lit
fi
swift_build_dir=$(build_directory ${host} swift)
@@ -2808,6 +2807,19 @@
LLDB_TEST_DEBUG_SERVER=""
fi
+ # Options to find the just-built libddispatch and Foundation.
+ if [[ "$(uname -s)" == "Darwin" || "${SKIP_BUILD_FOUNDATION}" ]] ; then
+ DOTEST_EXTRA=""
+ else
+ # This assumes that there are no spaces in any on these paths.
+ FOUNDATION_BUILD_DIR=$(build_directory ${host} foundation)
+ DOTEST_EXTRA="-I${FOUNDATION_BUILD_DIR}/Foundation"
+ DOTEST_EXTRA="${DOTEST_EXTRA} -I${FOUNDATION_BUILD_DIR}/Foundation/usr/lib/swift"
+ DOTEST_EXTRA="${DOTEST_EXTRA} -I${LIBDISPATCH_SOURCE_DIR}"
+ DOTEST_EXTRA="${DOTEST_EXTRA} -L${FOUNDATION_BUILD_DIR}/Foundation"
+ DOTEST_EXTRA="${DOTEST_EXTRA} -L${LIBDISPATCH_BUILD_DIR}"
+ DOTEST_EXTRA="${DOTEST_EXTRA} -L${LIBDISPATCH_BUILD_DIR}/src"
+ fi
call mkdir -p "${results_dir}"
with_pushd "${results_dir}" \
call env SWIFTCC="$(build_directory $LOCAL_HOST swift)/bin/swiftc" \
@@ -2818,7 +2830,8 @@
${LLDB_TEST_SUBDIR_CLAUSE} \
${LLDB_TEST_CATEGORIES} \
${LLDB_DOTEST_CC_OPTS} \
- ${LLDB_FORMATTER_OPTS}
+ ${LLDB_FORMATTER_OPTS} \
+ -E "${DOTEST_EXTRA}"
continue
;;
llbuild)
diff --git a/utils/build-toolchain b/utils/build-toolchain
index bf9fbbb..ec0910a 100755
--- a/utils/build-toolchain
+++ b/utils/build-toolchain
@@ -10,22 +10,92 @@
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+function usage() {
+ echo "$0 <bundle_prefix> [OPTIONS]"
+ echo ""
+ echo "<bundle_prefix> - Prefix to use for bundle name"
+ echo ""
+ echo "OPTIONS"
+ echo ""
+ echo "-h --help"
+ echo "Show help information."
+ echo ""
+ echo "-n --dry-run"
+ echo "Do a dry run."
+ echo ""
+ if [[ "$(uname -s)" == "Linux" ]] ; then
+ echo "-t --test"
+ echo "Run tests."
+ echo ""
+ fi
+}
+
cd "$(dirname $0)/.." || exit
SRC_DIR=$PWD
+# Set defaults
DRY_RUN=
-if [[ "$2" == "-n" || "$2" == "--dry-run" ]] ; then
- DRY_RUN="-n"
- shift
+BUNDLE_PREFIX=
+case $(uname -s) in
+ Darwin)
+ SWIFT_PACKAGE=buildbot_osx_package
+ ;;
+ Linux)
+ SWIFT_PACKAGE=buildbot_linux,no_test
+ ;;
+ *)
+ echo "Unrecognised platform $(uname -s)"
+ exit 1
+ ;;
+esac
+
+# Process command line arguments
+FIRST_ARG_PROCESSED=0
+while [ $# -ne 0 ]; do
+ case "$1" in
+ -n|--dry-run)
+ DRY_RUN="-n"
+ ;;
+ -t|--test)
+ if [ "$(uname -s)" == "Linux" ]; then
+ SWIFT_PACKAGE=buildbot_linux
+ else
+ echo "--test is not supported on \"$(uname -s)\". See --help"
+ exit 1
+ fi
+ ;;
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ *)
+ if [ ${FIRST_ARG_PROCESSED} -eq 0 ]; then
+ # This is the bundle prefix
+ BUNDLE_PREFIX="$1"
+ else
+ echo "Unrecognised argument \"$1\""
+ exit 1
+ fi
+ ;;
+ esac
+ FIRST_ARG_PROCESSED=1
+ shift
+done
+
+if [ -z "${BUNDLE_PREFIX}" ]; then
+ echo "Bundle prefix cannot be empty. See $0 --help"
+ exit 1
fi
+# Report the commands being run
+set -x
YEAR=$(date +"%Y")
MONTH=$(date +"%m")
DAY=$(date +"%d")
TOOLCHAIN_VERSION="swift-LOCAL-${YEAR}-${MONTH}-${DAY}-a"
ARCHIVE="${TOOLCHAIN_VERSION}-osx.tar.gz"
SYM_ARCHIVE="${TOOLCHAIN_VERSION}-osx-symbols.tar.gz"
-BUNDLE_PREFIX=${1:?Please specify bundle prefix e.g. $0 local.swift}
+BUNDLE_PREFIX=${BUNDLE_PREFIX:?Please specify a bundle prefix}
BUNDLE_IDENTIFIER="${BUNDLE_PREFIX}.${YEAR}${MONTH}${DAY}"
DISPLAY_NAME_SHORT="Local Swift Development Snapshot"
DISPLAY_NAME="${DISPLAY_NAME_SHORT} ${YEAR}-${MONTH}-${DAY}"
@@ -36,16 +106,7 @@
SWIFT_INSTALL_SYMROOT="${SRC_DIR}/swift-nightly-symroot"
SWIFT_TOOLCHAIN_DIR="/Library/Developer/Toolchains/${TOOLCHAIN_NAME}.xctoolchain"
SYMBOLS_PACKAGE="${SRC_DIR}/${SYM_ARCHIVE}"
-
-if [[ "$(uname -s)" == "Darwin" ]] ; then
- SWIFT_PACKAGE=buildbot_osx_package
-else
- if [[ "$2" == "-t" || "$2" == "--test" ]] ; then
- SWIFT_PACKAGE=buildbot_linux
- else
- SWIFT_PACKAGE=buildbot_linux,no_test
- fi
-fi
+DRY_RUN="${DRY_RUN}"
./utils/build-script ${DRY_RUN} --preset="${SWIFT_PACKAGE}" \
install_destdir="${SWIFT_INSTALL_DIR}" \
diff --git a/utils/gyb_sourcekit_support/UIDs.py b/utils/gyb_sourcekit_support/UIDs.py
index f087177..5769bc8 100644
--- a/utils/gyb_sourcekit_support/UIDs.py
+++ b/utils/gyb_sourcekit_support/UIDs.py
@@ -337,6 +337,8 @@
KIND('BuildConfigKeyword',
'source.lang.swift.syntaxtype.buildconfig.keyword'),
KIND('BuildConfigId', 'source.lang.swift.syntaxtype.buildconfig.id'),
+ KIND('PoundDirectiveKeyword',
+ 'source.lang.swift.syntaxtype.pounddirective.keyword'),
KIND('AttributeId', 'source.lang.swift.syntaxtype.attribute.id'),
KIND('AttributeBuiltin', 'source.lang.swift.syntaxtype.attribute.builtin'),
KIND('Number', 'source.lang.swift.syntaxtype.number'),
diff --git a/utils/gyb_sourcekit_support/__init__.py b/utils/gyb_sourcekit_support/__init__.py
index 94d2421..90b1a80 100644
--- a/utils/gyb_sourcekit_support/__init__.py
+++ b/utils/gyb_sourcekit_support/__init__.py
@@ -14,3 +14,13 @@
# utils/gyb_sourcekit_support/ directory as a module.
#
# ----------------------------------------------------------------------------
+from UIDs import UID_KEYS
+from UIDs import UID_KINDS
+from UIDs import UID_REQUESTS
+
+
+def check_uid_duplication():
+ all_external_names = [K.externalName for K in UID_KEYS] + \
+ [R.externalName for R in UID_REQUESTS] + \
+ [K.externalName for K in UID_KINDS]
+ return len(all_external_names) == len(set(all_external_names))
diff --git a/utils/gyb_syntax_support/CommonNodes.py b/utils/gyb_syntax_support/CommonNodes.py
index 7a6d627..371dcab 100644
--- a/utils/gyb_syntax_support/CommonNodes.py
+++ b/utils/gyb_syntax_support/CommonNodes.py
@@ -32,7 +32,7 @@
# code-block -> '{' stmt-list '}'
Node('CodeBlock', kind='Syntax',
- traits=['BracedSyntax'],
+ traits=['Braced', 'WithStatements'],
children=[
Child('LeftBrace', kind='LeftBraceToken'),
Child('Statements', kind='CodeBlockItemList'),
diff --git a/utils/gyb_syntax_support/DeclNodes.py b/utils/gyb_syntax_support/DeclNodes.py
index decb032..4f73f75 100644
--- a/utils/gyb_syntax_support/DeclNodes.py
+++ b/utils/gyb_syntax_support/DeclNodes.py
@@ -15,7 +15,7 @@
# typealias-name generic-parameter-clause?
# type-assignment
# typealias-name -> identifier
- Node('TypealiasDecl', kind='Decl', traits=['IdentifiedDeclSyntax'],
+ Node('TypealiasDecl', kind='Decl', traits=['IdentifiedDecl'],
children=[
Child('Attributes', kind='AttributeList',
is_optional=True),
@@ -36,7 +36,7 @@
# inheritance-clause? type-assignment?
# generic-where-clause?
# associatedtype-name -> identifier
- Node('AssociatedtypeDecl', kind='Decl', traits=['IdentifiedDeclSyntax'],
+ Node('AssociatedtypeDecl', kind='Decl', traits=['IdentifiedDecl'],
children=[
Child('Attributes', kind='AttributeList',
is_optional=True),
@@ -56,6 +56,7 @@
element='FunctionParameter'),
Node('ParameterClause', kind='Syntax',
+ traits=['Parenthesized'],
children=[
Child('LeftParen', kind='LeftParenToken'),
Child('ParameterList', kind='FunctionParameterList'),
@@ -85,19 +86,21 @@
# else-if-directive-clause -> '#elseif' expr stmt-list
Node('ElseifDirectiveClause', kind='Syntax',
+ traits=['WithStatements'],
children=[
Child('PoundElseif', kind='PoundElseifToken'),
Child('Condition', kind='Expr'),
- Child('Body', kind='CodeBlockItemList'),
+ Child('Statements', kind='CodeBlockItemList'),
]),
# if-config-decl -> '#if' expr stmt-list else-if-directive-clause-list
# else-clause? '#endif'
Node('IfConfigDecl', kind='Decl',
+ traits=['WithStatements'],
children=[
Child('PoundIf', kind='PoundIfToken'),
Child('Condition', kind='Expr'),
- Child('Body', kind='CodeBlockItemList'),
+ Child('Statements', kind='CodeBlockItemList'),
Child('ElseifDirectiveClauses', kind='ElseifDirectiveClauseList',
is_optional=True),
Child('ElseClause', kind='ElseDirectiveClause',
@@ -106,19 +109,21 @@
]),
Node('PoundErrorDecl', kind='Decl',
+ traits=['Parenthesized'],
children=[
Child('PoundError', kind='PoundErrorToken'),
- Child('LeftParenToken', kind='LeftParenToken'),
+ Child('LeftParen', kind='LeftParenToken'),
Child('Message', kind='StringLiteralExpr'),
- Child('RightParenToken', kind='RightParenToken')
+ Child('RightParen', kind='RightParenToken')
]),
Node('PoundWarningDecl', kind='Decl',
+ traits=['Parenthesized'],
children=[
Child('PoundWarning', kind='PoundWarningToken'),
- Child('LeftParenToken', kind='LeftParenToken'),
+ Child('LeftParen', kind='LeftParenToken'),
Child('Message', kind='StringLiteralExpr'),
- Child('RightParenToken', kind='RightParenToken')
+ Child('RightParen', kind='RightParenToken')
]),
Node('DeclModifier', kind='Syntax',
@@ -135,6 +140,7 @@
]),
Node('InheritedType', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('TypeName', kind='Type'),
Child('TrailingComma', kind='CommaToken', is_optional=True),
@@ -158,7 +164,7 @@
# '{' class-members '}'
# class-name -> identifier
Node('ClassDecl', kind='Decl',
- traits=['DeclGroupSyntax', 'IdentifiedDeclSyntax'],
+ traits=['DeclGroup', 'IdentifiedDecl'],
children=[
Child('Attributes', kind='AttributeList',
is_optional=True),
@@ -183,7 +189,7 @@
# '{' struct-members '}'
# struct-name -> identifier
Node('StructDecl', kind='Decl',
- traits=['DeclGroupSyntax', 'IdentifiedDeclSyntax'],
+ traits=['DeclGroup', 'IdentifiedDecl'],
children=[
Child('Attributes', kind='AttributeList',
is_optional=True),
@@ -201,7 +207,7 @@
]),
Node('ProtocolDecl', kind='Decl',
- traits=['DeclGroupSyntax', 'IdentifiedDeclSyntax'],
+ traits=['DeclGroup', 'IdentifiedDecl'],
children=[
Child('Attributes', kind='AttributeList',
is_optional=True),
@@ -222,7 +228,7 @@
# generic-where-clause?
# '{' extension-members '}'
# extension-name -> identifier
- Node('ExtensionDecl', kind='Decl', traits=['DeclGroupSyntax'],
+ Node('ExtensionDecl', kind='Decl', traits=['DeclGroup'],
children=[
Child('Attributes', kind='AttributeList',
is_optional=True),
@@ -237,7 +243,7 @@
Child('Members', kind='MemberDeclBlock'),
]),
- Node('MemberDeclBlock', kind='Syntax', traits=['BracedSyntax'],
+ Node('MemberDeclBlock', kind='Syntax', traits=['Braced'],
children=[
Child('LeftBrace', kind='LeftBraceToken'),
Child('Members', kind='DeclList'),
@@ -250,8 +256,9 @@
# source-file = code-block-item-list eof
Node('SourceFile', kind='Syntax',
+ traits=['WithStatements'],
children=[
- Child('Items', kind='CodeBlockItemList'),
+ Child('Statements', kind='CodeBlockItemList'),
Child('EOFToken', kind='EOFToken')
]),
@@ -266,6 +273,7 @@
# external-parameter-name? local-parameter-name ':'
# type '...'? '='? expression? ','?
Node('FunctionParameter', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('Attributes', kind='AttributeList',
is_optional=True),
@@ -315,7 +323,7 @@
element='Syntax',
element_name='Modifier'),
- Node('FunctionDecl', kind='Decl', traits=['IdentifiedDeclSyntax'],
+ Node('FunctionDecl', kind='Decl', traits=['IdentifiedDecl'],
children=[
Child('Attributes', kind='AttributeList',
is_optional=True),
@@ -403,9 +411,10 @@
# else-directive-clause -> '#else' stmt-list
Node('ElseDirectiveClause', kind='Syntax',
+ traits=['WithStatements'],
children=[
Child('PoundElse', kind='PoundElseToken'),
- Child('Body', kind='CodeBlockItemList'),
+ Child('Statements', kind='CodeBlockItemList'),
]),
# access-level-modifier -> 'private' | 'private' '(' 'set' ')'
@@ -416,11 +425,11 @@
Node('AccessLevelModifier', kind='Syntax',
children=[
Child('Name', kind='IdentifierToken'),
- Child('OpenParen', kind='LeftParenToken',
+ Child('LeftParen', kind='LeftParenToken',
is_optional=True),
Child('Modifier', kind='IdentifierToken',
is_optional=True),
- Child('CloseParen', kind='RightParenToken',
+ Child('RightParen', kind='RightParenToken',
is_optional=True),
]),
@@ -447,6 +456,7 @@
# (value)
Node('AccessorParameter', kind='Syntax',
+ traits=['Parenthesized'],
children=[
Child('LeftParen', kind='LeftParenToken'),
Child('Name', kind='IdentifierToken'),
@@ -467,7 +477,7 @@
Node('AccessorList', kind="SyntaxCollection", element='AccessorDecl'),
- Node('AccessorBlock', kind="Syntax", traits=['BracedSyntax'],
+ Node('AccessorBlock', kind="Syntax", traits=['Braced'],
children=[
Child('LeftBrace', kind='LeftBraceToken'),
Child('AccessorListOrStmtList', kind='Syntax',
@@ -479,6 +489,7 @@
# Pattern: Type = Value { get {} },
Node('PatternBinding', kind="Syntax",
+ traits=['WithTrailingComma'],
children=[
Child('Pattern', kind='Pattern'),
Child('TypeAnnotation', kind='TypeAnnotation', is_optional=True),
diff --git a/utils/gyb_syntax_support/ExprNodes.py b/utils/gyb_syntax_support/ExprNodes.py
index 0128f84..a54a057 100644
--- a/utils/gyb_syntax_support/ExprNodes.py
+++ b/utils/gyb_syntax_support/ExprNodes.py
@@ -59,6 +59,7 @@
Node('DeclNameArgumentList', kind='SyntaxCollection',
element='DeclNameArgument'),
Node('DeclNameArguments', kind='Syntax',
+ traits=['Parenthesized'],
children=[
Child('LeftParen', kind='LeftParenToken'),
Child('Arguments', kind='DeclNameArgumentList'),
@@ -181,6 +182,7 @@
]),
Node('TupleExpr', kind='Expr',
+ traits=['Parenthesized'],
children=[
Child('LeftParen', kind='LeftParenToken'),
Child('ElementList', kind='TupleElementList'),
@@ -218,6 +220,7 @@
# function-call-argument -> label? ':'? expression ','?
Node('FunctionCallArgument', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('Label', kind='IdentifierToken',
is_optional=True),
@@ -230,6 +233,7 @@
# An element inside a tuple element list
Node('TupleElement', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('Label', kind='IdentifierToken',
is_optional=True),
@@ -242,6 +246,7 @@
# element inside an array expression: expression ','?
Node('ArrayElement', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('Expression', kind='Expr'),
Child('TrailingComma', kind='CommaToken', is_optional=True),
@@ -249,6 +254,7 @@
# element inside an array expression: expression ','?
Node('DictionaryElement', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('KeyExpression', kind='Expr'),
Child('Colon', kind='ColonToken'),
@@ -338,6 +344,7 @@
]),
Node('ClosureCaptureItem', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child("Specifier", kind='TokenList', is_optional=True),
Child("Name", kind='IdentifierToken', is_optional=True),
@@ -357,6 +364,7 @@
]),
Node('ClosureParam', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('Name', kind='Token',
token_choices=[
@@ -384,7 +392,7 @@
]),
Node('ClosureExpr', kind='Expr',
- traits=['BracedSyntax'],
+ traits=['Braced', 'WithStatements'],
children=[
Child('LeftBrace', kind='LeftBraceToken'),
Child('Signature', kind='ClosureSignature', is_optional=True),
@@ -459,6 +467,7 @@
# expression segment in a string interpolation expression.
Node('ExpressionSegment', kind='Syntax',
+ traits=['Parenthesized'],
children=[
Child('Backslash', kind='BackslashToken'),
Child('LeftParen', kind='LeftParenToken'),
@@ -501,6 +510,7 @@
# e.g. "#keyPath(a.b.c)"
Node('ObjcKeyPathExpr', kind='Expr',
+ traits=['Parenthesized'],
children=[
Child('KeyPath', kind='PoundKeyPathToken'),
Child('LeftParen', kind='LeftParenToken'),
@@ -515,6 +525,7 @@
]),
# #fileLiteral(a, b, c)
Node('ObjectLiteralExpr', kind='Expr',
+ traits=['Parenthesized'],
children=[
Child('Identifier', kind='Token',
token_choices=[
diff --git a/utils/gyb_syntax_support/GenericNodes.py b/utils/gyb_syntax_support/GenericNodes.py
index b53b5cc..5019c56 100644
--- a/utils/gyb_syntax_support/GenericNodes.py
+++ b/utils/gyb_syntax_support/GenericNodes.py
@@ -15,6 +15,7 @@
# same-type-requirement -> type-identifier == type
Node('SameTypeRequirement', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('LeftTypeIdentifier', kind='Type'),
Child('EqualityToken', kind='Token',
@@ -34,6 +35,7 @@
# | type-name : type-identifier
# | type-name : protocol-composition-type
Node('GenericParameter', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('Attributes', kind='AttributeList',
is_optional=True),
@@ -56,6 +58,7 @@
# conformance-requirement -> type-identifier : type-identifier
Node('ConformanceRequirement', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('LeftTypeIdentifier', kind='Type'),
Child('Colon', kind='ColonToken'),
diff --git a/utils/gyb_syntax_support/PatternNodes.py b/utils/gyb_syntax_support/PatternNodes.py
index f8ebb5b..37ee30c 100644
--- a/utils/gyb_syntax_support/PatternNodes.py
+++ b/utils/gyb_syntax_support/PatternNodes.py
@@ -51,10 +51,11 @@
# tuple-pattern -> '(' tuple-pattern-element-list ')'
Node('TuplePattern', kind='Pattern',
+ traits=['Parenthesized'],
children=[
- Child('OpenParen', kind='LeftParenToken'),
+ Child('LeftParen', kind='LeftParenToken'),
Child('Elements', kind='TuplePatternElementList'),
- Child('CloseParen', kind='RightParenToken'),
+ Child('RightParen', kind='RightParenToken'),
]),
# wildcard-pattern -> '_' type-annotation?
@@ -67,13 +68,14 @@
# tuple-pattern-element -> identifier? ':' pattern ','?
Node('TuplePatternElement', kind='Syntax',
+ traits=['WithTrailingComma', 'Labeled'],
children=[
Child('LabelName', kind='IdentifierToken',
is_optional=True),
- Child('Colon', kind='ColonToken',
+ Child('LabelColon', kind='ColonToken',
is_optional=True),
Child('Pattern', kind='Pattern'),
- Child('Comma', kind='CommaToken',
+ Child('TrailingComma', kind='CommaToken',
is_optional=True),
]),
diff --git a/utils/gyb_syntax_support/StmtNodes.py b/utils/gyb_syntax_support/StmtNodes.py
index 09bdae6..3845029 100644
--- a/utils/gyb_syntax_support/StmtNodes.py
+++ b/utils/gyb_syntax_support/StmtNodes.py
@@ -12,6 +12,7 @@
# while-stmt -> label? ':'? 'while' condition-list code-block ';'?
Node('WhileStmt', kind='Stmt',
+ traits=['WithCodeBlock', 'Labeled'],
children=[
Child('LabelName', kind='IdentifierToken',
is_optional=True),
@@ -24,6 +25,7 @@
# defer-stmt -> 'defer' code-block ';'?
Node('DeferStmt', kind='Stmt',
+ traits=['WithCodeBlock'],
children=[
Child('DeferKeyword', kind='DeferToken'),
Child('Body', kind='CodeBlock'),
@@ -41,6 +43,7 @@
# repeat-while-stmt -> label? ':'? 'repeat' code-block 'while' expr ';'?
Node('RepeatWhileStmt', kind='Stmt',
+ traits=['WithCodeBlock', 'Labeled'],
children=[
Child('LabelName', kind='IdentifierToken',
is_optional=True),
@@ -54,6 +57,7 @@
# guard-stmt -> 'guard' condition-list 'else' code-block ';'?
Node('GuardStmt', kind='Stmt',
+ traits=['WithCodeBlock'],
children=[
Child('GuardKeyword', kind='GuardToken'),
Child('Conditions', kind='ConditionElementList'),
@@ -70,6 +74,7 @@
# for-in-stmt -> label? ':'? 'for' 'case'? pattern 'in' expr 'where'?
# expr code-block ';'?
Node('ForInStmt', kind='Stmt',
+ traits=['WithCodeBlock', 'Labeled'],
children=[
Child('LabelName', kind='IdentifierToken',
is_optional=True),
@@ -91,7 +96,7 @@
# switch-stmt -> identifier? ':'? 'switch' expr '{'
# switch-case-list '}' ';'?
Node('SwitchStmt', kind='Stmt',
- traits=['BracedSyntax'],
+ traits=['Braced', 'Labeled'],
children=[
Child('LabelName', kind='IdentifierToken',
is_optional=True),
@@ -110,6 +115,7 @@
# do-stmt -> identifier? ':'? 'do' code-block catch-clause-list ';'?
Node('DoStmt', kind='Stmt',
+ traits=['WithCodeBlock', 'Labeled'],
children=[
Child('LabelName', kind='IdentifierToken',
is_optional=True),
@@ -152,6 +158,7 @@
# | case-condition
# | optional-binding-condition
Node('ConditionElement', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('Condition', kind='Syntax',
node_choices=[
@@ -212,6 +219,7 @@
# if-stmt -> identifier? ':'? 'if' condition-list code-block
# else-clause ';'?
Node('IfStmt', kind='Stmt',
+ traits=['WithCodeBlock', 'Labeled'],
children=[
Child('LabelName', kind='IdentifierToken',
is_optional=True),
@@ -238,6 +246,7 @@
# else-clause -> 'else' code-block
Node('ElseBlock', kind='Syntax',
+ traits=['WithCodeBlock'],
children=[
Child('ElseKeyword', kind='ElseToken'),
Child('Body', kind='CodeBlock'),
@@ -246,9 +255,10 @@
# switch-case -> switch-case-label stmt-list
# | default-label stmt-list
Node('SwitchCase', kind='Syntax',
+ traits=['WithStatements'],
children=[
Child('Label', kind='Syntax'),
- Child('Body', kind='CodeBlockItemList'),
+ Child('Statements', kind='CodeBlockItemList'),
]),
# switch-default-label -> 'default' ':'
@@ -260,11 +270,12 @@
# case-item -> pattern where-clause? ','?
Node('CaseItem', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('Pattern', kind='Pattern'),
Child('WhereClause', kind='WhereClause',
is_optional=True),
- Child('Comma', kind='CommaToken',
+ Child('TrailingComma', kind='CommaToken',
is_optional=True),
]),
diff --git a/utils/gyb_syntax_support/Traits.py b/utils/gyb_syntax_support/Traits.py
index 6452a13..dfd104c 100644
--- a/utils/gyb_syntax_support/Traits.py
+++ b/utils/gyb_syntax_support/Traits.py
@@ -8,7 +8,7 @@
TRAITS = [
- Trait('DeclGroupSyntax',
+ Trait('DeclGroup',
children=[
Child('Attributes', kind='AttributeList', is_optional=True),
Child('AccessLevelModifier', kind='DeclModifier',
@@ -16,14 +16,41 @@
Child('Members', kind='MemberDeclBlock'),
]),
- Trait('BracedSyntax',
+ Trait('Braced',
children=[
Child('LeftBrace', kind='LeftBraceToken'),
Child('RightBrace', kind='RightBraceToken'),
]),
- Trait('IdentifiedDeclSyntax',
+ Trait('IdentifiedDecl',
children=[
Child('Identifier', kind='IdentifierToken'),
]),
+
+ Trait('WithCodeBlock',
+ children=[
+ Child('Body', kind='CodeBlock'),
+ ]),
+
+ Trait('Parenthesized',
+ children=[
+ Child('LeftParen', kind='LeftParenToken'),
+ Child('RightParen', kind='RightParenToken'),
+ ]),
+
+ Trait('WithTrailingComma',
+ children=[
+ Child('TrailingComma', kind='CommaToken', is_optional=True),
+ ]),
+
+ Trait('Labeled',
+ children=[
+ Child('LabelName', kind='IdentifierToken', is_optional=True),
+ Child('LabelColon', kind='ColonToken', is_optional=True),
+ ]),
+
+ Trait('WithStatements',
+ children=[
+ Child('Statements', kind='CodeBlockItemList'),
+ ]),
]
diff --git a/utils/gyb_syntax_support/TypeNodes.py b/utils/gyb_syntax_support/TypeNodes.py
index 38d0326..bbdc032 100644
--- a/utils/gyb_syntax_support/TypeNodes.py
+++ b/utils/gyb_syntax_support/TypeNodes.py
@@ -101,6 +101,7 @@
# tuple-type-element -> identifier? ':'? type-annotation ','?
Node('TupleTypeElement', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('InOut', kind='InOutToken',
is_optional=True),
@@ -133,6 +134,7 @@
# tuple-type -> '(' tuple-type-element-list ')'
Node('TupleType', kind='Type',
+ traits=['Parenthesized'],
children=[
Child('LeftParen', kind='LeftParenToken'),
Child('Elements', kind='TupleTypeElementList'),
@@ -143,6 +145,7 @@
# function-type -> attribute-list '(' function-type-argument-list ')'
# throwing-specifier? '->'? type?
Node('FunctionType', kind='Type',
+ traits=['Parenthesized'],
children=[
Child('LeftParen', kind='LeftParenToken'),
Child('Arguments', kind='TupleTypeElementList'),
@@ -178,6 +181,7 @@
# Dictionary<Int, String>
# ^~~~ ^~~~~~
Node('GenericArgument', kind='Syntax',
+ traits=['WithTrailingComma'],
children=[
Child('ArgumentType', kind='Type'),
Child('TrailingComma', kind='CommaToken',
diff --git a/utils/lldb/CMakeLists.txt b/utils/lldb/CMakeLists.txt
new file mode 100644
index 0000000..47cd0f7
--- /dev/null
+++ b/utils/lldb/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lldb-with-tools.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lldb-with-tools
+ @ONLY)
+
+file(COPY ${CMAKE_CURRENT_BINARY_DIR}/lldb-with-tools
+ DESTINATION "${SWIFT_RUNTIME_OUTPUT_INTDIR}"
+ FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
+ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
diff --git a/utils/lldb/lldb-with-tools.in b/utils/lldb/lldb-with-tools.in
new file mode 100644
index 0000000..907a959
--- /dev/null
+++ b/utils/lldb/lldb-with-tools.in
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+lldb -O 'command script import "@SWIFT_SOURCE_DIR@/utils/lldb/lldbToolBox.py"' $@
diff --git a/utils/lldb/lldbToolBox.py b/utils/lldb/lldbToolBox.py
new file mode 100644
index 0000000..d5abddc
--- /dev/null
+++ b/utils/lldb/lldbToolBox.py
@@ -0,0 +1,58 @@
+"""
+LLDB Helpers for working with the swift compiler.
+
+Load into LLDB with 'command script import /path/to/lldbToolBox.py'
+
+This will also import LLVM data formatters as well, assuming that llvm is next
+to the swift checkout.
+"""
+
+import os
+import subprocess
+import tempfile
+
+REPO_BASE = os.path.abspath(os.path.join(__file__, os.pardir, os.pardir,
+ os.pardir, os.pardir))
+SWIFT_REPO = os.path.join(REPO_BASE, "swift")
+LLVM_REPO = os.path.join(REPO_BASE, "llvm")
+LLVM_DATAFORMATTER_PATH = os.path.join(LLVM_REPO, "utils",
+ "lldbDataFormatters.py")
+
+
+def import_llvm_dataformatters(debugger):
+ if not os.access(LLVM_DATAFORMATTER_PATH, os.F_OK):
+ print("WARNING! Could not find LLVM data formatters!")
+ return
+ cmd = 'command script import {}'.format(LLVM_DATAFORMATTER_PATH)
+ debugger.HandleCommand(cmd)
+ print("Loaded LLVM data formatters.")
+
+
+VIEWCFG_PATH = os.path.join(SWIFT_REPO, "utils", "viewcfg")
+BLOCKIFYASM_PATH = os.path.join(SWIFT_REPO, "utils", "dev-scripts",
+ "blockifyasm")
+
+
+def create_swift_disassemble_viewcfg(debugger, command, exec_ctx, result,
+ internal_dict):
+ """
+ This function disassembles the current assembly frame into a temporary file
+ and then uses that temporary file as input to blockifyasm | viewcfg. This
+ will cause a pdf of the cfg to be opened on Darwin.
+ """
+ d = exec_ctx.frame.Disassemble()
+
+ with tempfile.TemporaryFile() as f:
+ f.write(d)
+ f.flush()
+ f.seek(0)
+ p1 = subprocess.Popen([BLOCKIFYASM_PATH], stdin=f,
+ stdout=subprocess.PIPE)
+ subprocess.Popen([VIEWCFG_PATH], stdin=p1.stdout)
+ p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.
+
+
+def __lldb_init_module(debugger, internal_dict):
+ import_llvm_dataformatters(debugger)
+ debugger.HandleCommand('command script add disassemble-asm-cfg '
+ '-f lldbToolBox.create_swift_disassemble_viewcfg')
diff --git a/utils/lldbToolBox.py b/utils/lldbToolBox.py
deleted file mode 100644
index 412eae1..0000000
--- a/utils/lldbToolBox.py
+++ /dev/null
@@ -1,30 +0,0 @@
-"""
-LLDB Helpers for working with the swift compiler.
-
-Load into LLDB with 'command script import /path/to/lldbToolBox.py'
-
-This will also import LLVM data formatters as well, assuming that llvm is next
-to the swift checkout.
-"""
-
-import os
-
-REPO_BASE = os.path.abspath(os.path.join(__file__, os.pardir, os.pardir,
- os.pardir))
-SWIFT_REPO = os.path.join(REPO_BASE, "swift")
-LLVM_REPO = os.path.join(REPO_BASE, "llvm")
-LLVM_DATAFORMATTER_PATH = os.path.join(LLVM_REPO, "utils",
- "lldbDataFormatters.py")
-
-
-def import_llvm_dataformatters(debugger):
- if not os.access(LLVM_DATAFORMATTER_PATH, os.F_OK):
- print("WARNING! Could not find LLVM data formatters!")
- return
- cmd = 'command script import {}'.format(LLVM_DATAFORMATTER_PATH)
- debugger.HandleCommand(cmd)
- print("Loaded LLVM data formatters.")
-
-
-def __lldb_init_module(debugger, internal_dict):
- import_llvm_dataformatters(debugger)
diff --git a/utils/sil-mode.el b/utils/sil-mode.el
index 54e025b..0da9cc5 100644
--- a/utils/sil-mode.el
+++ b/utils/sil-mode.el
@@ -151,7 +151,7 @@
"unchecked_bitwise_cast"
"ref_to_raw_pointer" "raw_pointer_to_ref"
"unowned_to_ref" "ref_to_unowned"
- "convert_function"
+ "convert_function" "convert_escape_to_noescape"
"ref_to_unmanaged" "unmanaged_to_ref"
"thin_function_to_pointer" "pointer_to_thin_function"
"ref_to_bridge_object"
diff --git a/utils/static-executable-args.lnk b/utils/static-executable-args.lnk
index 2c158a4..0d34ebd 100644
--- a/utils/static-executable-args.lnk
+++ b/utils/static-executable-args.lnk
@@ -1,6 +1,5 @@
-static
-lswiftCore
--lswiftImageInspectionStatic
-Xlinker
--defsym=__import_pthread_self=pthread_self
-Xlinker
diff --git a/validation-test/Driver/Dependencies/Inputs/rdar23148987/helper-1.swift b/validation-test/Driver/Dependencies/Inputs/rdar23148987/helper-1.swift
new file mode 100644
index 0000000..0b907bb
--- /dev/null
+++ b/validation-test/Driver/Dependencies/Inputs/rdar23148987/helper-1.swift
@@ -0,0 +1,3 @@
+public class Test {
+ func foo() {}
+}
\ No newline at end of file
diff --git a/validation-test/Driver/Dependencies/Inputs/rdar23148987/helper-2.swift b/validation-test/Driver/Dependencies/Inputs/rdar23148987/helper-2.swift
new file mode 100644
index 0000000..fd2643d
--- /dev/null
+++ b/validation-test/Driver/Dependencies/Inputs/rdar23148987/helper-2.swift
@@ -0,0 +1,3 @@
+public final class Test {
+ func foo() {}
+}
\ No newline at end of file
diff --git a/validation-test/Driver/Dependencies/Inputs/rdar23148987/output.json b/validation-test/Driver/Dependencies/Inputs/rdar23148987/output.json
new file mode 100644
index 0000000..7971d0c
--- /dev/null
+++ b/validation-test/Driver/Dependencies/Inputs/rdar23148987/output.json
@@ -0,0 +1,13 @@
+{
+ "./helper.swift": {
+ "object": "./helper.o",
+ "swift-dependencies": "./helper.swiftdeps",
+ },
+ "./main.swift": {
+ "object": "./main.o",
+ "swift-dependencies": "./main.swiftdeps",
+ },
+ "": {
+ "swift-dependencies": "./main~buildrecord.swiftdeps"
+ }
+}
diff --git a/validation-test/Driver/Dependencies/rdar23148987.swift b/validation-test/Driver/Dependencies/rdar23148987.swift
new file mode 100644
index 0000000..186d740
--- /dev/null
+++ b/validation-test/Driver/Dependencies/rdar23148987.swift
@@ -0,0 +1,61 @@
+// RUN: %empty-directory(%t)
+
+// RUN: cp %s %t/main.swift
+// RUN: cp %S/Inputs/rdar23148987/helper-1.swift %t/helper.swift
+// RUN: touch -t 201401240005 %t/*.swift
+
+// RUN: cd %t && %target-build-swift -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-1 %s
+
+// CHECK-1-NOT: warning
+// CHECK-1: {{^{$}}
+// CHECK-1: "kind": "began"
+// CHECK-1: "name": "compile"
+// CHECK-1: ".\/main.swift"
+// CHECK-1: {{^}$}}
+
+// CHECK-1: {{^{$}}
+// CHECK-1: "kind": "began"
+// CHECK-1: "name": "compile"
+// CHECK-1: ".\/helper.swift"
+// CHECK-1: {{^}$}}
+
+// RUN: ls %t/ | %FileCheck -check-prefix=CHECK-LS %s
+
+// CHECK-LS-DAG: main.o
+// CHECK-LS-DAG: helper.o
+
+// RUN: cd %t && %target-build-swift -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-1-SKIPPED %s
+
+// CHECK-1-SKIPPED-NOT: warning
+// CHECK-1-SKIPPED: {{^{$}}
+// CHECK-1-SKIPPED: "kind": "skipped"
+// CHECK-1-SKIPPED: "name": "compile"
+// CHECK-1-SKIPPED: ".\/main.swift"
+// CHECK-1-SKIPPED: {{^}$}}
+
+// CHECK-1-SKIPPED: {{^{$}}
+// CHECK-1-SKIPPED: "kind": "skipped"
+// CHECK-1-SKIPPED: "name": "compile"
+// CHECK-1-SKIPPED: ".\/helper.swift"
+// CHECK-1-SKIPPED: {{^}$}}
+
+// RUN: cp %S/Inputs/rdar23148987/helper-2.swift %t/helper.swift
+// RUN: touch -t 201401240006 %t/helper.swift
+// RUN: cd %t && %target-build-swift -c -incremental -output-file-map %S/Inputs/rdar23148987/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | %FileCheck -check-prefix=CHECK-2 %s
+
+// CHECK-2-NOT: warning
+// CHECK-2: {{^{$}}
+// CHECK-2: "kind": "began"
+// CHECK-2: "name": "compile"
+// CHECK-2: ".\/helper.swift"
+// CHECK-2: {{^}$}}
+
+// CHECK-2: {{^{$}}
+// CHECK-2: "kind": "began"
+// CHECK-2: "name": "compile"
+// CHECK-2: ".\/main.swift"
+// CHECK-2: {{^}$}}
+
+func test(obj: Test) {
+ obj.foo()
+}
diff --git a/validation-test/stdlib/Algorithm.swift b/validation-test/stdlib/Algorithm.swift
index 90076bd..8df47d2 100644
--- a/validation-test/stdlib/Algorithm.swift
+++ b/validation-test/stdlib/Algorithm.swift
@@ -74,10 +74,7 @@
expectEqual(c1.identity, max(a1, b1, c2, c1).identity)
}
-Algorithm.test("sorted/strings")
- .xfail(.nativeRuntime("String comparison: ICU vs. Foundation " +
- "https://bugs.swift.org/browse/SR-530"))
- .code {
+Algorithm.test("sorted/strings") {
expectEqual(
["Banana", "apple", "cherry"],
["apple", "Banana", "cherry"].sorted())
diff --git a/validation-test/stdlib/String.swift b/validation-test/stdlib/String.swift
index 082b30e..7d8885e 100644
--- a/validation-test/stdlib/String.swift
+++ b/validation-test/stdlib/String.swift
@@ -1,12 +1,21 @@
-// RUN: %target-run-simple-swift
-// REQUIRES: executable_test
+// RUN: %empty-directory(%t)
+// RUN: if [ %target-runtime == "objc" ]; \
+// RUN: then \
+// RUN: %target-clang -fobjc-arc %S/Inputs/NSSlowString/NSSlowString.m -c -o %t/NSSlowString.o && \
+// RUN: %target-build-swift -I %S/Inputs/NSSlowString/ %t/NSSlowString.o %s -Xfrontend -disable-access-control -o %t/String; \
+// RUN: else \
+// RUN: %target-build-swift %s -Xfrontend -disable-access-control -o %t/String; \
+// RUN: fi
+// RUN: %target-run %t/String
+// REQUIRES: executable_test
// XFAIL: interpret
import StdlibUnittest
import StdlibCollectionUnittest
#if _runtime(_ObjC)
+import NSSlowString
import Foundation // For NSRange
#endif
@@ -1138,7 +1147,7 @@
s2 = s
}
expectEqual(s2, s)
- expectLE(s.nativeCapacity, 34)
+ expectLE(s.nativeCapacity, 40)
}
StringTests.test("Construction") {
@@ -1165,24 +1174,6 @@
}
}
-// Check the internal functions are correct for ASCII values
-StringTests.test(
- "forall x: Int8, y: Int8 . x < 128 ==> x <ascii y == x <unicode y")
- .skip(.nativeRuntime("String._compareASCII undefined without _runtime(_ObjC)"))
- .code {
-#if _runtime(_ObjC)
- let asciiValues: [(value: UInt8, string: String)] = (0..<128).map {
- ($0, String(UnicodeScalar($0)))
- }
- for (v1, s1) in asciiValues {
- for (v2, s2) in asciiValues {
- expectEqual(s1 < s2, v1 < v2)
- }
- }
-#else
- expectUnreachable()
-#endif
-}
#if os(Linux) || os(FreeBSD) || os(PS4) || os(Android)
import Glibc
@@ -1937,4 +1928,158 @@
}
}
+struct ComparisonTestCase {
+ var strings: [String]
+ // var test: (String, String) -> Void
+ var comparison: _Ordering
+
+ init(_ strings: [String], _ comparison: _Ordering) {
+ self.strings = strings
+ self.comparison = comparison
+ }
+
+ func test() {
+ for pair in zip(strings, strings[1...]) {
+ switch comparison {
+ case .less:
+ expectLT(pair.0, pair.1)
+ case .greater:
+ expectGT(pair.0, pair.1)
+ case .equal:
+ expectEqual(pair.0, pair.1)
+ }
+ }
+ }
+
+ func testOpaqueStrings() {
+#if _runtime(_ObjC)
+ let opaqueStrings = strings.map { NSSlowString(string: $0) as String }
+ for pair in zip(opaqueStrings, opaqueStrings[1...]) {
+ switch comparison {
+ case .less:
+ expectLT(pair.0, pair.1)
+ case .greater:
+ expectGT(pair.0, pair.1)
+ case .equal:
+ expectEqual(pair.0, pair.1)
+ }
+ }
+#endif
+ }
+
+ func testOpaqueSubstrings() {
+#if _runtime(_ObjC)
+ for pair in zip(strings, strings[1...]) {
+ let string1 = pair.0.dropLast()
+ let string2 = pair.1
+ let opaqueString = (NSSlowString(string: pair.0) as String).dropLast()
+
+ guard string1.count > 0 else { return }
+
+ let expectedResult: _Ordering = string1 < string2 ? .less : (string1 > string2 ? .greater : .equal)
+ let opaqueResult: _Ordering = opaqueString < string2 ? .less : (opaqueString > string2 ? .greater : .equal)
+
+ expectEqual(opaqueResult, expectedResult)
+ }
+#endif
+ }
+}
+
+let comparisonTestCases = [
+ ComparisonTestCase(["a", "a"], .equal),
+ ComparisonTestCase(["abcdefg", "abcdefg"], .equal),
+ ComparisonTestCase(["", "Z", "a", "b", "c", "\u{00c5}", "á"], .less),
+
+ ComparisonTestCase(["ábcdefg", "ábcdefgh", "ábcdefghi"], .less),
+ ComparisonTestCase(["abcdefg", "abcdefgh", "abcdefghi"], .less),
+
+ ComparisonTestCase(["á", "\u{0061}\u{0301}"], .equal),
+ ComparisonTestCase(["à", "\u{0061}\u{0301}", "â", "\u{e3}", "a\u{0308}"], .less),
+
+ // Exploding scalars AND exploding segments
+ ComparisonTestCase(["\u{fa2}", "\u{fa1}\u{fb7}"], .equal),
+ ComparisonTestCase([
+ "\u{fa2}\u{fa2}\u{fa2}\u{fa2}",
+ "\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}"
+ ], .equal),
+ ComparisonTestCase([
+ "\u{fa2}\u{fa2}\u{fa2}\u{fa2}\u{fa2}\u{fa2}\u{fa2}\u{fa2}",
+ "\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}"
+ ], .equal),
+ ComparisonTestCase([
+ "a\u{fa2}\u{fa2}a\u{fa2}\u{fa2}\u{fa2}\u{fa2}\u{fa2}\u{fa2}",
+ "a\u{fa1}\u{fb7}\u{fa1}\u{fb7}a\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}\u{fa1}\u{fb7}"
+ ], .equal),
+
+ ComparisonTestCase(["😀", "😀"], .equal),
+ ComparisonTestCase(["\u{2f9df}", "\u{8f38}"], .equal),
+ ComparisonTestCase([
+ "a",
+ "\u{2f9df}", // D87E DDDF as written, but normalizes to 8f38
+ "\u{2f9df}\u{2f9df}", // D87E DDDF as written, but normalizes to 8f38
+ "👨🏻", // D83D DC68 D83C DFFB
+ "👨🏻⚕️", // D83D DC68 D83C DFFB 200D 2695 FE0F
+ "👩⚕️", // D83D DC69 200D 2695 FE0F
+ "👩🏾", // D83D DC69 D83C DFFE
+ "👩🏾⚕", // D83D DC69 D83C DFFE 200D 2695 FE0F
+ "😀", // D83D DE00
+ "😅", // D83D DE05
+ "🧀" // D83E DDC0 -- aka a really big scalar
+ ], .less),
+
+
+ ComparisonTestCase(["f̛̗̘̙̜̹̺̻̼͇͈͉͍͎̽̾̿̀́͂̓̈́͆͊͋͌̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦ͘͜͟͢͝͞͠͡", "ơ̗̘̙̜̹̺̻̼͇͈͉͍͎̽̾̿̀́͂̓̈́͆͊͋͌̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͥͦͧͨͩͪͫͬͭͮ͘"], .less),
+ ComparisonTestCase(["\u{f90b}", "\u{5587}"], .equal),
+
+ ComparisonTestCase(["a\u{1D160}a", "a\u{1D158}\u{1D1C7}"], .less),
+
+ ComparisonTestCase(["\u{212b}", "\u{00c5}"], .equal),
+ ComparisonTestCase([
+ "A",
+ "a",
+ "aa",
+ "ae",
+ "ae🧀",
+ "az",
+ "aze\u{300}",
+ "ae\u{301}",
+ "ae\u{301}ae\u{301}",
+ "ae\u{301}ae\u{301}ae\u{301}",
+ "ae\u{301}ae\u{301}ae\u{301}ae\u{301}",
+ "ae\u{301}ae\u{301}ae\u{301}ae\u{301}ae\u{301}",
+ "ae\u{301}ae\u{301}ae\u{301}ae\u{301}ae\u{301}ae\u{301}",
+ "ae\u{301}ae\u{301}ae\u{301}ae\u{301}ae\u{301}ae\u{301}ae\u{301}",
+ "ae\u{301}ae\u{301}ae\u{301}ae\u{301}ae\u{301}ae\u{301}ae\u{301}ae\u{301}",
+ "ae\u{302}",
+ "ae\u{302}{303}",
+ "ae\u{302}🧀",
+ "ae\u{303}",
+ "\u{f90b}\u{f90c}\u{f90d}", // Normalizes to BMP scalars
+ "🧀", // D83E DDC0 -- aka a really big scalar
+ "\u{FFEE}" // half width CJK dot
+ ], .less),
+
+ ComparisonTestCase(["ư̴̵̶̷̸̗̘̙̜̹̺̻̼͇͈͉͍͎̽̾̿̀́͂̓̈́͆͊͋͌̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦͧͨͩͪͫͬͭͮ͘͜͟͢͝͞͠͡", "ì̡̢̧̨̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̹̺̻̼͇͈͉͍͎́̂̃̄̉̊̋̌̍̎̏̐̑̒̓̽̾̿̀́͂̓̈́͆͊͋͌ͅ͏͓͔͕͖͙͐͑͒͗ͬͭͮ͘"], .greater),
+ ComparisonTestCase(["ư̴̵̶̷̸̗̘̙̜̹̺̻̼͇͈͉͍͎̽̾̿̀́͂̓̈́͆͊͋͌̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦͧͨͩͪͫͬͭͮ͘͜͟͢͝͞͠͡", "aì̡̢̧̨̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̹̺̻̼͇͈͉͍͎́̂̃̄̉̊̋̌̍̎̏̐̑̒̓̽̾̿̀́͂̓̈́͆͊͋͌ͅ͏͓͔͕͖͙͐͑͒͗ͬͭͮ͘"], .greater),
+ ComparisonTestCase(["ì̡̢̧̨̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̹̺̻̼͇͈͉͍͎́̂̃̄̉̊̋̌̍̎̏̐̑̒̓̽̾̿̀́͂̓̈́͆͊͋͌ͅ͏͓͔͕͖͙͐͑͒͗ͬͭͮ͘", "ì̡̢̧̨̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̹̺̻̼͇͈͉͍͎́̂̃̄̉̊̋̌̍̎̏̐̑̒̓̽̾̿̀́͂̓̈́͆͊͋͌ͅ͏͓͔͕͖͙͐͑͒͗ͬͭͮ͘"], .equal)
+]
+
+for test in comparisonTestCases {
+ StringTests.test("Comparison.\(test.strings)") {
+ test.test()
+ }
+
+ StringTests.test("Comparison.OpaqueString.\(test.strings)")
+ .skip(.linuxAny(reason: "NSSlowString requires ObjC interop"))
+ .code {
+ test.testOpaqueStrings()
+ }
+
+ StringTests.test("Comparison.OpaqueSubstring.\(test.strings)")
+ .skip(.linuxAny(reason: "NSSlowString requires ObjC interop"))
+ .code {
+ test.testOpaqueSubstrings()
+ }
+}
+
runAllTests()
diff --git a/validation-test/stdlib/StringHashableComparable.swift.gyb b/validation-test/stdlib/StringHashableComparable.swift.gyb
deleted file mode 100644
index 63d9715..0000000
--- a/validation-test/stdlib/StringHashableComparable.swift.gyb
+++ /dev/null
@@ -1,97 +0,0 @@
-// RUN: %target-run-simple-swiftgyb
-// REQUIRES: executable_test
-
-// This test requires that the standard library calls ICU
-// directly. It is not specific to Linux, it is just that on
-// Apple platforms we are using the NSString bridge right now.
-
-// REQUIRES: OS=linux-gnu
-
-import StdlibUnittest
-import StdlibUnicodeUnittest
-
-func assertASCIIRepresentationIfPossible(_ s: String) {
- for us in s.unicodeScalars {
- if !us.isASCII {
- return
- }
- }
- precondition(s._guts.isASCII)
-}
-
-func forceUTF16Representation(_ s: String) -> String {
- var s = s
- s += "\u{fffd}"
- s.removeSubrange(s.index(before: s.endIndex)..<s.endIndex)
- precondition(!s._guts.isASCII)
- return s
-}
-
-func calculateSortOrder(_ tests: inout [StringComparisonTest]) {
- tests.sort {
- collationElements(
- $0.collationElements,
- areLessThan: $1.collationElements
- )
- }
-
- tests[0].order = 0
- for i in tests.indices.dropFirst() {
- if collationElements(
- tests[i - 1].collationElements,
- areLessThan: tests[i].collationElements
- ) {
- tests[i].order = tests[i - 1].order! + 1
- } else {
- tests[i].order = tests[i - 1].order!
- }
- }
-}
-
-func checkStringHashableComparable(
- _ tests: [StringComparisonTest],
- stackTrace: SourceLocStack = SourceLocStack(),
- file: String = #file, line: UInt = #line
-) {
- var tests = tests
- calculateSortOrder(&tests)
-
- func comparisonOracle(_ i: Int, _ j: Int) -> ExpectedComparisonResult {
- return tests[i].order! <=> tests[j].order!
- }
-
- checkHashable(
- tests.map { $0.string },
- equalityOracle: { comparisonOracle($0, $1).isEQ() },
- stackTrace: stackTrace.pushIf(true, file: file, line: line))
-
- checkComparable(
- tests.map { $0.string },
- oracle: comparisonOracle,
- stackTrace: stackTrace.pushIf(true, file: file, line: line))
-}
-
-var StringTests = TestSuite("StringTests")
-
-StringTests.test("StringComparisonTest.allTests: tests are in ASCII representation")
- .forEach(in: StringComparisonTest.allTests) {
- test in
- assertASCIIRepresentationIfPossible(test.string)
-}
-
-StringTests.test("Comparable") {
- let allTestsInUTF16Representation = StringComparisonTest.allTests.map {
- test -> StringComparisonTest in
- return StringComparisonTest(
- forceUTF16Representation(test.string),
- test.collationElements,
- sourceLocation: SourceLoc(
- test.loc.file,
- test.loc.line,
- comment: (test.loc.comment ?? "") + "\nin Unicode representation"))
- }
- checkStringHashableComparable(StringComparisonTest.allTests + allTestsInUTF16Representation)
-}
-
-runAllTests()
-