diff --git a/.gitignore b/.gitignore index 1a68ee4f5b2e8..7f1565d805924 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,8 @@ #==============================================================================# cscope.files cscope.out +.vimrc +tags #==============================================================================# # Directories to ignore (do not add trailing '/'s, they skip symlinks). diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ecf99ac0a3ec..4c704388cd3dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -476,31 +476,17 @@ if(CMAKE_C_COMPILER_ID MATCHES Clang) add_compile_options($<$,$>:-Werror=gnu>) endif() -if(CMAKE_SYSTEM_NAME STREQUAL Darwin OR - EXISTS "${SWIFT_PATH_TO_LIBDISPATCH_SOURCE}") - set(SWIFT_BUILD_SYNTAXPARSERLIB_default TRUE) - set(SWIFT_BUILD_SOURCEKIT_default TRUE) -else() - set(SWIFT_BUILD_SYNTAXPARSERLIB_default FALSE) - set(SWIFT_BUILD_SOURCEKIT_default FALSE) -endif() -option(SWIFT_BUILD_SYNTAXPARSERLIB - "Build the Swift Syntax Parser library" - ${SWIFT_BUILD_SYNTAXPARSERLIB_default}) -option(SWIFT_BUILD_ONLY_SYNTAXPARSERLIB - "Only build the Swift Syntax Parser library" FALSE) -option(SWIFT_BUILD_SOURCEKIT - "Build SourceKit" - ${SWIFT_BUILD_SOURCEKIT_default}) -option(SWIFT_ENABLE_SOURCEKIT_TESTS - "Enable running SourceKit tests" - ${SWIFT_BUILD_SOURCEKIT_default}) - -if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin" AND - (SWIFT_BUILD_SYNTAXPARSERLIB OR SWIFT_BUILD_SOURCEKIT)) - set(SWIFT_NEED_EXPLICIT_LIBDISPATCH TRUE) -else() - set(SWIFT_NEED_EXPLICIT_LIBDISPATCH FALSE) +option(SWIFT_BUILD_SYNTAXPARSERLIB "Build the Swift Syntax Parser library" TRUE) +option(SWIFT_BUILD_ONLY_SYNTAXPARSERLIB "Only build the Swift Syntax Parser library" FALSE) +option(SWIFT_BUILD_SOURCEKIT "Build SourceKit" TRUE) +option(SWIFT_ENABLE_SOURCEKIT_TESTS "Enable running SourceKit tests" ${SWIFT_BUILD_SOURCEKIT}) + +if(SWIFT_BUILD_SYNTAXPARSERLIB OR SWIFT_BUILD_SOURCEKIT) + if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + if(NOT EXISTS "${SWIFT_PATH_TO_LIBDISPATCH_SOURCE}") + message(SEND_ERROR "SyntaxParserLib and SourceKit require libdispatch on non-Darwin hosts. Please specify SWIFT_PATH_TO_LIBDISPATCH_SOURCE") + endif() + endif() endif() # @@ -982,7 +968,7 @@ if (LLVM_ENABLE_DOXYGEN) message(STATUS "Doxygen: enabled") endif() -if(SWIFT_NEED_EXPLICIT_LIBDISPATCH) +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) if(CMAKE_C_COMPILER_ID STREQUAL Clang AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 3.8 OR LLVM_USE_SANITIZER) diff --git a/README.md b/README.md index 70f2318aebc0c..81d7fec3b582e 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,10 @@ There are two primary build systems to use: Xcode and Ninja. The Xcode build system allows you to work in Xcode, but Ninja is a bit faster and supports more environments. +First, make sure that you're in the swift directory: + + cd swift + To build using Ninja, run: swift/utils/build-script --enable-tensorflow --release-debuginfo @@ -127,7 +131,7 @@ the entire project in debug, you can run: For documentation of all available arguments, as well as additional usage information, see the inline help: - swift/utils/build-script -h + utils/build-script -h ### Customize TensorFlow support diff --git a/benchmark/single-source/NSStringConversion.swift b/benchmark/single-source/NSStringConversion.swift index 40ef7319d18a1..9b51720861c3e 100644 --- a/benchmark/single-source/NSStringConversion.swift +++ b/benchmark/single-source/NSStringConversion.swift @@ -17,6 +17,7 @@ import TestsUtils import Foundation fileprivate var test:NSString = "" +fileprivate var mutableTest = "" public let NSStringConversion = [ BenchmarkInfo(name: "NSStringConversion", @@ -65,7 +66,44 @@ public let NSStringConversion = [ BenchmarkInfo(name: "NSStringConversion.Rebridge.LongUTF8", runFunction: run_NSStringConversion_longNonASCII_rebridge, tags: [.validation, .api, .String, .bridging], - setUpFunction: { test = NSString(cString: "Thë qüick bröwn föx jumps over the lazy dög", encoding: String.Encoding.utf8.rawValue)! })] + setUpFunction: { test = NSString(cString: "Thë qüick bröwn föx jumps over the lazy dög", encoding: String.Encoding.utf8.rawValue)! } ), + BenchmarkInfo(name: "NSStringConversion.MutableCopy.UTF8", + runFunction: run_NSStringConversion_nonASCIIMutable, + tags: [.validation, .api, .String, .bridging], + setUpFunction: { mutableTest = "tëst" }), + BenchmarkInfo(name: "NSStringConversion.MutableCopy.Medium", + runFunction: run_NSStringConversion_mediumMutable, + tags: [.validation, .api, .String, .bridging], + setUpFunction: { mutableTest = "aaaaaaaaaaaaaaa" } ), + BenchmarkInfo(name: "NSStringConversion.MutableCopy.Long", + runFunction: run_NSStringConversion_longMutable, + tags: [.validation, .api, .String, .bridging], + setUpFunction: { mutableTest = "The quick brown fox jumps over the lazy dog" } ), + BenchmarkInfo(name: "NSStringConversion.MutableCopy.LongUTF8", + runFunction: run_NSStringConversion_longNonASCIIMutable, + tags: [.validation, .api, .String, .bridging], + setUpFunction: { mutableTest = "Thë qüick bröwn föx jumps over the lazy dög" } ), + BenchmarkInfo(name: "NSStringConversion.MutableCopy.Rebridge", + runFunction: run_NSStringConversion_rebridgeMutable, + tags: [.validation, .api, .String, .bridging], + setUpFunction: { mutableTest = "test" }), + BenchmarkInfo(name: "NSStringConversion.MutableCopy.Rebridge.UTF8", + runFunction: run_NSStringConversion_nonASCII_rebridgeMutable, + tags: [.validation, .api, .String, .bridging], + setUpFunction: { mutableTest = "tëst" }), + BenchmarkInfo(name: "NSStringConversion.MutableCopy.Rebridge.Medium", + runFunction: run_NSStringConversion_medium_rebridgeMutable, + tags: [.validation, .api, .String, .bridging], + setUpFunction: { mutableTest = "aaaaaaaaaaaaaaa" } ), + BenchmarkInfo(name: "NSStringConversion.MutableCopy.Rebridge.Long", + runFunction: run_NSStringConversion_long_rebridgeMutable, + tags: [.validation, .api, .String, .bridging], + setUpFunction: { mutableTest = "The quick brown fox jumps over the lazy dog" } ), + BenchmarkInfo(name: "NSStringConversion.MutableCopy.Rebridge.LongUTF8", + runFunction: run_NSStringConversion_longNonASCII_rebridgeMutable, + tags: [.validation, .api, .String, .bridging], + setUpFunction: { mutableTest = "Thë qüick bröwn föx jumps over the lazy dög" } ) +] public func run_NSStringConversion(_ N: Int) { let test:NSString = NSString(cString: "test", encoding: String.Encoding.ascii.rawValue)! @@ -103,6 +141,31 @@ public func run_NSStringConversion_longNonASCII(_ N: Int) { innerLoop(test, N, 300) } +fileprivate func innerMutableLoop(_ str: String, _ N: Int, _ scale: Int = 5000) { + for _ in 1...N * scale { + let copy = (str as NSString).mutableCopy() as! NSMutableString + for char in (identity(copy) as String).utf8 { + blackHole(char) + } + } +} + +public func run_NSStringConversion_nonASCIIMutable(_ N: Int) { + innerMutableLoop(mutableTest, N, 500) +} + +public func run_NSStringConversion_mediumMutable(_ N: Int) { + innerMutableLoop(mutableTest, N, 500) +} + +public func run_NSStringConversion_longMutable(_ N: Int) { + innerMutableLoop(mutableTest, N, 250) +} + +public func run_NSStringConversion_longNonASCIIMutable(_ N: Int) { + innerMutableLoop(mutableTest, N, 150) +} + fileprivate func innerRebridge(_ str: NSString, _ N: Int, _ scale: Int = 5000) { for _ in 1...N * scale { let bridged = identity(str) as String @@ -135,4 +198,33 @@ public func run_NSStringConversion_longNonASCII_rebridge(_ N: Int) { innerRebridge(test, N, 300) } +fileprivate func innerMutableRebridge(_ str: String, _ N: Int, _ scale: Int = 5000) { + for _ in 1...N * scale { + let copy = (str as NSString).mutableCopy() as! NSMutableString + let bridged = identity(copy) as String + blackHole(bridged) + blackHole(bridged as NSString) + } +} + +public func run_NSStringConversion_rebridgeMutable(_ N: Int) { + innerMutableRebridge(mutableTest, N, 1000) +} + +public func run_NSStringConversion_nonASCII_rebridgeMutable(_ N: Int) { + innerMutableRebridge(mutableTest, N, 500) +} + +public func run_NSStringConversion_medium_rebridgeMutable(_ N: Int) { + innerMutableRebridge(mutableTest, N, 500) +} + +public func run_NSStringConversion_long_rebridgeMutable(_ N: Int) { + innerMutableRebridge(mutableTest, N, 500) +} + +public func run_NSStringConversion_longNonASCII_rebridgeMutable(_ N: Int) { + innerMutableRebridge(mutableTest, N, 300) +} + #endif diff --git a/cmake/modules/StandaloneOverlay.cmake b/cmake/modules/StandaloneOverlay.cmake index 14829c59a5085..5a886c931e94e 100644 --- a/cmake/modules/StandaloneOverlay.cmake +++ b/cmake/modules/StandaloneOverlay.cmake @@ -10,7 +10,7 @@ endif() list(APPEND CMAKE_MODULE_PATH - "${SWIFT_SOURCE_ROOT}/llvm/cmake/modules" + "${SWIFT_SOURCE_ROOT}/llvm-project/llvm/cmake/modules" "${PROJECT_SOURCE_DIR}/../../../../cmake/modules" "${PROJECT_SOURCE_DIR}/../../../cmake/modules") diff --git a/cmake/modules/SwiftSource.cmake b/cmake/modules/SwiftSource.cmake index 941505c8d284b..770bbe53261ee 100644 --- a/cmake/modules/SwiftSource.cmake +++ b/cmake/modules/SwiftSource.cmake @@ -237,12 +237,8 @@ function(_compile_swift_files NOT "${SWIFTFILE_MODULE_NAME}" STREQUAL "DifferentiationUnittest") list(APPEND swift_flags "-enable-library-evolution") endif() - # FIXME(SR-11336): `-enable-ownership-stripping-after-serialization` for - # swiftCore causes test/AutoDiff/array.swift to crash, related to - # Array and key paths. - # Disabling the flag for swiftCore requires disabling the flag for all - # other standard library modules. - # list(APPEND swift_flags "-Xfrontend" "-enable-ownership-stripping-after-serialization") + # SWIFT_ENABLE_TENSORFLOW END + list(APPEND swift_flags "-Xfrontend" "-enable-ownership-stripping-after-serialization") endif() if(SWIFT_STDLIB_USE_NONATOMIC_RC) diff --git a/docs/Android.md b/docs/Android.md index 112603ccdf82e..02ff3267d4bcc 100644 --- a/docs/Android.md +++ b/docs/Android.md @@ -42,7 +42,7 @@ To follow along with this guide, you'll need: turn on remote debugging by following the official instructions: https://developer.chrome.com/devtools/docs/remote-debugging. -## Part One: "Hello, world" on Android +## "Hello, world" on Android ### 1. Downloading (or building) the Swift Android stdlib dependencies @@ -189,7 +189,7 @@ Hello, Android Congratulations! You've just run your first Swift program on Android. -## Part Two: Running the Swift test suite hosted on an Android device +## Running the Swift test suite hosted on an Android device When running the test suite, build products are automatically pushed to your device. As in part one, you'll need to connect your Android device via USB: @@ -213,3 +213,19 @@ $ utils/build-script \ --android-icu-i18n ~/libicu-android/armeabi-v7a/libicui18n.so \ --android-icu-i18n-include ~/libicu-android/armeabi-v7a/icu/source/i18n/ ``` + +## Build Android Toolchain + +This toolchain will generate the .so and .swiftmodule files of the Swift standard library and Foundation framework for the Android environment, armv7 architecture. Those files are needed when building any Swift library to be included in an application for Android. + +To build the toolchain run: + +``` +$ utils/android/build-toolchain +``` + +It will be built on: + +``` +path/to/swift-source/swift-android-toolchain +``` diff --git a/docs/AndroidBuild.md b/docs/AndroidBuild.md new file mode 100644 index 0000000000000..03d5f9eddad27 --- /dev/null +++ b/docs/AndroidBuild.md @@ -0,0 +1,181 @@ +# Building Swift SDK for Android on Windows + +Visual Studio 2019 or newer is needed to build the Swift SDK for Android on +Windows. + +## 1. Install Dependencies +- Install the latest version of [Visual Studio](https://www.visualstudio.com/downloads/) +- Make sure to include the android NDK in your installation. + +## 1. Clone the repositories +1. Configure git to work with Unix file endings +1. Clone `apple/swift-llvm` into a directory named `llvm` +1. Clone `apple/swift-corelibs-libdispatch` into a directory named `swift-corelibs-libdispatch` +1. Clone `apple/swift-corelibs-foundation` into a directory named `swift-corelibs-foundation`G +1. Clone `apple/swift-corelibs-xctest` into a directory named `swift-corelibs-xctest` +1. Clone `compnerd/swift-windows` into a directory named `swift-windows` + +- Currently, other repositories in the Swift project have not been tested and + may not be supported. + +This guide assumes that your sources live at the root of `S:`. If your sources +live elsewhere, you can create a substitution for this: + +```cmd +subst S: +``` + +```cmd +S: +git clone https://github.com/apple/swift-llvm llvm +git clone https://github.com/apple/swift-corelibs-libdispatch swift-corelibs-libdispatch +git clone https://github.com/apple/swift-corelibs-foundation swift-corelibs-foundation +git clone https://github.com/apple/swift-corelibs-xctest swift-corelibs-xctest +git clone https://github.com/compnerd/swift-windows swift-windows +``` + +## 1. Acquire the lastest toolchain and dependencies + +1. Download the toolchain, ICU, libxml2, and curl for android from + [Azure](https://dev.azure.com/compnerd/windows-swift) into `S:\b\a\Library`. + +- You can alternatively use `Download-AndroidArtifacts.ps1` from + [compnerd/windows-swift](https://www.github.com/compnerd/windows-swift) under + the utilities directory. This will implicitly setup the requisite directory + structure. + +## 1. Configure LLVM + +```cmd +md S:\b\a\llvm +cd S:\b\a\llvm +cmake -C S:\swift-windows\cmake\caches\android-armv7.cmake ^ + -G Ninja ^ + -DCMAKE_BUILD_TYPE=Release ^ + -DCMAKE_TOOLCHAIN_FILE=S:\swift-windows\cmake\toolchains\android.toolchain.cmake ^ + -DANDROID_ALTERNATE_TOOLCHAIN=S:/b/a/Library/Developer/Toolchains/unknown-Asserts-development.xctoolchain/usr ^ + -DLLVM_HOST_TRIPLE=armv7-unknown-linux-androideabi ^ + S:/llvm +``` + +## 1. Build and install the standard library + +- We must build and install the standard library to build the remainder of the + SDK + +```cmd +md S:\b\a\stdlib +cd S:\b\a\stdlib +cmake -C S:\windows-swift\cmake\caches\android-armv7.cmake ^ + -C S:\windows-swift\cmake\caches\swift-stdlib-android-armv7.cmake ^ + -G Ninja ^ + -DCMAKE_BUILD_TYPE=RelWithDebInfo ^ + -DCMAKE_INSTALL_PREFIX=S:/b/a/Library/Developer/Platforms/android.platform/Developer/SDKs/android.sdk/usr ^ + -DCMAKE_TOOLCHAIN_FILE=S:\windows-swift\cmake\toolchains\android.toolchain.cmake ^ + -DANDROID_ALTERNATE_TOOLCHAIN=S:/b/a/Library/Developer/Toolchains/unknown-Asserts-development.xctoolchain/usr ^ + -DLLVM_DIR=S:/b/a/llvm/lib/cmake/llvm ^ + -DSWIFT_NATIVE_SWIFT_TOOLS_PATH=S:/b/a/Library/Developer/Toolchains/unknown-Asserts-development.xctoolchain/usr/bin ^ + -DSWIFT_ANDROID_armv7_ICU_UC_INCLUDE=S:/b/a/Library/icu-64/usr/include/unicode ^ + -DSWIFT_ANDROID_armv7_ICU_UC=S:/b/a/Library/icu-64/usr/lib/libicuuc64.so ^ + -DSWIFT_ANDROID_armv7_ICU_I18N_INCLUDE=S:/b/a/Library/icu-64/usr/include ^ + -DSWIFT_ANDROID_armv7_ICU_I18N=S:/b/a/Library/icu-64/usr/lib/libicuin64.so ^ + S:/swift +ninja +ninja install +``` + +## 1. Build libdispatch + +- We *cannot* install libdispatch until after all builds are complete as that + will cause the Dispatch module to be imported twice and fail to build. + +```cmd +md S:\b\a\libdispatch +cd S:\b\a\libdispatch +cmake -C S:\windows-swift\cmake\caches\android-armv7.cmake ^ + -DSWIFT_ANDROID_SDK=S:/b/a/Library/Developer/Platforms/android.platform/Developer/SDKs/android.sdk ^ + -C S:\windows-swift\cmake\caches\android-armv7-swift-flags.cmake ^ + -G Ninja ^ + -DCMAKE_BUILD_TYPE=RelWithDebInfo ^ + -DCMAKE_INSTALL_PREFIX=S:/b/a/Library/Developer/Platforms/android.platform/Developer/SDKs/android.sdk/usr ^ + -DCMAKE_SWIFT_COMPILER=S:/b/a/Library/Developer/Toolchains/unknown-Asserts-development.xctoolchain/usr/bin/swiftc.exe ^ + -DCMAKE_TOOLCHAIN_FILE=S:\windows-swift\cmake\toolchains\android.toolchain.cmake ^ + -DANDROID_ALTERNATE_TOOLCHAIN=S:/b/a/Library/Developer/Toolchains/unknown-Asserts-development.xctoolchain/usr ^ + -DENABLE_SWIFT=YES ^ + -DENABLE_TESTING=NO ^ + S:/swift-corelibs-libdispatch +ninja +``` + +## 1. Build foundation + +```cmd +md S:\b\a\foundation +cd S:\b\a\foundation +cmake -C S:\windows-swift\cmake\caches\android-armv7.cmake ^ + -DSWIFT_ANDROID_SDK=S:/b/a/Library/Developer/Platforms/android.platform/Developer/SDKs/android.sdk ^ + -C S:\windows-swift\cmake\caches\android-armv7-swift-flags.cmake ^ + -G Ninja ^ + -DCMAKE_BUILD_TYPE=RelWithDebInfo ^ + -DCMAKE_INSTALL_PREFIX=S:/b/a/Library/Developer/Platforms/android.platform/Developer/SDKs/android.sdk/usr ^ + -DCMAKE_SWIFT_COMPILER=S:/b/a/Library/Developer/Toolchains/unknown-Asserts-development.xctoolchain/usr/bin/swiftc.exe ^ + -DCMAKE_TOOLCHAIN_FILE=S:\windows-swift\cmake\toolchains\android.toolchain.cmake ^ + -DANDROID_ALTERNATE_TOOLCHAIN=S:/b/a/Library/Developer/Toolchains/unknown-Asserts-development.xctoolchain/usr ^ + -DCURL_LIBRARY=S:/b/a/Library/libcurl-development/usr/lib/libcurl.a ^ + -DCURL_INCLUDE_DIR=S:/b/a/Library/libcurl-development/usr/include ^ + -DICU_INCLUDE_DIR=S:/b/a/Library/icu-64/usr/include ^ + -DICU_UC_LIBRARY=S:/b/a/Library/icu-64/usr/lib/libicuuc64.so ^ + -DICU_UC_LIBRARY_RELEASE=S:/b/a/Library/icu-64/usr/lib/libicuuc64.so ^ + -DICU_I18N_LIBRARY=S:/b/a/Library/icu-64/usr/lib/libiucin64.so ^ + -DICU_I18N_LIBRARY_RELEASE=S:/b/a/Library/icu-64/usr/lib/libicuin64.so ^ + -DLIBXML2_LIBRARY=S:/b/a/Library/libxml2-development/usr/lib/libxml2.a ^ + -DLIBXML2_INCLUDE_DIR=S:/b/a/Library/libxml2-development/usr/include/libxml2 ^ + -DFOUNDATION_PATH_TO_LIBDISPATCH_SOURCE=S:/swift-corelibs-libdispatch ^ + -DFOUNDATION_PATH_TO_LIBDISPATCH_BUILD=S:/b/a/libdispatch ^ + S:/swift-corelibs-foundation +ninja +``` + +## 1. Build XCTest + +```cmd +md S:\b\a\xctest +cd S:\b\a\xctest +cmake -C S:\swift-windows\cmake\caches\android-armv7.cmake ^ + -C S:\swift-windows\cmake\caches\android-armv7-swift-flags.cmake ^ + -G Ninja ^ + -DCMAKE_BUILD_TYPE=RelWithDebInfo ^ + -DCMAKE_INSTALL_PREFIX=S:/b/a/Library/Developer/Platforms/android.platform/Developer/SDKs/android.sdk/usr ^ + -DCMAKE_SWIFT_COMPILER=S:/b/a/Library/Developer/Toolchains/unknown-Asserts-development.xctoolchain/usr/bin/swiftc.exe ^ + -DCMAKE_TOOLCHAIN_FILE=S:\swift-windows\cmake\toolchains\android.toolchain.cmake ^ + -DANDROID_ALTERNATE_TOOLCHAIN=S:/b/a/Library/Developer/Toolchains/unknown-Asserts-development.xctoolchain/usr ^ + -DSWIFT_ANDROID_SDK=S:/b/a/Library/Developer/Platforms/andrfoid.platform/Developer/SDKs/android.sdk ^ + -DXCTEST_PATH_TO_FOUNDATION_BUILD=S:/b/a/foundation ^ + -DXCTEST_PATH_TO_LIBDISPATCH_SOURCE=S:/swift-corelibs-libdispatch ^ + -DXCTEST_PATH_TO_LIBDISPATCH_BUILD=S:/b/a/libdispatch ^ + -DENABLE_TESTING=NO ^ + S:/swift-corelibs-foundation +ninja +``` + +## 1. Install libdispatch + +```cmd +cd S:\b\a\libdispatch +ninja install +``` + +## 1. Install Foundation + +```cmd +cd S:\b\a\foundation +ninja install +``` + +## 1. Install XCTest + +```cmd +cd S:\b\a\xctest +ninja install +``` + diff --git a/docs/BuildManifesto.md b/docs/BuildManifesto.md new file mode 100644 index 0000000000000..f8ca34b81127a --- /dev/null +++ b/docs/BuildManifesto.md @@ -0,0 +1,96 @@ +# Build System + +## Introduction + +Modularising the build of Swift is a large undertaking that will simplify the +infrastructure used to build the compiler, runtime, standard library, as well +as the core libraries. Additionally, the work will enable a unified, uniform +build system that reduces the barrier to entry for new contributors. + +## Current State + +Currently, the Swift build is setup similar to the way that the GCC build was +setup. This requires the understanding of the terms `build`, `host`, `target` +as used by autotools. + +
+
build
+
the system where the package is being configured and compiled
+ x86_64-unknown-linux-gnu +
+
host
+
the system where the package runs (by default the same as build)
+ x86-64-unknown-windows-msvc +
+
target
+
the system for which the compiler tools generate code
+ aarch64-unknown-linux-android
+ NOTE this is not really supported properly in the original + build system +
+
+ +## Desired State + +It is preferable to instead consider the full package build as a set of builds +where you are doing normal builds with a differing set of `build` and `host` +values. That is, you can consider the regular host build (e.g. Linux) as: + +```Swift +[ + /* compiler */ (build: "x86_64-unknown-linux-gnu", host: "x86_64-unknown-linux-gnu"), + /* runtime */ (build: "x86_64-unknown-linux-gnu", host: "x86_64-unknown-linux-gnu"), + /* stdlib */ (build: "x86_64-unknown-linux-gnu", host: "x86_64-unknown-linux-gnu"), +] +``` + +Or for more complicated scenarios such as Darwin where you may be compiling for +Darwin and iOS as: + +```Swift +[ + /* compiler */ (build: "x86_64-apple-macosx10.14", host: "x86_64-apple-macosx10.14"), + /* runtime */ (build: "x86_64-apple-macosx10.14", host: "x86_64-apple-macosx10.14"), + /* stdlib */ (build: "x86_64-apple-macosx10.14", host: "x86_64-apple-macosx10.14"), + /* runtime */ (build: "x86_64-apple-macosx10.14", host: "armv7-apple-ios12.3"), + /* stdlib */ (build: "x86_64-apple-macosx10.14", host: "armv7-apple-ios12.3"), +] +``` + +This simplifies the build terminology by having to only deal with the terms +`build` and `host` which removes some of the confusion caused by the original +build system's implementation creating multiple terms and being designed around +the needs of the Darwin build. + +This also generalises to allow for multiple cross-compilations in a single build +invocation which allows the functionality currently available only on Darwin to +be applied to all the targets that Swift supports (and may support in the +future). + +Doing so also enables the build system to be trimmed significantly as we can use +CMake as it was designed to while retaining the ability to cross-compile. The +cross-compilation model for CMake involves invoking `cmake` multiple times with +`CMAKE_SYSTEM_NAME` and `CMAKE_SYSTEM_PROCESSOR` set appropriately to the host +that you would like to build for. This ensures that host specific behaviour is +explicitly handled properly (e.g. import libraries on Windows - something which +was shoehorned into the original CMake implementation in CMake) and corrects the +behaviour of the cmake `install` command. + +Another bit of functional flexibility that this system enables is the ability to +allow developers to focus entirely on the area that they are working in. The +runtime and standard library can be separated and built with a prebuilt +(nightly) release of the compiler toolchain, or focus entirely on building the +standard library for a certain set of targets. + +By organising the standard library build as a regular library, we enable the +ability to use the LLVM runtimes build to cross-compile the standard library for +multiple targets as long as the dependent system libraries are available at +build time. + +The ability to build the runtime components for different hosts allows building +the Swift SDK for various hosts on a single machine. This enables the build of +the android SDK and Linux SDKs on Windows and vice versa. + +Note that none of the changes described here prevent the workflows that are +possible with build-script today. + diff --git a/docs/DevelopmentTips.md b/docs/DevelopmentTips.md new file mode 100644 index 0000000000000..4e408baaf0ae8 --- /dev/null +++ b/docs/DevelopmentTips.md @@ -0,0 +1,43 @@ +# Development Tips + +## Compile times + +### Build using Ninja + +To *be* a productivity ninja, one must *use* `ninja`. `ninja` can be invoked inside the swift build directory, e.g. `/build/Ninja-ReleaseAssert/swift-macosx-x86_64/`. Running `ninja` (which is equivalent to `ninja all`) will build the local swift, stdlib and overlays. It doesn’t necessarily build all the testing infrastructure, benchmarks, etc. + +`ninja -t targets` gives a list of all possible targets to pass to ninja. This is useful for grepping. + +For this example, we will figure out how to quickly iterate on a change to the standard library to fix 32-bit build errors while building on a 64-bit host, suppressing warnings along the way. + +`ninja -t targets | grep stdlib | grep i386` will output many targets, but at the bottom we see `swift-stdlib-iphonesimulator-i386`, which looks like a good first step. This target will just build i386 parts and not waste our time also building the 64-bit stdlib, overlays, etc. + +Going further, ninja can spawn a web browser for you to navigate dependencies and rules. `ninja -t browse swift-stdlib-iphonesimulator-i386` will open a webpage with hyperlinks for all related targets. “target is built using” lists all this target’s dependencies, while “dependent edges build” list all the targets that depend directly on this. + +Clicking around a little bit, we can find `lib/swift/iphonesimulator/i386/libswiftCore.dylib` as a commonly-depended-upon target. This will perform just what is needed to compile the standard library for i386 and nothing else. + +Going further, for various reasons the standard library has lots of warnings. This is actively being addressed, but fixing all of them may require language features, etc. In the mean time, let’s suppress warnings in our build so that we just see the errors. `ninja -nv lib/swift/iphonesimulator/i386/libswiftCore.dylib` will show us the actual commands ninja will issue to build the i386 stdlib. (You’ll notice that an incremental build here is merely 3 commands as opposed to ~150 for `swift-stdlib-iphonesimulator-i386`). + +Copy the invocation that has ` -o /swift-macosx-x86_64/stdlib/public/core/iphonesimulator/i386/Swift.o`, so that we can perform the actual call to swiftc ourselves. Tack on `-suppress-warnings` at the end, and now we have the command to just build `Swift.o` for i386 while only displaying the actual errors. + +### Use sccache to cache build artifacts + +Compilation times for the compiler and the standard library can be agonizing, especially for cold builds. This is particularly painful if + +* You're bisecting an issue over a large period of time. +* You're switching between Xcode versions to debug issues. +* You have multiple distinct work directories, say for working on multiple things at once. + +[`sccache`](https://github.com/mozilla/sccache) provides a mostly automatic caching experience for C and C++ build artifacts. Here is how you can set it up and use it on macOS: + +``` +$ brew install sccache +$ sccache --start-server +$ ./swift/utils/build-script MY_ARGS --cmake-c-launcher $(which sccache) --cmake-cxx-launcher $(which sccache) +``` + +Given the size of artifacts generated, you might also want to bump the cache size from the default 10GB to something larger, say by putting `export SCCACHE_CACHE_SIZE="50G"` in your dotfile(s). + +You can run some compiles to see if it is actually doing something by running `sccache --show-stats`. Depending on the exact compilation task you're running, you might see very different cache hit rates. For example, `sccache` is particularly effective if you're rebuilding LLVM, which doesn't change so frequently from the Swift compiler's perspective. On the other hand, if you're changing the compiler's AST, the cache hit rate is likely to be much lower. + +One known issue with `sccache` is that you might occassionally get an "error: Connection to server timed out", even though you didn't stop the server. Simply re-running the build command usually works. diff --git a/docs/DifferentiableProgramming.md b/docs/DifferentiableProgramming.md index 935f7a94572a0..77b52180cce24 100644 --- a/docs/DifferentiableProgramming.md +++ b/docs/DifferentiableProgramming.md @@ -238,13 +238,12 @@ Differentiation is the process of computing derivatives. See the ["Math Introduction"](#math-introduction) section below for more details. Derivatives are a fundamental tool in calculus and have applications in many -domains, notably deep learning. Numerical computing in Swift Swift is an -expressive, high-performance language that is a great fit for numerical -applications. Recent proposals have paved the way for low-level numerical -computing in Swift: [AdditiveArithmetic][SE-0233], SIMD [[1][SE-0229]] -[[2][SE-0251]], [generic math functions][SE-0246]. However, high-level numerical -computing applications, including machine learning and artificial intelligence, -require more work. +domains, notably deep learning. Numerical computing in Swift is an expressive, +high-performance language that is a great fit for numerical applications. Recent +proposals have paved the way for low-level numerical computing in Swift: +[AdditiveArithmetic][SE-0233], SIMD [[1][SE-0229]] [[2][SE-0251]], [generic math +functions][SE-0246]. However, high-level numerical computing applications, +including machine learning and artificial intelligence, require more work. We believe that first-class differentiable programming is a big step towards high-level numerical computing support and will make Swift a real contender in @@ -971,21 +970,20 @@ public protocol Differentiable { /// A closure that produces a zero tangent vector and does not capture `self`. /// - /// A zero tangent vector of `self` is equal to `TangentVector.zero` - /// sometimes. In some cases, the zero tangent vector dependes on - /// information on `self`, such as shape. For differentiable programming, it - /// is more memory-efficient to define a custom - /// `zeroTangentVectorInitializer` to return a closure that captures and - /// uses such information to create a zero tangent vector. For example: + /// In some cases, the zero tangent vector of `self` is equal to + /// `TangentVector.zero`. In other cases, the zero tangent vector depends on + /// information in `self`, such as shape for an n-dimensional array type. + /// For differentiable programming, it is more memory-efficient to define a + /// custom `zeroTangentVectorInitializer` property which returns a closure + /// that captures and uses only the necessary information to create a zero + /// tangent vector. For example: /// /// ```swift /// struct Vector { - /// var scalars: [Float] - /// var count: Int { scalars.count } - /// init(repeating repeatedElement: Float, count: Int) { ... } + /// var scalars: [Float] + /// var count: Int { scalars.count } + /// init(repeating repeatedElement: Float, count: Int) { ... } /// } - /// - /// ... /// /// extension Vector: Differentiable { /// typealias TangentVector = Vector @@ -1829,15 +1827,12 @@ The `@differentiable` attribute requires the function type it is attached to have differentiable parameters and results. Each parameter and result must conform to the `Differentiable` protocol (or `Differentiable & AdditiveArithmetic` when the attribute is `@differentiable(linear)`) unless it -is marked with `@nondiff`. +is marked with `@noDerivative`.

-_Note: `@nondiff` stands for "not being differentiated", and will likely be -unified with `@noDerivative`._ - #### Type conversion The subtyping relation among `@differentiable(linear)`, `@differentiable`, and @@ -1901,13 +1896,13 @@ let f2: (Float) -> Float = f1 ``` A `@differentiable` function can also be converted to a function which is -identical except that more of its parameters are marked with `@nondiff`. +identical except that more of its parameters are marked with `@noDerivative`. ```swift func addOne(_ x: Float) -> Float { x + 1 } let f0: @differentiable (Float, Float, Float) -> Float = addOne -let f1: @differentiable (@nondiff Float, Float, Float) -> Float = f0 -let f2: @differentiable (@nondiff Float, Float, @nondiff Float) -> Float = f1 +let f1: @differentiable (@noDerivative Float, Float, Float) -> Float = f0 +let f2: @differentiable (@noDerivative Float, Float, @noDerivative Float) -> Float = f1 ``` #### Implied generic constraints @@ -1977,19 +1972,19 @@ Neural network trainer objects that store loss functions, e.g. Like function declarations with a `@differentiable` attribute, differentiable function values can also be differentiable with respect to a subset of parameters. This is expressed as part of type information, in `@differentiable` -and `@differentiable(linear)` function types, using a `@nondiff` attribute at +and `@differentiable(linear)` function types, using a `@noDerivative` attribute at each parameter that is not being differentiated with respect to. By default, all parameters are being differentiated with respect to. When a -`@nondiff` attribute is specified for a parameter in a `@differentiable` +`@noDerivative` attribute is specified for a parameter in a `@differentiable` function type, values of this function type are not differentiable (or linear) with respect to the parameter. ```swift let f0: @differentiable (Float, Float) -> Float = { $0 * $1 } let f1: @differentiable(linear) (Float, Float) -> Float = { $0 + $1 } -let f2: @differentiable(linear) (Float, @nondiff Float) -> Float = { $0 * $1 } -let f3: @differentiable (@nondiff Int, Float, @nondiff Int) -> Float = { +let f2: @differentiable(linear) (Float, @noDerivative Float) -> Float = { $0 * $1 } +let f3: @differentiable (@noDerivative Int, Float, @noDerivative Int) -> Float = { $0 ? Float($1) + $2 : 0 } ``` @@ -1997,13 +1992,13 @@ let f3: @differentiable (@nondiff Int, Float, @nondiff Int) -> Float = { Differentiability of parameters in a function type is important for type conversions and is part of the subtyping rule: Any `@differentiable` or `@differentiable(linear)` function type is a subtype of the same function type -with more `@nondiff` parameters than there originally are. +with more `@noDerivative` parameters than there originally are. ```swift let f0: @differentiable (Float, Float) -> Float = { $0 * $1 } -_ = f0 as @differentiable (Float, @nondiff Float) -> Float -_ = f0 as @differentiable (@nondiff Float, Float) -> Float -_ = f0 as @differentiable (@nondiff Float, @nondiff Float) -> Float +_ = f0 as @differentiable (Float, @noDerivative Float) -> Float +_ = f0 as @differentiable (@noDerivative Float, Float) -> Float +_ = f0 as @differentiable (@noDerivative Float, @noDerivative Float) -> Float ``` ### Differentiable operators diff --git a/docs/ErrorHandlingRationale.rst b/docs/ErrorHandlingRationale.rst index 71dd3e4de5fc3..a55956b868639 100644 --- a/docs/ErrorHandlingRationale.rst +++ b/docs/ErrorHandlingRationale.rst @@ -1180,7 +1180,7 @@ Haskell Haskell provides three different common error-propagation mechanisms. The first is that, like many other functional languages, it supports -manual propagation with a ``Maybe`` type. A function can return ``None`` +manual propagation with a ``Maybe`` type. A function can return ``Nothing`` to indicate that it couldn't produce a more useful result. This is the most common failure method for functions in the functional subset of the library. diff --git a/docs/GenericsManifesto.md b/docs/GenericsManifesto.md index f759d26974e04..7a031bf5cd51d 100644 --- a/docs/GenericsManifesto.md +++ b/docs/GenericsManifesto.md @@ -88,6 +88,30 @@ var d1 = StringDictionary() var d2: Dictionary = d1 // okay: d1 and d2 have the same type, Dictionary ``` +### Generic associatedtypes + +Associatedtypes could be allowed to carry generic parameters. + +```Swift + protocol Wrapper { + associatedtype Wrapped + + static func wrap(_ t: T) -> Wrapped + } +``` + +Generic associatedtypes would support all constraints supported by the language including where clauses. As with non-generic associatedtypes conforming types would be required to provide a nested type or typealias matching the name of the associatedtype. However, in this case the nested type or typealias would be generic. + +```Swift + enum OptionalWrapper { + typealias Wrapped = Optional + + static func wrap(_ t: T) -> Optional + } +``` + +Note: generic associatedtypes address many use cases also addressed by higher-kinded types but with lower implementation complexity. + ### Generic subscripts *This feature has been accepted in [SE-0148](https://github.com/apple/swift-evolution/blob/master/proposals/0148-generic-subscripts.md), was tracked by [SR-115](https://bugs.swift.org/browse/SR-115) and was released with Swift 4.* @@ -249,6 +273,21 @@ typealias AnyObject = protocol See the "Existentials" section, particularly "Generalized existentials", for more information. +### Generalized supertype constraints + +Currently, supertype constraints may only be specified using a concrete class or protocol type. This prevents us from abstracting over the supertype. + +```Swift +protocol P { + associatedtype Base + associatedtype Derived: Base +} +``` + +In the above example `Base` may be any type. `Derived` may be the same as `Base` or may be _any_ subtype of `Base`. All subtype relationships supported by Swift should be supported in this context including (but not limited to) classes and subclasses, existentials and conforming concrete types or refining existentials, `T?` and `T`, `((Base) -> Void)` and `((Derived) -> Void)`, etc. + +Generalized supertype constraints would be accepted in all syntactic locations where generic constraints are accepted. + ### Allowing subclasses to override requirements satisfied by defaults (*) When a superclass conforms to a protocol and has one of the protocol's requirements satisfied by a member of a protocol extension, that member currently cannot be overridden by a subclass. For example: diff --git a/docs/HighLevelSILOptimizations.rst b/docs/HighLevelSILOptimizations.rst index 4b97b75705577..8646e741d9b61 100644 --- a/docs/HighLevelSILOptimizations.rst +++ b/docs/HighLevelSILOptimizations.rst @@ -135,7 +135,7 @@ Array, ContiguousArray, and ArraySlice data-structures. We consider the array state to consist of a set of disjoint elements -and a storage descriptor that encapsulates nonelement data such as the +and a storage descriptor that encapsulates non-element data such as the element count and capacity. Operations that semantically write state are always *control dependent*. A control dependent operation is one that may only be executed on the control flow paths in which the diff --git a/docs/LibraryEvolution.rst b/docs/LibraryEvolution.rst index a66868a9bf4fe..2a44a40db4228 100644 --- a/docs/LibraryEvolution.rst +++ b/docs/LibraryEvolution.rst @@ -3,18 +3,42 @@ .. default-role:: term .. title:: Library Evolution Support in Swift ("Resilience") -:Author: Jordan Rose -:Author: John McCall - .. note:: This document uses some Sphinx-specific features which are not available on - GitHub. For proper rendering, download and build the docs yourself. Jordan - Rose also posts occasional snapshots at - https://jrose-apple.github.io/swift-library-evolution/. + GitHub. For proper rendering, download and build the docs yourself. + +Since Swift 5, ABI-stable platforms have supported `library evolution`_, the +ability to change a library without breaking source or binary compatibility. +This model is intended to serve library designers whose libraries will evolve +over time. Such libraries must be both `backwards-compatible`, meaning that +existing clients should continue to work even when the library is updated, and +`forwards-compatible`, meaning that future clients will be able run using the +current version of the library. In simple terms: + +- Last year's apps should work with this year's library. +- Next year's apps should work with this year's library. + +This document is intended to be a specification for *which* changes can be made +without breaking binary compatibility. When a library author wants to make a +change, they can jump to the relevant section of this document to see if it's +allowed. Anything *not* listed in this document should be assumed unsafe, i.e. +changing it will break binary compatibility. + +Library evolution was formally described in `SE-0260 `_, but this +document should be kept up to date as new features are added to the language. + +.. _library evolution: https://swift.org/blog/abi-stability-and-more/ +.. _SE0260: https://github.com/apple/swift-evolution/blob/master/proposals/0260-library-evolution.md + +.. contents:: :local: + -One of Swift's primary design goals is to allow efficient execution of code -without sacrificing load-time abstraction of implementation. +Background +========== + +One of Swift's primary design goals has always been to allow efficient +execution of code without sacrificing load-time abstraction of implementation. Abstraction of implementation means that code correctly written against a published interface will correctly function when the underlying implementation @@ -49,24 +73,14 @@ This last point is a specific case of a general tenet of Swift: **the default behavior is safe**. Where possible, choices made when an entity is first published should not limit its evolution in the future. -.. contents:: :local: - Introduction ============ -This model is intended to serve library designers whose libraries will evolve -over time. Such libraries must be both `backwards-compatible`, meaning that -existing clients should continue to work even when the library is updated, and -`forwards-compatible`, meaning that future clients will be able run using the -current version of the library. In simple terms: - -- Last year's apps should work with this year's library. -- Next year's apps should work with this year's library. - This document will frequently refer to a *library* which vends public APIs, and a single *client* that uses them. The same principles apply even when multiple -libraries and multiple clients are involved. +libraries and multiple clients are involved. It also uses the term `ABI-public` +introduced in `SE-0193 `_. This document is primarily concerned with `binary compatibility`, i.e. what changes can safely be made to a library between releases that will not break @@ -91,18 +105,18 @@ library, as used by the `Swift Package Manager`_). Because a client always uses a particular version of such a library, there is no need to worry about backwards- or forwards-compatibility at the binary level. Just as developers with a single app target are not forced to think about access control, anyone -writing a bundled library should not be required to use any of the annotations -described below in order to achieve full performance. +writing a bundled library should (ideally) not be required to use any of the +annotations described below in order to achieve full performance. +.. _SE0193: https://github.com/apple/swift-evolution/blob/master/proposals/0193-cross-module-inlining-and-specialization.md .. _Swift Package Manager: https://swift.org/package-manager/ .. note:: This model may, however, be useful for library authors that want to - preserve *source* compatibility, and it is hoped that the tool for - `Checking Binary Compatibility`_ described below will also be useful for - this purpose. Additionally, we may decide to use some of these annotations - as performance hints for *non-*\ optimized builds. + preserve *source* compatibility, though this document mostly doesn't + discuss that. Additionally, some of these annotations are useful for + performance today, such as ``@inlinable``. The term "resilience" comes from the occasional use of "fragile" to describe certain constructs that have very strict binary compatibility rules. For @@ -112,164 +126,6 @@ changing the fields in a struct will not automatically cause problems for existing clients, so we say the struct is "resilient". -Using Versioned API -=================== - -References to a versioned API must always be guarded with the appropriate -availability checks. This means that any client entities that rely on certain -APIs from a library must themselves be restricted to contexts in which those -APIs are available. This is accomplished using the ``@available`` attribute, by -specifying the name of the client library along with the required version:: - - // Client code - @available(Magician 1.5) - class CrystalBallView : MagicView { /*...*/ } - -Library versions can also be checked dynamically using ``#available``, allowing -for fallback behavior when the requested library version is not present:: - - func scareMySiblings() { - if #available(Magician 1.2) { - summonDemons() - } else { - print("BOO!!") - } - } - -.. note:: - - Possible implementations include generating a hidden symbol into a library, - or putting the version number in some kind of metadata, like the Info.plist - in a framework bundle on Darwin platforms. - -This is essentially the same model as the availability checking released in -Swift 2.0, but generalized for checking library versions instead of just OS -versions. - - -Declaring Library Version Dependencies -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Swift's current availability model includes the notion of a *minimum deployment -target,* the version of an OS that must be present for the program being -compiled to run at all. For example, a program compiled with a minimum -deployment target of iOS 9.2 will not launch on iOS 9.0. - -The generalized model above suggests being able to make similar guarantees for -individual libraries. For example, a client program may depend on version 1.1 -of the "Magician" library; trying to run using version 1.0 will result in -errors. By declaring this at compile-time, the client code can omit -``@available`` and ``#available`` checks that are satisfied by the minimum -library version. - -Both the syntax and enforcement of this feature are not covered by this -document. - - -Publishing Versioned API -======================== - -A library's API is already marked with the ``public`` modifier, but if a -client wants to work with multiple releases of the library, the API needs -versioning information as well. A *versioned entity* represents anything with a -run-time presence that a client may rely on; its version records when the entity -was first exposed publicly in its library. Put another way, it is the oldest -version of the library where the entity may be used. - -- Classes, structs, enums, and protocols may all be versioned entities. -- Methods, properties, subscripts, and initializers may be versioned entities. -- Top-level functions, variables, and constants may be versioned entities. -- Protocol conformances may be versioned entities, despite not explicitly having - a declaration in Swift, because a client may depend on them. - See `New Conformances`_, below. -- Typealiases are treated as versioned entities for the purpose of verifying - availability, even though they have no run-time presence. - -In a versioned library, any top-level public entity from the list above may not -be made ``public`` (or ``open``) without an appropriate version. A public -entity declared within a versioned type (or an extension of a versioned type) -will default to having the same version as the type. - -In this document, the term "public" includes classes and members marked -``open``. - -Code within a library may generally use all other entities declared within the -library (barring their own availability checks), since the entire library is -shipped as a unit. That is, even if a particular API was introduced in v1.0, -its (non-public) implementation may refer to APIs introduced in later versions. - -Certain uses of ``internal`` entities require them to be part of a library's -binary interface, which means they need to be versioned as well. See -`Versioning Internal Declarations`_ below. - -In addition to versioned entities, there are also attributes that are safe to -add to declarations when releasing a new version of a library. In most cases, -clients can only take advantage of the attributes when using the new release of -the library, and therefore the attributes also need to record the version in -which they were introduced; these are called *versioned attributes.* If the -version is omitted, it is assumed to be the version of the declaration to which -the attribute is attached. - -The syntax for marking an entity as versioned has not yet been decided, but the -rest of this document will use syntax #1 described below. - - -Syntax #1: Attributes -~~~~~~~~~~~~~~~~~~~~~ - -:: - - @available(1.2) - public func summonDemons() - - @available(1.0) @inlinable(1.2) - public func summonElves() - -Using the same attribute for both publishing and using versioned APIs helps tie -the feature together and enforces a consistent set of rules. However, there are -several other annotations described later in this document that also need -versioning information, and it may not be obvious what the version number means -outside the context of ``available``. - - -Syntax #2: Version Blocks -~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - #version(1.2) - public func summonDemons() - - #version(1.0) {} - #version(1.2) { @inlinable } - public func summonElves() - -Since there are potentially many annotations on a declaration that need -versioning information, it may make sense to group them together in some way. -Only certain annotations would support being versioned in this way. - - -Syntax #3: The ``public`` modifier -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - public(1.2) func summonDemons() - - /* @inlinable ?? */ - public(1.0) func summonElves() - -Putting the version on the public modifier is the most concise option. However, -there's no obvious syntax here for adding versions to other annotations that -may apply to a declaration. - -(Also, at one point there was a proposal to tag API only intended for certain -clients using a similar syntax: ``public("Foundation")``, for example, for APIs -only meant to be used by Foundation. These could then be stripped out of the -public interface for a framework before being widely distributed. But that -could easily use an alternate syntax.) - - Supported Evolution =================== @@ -277,45 +133,44 @@ This section describes the various changes that are safe to make when releasing a new version of a library, i.e. changes that will not break binary compatibility. They are organized by declaration type. -Anything *not* listed in this document should be assumed unsafe. - - Top-Level Functions ~~~~~~~~~~~~~~~~~~~ -A versioned top-level function is fairly restricted in how it can be changed. +An ABI-public top-level function is fairly restricted in how it can be changed. The following changes are permitted: -- Changing the body of the function. +- Changing the body of the function (as long as it is not ``@inlinable``; see + below). - Changing *internal* parameter names (i.e. the names used within the function body, not the labels that are part of the function's full name). - Reordering generic requirements (but not the generic parameters themselves). - Adding a default argument expression to a parameter. - Changing or removing a default argument is a `binary-compatible source-breaking change`. -- The ``@discardableResult`` and ``@warn_unqualified_access`` attributes may - be added to a function without any additional versioning information. +- Adding or removing the ``@discardableResult`` and ``@warn_unqualified_access`` + attributes. No other changes are permitted; the following are particularly of note: -- A versioned function may not change its parameters or return type. -- A versioned function may not change its generic requirements. -- A versioned function may not change its external parameter names (labels). -- A versioned function may not add, remove, or reorder parameters, whether or +- An ABI-public function may not change its parameters or return type. +- An ABI-public function may not change its generic requirements. +- An ABI-public function may not change its external parameter names (labels). +- An ABI-public function may not add, remove, or reorder parameters, whether or not they have default arguments. -- A versioned function that throws may not become non-throwing or vice versa. +- An ABI-public function that throws may not become non-throwing or vice versa. - The ``@escaping`` attribute may not be added to or removed from a parameter. - It is not a `versioned attribute` and so there is no way to guarantee that it - is safe when a client deploys against older versions of the library. +- Adding or removing a function builder from a parameter is a + `binary-compatible source-breaking change`. Inlinable Functions ------------------- -Functions are a very common example of resilience: the function's declaration -is published as API, but its body may change between library versions as long -as it upholds the same semantic contracts. This applies to other function-like -constructs as well: initializers, accessors, and deinitializers. +Functions are a very common example of "abstraction of implementation": the +function's declaration is published as API, but its body may change between +library versions as long as it upholds the same semantic contracts. This +applies to other function-like constructs as well: initializers, accessors, and +deinitializers. However, sometimes it is useful to provide the body to clients as well. There are a few common reasons for this: @@ -331,12 +186,9 @@ are a few common reasons for this: - The function is generic and its performance may be greatly increased by specialization in the client. -A versioned function marked with the ``@inlinable`` attribute makes its body -available to clients as part of the module's public interface. ``@inlinable`` -is a `versioned attribute`; clients may not assume that the body of the -function is suitable when deploying against older versions of the library. - -Clients are not required to inline a function marked ``@inlinable``. +An ABI-public function marked with the ``@inlinable`` attribute makes its body +available to clients as part of the module's public interface. Clients are not +required to inline a function marked ``@inlinable``. .. note:: @@ -348,17 +200,15 @@ Clients are not required to inline a function marked ``@inlinable``. Any local functions or closures within an inlinable function are treated as ``@_alwaysEmitIntoClient`` (see below). A client that inlines the containing function must emit its own copy of the local functions or closures. This is -important in case it is necessary to change the inlinable function later; -existing clients should not be depending on internal details of the previous -implementation. +important in case it is necessary to change the inlinable function later. Removing the ``@inlinable`` attribute completely---say, to reference private -implementation details that should not be `versioned `---is a -safe change. However, existing clients will of course not be affected by this -change, and any future use of the function must take this into account. +implementation details that should not be ABI-public---is a safe change. +However, existing clients will of course not be affected by this change, and +any future use of the function must take this into account. Although they are not a supported feature for arbitrary libraries at this time, -`transparent`_ functions are implicitly marked ``@inlinable``. +public `transparent`_ functions are implicitly marked ``@inlinable``. .. _transparent: https://github.com/apple/swift/blob/master/docs/TransparentAttr.rst @@ -394,19 +244,15 @@ polar representation:: } and the ``x`` and ``y`` properties have now disappeared. To avoid this, the -bodies of inlinable functions have the following restrictions: +bodies of inlinable functions have the following restrictions (enforced by the +compiler): - They may not define any local types. - They must not reference any ``private`` or ``fileprivate`` entities. - They must not reference any ``internal`` entities except for those that have - been ``versioned ` and those declared ``@inlinable``. See - below for a discussion of versioning internal API. - -- They must not reference any entities from the current module introduced - after the function was made inlinable, except under appropriate availability - guards. + been declared ``@usableFromInline`` or ``@inlinable``. Always Emit Into Client @@ -428,118 +274,64 @@ is a binary-compatible source-breaking change. Default Argument Expressions ---------------------------- -Default argument expressions for functions that are public, versioned, or -inlinable are implicitly ``@_alwaysEmitIntoClient``. They are subject to -similar restrictions: - -- They may not define any local types. - -- They must not reference any non-``public`` entities. - -- They must not reference any entities from the current module introduced - after the default argument was added, except under appropriate availability - guards. - -A default argument implicitly has the same availability as the function it is -attached to. Because default argument expressions can be added and removed, a -client that uses one must always emit its own copy of the implementation. +Default argument expressions for functions that are ABI-public are implicitly +``@_alwaysEmitIntoClient``. They are subject to the same restrictions as +inlinable functions except that they also must not reference any non-``public`` +entities, even if they are ``@usableFromInline`` or ``@inlinable``. This is to +make sure a default argument expression can always be written explicitly by a +caller. Top-Level Variables and Constants ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Given a versioned module-scope variable declared with ``var``, the following +Given an ABI-public module-scope variable declared with ``var``, the following changes are permitted: - Adding (but not removing) a public setter to a computed variable. -- Adding or removing a non-public, non-versioned setter. +- Adding or removing a non-ABI-public setter. - Changing from a stored variable to a computed variable, or vice versa, as - long as a previously versioned setter is not removed. + long as a previously ABI-public setter is not removed. - As a special case of the above, adding or removing ``lazy`` from a stored property. -- Changing the body of an accessor. +- Changing the body of an accessor, if the property is not marked ``@inlinable`` + (see below). - Adding or removing an observing accessor (``willSet`` or ``didSet``) to/from an existing variable. This is effectively the same as modifying the body of a setter. - Changing the initial value of a stored variable. -- Adding or removing ``weak`` from a variable with ``Optional`` type. -- Adding or removing ``unowned`` from a variable. +- Adding or removing ``weak`` to/from a variable with ``Optional`` type. +- Adding or removing ``unowned`` to/from a variable. - Adding or removing ``@NSCopying`` to/from a variable. - -If a public setter is added after the property is first exposed (whether the -property is stored or computed), it must be versioned independently of the -property itself. - -.. admonition:: TODO - - This needs syntax. - -Additionally, for a module-scope constant declared with ``let``, the following +- If the variable is get-only, or if it has a non-ABI-public setter, it may be + replaced by a ``let`` constant. +- Adding a property wrapper to a variable, or changing from one property + wrapper to another, as long as an ABI-public setter or projected value + (``$foo``) is not removed +- Removing a property wrapper from a variable, as long as the property wrapper + didn't have a projected value (``$foo``). + +For an ABI-public module-scope constant declared with ``let``, the following changes are permitted: - Changing the value of the constant. - -It is *not* safe to change a ``let`` constant into a variable or vice versa. -Top-level constants are assumed not to change for the entire lifetime of the -program once they have been initialized. - -.. admonition:: TODO - - We could make it safe to turn a read-only ``var`` into a ``let``, but do we - want to? We would have to come up with syntax for declaring when it - changed, at least. +- Replacing the constant with a variable. Giving Up Flexibility --------------------- -Both top-level constants and variables can be marked ``@inlinableAccess`` to -allow clients to access them more efficiently. This restricts changes a fair -amount: +Top-level computed variables can be marked ``@inlinable`` just like functions. +This restricts changes a fair amount: -- Adding a versioned setter to a computed variable is still permitted. -- Adding or removing a non-public, non-versioned setter is still permitted. -- Changing from stored to computed or vice versa is forbidden, because it would - break existing clients. -- Similarly, adding or removing ``lazy`` is forbidden. +- Adding an ABI-public setter to a computed variable is still permitted. +- Adding or removing a non-ABI-public setter is still permitted. - Changing the body of an accessor is a `binary-compatible source-breaking change`. -- Adding/removing observing accessors is likewise a `binary-compatible - source-breaking change`. -- Changing the initial value of a stored variable is still permitted. -- Changing the value of a constant is a `binary-compatible source-breaking - change`. -- Adding or removing ``weak`` is forbidden. -- Adding or removing ``unowned`` is forbidden. -- Adding or removing ``@NSCopying`` to/from a variable is `binary-compatible - source-breaking change`. - -.. admonition:: TODO - - It Would Be Nice(tm) to allow marking the *getter* of a top-level variable - inlinable while still allowing the setter to change. This would need - syntax, though. Any inlinable accessors must follow the rules for `inlinable functions`_, as described above. -Note that if a constant's initial value expression has any observable side -effects, including the allocation of class instances, it must not be treated -as inlinable. A constant must always behave as if it is initialized exactly -once. - -.. admonition:: TODO - - Is this a condition we can detect at compile-time? Do we have to be - restricted to things that can be lowered to compile-time constants? - -.. admonition:: TODO - - ``@inlinableAccess`` isn't implemented yet, but for computed properties we - already allow putting ``@inlinable`` on the accessors individually. That - doesn't support all the use cases, like promising that a stored property - will remain stored, but it also provides flexibility in only making *one* - accessor inlinable. Is that important? Structs ~~~~~~~ @@ -547,26 +339,43 @@ Structs Swift structs are a little more flexible than their C counterparts. By default, the following changes are permitted: -- Reordering any existing members, including stored properties. +- Reordering any existing members, including stored properties (unless the + struct is marked ``@frozen``; see below). - Adding any new members, including stored properties. -- Changing existing properties from stored to computed or vice versa. +- Changing existing properties from stored to computed or vice versa (unless the + struct is marked ``@frozen``; see below). - As a special case of the above, adding or removing ``lazy`` from a stored property. - Changing the body of any methods, initializers, or accessors. - Adding or removing an observing accessor (``willSet`` or ``didSet``) to/from - an existing property. This is effectively the same as modifying the body of a - setter. -- Removing any non-public, non-versioned members, including stored properties. -- Adding a new protocol conformance (with proper availability annotations). -- Removing conformances to non-public protocols. + an existing property (unless the struct is marked ``@frozen``; see below). + This is effectively the same as modifying the body of a setter. +- Removing any non-ABI-public members, including stored properties. +- Adding a conformance to an ABI-public protocol *that was introduced in the + same release* (see below). +- Adding or removing a conformance to a non-ABI-public protocol. +- Adding ``@dynamicCallable`` to the struct. The important most aspect of a Swift struct is its value semantics, not its -layout. +layout. Note that adding a stored property to a struct is *not* a breaking +change even with Swift's synthesis of memberwise and no-argument initializers; +these initializers are always ``internal`` and thus not exposed to clients +outside the module. It is not safe to add or remove ``mutating`` or ``nonmutating`` from a member -or accessor within a struct. These modifiers are not `versioned attributes -` and as such there is no safety guarantee for a client -deploying against an earlier version of the library. +or accessor within a struct. + +If a conformance is added to a type in version 1.1 of a library, it's important +that it isn't accessed in version 1.0. This means that it is only safe to add +new conformances to ABI-public protocols when the protocol is introduced, and +not after. If the protocol comes from a separate module, there is no safe way +to conform to it. + +.. admonition:: TODO + + Coming up with a way to do this, either with availability annotations for + protocol conformances or a way to emit a fallback copy of the conformance + for clients on older library versions to use, is highly desired. Methods and Initializers @@ -574,28 +383,21 @@ Methods and Initializers For the most part struct methods and initializers are treated exactly like top-level functions. They permit all of the same modifications and can also be -marked ``@inlinable``, with the same restrictions. Inlinable initializers must -always delegate to another initializer or assign an entire value to ``self``, -since new properties may be added between new releases. For the same reason, -initializers declared outside of the struct's module must always delegate to -another initializer or assign to ``self``. +marked ``@inlinable``, with the same restrictions. + +Inlinable initializers must always delegate to another initializer or assign an +entire value to ``self``, since new properties may be added between new +releases. For the same reason, initializers declared outside of the struct's +module must always delegate to another initializer or assign to ``self``. This +is enforced by the compiler. Properties ---------- -Struct properties behave largely the same as top-level bindings. They permit -all of the same modifications, and also allow adding or removing an initial -value entirely. - -Struct properties can also be marked ``@inlinableAccess``, with the same -restrictions as for top-level bindings. An inlinable stored property may not -become computed, but the offset of its storage within the struct is not -necessarily fixed. - -Like top-level constants, it is *not* safe to change a ``let`` property into a -variable or vice versa. Properties declared with ``let`` are assumed not to -change for the entire lifetime of the program once they have been initialized. +Struct properties behave largely the same as top-level variables and constants. +They permit all of the same modifications, and also allow adding or removing an +initial value entirely. Subscripts @@ -605,7 +407,7 @@ Subscripts behave largely the same as properties, except that there are no stored subscripts. This means that the following changes are permitted: - Adding (but not removing) a public setter. -- Adding or removing a non-public, non-versioned setter. +- Adding or removing a non-ABI-public setter. - Changing the body of an accessor. - Changing index parameter internal names (i.e. the names used within the accessor bodies, not the labels that are part of the subscript's full name). @@ -614,64 +416,19 @@ stored subscripts. This means that the following changes are permitted: - Changing or removing a default argument is a `binary-compatible source-breaking change`. -Like properties, subscripts can be marked ``@inlinableAccess``, which makes +Like properties, subscripts can be marked ``@inlinable``, which makes changing the body of an accessor a `binary-compatible source-breaking change`. Any inlinable accessors must follow the rules for `inlinable functions`_, as described above. -New Conformances ----------------- - -If a conformance is added to a type in version 1.1 of a library, it's important -that it isn't accessed in version 1.0. This is implied if the protocol itself -was introduced in version 1.1, but needs special handling if both the protocol -and the type were available earlier. In this case, the conformance *itself* -needs to be labeled as being introduced in version 1.1, so that the compiler -can enforce its safe use. - -.. note:: - - This may feel like a regression from Objective-C, where `duck typing` would - allow a ``Wand`` to be passed as an ``id `` without ill effects. - However, ``Wand`` would still fail a ``-conformsToProtocol:`` check in - version 1.0 of the library, and so whether or not the client code will work - is dependent on what should be implementation details of the library. - -We've considered two possible syntaxes for this:: - - @available(1.1) - extension Wand : MagicType {/*...*/} - -and - -:: - - extension Wand : @available(1.1) MagicType {/*...*/} - -The former requires fewer changes to the language grammar, but the latter could -also be used on the declaration of the type itself (i.e. the ``struct`` -declaration). - -If we went with the former syntax, applying ``@available`` to an extension -would override the default availability of entities declared within the -extension; unlike access control, entities within the extension may freely -declare themselves to be either more or less available than what the extension -provides. - -We could also implement a ``@_alwaysEmitIntoClient`` attribute for conformances. -This introduces its own challenges with runtime uniquing of witness tables now -necessary for conformances. - - Frozen Structs -------------- -To opt out of this flexibility, a struct may be marked ``@frozen``. -This promises that no stored properties will be added to or removed from the -struct, even non-public ones. Additionally, all versioned instance stored -properties in a ``@frozen`` struct are implicitly declared -``@inlinable`` (as described above for top-level variables). In effect: +To opt out of this flexibility, a struct may be marked ``@frozen``. This +promises that no stored properties will be added to or removed from the struct, +even non-ABI-public ones, and allows the compiler to optimize as such. These +stored properties also must not have any observing accessors. In effect: - Reordering stored instance properties (public or non-public) is not permitted. Reordering all other members is still permitted. @@ -681,22 +438,20 @@ properties in a ``@frozen`` struct are implicitly declared vice versa is not permitted. - Similarly, adding or removing ``lazy`` from a stored property is not permitted. -- Changing the body of any *existing* methods, initializers, computed property - accessors, or non-instance stored property accessors is permitted. Changing - the body of a stored instance property observing accessor is permitted if the - property is not `versioned `, and considered a - `binary-compatible source-breaking change` if it is. -- Adding or removing observing accessors from any - `versioned ` stored instance properties (public or - non-public) is not permitted. +- Changing the body of any *existing* methods, initializers, or computed + property accessors is still permitted. +- Adding observing accessors to any stored instance properties (public or + non-public) is not permitted (and is checked by the compiler). - Removing stored instance properties is not permitted. Removing any other - non-public, non-versioned members is still permitted. -- Adding a new protocol conformance is still permitted. -- Removing conformances to non-public protocols is still permitted. + non-ABI-public members is still permitted. +- Adding a new protocol conformance is still permitted, per the usual + restrictions. +- Removing conformances to non-ABI-public protocols is still permitted. +- Adding, changing, or removing property wrappers is not permitted. Additionally, if the type of any stored instance property includes a struct or -enum, that struct or enum must be `versioned `. This includes -generic parameters and members of tuples. +enum, that struct or enum must be ABI-public. This includes generic parameters, +members of tuples, and property wrappers for stored instance properties. .. note:: @@ -707,18 +462,16 @@ generic parameters and members of tuples. While adding or removing stored properties is forbidden, existing properties may still be modified in limited ways: -- An existing non-public, non-versioned property may change its access level to - any other non-public access level. -- A non-versioned ``internal`` property may be versioned (see `Versioning - Internal Declarations`_). -- A versioned ``internal`` property may be made ``public`` (without changing - its version). +- An existing non-ABI-public property may change its access level to any other + non-public access level. +- ``@usableFromInline`` may be added to an ``internal`` property (with the + current availability version, if necessary). +- A ``@usableFromInline`` property may be made ``public``. + +Adding or removing ``@frozen`` from an existing struct is forbidden. An initializer of a frozen struct may be declared ``@inlinable`` even -if it does not delegate to another initializer, as long as the ``@inlinable`` -attribute, or the initializer itself, is not introduced earlier than the -``@frozen`` attribute and the struct has no non-versioned stored -properties. +if it does not delegate to another initializer. A ``@frozen`` struct is *not* guaranteed to use the same layout as a C struct with a similar "shape". If such a struct is necessary, it should be @@ -726,33 +479,13 @@ defined in a C header and imported into Swift. .. note:: - We can add a *different* feature to control layout some day, or something + We may add a *different* feature to control layout some day, or something equivalent, but this feature should not restrict Swift from doing useful - things like minimizing member padding. At the very least, Swift structs - don't guarantee the same tail padding that C structs do. - -.. note:: - - Hypothetically, we could use a different model where a ``@frozen`` - struct only guarantees the "shape" of the struct, so to speak, while - leaving all property accesses to go through function calls. This would - allow stored properties to change their accessors, or (with the Behaviors - proposal) to change a behavior's implementation, or change from one - behavior to another. However, the *most common case* here is probably just - a simple C-like struct that groups together simple values, with only public - stored properties and no observing accessors, and having to opt into direct - access to those properties seems unnecessarily burdensome. The struct is - being declared ``@frozen`` for a reason, after all: it's been - discovered that its use is causing performance issues. - - Consequently, as a first pass we may just require all stored properties in - a ``@frozen`` struct, public or non-public, to have trivial - accessors, i.e. no observing accessors and no behaviors. - -``@frozen`` is a `versioned attribute`. This is so that clients can -deploy against older versions of the library, which may have a different layout -for the struct. (In this case the client must manipulate the struct as if the -``@frozen`` attribute were absent.) + things like minimizing member padding. While the layout of ``@frozen`` + structs is part of the stable ABI on Apple platforms now, it's not + something that can't be revised in the future (with appropriate + compatibility considerations). At the very least, Swift structs don't + guarantee the same tail padding that C structs do. Enums @@ -763,16 +496,17 @@ without breaking binary compatibility. As with structs, this results in a fair amount of indirection when dealing with enum values, in order to potentially accommodate new values. More specifically, the following changes are permitted: -- Adding a new case. -- Reordering existing cases is a `binary-compatible source-breaking change`. In - particular, if an enum is RawRepresentable, changing the raw representations - of cases may break existing clients who use them for serialization. +- Adding a new case (unless the enum is marked ``@frozen``; see below). +- Reordering existing cases is a `binary-compatible source-breaking change` + (unless the struct is marked ``@frozen``; see below). In particular, both + CaseIterable and RawRepresentable default implementations may affect client + behavior. - Adding a raw type to an enum that does not have one. -- Removing a non-public, non-versioned case. - Adding any other members. -- Removing any non-public, non-versioned members. -- Adding a new protocol conformance (with proper availability annotations). -- Removing conformances to non-public protocols. +- Removing any non-ABI-public members. +- Adding a new protocol conformance, with the same restrictions as for structs. +- Removing conformances to non-ABI-public protocols. +- Adding ``@dynamicCallable`` to the enum. .. note:: @@ -781,12 +515,6 @@ accommodate new values. More specifically, the following changes are permitted: representation for the value, just as it may discard fields of structs that are provably never accessed. -.. note:: - - Non-public cases in public enums don't exist at the moment, but they *can* - be useful, and they require essentially the same implementation work as - cases added in future versions of a library. - Adding or removing the ``@objc`` attribute from an enum is not permitted; this affects the enum's memory representation and is not backwards-compatible. @@ -809,19 +537,18 @@ members. Frozen Enums ------------ -A library owner may opt out of this flexibility by marking a versioned enum as -``@frozen``. A "frozen" enum may not have any cases with less access than the -enum itself, and may not add new cases in the future. This guarantees to -clients that the enum cases are exhaustive. In particular: +A library owner may opt out of this flexibility by marking an ABI-public enum +as ``@frozen``. A "frozen" enum may not add new cases in the future, +guaranteeing to clients that the current set of enum cases is exhaustive. In +particular: - Adding new cases is not permitted. - Reordering existing cases is not permitted. -- Removing a non-public case is not applicable. - Adding a raw type is still permitted. - Adding any other members is still permitted. -- Removing any non-public, non-versioned members is still permitted. +- Removing any non-ABI-public members is still permitted. - Adding a new protocol conformance is still permitted. -- Removing conformances to non-public protocols is still permitted. +- Removing conformances to non-ABI-public protocols is still permitted. .. note:: @@ -829,24 +556,12 @@ clients that the enum cases are exhaustive. In particular: the library would still have to treat the enum as opaque and would still have to be able to handle unknown cases in their ``switch`` statements. -``@frozen`` is a `versioned attribute`. This is so that clients can deploy -against older versions of the library, which may have non-public cases in the -enum. (In this case the client must manipulate the enum as if the ``@frozen`` -attribute were absent.) All cases that are not versioned become implicitly -versioned with this number. +Adding or removing ``@frozen`` from an existing enum is forbidden. Even for default "non-frozen" enums, adding new cases should not be done lightly. Any clients attempting to do an exhaustive switch over all enum cases will likely not handle new cases well. -.. note:: - - One possibility would be a way to map new cases to older ones on older - clients. This would only be useful for certain kinds of enums, though, and - adds a lot of additional complexity, all of which would be tied up in - versions. Our generalized switch patterns probably make it hard to nail - down the behavior here. - Protocols ~~~~~~~~~ @@ -861,19 +576,12 @@ There are very few safe changes to make to protocols and their members: - Reordering generic requirements is permitted (but not the generic parameters themselves). - The ``@discardableResult`` and ``@warn_unqualified_access`` attributes may - be added to a function requirement without any additional versioning - information. - -New requirements can be added to a protocol. However, restrictions around -existential types mean that adding new associated types or non-type requirements -involving ``Self`` can break source compatibility. For this reason, the following -are `binary-compatible source-breaking changes `: - -- A new non-type requirement may be added to a protocol, as long as it has an - unconstrained default implementation in a protocol extension of the - protocol itself or some other protocol it refines. -- A new associated type requirement may be added as long as it has a - default. + be added to or removed from a function requirement. +- A new non-type requirement may be added (with the appropriate availability), + as long as it has an unconstrained default implementation. If the requirement + uses ``Self`` and the protocol has no other requirements using ``Self`` and + no associated types, this is a `binary-compatible source-breaking change` due + to restrictions on protocol value types. All other changes to the protocol itself are forbidden, including: @@ -902,19 +610,23 @@ support all of the following changes: - Changing existing properties from stored to computed or vice versa. - As a special case of the above, adding or removing ``lazy`` from a stored property. -- Changing the body of any methods, initializers, or accessors. +- Changing the body of any methods, initializers, accessors, or deinitializers. - Adding or removing an observing accessor (``willSet`` or ``didSet``) to/from an existing property. This is effectively the same as modifying the body of a setter. -- Removing any non-public, non-versioned members, including stored properties. -- Adding a new protocol conformance (with proper availability annotations). -- Removing conformances to non-public protocols. +- Removing any non-ABI-public members, including stored properties. +- Adding a new protocol conformance (subject to the same restrictions as for + structs). +- Removing conformances to non-ABI-public protocols. +- Adding ``@dynamicCallable`` to the class. Omitted from this list is the free addition of new members. Here classes are a little more restrictive than structs; they only allow the following changes: - Adding a new convenience initializer. -- Adding a new designated initializer, if the class is not ``open``. +- Adding a new designated initializer, if the class is not ``open`` and any + ``open`` subclasses that previously inherited convenience initializers + continue to do so. - Adding a deinitializer. - Adding new, non-overriding method, subscript, or property. - Adding a new overriding member, though if the class is ``open`` the type of @@ -923,8 +635,6 @@ little more restrictive than structs; they only allow the following changes: Finally, classes allow the following changes that do not apply to structs: -- A public class may be made ``open`` if it is not already marked ``final``. -- A non-``open`` public class may be marked ``final``. - Removing an explicit deinitializer. (A class with no declared deinitializer effectively has an implicit deinitializer.) - "Moving" a method, subscript, or property up to its superclass. The @@ -935,55 +645,35 @@ Finally, classes allow the following changes that do not apply to structs: removed as long as the generic parameters, formal parameters, and return type *exactly* match the overridden declaration. Any existing callers should automatically use the superclass implementation. -- Within an ``open`` class, any public method, subscript, or property may be - marked ``open`` if it is not already marked ``final``. -- Any method, subscript, or property may be marked ``final`` if it is not - already marked ``open``. +- ``final`` can be added to or removed from any non-ABI-public class, or any + non-ABI-public member of a class. - ``@IBOutlet``, ``@IBAction``, ``@IBInspectable``, and ``@GKInspectable`` may - be added to a member without providing any extra version information. + be added to a member that is already exposed to Objective-C (either explicitly + with ``@objc`` or implicitly through overriding or protocol requirements). Removing any of these is a `binary-compatible source-breaking change` if the member remains ``@objc``, and disallowed if not. -- Likewise, ``@IBDesignable`` may be added to a class without providing any - extra version information. Removing it is considered a `binary-compatible - source-breaking change`. +- ``@IBDesignable`` may be added to a class; removing it is considered a + `binary-compatible source-breaking change`. - Changing a class's superclass ``A`` to another class ``B``, *if* class ``B`` is a subclass of ``A`` *and* class ``B``, along with any superclasses between it and class ``A``, were introduced in the latest version of the library. -.. admonition:: TODO - - This last is very tricky to get right. We've seen it happen a few times in - Apple's SDKs, but at least one of them, `NSCollectionViewItem`_ becoming a - subclass of NSViewController instead of the root class NSObject, doesn't - strictly follow the rules. While NSViewController was introduced in the - same version of the OS, its superclass, NSResponder, was already present. - If a client app was deploying to an earlier version of the OS, would - NSCollectionViewItem be a subclass of NSResponder or not? How would the - compiler be able to enforce this? - -.. admonition:: TODO - - Both ``final`` and ``open`` may be applied to a declaration after it has - been made public. However, these need to be treated as - `versioned attributes `. It's not clear what syntax - should be used for this. - -.. _NSCollectionViewItem: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSCollectionViewItem_Class/index.html - Other than those detailed above, no other changes to a class or its members are permitted. In particular: -- An ``open`` class or member cannot become non-``open``. -- ``final`` may not be removed from a class or its members. (The presence of - ``final`` enables optimization.) -- ``dynamic`` may not be added to *or* removed from any members. Existing - clients would not know to invoke the member dynamically. +- ``open`` cannot be added to or removed from an ABI-public class or member. +- ``final`` may not be added to or removed from an ABI-public class or its + ABI-public members. (The presence of ``final`` enables optimization.) +- ``dynamic`` may not be added to *or* removed from any ABI-public members. + Existing clients would not know to invoke the member dynamically. - A ``final`` override of a member may *not* be removed, even if the type matches exactly; existing clients may be performing a direct call to the implementation instead of using dynamic dispatch. - ``@objc`` and ``@nonobjc`` may not be added to or removed from the class or - any existing members. -- ``@NSManaged`` may not be added to or removed from any existing members. + any existing members, except if the member already was or was not exposed to + Objective-C. +- ``@NSManaged`` may not be added to or removed from any existing + ABI-public members. .. admonition:: TODO @@ -1004,12 +694,6 @@ A new ``required`` initializer may be added to a class only if it is a convenience initializer; that initializer may only call existing ``required`` initializers. An existing initializer may not be marked ``required``. -.. admonition:: TODO - - This implies a different rule for inheriting ``required`` convenience - initializers than non-required convenience initializers, which is not - currently implemented. - All of the modifications permitted for top-level functions are also permitted for class initializers. Convenience initializers may be marked ``@inlinable``, with the same restrictions as top-level functions; designated initializers may @@ -1030,20 +714,13 @@ little. They allow the following changes: - Adding a default argument expression to a parameter. - Changing or removing a default argument is a `binary-compatible source-breaking change`. -- The ``@discardableResult`` and ``@warn_unqualified_access`` attributes may - be added to a method without any additional versioning information. +- Adding or removing the ``@discardableResult`` and ``@warn_unqualified_access`` + attributes. Class and instance methods may be marked ``@inlinable``, with the same restrictions as struct methods. Additionally, only non-overriding ``final`` methods may be marked ``@inlinable``. -.. note:: - - A previous draft of this document allowed non-``final`` methods to be - marked ``@inlinable``, permitting inlining based on speculative - devirtualization. This was removed because of the added complexity for - users. - Properties ---------- @@ -1053,9 +730,9 @@ struct properties, but the potential for overrides complicates things a little. Variable properties (those declared with ``var``) allow the following changes: - Adding (but not removing) a computed setter to a non-``open`` property. -- Adding or removing a non-public, non-versioned setter. +- Adding or removing a non-ABI-public setter. - Changing from a stored property to a computed property, or vice versa, as - long as a previously versioned setter is not removed. + long as a previously ABI-public setter is not removed. - Changing the body of an accessor. - Adding or removing an observing accessor (``willSet`` or ``didSet``) to/from an existing variable. This is effectively the same as modifying the body of a @@ -1063,7 +740,15 @@ Variable properties (those declared with ``var``) allow the following changes: - Adding, removing, or changing the initial value of a stored variable. - Adding or removing ``weak`` from a variable with ``Optional`` type. - Adding or removing ``unowned`` from a variable. -- Adding or removing ``@NSCopying`` to/from a variable. +- Adding or removing ``@NSCopying`` from a variable. +- Adding a property wrapper to a non-``open`` variable, or changing from one + property wrapper to another, as long as an ABI-public setter or projected + value (``$foo``) is not removed. +- Adding a property wrapper to an ``open`` variable, or changing from one + property wrapper to another, as long as an ABI-public setter or projected + value (``$foo``) is not added or removed. +- Removing a property wrapper from a variable, as long as the property wrapper + didn't have a projected value (``$foo``). Adding a public setter to an ``open`` property is a `binary-compatible source-breaking change`; any existing overrides will not @@ -1072,9 +757,8 @@ know what to do with the setter and will likely not behave correctly. Constant properties (those declared with ``let``) still permit changing their value, as well as adding or removing an initial value entirely. -Non-overriding ``final`` variable and constant properties (on both instances -and classes) may be marked ``@inlinableAccess``. This behaves as described for -struct properties. +Non-overriding ``final`` computed properties (on both instances and classes) +may be marked ``@inlinable``. This behaves as described for struct properties. Subscripts @@ -1085,7 +769,7 @@ counterparts with a few small changes: - Adding (but not removing) a public setter to a non-``open`` subscript is permitted. -- Adding or removing a non-public, non-versioned setter is permitted. +- Adding or removing a non-ABI-public setter is permitted. - Changing the body of an accessor is permitted. - Changing index parameter internal names is permitted. - Reordering generic requirements (but not the generic parameters themselves) @@ -1098,23 +782,10 @@ Adding a public setter to an ``open`` subscript is a `binary-compatible source-breaking change`; any existing overrides will not know what to do with the setter and will likely not behave correctly. -Non-overriding ``final`` class subscripts may be marked ``@inlinableAccess``, +Non-overriding ``final`` class subscripts may be marked ``@inlinable``, which behaves as described for struct subscripts. -Possible Restrictions on Classes --------------------------------- - -In addition to ``final``, it may be useful to restrict the stored properties of -a class instance, like `Frozen Structs`_. However, there are open -questions about how this would actually work, and the compiler still wouldn't -be able to make much use of the information, because classes from other -libraries must almost always be allocated on the heap. - -The design of this annotation is not covered by this document. As a purely -additive feature, it can be added to the model at any time. - - Extensions ~~~~~~~~~~ @@ -1127,18 +798,19 @@ The following changes are permitted: as both extensions have the exact same constraints. - Adding any new member. - Reordering members. -- Removing any non-public, non-versioned member. +- Removing any non-ABI-public member. - Changing the body of any methods, initializers, or accessors. Additionally, non-protocol extensions allow a few additional changes: - Moving a member from an unconstrained extension to the declaration of the base type, provided that the declaration is in the same module. The reverse - is permitted for all members except stored properties, although note that - moving all initializers out of a type declaration may cause a new one to be - implicitly synthesized. -- Adding a new protocol conformance (with proper availability annotations). -- Removing conformances to non-public protocols. + is permitted for all members that would be valid to declare in an extension, + although note that moving all initializers out of a type declaration may + cause a new one to be implicitly synthesized. +- Adding a new protocol conformance (subject to the same restrictions discussed + for structs). +- Removing conformances to non-ABI-public protocols. .. note:: @@ -1159,8 +831,6 @@ existing operators are not changed at all except for the following: Any other change counts as a `binary-compatible source-breaking change`. -Operator and precedence group declarations are not versioned. - Typealiases ~~~~~~~~~~~ @@ -1173,115 +843,39 @@ clients, they cannot recompile their code and get correct behavior. Top-level typealiases only exist at compile-time, so changing the underlying type of one is a `binary-compatible source-breaking change`. However, if the -typealias is *used* in the type of any `versioned entity` in a library, it +typealias is *used* in the type of any ABI-public declaration in a library, it may be an actual breaking change and would not be permitted. It is always permitted to change the *use* of a public typealias to its underlying type, and vice versa, at any location in the program. -Typealiases are `versioned ` despite being compile-time +Typealiases require availability annotations despite being compile-time constructs in order to verify the availability of their underlying types. -A Unifying Theme -~~~~~~~~~~~~~~~~ - -So far this document has talked about ways to give up flexibility for several -different kinds of declarations: namely ``@inlinable`` for functions, and -``@frozen`` for enums and structs. Each of these has a different set of -constraints it enforces on the library author and promises it makes to clients. -However, they follow a common theme of giving up the flexibility of future -changes in exchange for improved performance and perhaps some semantic -guarantees. Therefore, these attributes are informally referred to as -"fragility attributes". - +``@usableFromInline`` +===================== -Versioning Internal Declarations -================================ - -The initial discussion on versioning focused on public APIs, making sure -that a client knows what features they can use when a specific version of a -library is present. Inlinable functions have much the same constraints, except -the inlinable function is the client and the entities being used may not be -public. - -Adding a versioning annotation to an ``internal`` entity promises that the -entity will be available at link time in the containing module's binary. This -makes it safe to refer to such an entity from an inlinable function. If the -entity is ever made ``public`` or ``open``, its availability should not be -changed; not only is it safe for new clients to rely on it, but *existing* -clients require its presence as well. +Adding ``@usableFromInline`` to an ``internal`` entity promises that the entity +will be available at link time in the containing module's binary. This makes it +safe to refer to such an entity from an inlinable function or in the stored +properties of a frozen struct. ``@usableFromInline`` declarations shipped as +part of an OS should have availability just like ``public`` declarations; if +the entity is ever made ``public`` or ``open``, its availability should not be +changed. .. note:: - Why isn't this a special form of ``public``? Because we don't want it to - imply everything that ``public`` does, such as requiring overrides to be - ``public``. + Why isn't ``@usableFromInline`` a special form of ``public``? Because we + don't want it to imply everything that ``public`` does, such as requiring + overrides to be ``public``. -In libraries without binary compatibility concerns, the equivalent annotation -is ``@usableFromInline``, since inlinable functions are the only way that a -non-public entity can be referenced from outside of a module. +Because a ``@usableFromInline`` class member may eventually be made ``open``, +the compiler must assume that new overrides may eventually appear from outside +the module if the class is marked ``open`` unless the member is marked +``final``. -Because a versioned class member may eventually be made ``open``, it must be -assumed that new overrides may eventually appear from outside the module if the -class is marked ``open`` unless the member is marked ``final``. - -Non-public conformances are never considered versioned, even if both the -conforming type and the protocol are versioned. A conformance is considered -public if and only if both the conforming type and protocol are public. - -Entities declared ``private`` or ``fileprivate`` may not be versioned; the -mangled name of such an entity includes an identifier based on the containing -file, which means moving the declaration to another file changes the entity's -mangled name. This implies that a client would not be able to find the entity -at run time if the source code is reorganized, which is unacceptable. - -.. note:: - - There are ways around this limitation, the most simple being that versioned - ``private`` entities are subject to the same cross-file redeclaration rules - as ``internal`` entities. However, this is a purely additive feature, so to - keep things simple we'll stick with the basics. - -We could do away with the entire feature if we restricted inlinable functions -and frozen structs to only refer to public entities. However, this -removes one of the primary reasons to make something inlinable: to allow -efficient access to a type while still protecting its invariants. - - -"Backdating" -============ - -*Backdating* refers to releasing a new version of a library that contains -changes, but pretending those changes were made in a previous version of the -library. For example, you might want to release version 1.2 of the "Magician" -library, but pretend that the "SpellIncantation" struct was frozen -since its introduction in version 1.0. - -**This is not safe.** - -Backdating the availability a versioned entity that was previously non-public -is clearly not safe: older versions of the library will not expose the entity -as part of their ABI. What may be less obvious is that the fragility attributes -likewise are not safe to backdate, even if you know the attributes could have -been added in the past. To give one example, the presence of ``@frozen`` may -affect the layout and calling conventions for an enum or struct. - -.. note:: - - If we add an "SPI" feature, such that the use of specific public entities - is limited to certain clients, it *will* be safe to change the set of - clients, or remove the restriction altogether. In fact, in such cases the - library author is *required* to *not* change the availability info that was - originally presented for the limited set of clients, since as mentioned - above this may affect how those existing clients use the entities declared - in the library. - -The one exception is ``@inlinable``, which does not change how a function is -called or otherwise used at the ABI level. If the implementation being provided -is compatible with a previous version of a library, and the function was -present and public (or `versioned `) there, then the library -author may choose to backdate the ``@inlinable`` annotation. +For more information, see `SE-0193 `_. Optimization @@ -1299,363 +893,27 @@ several ways. For example: - A struct may have additional members in the future, so client code must not assume it fits in any fixed-sized allocation. -In order to make sure client code doesn't make unsafe assumptions, queries -about properties that may change between library versions must be parameterized -with the `availability context` that is using the entity. An availability -context is a set of minimum platform and library versions that can be assumed -present for code executing within the context. (See `Declaring Library Version -Dependencies`_.) This allows the compiler to answer the question, "Given what I -know about where this code will be executed, what can I assume about a -particular entity being used?". - If the entity is declared within the same module as the code that's using it, then the code is permitted to know all the details of how the entity is declared. After all, if the entity is changed, the code that's using it will be -recompiled. +recompiled. However, if the entity is declared in another module, then the code +using it must be more conservative, and will therefore receive more +conservative answers to its queries. (For example, a stored property may be +treated as computed.) -However, if the entity is declared in another module, then the code using it -must be more conservative, and will therefore receive more conservative answers -to its queries. For example, a stored property may report itself as computed. - -The presence of versioned fragility attributes makes the situation more -complicated. Within a client function that requires version 1.5 of a particular -library, the compiler should be able to take advantage of any fragility -information (and performance assertions) introduced prior to version 1.5. - - -Inlinable Code -~~~~~~~~~~~~~~ - -By default, the availability context for a library always includes the latest -version of the library itself, since that code is always distributed as a unit. -However, this is not true for functions that have been marked inlinable (see -`Inlinable Functions`_ above). Inlinable code must be treated as if it is -outside the current module, since once it's inlined it will be. - -For inlinable code, the availability context is exactly the same as the -equivalent non-inlinable code except that the assumed version of the -containing library is the version attached to the ``@inlinable`` attribute, or -the version of the library in which the entity was introduced, and any `library -version dependencies <#declaring-library-version-dependencies>`_ or minimum -deployment target must be specified explicitly using ``@available``. Code -within this context must be treated as if the containing library were just a -normal dependency. - -A versioned inlinable function still has an exported symbol in the library -binary, which may be used when the function is referenced from a client rather -than called. This version of the function is not subject to the same -restrictions as the version that may be inlined, and so it may be desirable to -compile a function twice: once for inlining, once for maximum performance. - -If the body of an inlinable function is used in any way by a client module -(say, to determine that it does not read any global variables), that module -must take care to emit and use its own copy of the function. This is because -analysis of the function body may not apply to the version of the function -currently in the library. - - -Local Availability Contexts -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Swift availability contexts aren't just at the declaration level; they also -cover specific regions of code inside function bodies as well. These "local" -constructs are formed using the ``#available`` construct, which performs a -dynamic check. - -In theory, it would be legal to allow code dominated by a ``#available`` check -to take advantage of additional fragility information introduced by the more -restrictive dependencies that were checked for. However, this is an additional -optimization that may be complicated to implement (and even to represent -properly in SIL), and so it is not a first priority. - - -Other Promises About Types -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Advanced users may want to promise more specific things about various types. -These are similar to the internal ``effects`` attribute we have for functions, -except that they can be enforced by the compiler. - -- ``trivial``: Promises that assignment just requires a fixed-size bit-for-bit - copy without any indirection or reference-counting operations. - -- ``maximumFootprint(sizeInBits: N, alignmentInBits: A)``: Promises that the - type's size and required alignment are at most N bits and A bits, - respectively. (Both may be smaller.) - -- ``fixedSize``: Promises that the type has *some* size known at compile-time, - allowing optimizations like promoting allocations to the stack. Only applies - to fixed-contents structs and closed enums, which can already infer this - information; the explicit annotation allows it to be enforced. - -Collectively these features are known as "performance assertions", to -underscore the fact that they do not affect how a type is used at the source -level, but do allow for additional optimizations. We may also expose some of -these qualities to static or dynamic queries for performance-sensitive code. - -.. note:: Previous revisions of this document contained a ``noPayload`` - assertion for enums. However, this doesn't actually offer any additional - optimization opportunities over combining ``trivial`` with - ``maximumFootprint``, and the latter is more flexible. - -.. note:: None of these names / spellings are final. The name "trivial" comes - from C++, though Swift's trivial is closer to C++'s "`trivially - copyable`__". - -All of these features need to be versioned, just like the more semantic -fragility attributes above. The exact spelling is not proposed by this document. - -__ http://en.cppreference.com/w/cpp/types/is_trivially_copyable - - -Resilience Domains -================== - -As described in the `Introduction`_, the features and considerations discussed -in this document do not apply to libraries distributed in a bundle with their -clients. In this case, a client can rely on all the current implementation -details of its libraries when compiling, since the same version of the library -is guaranteed to be present at run time. This allows more optimization than -would otherwise be possible. - -In some cases, a collection of libraries may be built and delivered together, -even though their clients may be packaged separately. (For example, the ICU -project is usually built into several library binaries, but these libraries are -always distributed together.) While the *clients* cannot rely on a particular -version of any library being present, the various libraries in the collection -should be able to take advantage of the implementations of their dependencies -also in the collection---that is, it should treat all entities as if marked -with the appropriate fragility attributes. Modules in this sort of collection -are said to be in the same *resilience domain.* - -Exactly how resilience domains are specified is not covered by this document, -and indeed they are an additive feature. One possibility is that a library's -resilience domain defaults to the name of the module, but can be overridden. If -a client has the same resilience domain name as a library it is using, it may -assume that version of the library will be present at run time. - - -Deployments -~~~~~~~~~~~ - -Related to the concept of a resilience domain is a *deployment.* While a -resilience domain allows related libraries to be compiled more efficiently, -a deployment groups related libraries together to present semantic version -information to clients. The simplest example of this might be an OS release: -OS X 10.10.0 contains Foundation version 1151.16 and AppKit version 1343. A -deployment thus acts as a "virtual dependency": clients that depend on -OS X 10.10 can rely on the presence of both of the library versions above. - -The use of deployments allows clients to only have to think about aggregate -dependencies, instead of listing every library they might depend on. It also -allows library authors to build `many versions of a library`__ within a larger -release cycle, as well as allowing a vendor to bundle together many libraries -with uncoordinated release schedules and release them as a logical unit. - -__ https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Constants/index.html#//apple_ref/doc/constant_group/Foundation_Framework_Version_Numbers - -There are lots of details to figure out here, including how to distribute this -information. In particular, just like libraries publish the history of their -own APIs, a deployment must publish the history of their included library -versions, i.e. not just that OS X 10.10 contains Foundation 1151.16 and AppKit -1343, but also that OS X 10.9 contains Foundation 1056 and AppKit 1265, and that -OS X 10.8 contains Foundation 945.0 and AppKit 1187, and so on, back to the -earliest version of the deployment that is supported. - - - -Checking Binary Compatibility -============================= - -With this many manual controls, it's important that library owners be able to -check their work. Therefore, we intend to build a tool that can compare two -versions of a library's public interface, and present any suspect differences -for verification. Important cases include but are not limited to: - -- Removal of versioned entities. - -- Incompatible modifications to versioned entities, such as added protocol - conformances lacking versioning information. - -- Unsafe `backdating <#backdating>`_. - -- Unsafe modifications to entities marked with fragility attributes, such as - adding a stored property to a ``@frozen`` struct. - -Wherever possible, this tool should also check for `binary-compatible -source-breaking changes `, such as -changing a default argument from ``false`` to ``true``. - - -Automatic Versioning -~~~~~~~~~~~~~~~~~~~~ - -A possible extension of this "checker" would be a tool that *automatically* -generates versioning information for entities in a library, given the previous -public interface of the library. This would remove the need for versions on any -of the fragility attributes, and declaring versioned API would be as simple as -marking an entity ``public``. Obviously this would also remove the possibility -of human error in managing library versions. - -However, making this tool has a number of additional difficulties beyond the -simple checker tool: - -- The tool must be able to read past library interface formats. This is true - for a validation tool as well, but the cost of failure is much higher. - Similarly, the past version of a library *must* be available to correctly - compile a new version. - -- Because the information goes into a library's public interface, the - versioning tool must either be part of the compilation process, modify the - interface generated by compilation, or produce a sidecar file that can be - loaded when compiling the client. In any case, it must *produce* information - in addition to *consuming* it. - -- Occasionally a library owner may want to override the inferred versions. This - can be accomplished by providing explicit versioning information, as - described above. - -- Bugs in the tool manifest as bugs in client programs. - -Because this tool would require a fair amount of additional work, it is not -part of this initial model. It is something we may decide to add in the future. - - -Open Issues -=========== - -There are still a number of known issues with the model described in this -document. We should endeavor to account for each of them, and if we can't come -up with a satisfactory implementation we should at least make sure that they -will not turn into pitfalls for library or client developers. - - -Subclass and base both conform to protocol -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - // Library, version 1 - class Elf {} - protocol Summonable {} - -:: - - // Client, version 1 - class ShoemakingElf : Elf, Summonable {} - -:: - - // Library, version 2 - @available(2.0) - extension Elf : Summonable {} - -Now ``ShoemakingElf`` conforms to ``Summonable`` in two different ways, which -may be incompatible (especially if ``Summonable`` had associated types or -requirements involving ``Self``). - -Additionally, the client can't even remove ``ShoemakingElf``'s conformance to -``Summonable``, because it may itself be a library with other code depending on -it. We could fix that with an annotation to explicitly inherent the conformance -of ``Summonable`` from the base class, but even that may not be possible if -there are incompatible associated types involved (because changing a member -typealias is not a safe change). - -One solution is to disallow adding a conformance for an existing protocol to an -``open`` class. - - -Recompiling changes a protocol's implementation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - // Library, version 1 - protocol MagicType {} - protocol Wearable {} - func use(_ item: T) {} - -:: - - // Client, version 1 - struct Amulet : MagicType, Wearable {} - use(Amulet()) - -:: - - // Library, version 2 - protocol MagicType { - @available(2.0) - func equip() { print("Equipped.") } - } - - extension Wearable where Self: MagicType { - @available(2.0) - func equip() { print("You put it on.") } - } - - func use(_ item: T) { item.equip() } - -Before the client is recompiled, the implementation of ``equip()`` used for -``Amulet`` instances can only be the default implementation, i.e. the one that -prints "Equipped". However, recompiling the client will result in the -constrained implementation being considered a "better" match for the protocol -requirement, thus changing the behavior of the program. - -This should never change the *meaning* of a program, since the default -implementation for a newly-added requirement should always be *correct.* -However, it may have significantly different performance characteristics or -side effects that would make the difference in behavior a surprise. - -This is similar to adding a new overload to an existing set of functions, which -can also change the meaning of client code just by recompiling. However, the -difference here is that the before-recompilation behavior was never requested -or acknowledged by the client; it's just the best the library can do. - -A possible solution here is to require the client to acknowledge the added -requirement in some way when it is recompiled. - -(We do not want to perform overload resolution at run time to find the best -possible default implementation for a given type.) +As a special case, inlinable code must be treated as if it is outside the +current module, since once it's inlined it will be. Summary ======= -When possible, Swift gives library authors freedom to evolve their code -without breaking binary compatibility. This has implications for both the -semantics and performance of client code, and so library owners also have tools -to waive the ability to make certain future changes. The language guarantees -that client code will never accidentally introduce implicit dependencies on -specific versions of libraries. - - -Related Proposals -================= - -The following proposals (some currently in the process, some planned) will -affect the model described in this document, or concern the parts of this -document that affect language semantics: - -- Non-exhaustive enums (`SE-0192 `_) -- Inlineable functions (`SE-0193 `_) -- Frozen structs and enums (`SE-0260 `_) -- (draft) `Overridable methods in extensions`_ -- (planned) Restricting retroactive modeling (protocol conformances for types you don't own) -- (planned) `Generalized existentials (values of protocol type) `_ -- (planned) Removing the "constant" guarantee for 'let' across module boundaries -- (future) Performance annotations for types -- (future) Attributes for stored property accessors -- (future) Stored properties in extensions - -.. _Overridable methods in extensions: https://github.com/jrose-apple/swift-evolution/blob/overridable-members-in-extensions/proposals/nnnn-overridable-members-in-extensions.md -.. _Generics: https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generalized-existentials -.. _SE0192: https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md -.. _SE0193: https://github.com/apple/swift-evolution/blob/master/proposals/0193-cross-module-inlining-and-specialization.md -.. _SE0260: https://github.com/apple/swift-evolution/blob/master/proposals/0260-library-evolution.md - -This does not mean all of these proposals need to be accepted, only that their -acceptance or rejection will affect this document. +When possible, Swift gives library authors freedom to evolve their code without +breaking binary compatibility. This has implications for both the semantics and +performance of client code, and so library owners also have tools to waive the +ability to make certain future changes. When shipping libraries as part of the +OS, the availability model guarantees that client code will never accidentally +introduce implicit dependencies on specific versions of libraries. Glossary @@ -1668,18 +926,17 @@ Glossary including things like symbol names, calling conventions, and type layout information. Stands for "Application Binary Interface". + ABI-public + Describes entities that are part of a library's `ABI`. Marked ``public``, + ``open``, ``@usableFromInline``, or ``@inlinable`` in Swift. See + `SE-0193 `_ for more information. + API An `entity` in a library that a `client` may use, or the collection of all such entities in a library. (If contrasting with `SPI`, only those entities that are available to arbitrary clients.) Marked ``public`` or ``open`` in Swift. Stands for "Application Programming Interface". - availability context - The collection of library and platform versions that can be assumed, at - minimum, to be present in a certain block of code. Availability contexts - are always properly nested, and the global availability context includes - the module's minimum deployment target and minimum dependency versions. - backwards-compatible A modification to an API that does not break existing clients. May also describe the API in question. @@ -1718,21 +975,10 @@ Glossary An API that is designed to handle future clients, perhaps allowing certain changes to be made without changing the ABI. - fragility attribute - See `A Unifying Theme`_. - module The primary unit of code sharing in Swift. Code in a module is always built together, though it may be spread across several source files. - performance assertion - See `Other Promises About Types`_. - - resilience domain - A grouping for code that will always be recompiled and distributed - together, and can thus take advantage of details about a type - even if it changes in the future. - SPI A subset of `API` that is only available to certain clients. Stands for "System Programming Interface". @@ -1741,9 +987,3 @@ Glossary In this document, a collection of code in a single Swift module that is built together; a "compilation unit". Roughly equivalent to a target in Xcode. - - versioned entity - See `Publishing Versioned API`_. - - versioned attribute - See `Publishing Versioned API`_. diff --git a/docs/LibraryEvolutionManifesto.md b/docs/LibraryEvolutionManifesto.md new file mode 100644 index 0000000000000..e2bad23a8a408 --- /dev/null +++ b/docs/LibraryEvolutionManifesto.md @@ -0,0 +1,215 @@ +# Introduction + +This document is intended to discuss current issues in and possible future expansions of Swift's model for ABI-stable _library evolution,_ described in [LibraryEvolution.rst][]. Like other "manifesto" documents in the Swift community, it sets out related tasks in service of a general goal, though this is still an exploration of the space more than a to-do list. + +[LibraryEvolution.rst]: ./LibraryEvolution.rst + + +# Open Issues + + +## Recompiling changes a protocol's implementation + +```swift +// Library, version 1 +protocol MagicType {} +protocol Wearable {} +func use(_ item: T) {} +``` + +```swift +// Client, version 1 +struct Amulet : MagicType, Wearable {} +use(Amulet()) +``` + +```swift +// Library, version 2 +protocol MagicType { + @available(dishwasherOS 2.0, *) + func equip() +} +extension MagicType { + @available(dishwasherOS 2.0, *) + func equip() { print("Equipped.") } +} + +protocol Wearable {} +extension Wearable where Self: MagicType { + @available(dishwasherOS 2.0, *) + func equip() { print("You put it on.") } +} + +func use(_ item: T) { item.equip() } +``` + +Let's say we're running dishwasherOS 2.0. Before the client is recompiled, the implementation of `equip()` used for `Amulet` instances can only be the default implementation, i.e. the one that prints "Equipped". However, recompiling the client will result in the constrained implementation being considered a "better" match for the protocol requirement, thus changing the behavior of the program. + +This should never change the *meaning* of a program, since the default implementation for a newly-added requirement should always be *correct.* However, it may have significantly different performance characteristics or side effects that would make the difference in behavior a surprise. + +This is similar to adding a new overload to an existing set of functions, which can also change the meaning of client code just by recompiling. However, the difference here is that the before-recompilation behavior was never requested or acknowledged by the client; it's just the best the library can do. + +A possible solution here is to require the client to acknowledge the added requirement in some way when it is recompiled. + +(We do not want to perform overload resolution at run time to find the best possible default implementation for a given type.) + + +# Evolving Attributes + +A number of annotations (attributes and modifiers) would benefit from being able to change between releases of a library. For example: + +- Making a `public` class `open`. +- Making a `public` class `final`. +- Making a struct or enum `@frozen`. +- Making a function `@inlinable`. + +However, all of these changes have to be associated with a specific release to be correct: + +- The newly-`open` class can't be subclassed if the client's deployment target is too old. +- Convenience initializers on a newly-`final` class can't satisfy protocol requirements if the client's deployment target is too old. +- A newly-`@frozen` struct may have had more private stored properties in the past. +- A newly-`@inlinable` function's body may not work correctly with older versions of the library. + +While solutions can be tailored to each of these problems, they have a common need to record the OS version when an annotation is added or changed. Without that, we're locked in to the way a declaration is originally published, or having to take correctness on faith. + +## Limitations + +For any annotation that affects the calling conventions of a function specifically, it becomes tricky to add or remove that annotation without breaking ABI. Consider the example of a struct becoming `@frozen`. Normally, functions that pass or return non-frozen structs have to do so indirectly (i.e. through a pointer), whereas frozen structs that are "small enough" (according to the ABI) can be passed in registers instead. So we get tables like this: + +Frozen struct | used in a module's ABI | used in non-public ways +---|---|--- +in its own module | direct | direct +in a client with library evolution | direct | direct +in a client without library evolution (like an app) | direct | direct + +Non-frozen struct | used in a module's ABI | used in non-public ways +---|---|--- +in its own module | indirect (no promises) | direct +in a client with library evolution | indirect (knows nothing) | indirect (knows nothing) +in a client without library evolution (like an app) | indirect (knows nothing) | indirect (knows nothing) + +However, for any library *or client* with library evolution enabled, the ABI columns must not change. That implies that marking a struct as frozen *after its initial release* is different from marking the struct frozen from the start. + +Frozen struct that used to be non-frozen | used in a module's ABI | used in non-public ways +---|---|--- +in its own module | indirect (ABI compat) | direct +in a client with library evolution | indirect (ABI compat) | direct +in a client without library evolution (like an app) | direct | direct + +There are a few ways to improve upon this, the most obvious being that any APIs with newer availability than when the struct became frozen can pass the struct around directly. It's worth noting that a library's minimum deployment target *cannot* be used for this purpose, since changing a minimum deployment target is not supposed to change a library's ABI. + +This isn't a *terrible* performance cost; remember that all C++ methods take `this` indirectly, and clients with new enough deployment targets can still *manipulate* the values directly even if the calling convention can't change. But it's something to think about for every annotation that can change after a type is introduced. + + +# Additional Annotations + +## Layout Constraints + +Developers with performance-sensitive use cases may want to promise more specific things about various types and have the compiler enforce them. + +- "trivial": Promises that assignment just requires a fixed-size bit-for-bit copy without any indirection or reference-counting operations. This may allow more efficient copying and destruction of values. + +- "maximum size N/alignment A": Promises that the type's size and required alignment are at most N bits and A bits, respectively. (Both may be smaller.) This would make it easier for the compiler to work with values on the stack. + +(Neither of these names / spellings are final. The name "trivial" comes from C++, though Swift's trivial is closer to C++'s "[trivially copyable][]".) + +Both of these annotations are things the compiler already knows when a type is declared, but writing them explicitly (a) allows the developer to check that they've made something properly optimizable, and (b) promises not to change that behavior between releases, even if, say, stored properties are added to or removed from a struct. + +[trivially copyable]: http://en.cppreference.com/w/cpp/types/is_trivially_copyable + + +## Frozen classes + +The compiler actually has basic support for frozen classes, which allow stored properties to be accessed directly by offset from the class reference. There's no real reason why this can't be supported more generally, but confusion around *what's* being frozen and the rarity of wanting to make this promise anyway kept it out of [SE-0260][]. + +[SE-0260]: https://github.com/apple/swift-evolution/blob/master/proposals/0260-library-evolution.md + + +# Generalized Availability Model + +This section is focused on various ways to extend the OS-version-based availability model. + +## Per-library availability + +As a placeholder, imagine replacing OS versions with library versions in the various parts of Swift's availability checking syntax: + +```swift +// Client code +@available(Magician 1.5) +class CrystalBallView : MagicView { /*...*/ } + +func scareMySiblings() { + if #available(Magician 1.2) { + summonDemons() + } else { + print("BOO!!") + } +} +``` + +This sort of version checking is important for *backward*-deployment, where the developer has the interface available for a new version of a library (Magician 1.5), but might end up running the client against an old version (Magician 1.0). It's not interesting for *forward*-deployment, however—that's all up to the library to preserve ABI compatibility. + +Possible implementations for version checking include generating a hidden symbol into a library, or putting the version number in some kind of metadata, like the Info.plist in a framework bundle on Apple platforms. + + +### Publishing API with availability + +A library's API is already marked with the `public` modifier, but if a client wants to work with multiple releases of the library, the API needs availability information as well. Declaring availability on an entity using the *current* library's name specifies the oldest version in which that entity can be used. + +- Classes, structs, enums, and protocols may all have availability. +- Methods, properties, subscripts, and initializers may all have availability. +- Top-level functions, variables, and constants may have availability. +- Typealiases are treated as having availability for the purpose of availability checking, even though they have no run-time presence. + +In a versioned library, any top-level public entity from the list above may not be made ABI-public (`public`, `open`, `@usableFromInline`, or `@inlinable`) without availability. A public entity declared within a type (or an extension of a type) will default to having the same availability as the type. + +Code within a library may generally use all other entities declared within the library (barring their own availability checks), since the entire library is shipped as a unit. That is, even if a particular API was introduced in v1.0, its (non-public) implementation may refer to APIs introduced in later versions. Inlinable functions are the exception to this, since inlined code ends up outside the original module. + + +### Declaring library version dependencies + +Swift's current OS-based availability model includes the notion of a _minimum deployment target,_ the version of an OS that must be present for the program being compiled to run at all. For example, a program compiled with a minimum deployment target of iOS 9.2 will not launch on iOS 9.0. + +The generalized model suggests being able to make similar guarantees for individual libraries. For example, a client program may depend on version 1.1 of the "Magician" library; trying to run using version 1.0 will result in errors. By declaring this at compile-time, the client code can omit `@available` and `#available` checks that are satisfied by the minimum library version. + + +## Resilience domains + +In general, the features around library evolution for ABI stability's sake do not apply to clients that bundle their dependencies with them (such as an iOS app embedding third-party frameworks). In this case, a client can rely on all the current implementation details of its libraries when compiling, since the same version of the library is guaranteed to be present at run time. This allows more optimization than would otherwise be possible. + +In some cases, a collection of libraries may be built and delivered together, even though their clients may be packaged separately. (For example, the ICU project is usually built into several library binaries, but these libraries are always distributed together.) While the *clients* cannot rely on a particular version of any library being present, the various libraries in the collection should be able to take advantage of the implementations of their dependencies also in the collection---that is, it should treat types as frozen (except where it would affect public-facing ABI). We've used the term _resilience domain_ to describe modules in this sort of collection. + +There's no design yet for how resilience domains should be specified. In today's compiler, every library with library evolution enabled is in its own resilience domain, and every library that *doesn't* have library evolution enabled is in the "app" resilience domain. + +### Deployments + +Related to the concept of a resilience domain is a _deployment._ While a resilience domain allows related libraries to be compiled more efficiently, a deployment groups related libraries together to present semantic version information to clients. The simplest example of this might be an OS release: OS X 10.10.0 contains Foundation version 1151.16 and AppKit version 1343. A deployment thus acts as a "virtual dependency": clients that depend on OS X 10.10 can rely on the presence of both of the library versions above. + +The use of deployments allows clients to only have to think about aggregate dependencies, instead of listing every library they might depend on. It also allows library authors to build [many versions of a library][Foundation version numbers] within a larger release cycle, as well as allowing a vendor to bundle together many libraries with uncoordinated release schedules and release them as a logical unit. + +[Foundation version numbers]: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Constants/index.html#//apple_ref/doc/constant_group/Foundation_Framework_Version_Numbers + +There are lots of details to figure out here, including how to distribute this information. In particular, just like libraries publish the history of their own APIs, a deployment must publish the history of their included library versions, i.e. not just that OS X 10.10 contains Foundation 1151.16 and AppKit 1343, but also that OS X 10.9 contains Foundation 1056 and AppKit 1265, and that OS X 10.8 contains Foundation 945.0 and AppKit 1187, and so on, back to the earliest version of the deployment that is supported. + +Obviously, formalizing a model here is probably most useful for people distributing ABI-stable Swift libraries as part of an OS, i.e. Apple. + + +# Automated Tooling + +## ABI Checker + +The Swift repository has a basic ABI checker in the form of swift-api-digester. This tool looks at two versions of a library and determines if there are any changes which are known to be unsafe (say, changing the type of a function parameter). It would be nice™ to integrate this into SwiftPM and Xcode in some way. + +## Automatic Versioning + +A possible extension of the ABI checker would be a tool that *automatically* generates versioning information for entities in a library, given the previous public interface of the library. This would remove the need for versions on annotations, and declaring new public API would be as simple as marking an entity `public`. Obviously this would also remove the possibility of human error in managing library versions. + +However, making this tool has a number of additional difficulties beyond the simple checker tool: + +- The tool must be able to read past library interface formats. This is true for a validation tool as well, but the cost of failure is much higher. Similarly, the past version of a library *must* be available to correctly compile a new version. + +- Because the information goes into a library's public interface, the versioning tool must either be part of the compilation process, modify the interface generated by compilation, or produce a sidecar file that can be loaded when compiling the client. In any case, it must *produce* information in addition to *consuming* it. + +- Occasionally a library owner may want to override the inferred versions. This can be accomplished by providing explicit versioning information, as described above. + +- Bugs in the tool manifest as bugs in client programs. diff --git a/docs/OptimizationTips.rst b/docs/OptimizationTips.rst index 77e31b909175b..60171e08f3a13 100644 --- a/docs/OptimizationTips.rst +++ b/docs/OptimizationTips.rst @@ -82,7 +82,7 @@ in the following code snippet, ``a.aProperty``, ``a.doSomething()`` and dynamic doSomethingElse() { ... } } - class B : A { + class B: A { override var aProperty { get { ... } set { ... } @@ -155,7 +155,7 @@ assuming ``E``, ``F`` do not have any overriding declarations in the same file: } class F { - fileprivate var myPrivateVar : Int + fileprivate var myPrivateVar: Int } func usingE(_ e: E) { @@ -193,11 +193,11 @@ Array. // Don't use a class here. struct PhonebookEntry { - var name : String - var number : [Int] + var name: String + var number: [Int] } - var a : [PhonebookEntry] + var a: [PhonebookEntry] Keep in mind that there is a trade-off between using large value types and using reference types. In certain cases, the overhead of copying and moving around @@ -277,9 +277,9 @@ safe. :: - a : [Int] - b : [Int] - c : [Int] + a: [Int] + b: [Int] + c: [Int] // Precondition: for all a[i], b[i]: a[i] + b[i] does not overflow! for i in 0 ... n { @@ -368,12 +368,12 @@ represented as values, so this example is somewhat realistic. :: protocol P {} - struct Node : P { - var left, right : P? + struct Node: P { + var left, right: P? } struct Tree { - var node : P? + var node: P? init() { ... } } @@ -402,8 +402,8 @@ argument drops from being O(n), depending on the size of the tree to O(1). :: - struct Tree : P { - var node : [P?] + struct Tree: P { + var node: [P?] init() { node = [thing] } @@ -435,13 +435,13 @@ construct such a data structure: :: final class Ref { - var val : T - init(_ v : T) {val = v} + var val: T + init(_ v: T) {val = v} } struct Box { - var ref : Ref - init(_ x : T) { ref = Ref(x) } + var ref: Ref + init(_ x: T) { ref = Ref(x) } var value: T { get { return ref.val } @@ -506,7 +506,7 @@ alive. withExtendedLifetime(Head) { // Create an Unmanaged reference. - var Ref : Unmanaged = Unmanaged.passUnretained(Head) + var Ref: Unmanaged = Unmanaged.passUnretained(Head) // Use the unmanaged reference in a call/variable access. The use of // _withUnsafeGuaranteedRef allows the compiler to remove the ultimate @@ -540,7 +540,7 @@ protocols as class-only protocols to get better runtime performance. :: - protocol Pingable : AnyObject { func ping() -> Int } + protocol Pingable: AnyObject { func ping() -> Int } .. https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html diff --git a/docs/StandardLibraryProgrammersManual.md b/docs/StandardLibraryProgrammersManual.md index 8731c2db79392..4ef49ccd1c2ec 100644 --- a/docs/StandardLibraryProgrammersManual.md +++ b/docs/StandardLibraryProgrammersManual.md @@ -239,24 +239,3 @@ internal mutating func _roundSlowPath(_ rule: FloatingPointRoundingRule) { Because `_roundSlowPath(_:)` isn't inlinable, the version of `round(_:)` that gets called at run time will always be the version implemented in the standard library dylib. And since FloatingPointRoundingRule is *also* defined in the standard library, we know it'll never be out of sync with this version of `round(_:)`. Maybe some day we'll have special syntax in the language to say "call this method without allowing inlining" to get the same effect, but for now, this Curiously Recursive Inlinable Switch Pattern allows for safe inlining of switches over non-frozen enums with less boilerplate than you might otherwise have. Not none, but less. - - -## Productivity Hacks - -### Be a Ninja - -To *be* a productivity ninja, one must *use* `ninja`. `ninja` can be invoked inside the swift build directory, e.g. `/build/Ninja-ReleaseAssert/swift-macosx-x86_64/`. Running `ninja` (which is equivalent to `ninja all`) will build the local swift, stdlib and overlays. It doesn’t necessarily build all the testing infrastructure, benchmarks, etc. - -`ninja -t targets` gives a list of all possible targets to pass to ninja. This is useful for grepping. - -For this example, we will figure out how to quickly iterate on a change to the standard library to fix 32-bit build errors while building on a 64-bit host, suppressing warnings along the way. - -`ninja -t targets | grep stdlib | grep i386` will output many targets, but at the bottom we see `swift-stdlib-iphonesimulator-i386`, which looks like a good first step. This target will just build i386 parts and not waste our time also building the 64-bit stdlib, overlays, etc. - -Going further, ninja can spawn a web browser for you to navigate dependencies and rules. `ninja -t browse swift-stdlib-iphonesimulator-i386` will open a webpage with hyperlinks for all related targets. “target is built using” lists all this target’s dependencies, while “dependent edges build” list all the targets that depend directly on this. - -Clicking around a little bit, we can find `lib/swift/iphonesimulator/i386/libswiftCore.dylib` as a commonly-depended-upon target. This will perform just what is needed to compile the standard library for i386 and nothing else. - -Going further, for various reasons the standard library has lots of warnings. This is actively being addressed, but fixing all of them may require language features, etc. In the mean time, let’s suppress warnings in our build so that we just see the errors. `ninja -nv lib/swift/iphonesimulator/i386/libswiftCore.dylib` will show us the actual commands ninja will issue to build the i386 stdlib. (You’ll notice that an incremental build here is merely 3 commands as opposed to ~150 for `swift-stdlib-iphonesimulator-i386`). - -Copy the invocation that has ` -o /swift-macosx-x86_64/stdlib/public/core/iphonesimulator/i386/Swift.o`, so that we can perform the actual call to swiftc ourselves. Tack on `-suppress-warnings` at the end, and now we have the command to just build `Swift.o` for i386 while only displaying the actual errors. diff --git a/docs/WindowsBuild.md b/docs/WindowsBuild.md index 9f3a4002d7b89..9aa98d27a84f1 100644 --- a/docs/WindowsBuild.md +++ b/docs/WindowsBuild.md @@ -98,45 +98,20 @@ ninja -C S:\b\libdispatch check ## Build swift-corelibs-foundation ```cmd -md "S:\b\foundation" -cd "S:\b\foundation -cmake -G Ninja^ - -DCMAKE_BUILD_TYPE=RelWithDebInfo^ - -DCMAKE_C_COMPILER=clang-cl^ - -DCMAKE_SWIFT_COMPILER=S:\b\toolchain\bin\swiftc.exe^ - -DCURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib"^ - -DCURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include"^ - -DENABLE_TESTING=NO^ - -DICU_ROOT="S:/Library/icu-64"^ - -DLIBXML2_LIBRARY="S:/Library/libxml2-development/usr/lib/libxml2.lib"^ - -DLIBXML2_INCLUDE_DIR="S:/Library/libxml2-development/usr/include"^ - -DFOUNDATION_PATH_TO_LIBDISPATCH_SOURCE=S:\swift-corelibs-libdispatch^ - -DFOUNDATION_PATH_TO_LIBDISPATCH_BUILD=S:\b\libdispatch^ - S:\swift-corelibs-foundation -ninja +cmake -B S:\b\foundation -G Ninja -S S:\toolchain\swift-corelibs-foundation -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=clang-cl -DCMAKE_Swift_COMPILER=S:\b\toolchain\bin\swiftc.exe -DCURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib" -DCURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include" -DICU_ROOT="S:/Library/icu-64" -DLIBXML2_LIBRARY="S:/Library/libxml2-development/usr/lib/libxml2.lib" -DLIBXML2_INCLUDE_DIR="S:/Library/libxml2-development/usr/include" -DENABLE_TESTING=NO -Ddisptch_DIR=S:/b/libdispatch/cmake/modules +ninja -C S:\b\foundation ``` - Add Foundation to your path: ```cmd -path S:\b\foundation;%PATH% +path S:\b\foundation\Foundation;%PATH% ``` ## Build swift-corelibs-xctest ```cmd -md "S:\b\xctest" -cd "S:\b\xctest" -cmake -G Ninja^ - -DBUILD_SHARED_LIBS=YES^ - -DCMAKE_BUILD_TYPE=RelWithDebInfo^ - -DCMAKE_SWIFT_COMPILER=S:\b\toolchain\bin\swiftc.exe^ - -DXCTEST_PATH_TO_FOUNDATION_BUILD=S:\b\foundation^ - -DXCTEST_PATH_TO_LIBDISPATCH_SOURCE=S:\swift-corelibs-libdispatch^ - -DXCTEST_PATH_TO_LIBDISPATCH_BUILD=S:\b\libdispatch^ - -DLIT_COMMAND=S:\llvm\utils\lit\lit.py^ - -DPYTHON_EXECUTABLE=C:\Python27\python.exe^ - S:\swift-corelibs-xctest -ninja +cmake -B S:\b\xctest -G Ninja -S S:\toolchain\swift-corelibs-xctest -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -Ddispatch_DIR=S:\b\dispatch\cmake\modules -DFoundation_DIR=S:\b\foundation\cmake\modules -DLIT_COMMAND=S:\toolchain\llvm\utils\lit\lit.py -DPYTHON_EXECUTABLE=C:\Python27\python.exe +ninja -C S:\b\xctest ``` - Add XCTest to your path: @@ -153,22 +128,8 @@ ninja -C S:\b\xctest check-xctest ## Rebuild Foundation ```cmd -cd "S:\b\foundation -cmake -G Ninja^ - -DCMAKE_BUILD_TYPE=RelWithDebInfo^ - -DCMAKE_C_COMPILER=clang-cl^ - -DCMAKE_SWIFT_COMPILER=S:\b\toolchain\bin\swiftc.exe^ - -DCURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib"^ - -DCURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include"^ - -DENABLE_TESTING=YES^ - -DICU_ROOT="S:/Library/icu-64"^ - -DLIBXML2_LIBRARY="S:/Library/libxml2-development/usr/lib/libxml2.lib"^ - -DLIBXML2_INCLUDE_DIR="S:/Library/libxml2-development/usr/include"^ - -DFOUNDATION_PATH_TO_LIBDISPATCH_SOURCE=S:\swift-corelibs-libdispatch^ - -DFOUNDATION_PATH_TO_LIBDISPATCH_BUILD=S:\b\libdispatch^ - -DFOUNDATION_PATH_TO_XCTEST_BUILD=S:\b\xctest^ - S:\swift-corelibs-foundation -ninja +cmake -B S:\b\foundation -G Ninja -S S:\toolchain\swift-corelibs-foundation -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=clang-cl -DCMAKE_Swift_COMPILER=S:/b/toolchain/bin/swiftc.exe -DCURL_LIBRARY="S:/Library/libcurl-development/usr/lib/libcurl.lib" -DCURL_INCLUDE_DIR="S:/Library/libcurl-development/usr/include" -DICU_ROOT="S:/Library/icu-64" -DLIBXML2_LIBRARY="S:/Library/libxml2-development/usr/lib/libxml2.lib" -DLIBXML2_INCLUDE_DIR="S:/Library/libxml2-development/usr/include" -DENABLE_TESTING=YES -Ddisptch_DIR=S:/b/libdispatch/cmake/modules -DXCTest_DIR=S:/b/xctest/cmake/modules +ninja -C S:\b\foundation ``` ## Test Foundation diff --git a/include/swift/ABI/ValueWitness.def b/include/swift/ABI/ValueWitness.def index d07eca212993c..646deb4bd0d78 100644 --- a/include/swift/ABI/ValueWitness.def +++ b/include/swift/ABI/ValueWitness.def @@ -160,7 +160,8 @@ FUNCTION_VALUE_WITNESS(assignWithTake, MUTABLE_VALUE_TYPE, (MUTABLE_VALUE_TYPE, MUTABLE_VALUE_TYPE, TYPE_TYPE)) -/// unsigned (*getEnumTagSinglePayload)(const T* enum, UINT_TYPE emptyCases) +/// unsigned (*getEnumTagSinglePayload)(const T* enum, UINT_TYPE emptyCases, +/// M *self); /// Given an instance of valid single payload enum with a payload of this /// witness table's type (e.g Optional) , get the tag of the enum. FUNCTION_VALUE_WITNESS(getEnumTagSinglePayload, @@ -169,7 +170,7 @@ FUNCTION_VALUE_WITNESS(getEnumTagSinglePayload, (IMMUTABLE_VALUE_TYPE, UINT_TYPE, TYPE_TYPE)) /// void (*storeEnumTagSinglePayload)(T* enum, UINT_TYPE whichCase, -/// UINT_TYPE emptyCases) +/// UINT_TYPE emptyCases, M *self); /// Given uninitialized memory for an instance of a single payload enum with a /// payload of this witness table's type (e.g Optional), store the /// tag. diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index c7960a040e196..2347b879e4ee6 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -203,8 +203,9 @@ class ASTContext final { ASTContext(const ASTContext&) = delete; void operator=(const ASTContext&) = delete; - ASTContext(LangOptions &langOpts, SearchPathOptions &SearchPathOpts, - SourceManager &SourceMgr, DiagnosticEngine &Diags); + ASTContext(LangOptions &langOpts, TypeCheckerOptions &typeckOpts, + SearchPathOptions &SearchPathOpts, SourceManager &SourceMgr, + DiagnosticEngine &Diags); public: // Members that should only be used by ASTContext.cpp. @@ -215,10 +216,9 @@ class ASTContext final { void operator delete(void *Data) throw(); - static ASTContext *get(LangOptions &langOpts, + static ASTContext *get(LangOptions &langOpts, TypeCheckerOptions &typeckOpts, SearchPathOptions &SearchPathOpts, - SourceManager &SourceMgr, - DiagnosticEngine &Diags); + SourceManager &SourceMgr, DiagnosticEngine &Diags); ~ASTContext(); /// Optional table of counters to report, nullptr when not collecting. @@ -230,6 +230,9 @@ class ASTContext final { /// The language options used for translation. LangOptions &LangOpts; + /// The type checker options. + TypeCheckerOptions &TypeCheckerOpts; + /// The search path options used by this AST context. SearchPathOptions &SearchPathOpts; @@ -276,6 +279,11 @@ class ASTContext final { /// The # of times we have performed typo correction. unsigned NumTypoCorrections = 0; + /// The next auto-closure discriminator. This needs to be preserved + /// across invocations of both the parser and the type-checker. + unsigned NextAutoClosureDiscriminator = 0; + + // SWIFT_ENABLE_TENSORFLOW /// Cache of autodiff-associated vector spaces. llvm::DenseMap> AutoDiffVectorSpaces; @@ -284,6 +292,7 @@ class ASTContext final { /// same set of parameters. llvm::DenseMap, DifferentiableAttr *> DifferentiableAttrs; + // SWIFT_ENABLE_TENSORFLOW END private: /// The current generation number, which reflects the number of @@ -593,10 +602,6 @@ class ASTContext final { ForeignLanguage language, const DeclContext *dc); - /// Add a declaration that was synthesized to a per-source file list if - /// if is part of a source file. - void addSynthesizedDecl(Decl *decl); - /// Add a cleanup function to be called when the ASTContext is deallocated. void addCleanup(std::function cleanup); diff --git a/include/swift/AST/ASTTypeIDZone.def b/include/swift/AST/ASTTypeIDZone.def index 75021ab10d678..ea3bdab6c8820 100644 --- a/include/swift/AST/ASTTypeIDZone.def +++ b/include/swift/AST/ASTTypeIDZone.def @@ -45,6 +45,7 @@ SWIFT_TYPEID_NAMED(OpaqueTypeDecl *, OpaqueTypeDecl) SWIFT_TYPEID_NAMED(OperatorDecl *, OperatorDecl) SWIFT_TYPEID_NAMED(Optional, PropertyWrapperMutability) +SWIFT_TYPEID_NAMED(ParamDecl *, ParamDecl) SWIFT_TYPEID_NAMED(PatternBindingEntry *, PatternBindingEntry) SWIFT_TYPEID_NAMED(PrecedenceGroupDecl *, PrecedenceGroupDecl) SWIFT_TYPEID_NAMED(ProtocolDecl *, ProtocolDecl) diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 669a0a65e1f56..36d1d0ad3ea1e 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -506,7 +506,6 @@ SIMPLE_DECL_ATTR(_nonEphemeral, NonEphemeral, ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove, 90) -// SWIFT_ENABLE_TENSORFLOW DECL_ATTR(differentiable, Differentiable, OnAccessor | OnConstructor | OnFunc | OnVar | OnSubscript | LongAttribute | AllowMultipleAttributes | diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 83ceedc6b3e87..2453eb5e8cc82 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -27,6 +27,7 @@ #include "swift/Basic/Version.h" #include "swift/AST/Identifier.h" #include "swift/AST/AttrKind.h" +#include "swift/AST/AutoDiff.h" #include "swift/AST/ConcreteDeclRef.h" #include "swift/AST/DeclNameLoc.h" #include "swift/AST/KnownProtocols.h" @@ -35,8 +36,6 @@ #include "swift/AST/Requirement.h" #include "swift/AST/TrailingCallArguments.h" #include "swift/AST/TypeLoc.h" -// SWIFT_ENABLE_TENSORFLOW -#include "swift/AST/AutoDiff.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" @@ -167,7 +166,7 @@ class TypeAttributes { static const char *getAttrName(TypeAttrKind kind); }; -class AttributeBase { +class alignas(1 << AttrAlignInBits) AttributeBase { public: /// The location of the '@'. const SourceLoc AtLoc; @@ -1523,563 +1522,561 @@ class CustomAttr final : public DeclAttribute, } }; -// SWIFT_ENABLE_TENSORFLOW -struct DeclNameWithLoc { - DeclName Name; - DeclNameLoc Loc; -}; - -// SWIFT_ENABLE_TENSORFLOW -/// Attribute that marks a function as differentiable and optionally specifies -/// custom associated derivative functions: 'jvp' and 'vjp'. +/// Relates a property to its projection value property, as described by a property wrapper. For +/// example, given +/// \code +/// @A var foo: Int +/// \endcode /// -/// Examples: -/// @differentiable(jvp: jvpFoo where T : FloatingPoint) -/// @differentiable(wrt: (self, x, y), jvp: jvpFoo) -class DifferentiableAttr final - : public DeclAttribute, - private llvm::TrailingObjects { - friend TrailingObjects; - friend class DifferentiableAttributeParameterIndicesRequest; +/// Where \c A is a property wrapper that has a \c projectedValue property, the compiler +/// synthesizes a declaration $foo an attaches the attribute +/// \c _projectedValuePropertyAttr($foo) to \c foo to record the link. +class ProjectedValuePropertyAttr : public DeclAttribute { +public: + ProjectedValuePropertyAttr(Identifier PropertyName, + SourceLoc AtLoc, SourceRange Range, + bool Implicit) + : DeclAttribute(DAK_ProjectedValueProperty, AtLoc, Range, Implicit), + ProjectionPropertyName(PropertyName) {} - /// The declaration on which the `@differentiable` attribute is declared. - Decl *OriginalDeclaration = nullptr; - /// Whether this function is linear. - bool Linear; - /// The number of parsed parameters specified in 'wrt:'. - unsigned NumParsedParameters = 0; - /// The JVP function. - Optional JVP; - /// The VJP function. - Optional VJP; - /// The JVP function (optional), resolved by the type checker if JVP name is - /// specified. - FuncDecl *JVPFunction = nullptr; - /// The VJP function (optional), resolved by the type checker if VJP name is - /// specified. - FuncDecl *VJPFunction = nullptr; - /// The differentiation parameters' indices, resolved by the type checker. - /// The bit stores whether the parameter indices have been computed. - llvm::PointerIntPair ParameterIndicesAndBit; - /// The trailing where clause (optional). - TrailingWhereClause *WhereClause = nullptr; - /// The generic signature for autodiff derivative functions. Resolved by the - /// type checker based on the original function's generic signature and the - /// attribute's where clause requirements. This is set only if the attribute - /// has a where clause. - GenericSignature DerivativeGenericSignature = GenericSignature(); + // The projection property name. + const Identifier ProjectionPropertyName; - explicit DifferentiableAttr(bool implicit, SourceLoc atLoc, - SourceRange baseRange, bool linear, - ArrayRef parameters, - Optional jvp, - Optional vjp, - TrailingWhereClause *clause); + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DAK_ProjectedValueProperty; + } +}; - explicit DifferentiableAttr(Decl *original, bool implicit, SourceLoc atLoc, - SourceRange baseRange, bool linear, - IndexSubset *indices, - Optional jvp, - Optional vjp, - GenericSignature derivativeGenericSignature); +/// Attribute that asks the compiler to generate a function that returns a +/// quoted representation of the attributed declaration. +/// +/// @quoted +/// func identity(_ x: Int) -> Int { +/// return x; +/// } +/// +/// The generated function, called "quote decl", looks along the following lines +/// (the exact representation may change over time since quasiquotes are an +/// experimental feature, e.g. the name may end up being mangled as per #13): +/// +/// func _quotedIdentity() -> Tree { +/// return #quote{ +/// func identity(_ x: Int) -> Int { +/// return x; +/// } +/// } +/// } +/// +/// Quote decls are not supposed to be called manually. Instead, it is expected +/// that #quote(...) will be used to obtain representations of @quoted +/// declarations, by synthesizing calls to quote decls. This way users don't +/// have to know the details of name mangling in the presence of overloads etc: +/// +/// #quote(identity) +/// +/// Unquote( +/// Name( +/// "foo", +/// "s:4main3fooyS2fF", +/// FunctionType( +/// [], +/// [TypeName("Int", "s:Si")], +/// TypeName("Int", "s:Si"))), +/// { () -> Tree in quotedIdentity() }, +/// FunctionType( +/// [], +/// [TypeName("Int", "s:Si")], +/// TypeName("Int", "s:Si"))) +class QuotedAttr final : public DeclAttribute { + FuncDecl *QuoteDecl; + + explicit QuotedAttr(FuncDecl *quoteDecl, SourceLoc atLoc, SourceRange range, + bool implicit); public: - static DifferentiableAttr *create(ASTContext &context, bool implicit, - SourceLoc atLoc, SourceRange baseRange, - bool linear, - ArrayRef params, - Optional jvp, - Optional vjp, - TrailingWhereClause *clause); + FuncDecl *getQuoteDecl() const { return QuoteDecl; } + void setQuoteDecl(FuncDecl *quoteDecl) { QuoteDecl = quoteDecl; } - static DifferentiableAttr *create(Decl *original, bool implicit, - SourceLoc atLoc, SourceRange baseRange, - bool linear, IndexSubset *indices, - Optional jvp, - Optional vjp, - GenericSignature derivativeGenSig); + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DAK_Quoted; + } - Decl *getOriginalDeclaration() const { return OriginalDeclaration; } - void setOriginalDeclaration(Decl *decl); + static QuotedAttr *create(ASTContext &context, SourceLoc atLoc, + SourceRange range, bool implicit); - /// Get the optional 'jvp:' function name and location. - /// Use this instead of `getJVPFunction` to check whether the attribute has a - /// registered JVP. - Optional getJVP() const { return JVP; } + static QuotedAttr *create(ASTContext &context, FuncDecl *quoteDecl, + SourceLoc atLoc, SourceRange range, bool implicit); +}; - /// Get the optional 'vjp:' function name and location. - /// Use this instead of `getVJPFunction` to check whether the attribute has a - /// registered VJP. - Optional getVJP() const { return VJP; } +/// Attributes that may be applied to declarations. +class DeclAttributes { + /// Linked list of declaration attributes. + DeclAttribute *DeclAttrs; - bool hasComputedParameterIndices() const; - IndexSubset *getParameterIndices() const; - void setParameterIndices(IndexSubset *paramIndices); +public: + DeclAttributes() : DeclAttrs(nullptr) {} - /// The parsed differentiation parameters, i.e. the list of parameters - /// specified in 'wrt:'. - ArrayRef getParsedParameters() const { - return {getTrailingObjects(), NumParsedParameters}; - } - MutableArrayRef getParsedParameters() { - return {getTrailingObjects(), NumParsedParameters}; - } - size_t numTrailingObjects(OverloadToken) const { - return NumParsedParameters; + bool isEmpty() const { + return DeclAttrs == nullptr; } - - bool isLinear() const { return Linear; } - - TrailingWhereClause *getWhereClause() const { return WhereClause; } - GenericSignature getDerivativeGenericSignature() const { - return DerivativeGenericSignature; - } - void setDerivativeGenericSignature(GenericSignature derivativeGenSig) { - DerivativeGenericSignature = derivativeGenSig; + void getAttrRanges(SmallVectorImpl &Ranges) const { + for (auto Attr : *this) { + auto R = Attr->getRangeWithAt(); + if (R.isValid()) + Ranges.push_back(R); + } } - FuncDecl *getJVPFunction() const { return JVPFunction; } - void setJVPFunction(FuncDecl *decl); - FuncDecl *getVJPFunction() const { return VJPFunction; } - void setVJPFunction(FuncDecl *decl); + /// If this attribute set has a prefix/postfix attribute on it, return this. + UnaryOperatorKind getUnaryOperatorKind() const { + if (hasAttribute()) + return UnaryOperatorKind::Prefix; + if (hasAttribute()) + return UnaryOperatorKind::Postfix; + return UnaryOperatorKind::None; + } - bool parametersMatch(const DifferentiableAttr &other) const { - return getParameterIndices() == other.getParameterIndices(); + bool isUnavailable(const ASTContext &ctx) const { + return getUnavailable(ctx) != nullptr; } - /// Get the derivative generic environment for the given `@differentiable` - /// attribute and original function. - GenericEnvironment * - getDerivativeGenericEnvironment(AbstractFunctionDecl *original) const; + /// Determine whether there is a swiftVersionSpecific attribute that's + /// unavailable relative to the provided language version. + bool + isUnavailableInSwiftVersion(const version::Version &effectiveVersion) const; - // Print the attribute to the given stream. - // If `omitWrtClause` is true, omit printing the `wrt:` clause. - // If `omitDerivativeFunctions` is true, omit printing derivative functions. - void print(llvm::raw_ostream &OS, const Decl *D, - bool omitWrtClause = false, - bool omitDerivativeFunctions = false) const; + /// Returns the first @available attribute that indicates + /// a declaration is unavailable, or the first one that indicates it's + /// potentially unavailable, or null otherwise. + const AvailableAttr *getPotentiallyUnavailable(const ASTContext &ctx) const; - static bool classof(const DeclAttribute *DA) { - return DA->getKind() == DAK_Differentiable; - } -}; + /// Returns the first @available attribute that indicates + /// a declaration is unavailable, or null otherwise. + const AvailableAttr *getUnavailable(const ASTContext &ctx) const; -// SWIFT_ENABLE_TENSORFLOW -/// Attribute that registers a function as a derivative of another function. -/// -/// Examples: -/// @derivative(of: sin(_:)) -/// @derivative(of: +, wrt: (lhs, rhs)) -class DerivativeAttr final - : public DeclAttribute, - private llvm::TrailingObjects { - friend TrailingObjects; + /// Returns the first @available attribute that indicates + /// a declaration is deprecated on all deployment targets, or null otherwise. + const AvailableAttr *getDeprecated(const ASTContext &ctx) const; - /// The original function name. - DeclNameWithLoc OriginalFunctionName; - /// The original function declaration, resolved by the type checker. - AbstractFunctionDecl *OriginalFunction = nullptr; - /// The number of parsed parameters specified in 'wrt:'. - unsigned NumParsedParameters = 0; - /// The differentiation parameters' indices, resolved by the type checker. - IndexSubset *ParameterIndices = nullptr; + SWIFT_DEBUG_DUMPER(dump(const Decl *D = nullptr)); + void print(ASTPrinter &Printer, const PrintOptions &Options, + const Decl *D = nullptr) const; + static void print(ASTPrinter &Printer, const PrintOptions &Options, + ArrayRef FlattenedAttrs, + const Decl *D = nullptr); - explicit DerivativeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, - DeclNameWithLoc original, - ArrayRef params); + template + class iterator_base : public std::iterator { + T *Impl; + public: + explicit iterator_base(T *Impl) : Impl(Impl) {} + DERIVED &operator++() { Impl = Impl->Next; return (DERIVED&)*this; } + bool operator==(const iterator_base &X) const { return X.Impl == Impl; } + bool operator!=(const iterator_base &X) const { return X.Impl != Impl; } + T *operator*() const { return Impl; } + T &operator->() const { return *Impl; } + }; - explicit DerivativeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, - DeclNameWithLoc original, IndexSubset *indices); + /// Add a constructed DeclAttribute to this list. + void add(DeclAttribute *Attr) { + Attr->Next = DeclAttrs; + DeclAttrs = Attr; + } -public: - static DerivativeAttr *create(ASTContext &context, bool implicit, - SourceLoc atLoc, SourceRange baseRange, - DeclNameWithLoc original, - ArrayRef params); + // Iterator interface over DeclAttribute objects. + class iterator : public iterator_base { + public: + explicit iterator(DeclAttribute *Impl) : iterator_base(Impl) {} + }; - static DerivativeAttr *create(ASTContext &context, bool implicit, - SourceLoc atLoc, SourceRange baseRange, - DeclNameWithLoc original, IndexSubset *indices); + class const_iterator : public iterator_base { + public: + explicit const_iterator(const DeclAttribute *Impl) + : iterator_base(Impl) {} + }; - DeclNameWithLoc getOriginalFunctionName() const { - return OriginalFunctionName; - } - AbstractFunctionDecl *getOriginalFunction() const { - return OriginalFunction; - } - void setOriginalFunction(AbstractFunctionDecl *decl) { - OriginalFunction = decl; + iterator begin() { return iterator(DeclAttrs); } + iterator end() { return iterator(nullptr); } + const_iterator begin() const { return const_iterator(DeclAttrs); } + const_iterator end() const { return const_iterator(nullptr); } + + /// Retrieve the first attribute of the given attribute class. + template + const ATTR *getAttribute(bool AllowInvalid = false) const { + return const_cast(this)->getAttribute(AllowInvalid); } - /// The parsed differentiation parameters, i.e. the list of parameters - /// specified in 'wrt:'. - ArrayRef getParsedParameters() const { - return {getTrailingObjects(), NumParsedParameters}; + template + ATTR *getAttribute(bool AllowInvalid = false) { + for (auto Attr : *this) + if (auto *SpecificAttr = dyn_cast(Attr)) + if (SpecificAttr->isValid() || AllowInvalid) + return SpecificAttr; + return nullptr; } - MutableArrayRef getParsedParameters() { - return {getTrailingObjects(), NumParsedParameters}; + + /// Determine whether there is an attribute with the given attribute class. + template + bool hasAttribute(bool AllowInvalid = false) const { + return getAttribute(AllowInvalid) != nullptr; } - size_t numTrailingObjects(OverloadToken) const { - return NumParsedParameters; + + /// Retrieve the first attribute with the given kind. + const DeclAttribute *getAttribute(DeclAttrKind DK, + bool AllowInvalid = false) const { + for (auto Attr : *this) + if (Attr->getKind() == DK && (Attr->isValid() || AllowInvalid)) + return Attr; + return nullptr; } - IndexSubset *getParameterIndices() const { - return ParameterIndices; +private: + /// Predicate used to filter MatchingAttributeRange. + template struct ToAttributeKind { + ToAttributeKind() {} + + Optional + operator()(const DeclAttribute *Attr) const { + if (isa(Attr) && (Attr->isValid() || AllowInvalid)) + return cast(Attr); + return None; + } + }; + +public: + template + using AttributeKindRange = + OptionalTransformRange, + ToAttributeKind, + const_iterator>; + + /// Return a range with all attributes in DeclAttributes with AttrKind + /// ATTR. + template + AttributeKindRange getAttributes() const { + return AttributeKindRange( + make_range(begin(), end()), ToAttributeKind()); } - void setParameterIndices(IndexSubset *pi) { - ParameterIndices = pi; + + // Remove the given attribute from the list of attributes. Used when + // the attribute was semantically invalid. + void removeAttribute(const DeclAttribute *attr) { + // If it's the first attribute, remove it. + if (DeclAttrs == attr) { + DeclAttrs = attr->Next; + return; + } + + // Otherwise, find it in the list. This is inefficient, but rare. + for (auto **prev = &DeclAttrs; *prev; prev = &(*prev)->Next) { + if ((*prev)->Next == attr) { + (*prev)->Next = attr->Next; + return; + } + } + llvm_unreachable("Attribute not found for removal"); } - static bool classof(const DeclAttribute *DA) { - return DA->getKind() == DAK_Derivative; + /// Set the raw chain of attributes. Used for deserialization. + void setRawAttributeChain(DeclAttribute *Chain) { + DeclAttrs = Chain; } + + SourceLoc getStartLoc(bool forModifiers = false) const; }; -// TODO(TF-999): Remove deprecated `@differentiating` attribute. -using DifferentiatingAttr = DerivativeAttr; +struct DeclNameWithLoc { + DeclName Name; + DeclNameLoc Loc; +}; -/// Attribute that registers a function as a transpose of another function. +/// Attribute that marks a function as differentiable and optionally specifies +/// custom associated derivative functions: 'jvp' and 'vjp'. /// /// Examples: -/// @transpose(of: foo) -/// @transpose(of: +, wrt: (lhs, rhs)) -class TransposeAttr final +/// @differentiable(jvp: jvpFoo where T : FloatingPoint) +/// @differentiable(wrt: (self, x, y), jvp: jvpFoo) +class DifferentiableAttr final : public DeclAttribute, - private llvm::TrailingObjects { + private llvm::TrailingObjects { friend TrailingObjects; + friend class DifferentiableAttributeParameterIndicesRequest; - /// The base type of the original function. - /// This is non-null only when the original function is not top-level (i.e. it - /// is an instance/static method). - TypeRepr *BaseType; - /// The original function name. - DeclNameWithLoc OriginalFunctionName; - /// The original function declaration, resolved by the type checker. - AbstractFunctionDecl *OriginalFunction = nullptr; + /// The declaration on which the `@differentiable` attribute is declared. + Decl *OriginalDeclaration = nullptr; + /// Whether this function is linear. + bool Linear; /// The number of parsed parameters specified in 'wrt:'. unsigned NumParsedParameters = 0; - /// The transposed parameters' indices, resolved by the type checker. - IndexSubset *ParameterIndices = nullptr; + /// The JVP function. + Optional JVP; + /// The VJP function. + Optional VJP; + /// The JVP function (optional), resolved by the type checker if JVP name is + /// specified. + FuncDecl *JVPFunction = nullptr; + /// The VJP function (optional), resolved by the type checker if VJP name is + /// specified. + FuncDecl *VJPFunction = nullptr; + /// The differentiation parameters' indices, resolved by the type checker. + /// The bit stores whether the parameter indices have been computed. + llvm::PointerIntPair ParameterIndicesAndBit; + /// The trailing where clause (optional). + TrailingWhereClause *WhereClause = nullptr; + /// The generic signature for autodiff derivative functions. Resolved by the + /// type checker based on the original function's generic signature and the + /// attribute's where clause requirements. This is set only if the attribute + /// has a where clause. + GenericSignature DerivativeGenericSignature = GenericSignature(); - explicit TransposeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, - TypeRepr *baseType, DeclNameWithLoc original, - ArrayRef params); + explicit DifferentiableAttr(bool implicit, SourceLoc atLoc, + SourceRange baseRange, bool linear, + ArrayRef parameters, + Optional jvp, + Optional vjp, + TrailingWhereClause *clause); - explicit TransposeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, - TypeRepr *baseType, DeclNameWithLoc original, - IndexSubset *indices); + explicit DifferentiableAttr(Decl *original, bool implicit, SourceLoc atLoc, + SourceRange baseRange, bool linear, + IndexSubset *indices, + Optional jvp, + Optional vjp, + GenericSignature derivativeGenericSignature); public: - static TransposeAttr *create(ASTContext &context, bool implicit, - SourceLoc atLoc, SourceRange baseRange, - TypeRepr *baseType, DeclNameWithLoc original, - ArrayRef params); + static DifferentiableAttr *create(ASTContext &context, bool implicit, + SourceLoc atLoc, SourceRange baseRange, + bool linear, + ArrayRef params, + Optional jvp, + Optional vjp, + TrailingWhereClause *clause); - static TransposeAttr *create(ASTContext &context, bool implicit, - SourceLoc atLoc, SourceRange baseRange, - TypeRepr *baseType, DeclNameWithLoc original, - IndexSubset *indices); + static DifferentiableAttr *create(Decl *original, bool implicit, + SourceLoc atLoc, SourceRange baseRange, + bool linear, IndexSubset *indices, + Optional jvp, + Optional vjp, + GenericSignature derivativeGenSig); - TypeRepr *getBaseType() const { return BaseType; } - DeclNameWithLoc getOriginalFunctionName() const { - return OriginalFunctionName; - } - AbstractFunctionDecl *getOriginalFunction() const { - return OriginalFunction; - } - void setOriginalFunction(AbstractFunctionDecl *decl) { - OriginalFunction = decl; - } + Decl *getOriginalDeclaration() const { return OriginalDeclaration; } + void setOriginalDeclaration(Decl *decl); - /// The parsed transposed parameters, i.e. the list of parameters specified in - /// 'wrt:'. - ArrayRef getParsedParameters() const { - return {getTrailingObjects(), NumParsedParameters}; - } - MutableArrayRef getParsedParameters() { + /// Get the optional 'jvp:' function name and location. + /// Use this instead of `getJVPFunction` to check whether the attribute has a + /// registered JVP. + Optional getJVP() const { return JVP; } + + /// Get the optional 'vjp:' function name and location. + /// Use this instead of `getVJPFunction` to check whether the attribute has a + /// registered VJP. + Optional getVJP() const { return VJP; } + + bool hasComputedParameterIndices() const; + IndexSubset *getParameterIndices() const; + void setParameterIndices(IndexSubset *paramIndices); + + /// The parsed differentiation parameters, i.e. the list of parameters + /// specified in 'wrt:'. + ArrayRef getParsedParameters() const { + return {getTrailingObjects(), NumParsedParameters}; + } + MutableArrayRef getParsedParameters() { return {getTrailingObjects(), NumParsedParameters}; } size_t numTrailingObjects(OverloadToken) const { return NumParsedParameters; } + + bool isLinear() const { return Linear; } - IndexSubset *getParameterIndices() const { - return ParameterIndices; + TrailingWhereClause *getWhereClause() const { return WhereClause; } + + GenericSignature getDerivativeGenericSignature() const { + return DerivativeGenericSignature; } - void setParameterIndices(IndexSubset *pi) { - ParameterIndices = pi; + void setDerivativeGenericSignature(GenericSignature derivativeGenSig) { + DerivativeGenericSignature = derivativeGenSig; } - static bool classof(const DeclAttribute *DA) { - return DA->getKind() == DAK_Transpose; + FuncDecl *getJVPFunction() const { return JVPFunction; } + void setJVPFunction(FuncDecl *decl); + FuncDecl *getVJPFunction() const { return VJPFunction; } + void setVJPFunction(FuncDecl *decl); + + bool parametersMatch(const DifferentiableAttr &other) const { + return getParameterIndices() == other.getParameterIndices(); } -}; -/// Relates a property to its projection value property, as described by a property wrapper. For -/// example, given -/// \code -/// @A var foo: Int -/// \endcode -/// -/// Where \c A is a property wrapper that has a \c projectedValue property, the compiler -/// synthesizes a declaration $foo an attaches the attribute -/// \c _projectedValuePropertyAttr($foo) to \c foo to record the link. -class ProjectedValuePropertyAttr : public DeclAttribute { -public: - ProjectedValuePropertyAttr(Identifier PropertyName, - SourceLoc AtLoc, SourceRange Range, - bool Implicit) - : DeclAttribute(DAK_ProjectedValueProperty, AtLoc, Range, Implicit), - ProjectionPropertyName(PropertyName) {} + /// Get the derivative generic environment for the given `@differentiable` + /// attribute and original function. + GenericEnvironment * + getDerivativeGenericEnvironment(AbstractFunctionDecl *original) const; - // The projection property name. - const Identifier ProjectionPropertyName; + // Print the attribute to the given stream. + // If `omitWrtClause` is true, omit printing the `wrt:` clause. + // If `omitDerivativeFunctions` is true, omit printing derivative functions. + void print(llvm::raw_ostream &OS, const Decl *D, + bool omitWrtClause = false, + bool omitDerivativeFunctions = false) const; static bool classof(const DeclAttribute *DA) { - return DA->getKind() == DAK_ProjectedValueProperty; + return DA->getKind() == DAK_Differentiable; } }; -/// Attribute that asks the compiler to generate a function that returns a -/// quoted representation of the attributed declaration. -/// -/// @quoted -/// func identity(_ x: Int) -> Int { -/// return x; -/// } -/// -/// The generated function, called "quote decl", looks along the following lines -/// (the exact representation may change over time since quasiquotes are an -/// experimental feature, e.g. the name may end up being mangled as per #13): -/// -/// func _quotedIdentity() -> Tree { -/// return #quote{ -/// func identity(_ x: Int) -> Int { -/// return x; -/// } -/// } -/// } -/// -/// Quote decls are not supposed to be called manually. Instead, it is expected -/// that #quote(...) will be used to obtain representations of @quoted -/// declarations, by synthesizing calls to quote decls. This way users don't -/// have to know the details of name mangling in the presence of overloads etc: -/// -/// #quote(identity) +// SWIFT_ENABLE_TENSORFLOW +/// Attribute that registers a function as a derivative of another function. /// -/// Unquote( -/// Name( -/// "foo", -/// "s:4main3fooyS2fF", -/// FunctionType( -/// [], -/// [TypeName("Int", "s:Si")], -/// TypeName("Int", "s:Si"))), -/// { () -> Tree in quotedIdentity() }, -/// FunctionType( -/// [], -/// [TypeName("Int", "s:Si")], -/// TypeName("Int", "s:Si"))) -class QuotedAttr final : public DeclAttribute { - FuncDecl *QuoteDecl; - - explicit QuotedAttr(FuncDecl *quoteDecl, SourceLoc atLoc, SourceRange range, - bool implicit); - -public: - FuncDecl *getQuoteDecl() const { return QuoteDecl; } - void setQuoteDecl(FuncDecl *quoteDecl) { QuoteDecl = quoteDecl; } - - static bool classof(const DeclAttribute *DA) { - return DA->getKind() == DAK_Quoted; - } +/// Examples: +/// @derivative(of: sin(_:)) +/// @derivative(of: +, wrt: (lhs, rhs)) +class DerivativeAttr final + : public DeclAttribute, + private llvm::TrailingObjects { + friend TrailingObjects; - static QuotedAttr *create(ASTContext &context, SourceLoc atLoc, - SourceRange range, bool implicit); + /// The original function name. + DeclNameWithLoc OriginalFunctionName; + /// The original function declaration, resolved by the type checker. + AbstractFunctionDecl *OriginalFunction = nullptr; + /// The number of parsed parameters specified in 'wrt:'. + unsigned NumParsedParameters = 0; + /// The differentiation parameters' indices, resolved by the type checker. + IndexSubset *ParameterIndices = nullptr; - static QuotedAttr *create(ASTContext &context, FuncDecl *quoteDecl, - SourceLoc atLoc, SourceRange range, bool implicit); -}; + explicit DerivativeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, + DeclNameWithLoc original, + ArrayRef params); -/// Attributes that may be applied to declarations. -class DeclAttributes { - /// Linked list of declaration attributes. - DeclAttribute *DeclAttrs; + explicit DerivativeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, + DeclNameWithLoc original, IndexSubset *indices); public: - DeclAttributes() : DeclAttrs(nullptr) {} + static DerivativeAttr *create(ASTContext &context, bool implicit, + SourceLoc atLoc, SourceRange baseRange, + DeclNameWithLoc original, + ArrayRef params); - bool isEmpty() const { - return DeclAttrs == nullptr; - } + static DerivativeAttr *create(ASTContext &context, bool implicit, + SourceLoc atLoc, SourceRange baseRange, + DeclNameWithLoc original, IndexSubset *indices); - void getAttrRanges(SmallVectorImpl &Ranges) const { - for (auto Attr : *this) { - auto R = Attr->getRangeWithAt(); - if (R.isValid()) - Ranges.push_back(R); - } + DeclNameWithLoc getOriginalFunctionName() const { + return OriginalFunctionName; } - - /// If this attribute set has a prefix/postfix attribute on it, return this. - UnaryOperatorKind getUnaryOperatorKind() const { - if (hasAttribute()) - return UnaryOperatorKind::Prefix; - if (hasAttribute()) - return UnaryOperatorKind::Postfix; - return UnaryOperatorKind::None; + AbstractFunctionDecl *getOriginalFunction() const { + return OriginalFunction; } - - bool isUnavailable(const ASTContext &ctx) const { - return getUnavailable(ctx) != nullptr; + void setOriginalFunction(AbstractFunctionDecl *decl) { + OriginalFunction = decl; } - /// Determine whether there is a swiftVersionSpecific attribute that's - /// unavailable relative to the provided language version. - bool - isUnavailableInSwiftVersion(const version::Version &effectiveVersion) const; + /// The parsed differentiation parameters, i.e. the list of parameters + /// specified in 'wrt:'. + ArrayRef getParsedParameters() const { + return {getTrailingObjects(), NumParsedParameters}; + } + MutableArrayRef getParsedParameters() { + return {getTrailingObjects(), NumParsedParameters}; + } + size_t numTrailingObjects(OverloadToken) const { + return NumParsedParameters; + } - /// Returns the first @available attribute that indicates - /// a declaration is unavailable, or the first one that indicates it's - /// potentially unavailable, or null otherwise. - const AvailableAttr *getPotentiallyUnavailable(const ASTContext &ctx) const; + IndexSubset *getParameterIndices() const { + return ParameterIndices; + } + void setParameterIndices(IndexSubset *pi) { + ParameterIndices = pi; + } - /// Returns the first @available attribute that indicates - /// a declaration is unavailable, or null otherwise. - const AvailableAttr *getUnavailable(const ASTContext &ctx) const; + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DAK_Derivative; + } +}; - /// Returns the first @available attribute that indicates - /// a declaration is deprecated on all deployment targets, or null otherwise. - const AvailableAttr *getDeprecated(const ASTContext &ctx) const; +// TODO(TF-999): Remove deprecated `@differentiating` attribute. +using DifferentiatingAttr = DerivativeAttr; - SWIFT_DEBUG_DUMPER(dump(const Decl *D = nullptr)); - void print(ASTPrinter &Printer, const PrintOptions &Options, - const Decl *D = nullptr) const; - static void print(ASTPrinter &Printer, const PrintOptions &Options, - ArrayRef FlattenedAttrs, - const Decl *D = nullptr); +/// Attribute that registers a function as a transpose of another function. +/// +/// Examples: +/// @transpose(of: foo) +/// @transpose(of: +, wrt: (lhs, rhs)) +class TransposeAttr final + : public DeclAttribute, + private llvm::TrailingObjects { + friend TrailingObjects; - template - class iterator_base : public std::iterator { - T *Impl; - public: - explicit iterator_base(T *Impl) : Impl(Impl) {} - DERIVED &operator++() { Impl = Impl->Next; return (DERIVED&)*this; } - bool operator==(const iterator_base &X) const { return X.Impl == Impl; } - bool operator!=(const iterator_base &X) const { return X.Impl != Impl; } - T *operator*() const { return Impl; } - T &operator->() const { return *Impl; } - }; + /// The base type of the original function. + /// This is non-null only when the original function is not top-level (i.e. it + /// is an instance/static method). + TypeRepr *BaseType; + /// The original function name. + DeclNameWithLoc OriginalFunctionName; + /// The original function declaration, resolved by the type checker. + AbstractFunctionDecl *OriginalFunction = nullptr; + /// The number of parsed parameters specified in 'wrt:'. + unsigned NumParsedParameters = 0; + /// The transposed parameters' indices, resolved by the type checker. + IndexSubset *ParameterIndices = nullptr; - /// Add a constructed DeclAttribute to this list. - void add(DeclAttribute *Attr) { - Attr->Next = DeclAttrs; - DeclAttrs = Attr; - } + explicit TransposeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, + TypeRepr *baseType, DeclNameWithLoc original, + ArrayRef params); - // Iterator interface over DeclAttribute objects. - class iterator : public iterator_base { - public: - explicit iterator(DeclAttribute *Impl) : iterator_base(Impl) {} - }; + explicit TransposeAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, + TypeRepr *baseType, DeclNameWithLoc original, + IndexSubset *indices); - class const_iterator : public iterator_base { - public: - explicit const_iterator(const DeclAttribute *Impl) - : iterator_base(Impl) {} - }; +public: + static TransposeAttr *create(ASTContext &context, bool implicit, + SourceLoc atLoc, SourceRange baseRange, + TypeRepr *baseType, DeclNameWithLoc original, + ArrayRef params); - iterator begin() { return iterator(DeclAttrs); } - iterator end() { return iterator(nullptr); } - const_iterator begin() const { return const_iterator(DeclAttrs); } - const_iterator end() const { return const_iterator(nullptr); } + static TransposeAttr *create(ASTContext &context, bool implicit, + SourceLoc atLoc, SourceRange baseRange, + TypeRepr *baseType, DeclNameWithLoc original, + IndexSubset *indices); - /// Retrieve the first attribute of the given attribute class. - template - const ATTR *getAttribute(bool AllowInvalid = false) const { - return const_cast(this)->getAttribute(AllowInvalid); + TypeRepr *getBaseType() const { return BaseType; } + DeclNameWithLoc getOriginalFunctionName() const { + return OriginalFunctionName; } - - template - ATTR *getAttribute(bool AllowInvalid = false) { - for (auto Attr : *this) - if (auto *SpecificAttr = dyn_cast(Attr)) - if (SpecificAttr->isValid() || AllowInvalid) - return SpecificAttr; - return nullptr; + AbstractFunctionDecl *getOriginalFunction() const { + return OriginalFunction; } - - /// Determine whether there is an attribute with the given attribute class. - template - bool hasAttribute(bool AllowInvalid = false) const { - return getAttribute(AllowInvalid) != nullptr; + void setOriginalFunction(AbstractFunctionDecl *decl) { + OriginalFunction = decl; } - /// Retrieve the first attribute with the given kind. - const DeclAttribute *getAttribute(DeclAttrKind DK, - bool AllowInvalid = false) const { - for (auto Attr : *this) - if (Attr->getKind() == DK && (Attr->isValid() || AllowInvalid)) - return Attr; - return nullptr; + /// The parsed transposed parameters, i.e. the list of parameters specified in + /// 'wrt:'. + ArrayRef getParsedParameters() const { + return {getTrailingObjects(), NumParsedParameters}; } - -private: - /// Predicate used to filter MatchingAttributeRange. - template struct ToAttributeKind { - ToAttributeKind() {} - - Optional - operator()(const DeclAttribute *Attr) const { - if (isa(Attr) && (Attr->isValid() || AllowInvalid)) - return cast(Attr); - return None; - } - }; - -public: - template - using AttributeKindRange = - OptionalTransformRange, - ToAttributeKind, - const_iterator>; - - /// Return a range with all attributes in DeclAttributes with AttrKind - /// ATTR. - template - AttributeKindRange getAttributes() const { - return AttributeKindRange( - make_range(begin(), end()), ToAttributeKind()); + MutableArrayRef getParsedParameters() { + return {getTrailingObjects(), NumParsedParameters}; } - - // Remove the given attribute from the list of attributes. Used when - // the attribute was semantically invalid. - void removeAttribute(const DeclAttribute *attr) { - // If it's the first attribute, remove it. - if (DeclAttrs == attr) { - DeclAttrs = attr->Next; - return; - } - - // Otherwise, find it in the list. This is inefficient, but rare. - for (auto **prev = &DeclAttrs; *prev; prev = &(*prev)->Next) { - if ((*prev)->Next == attr) { - (*prev)->Next = attr->Next; - return; - } - } - llvm_unreachable("Attribute not found for removal"); + size_t numTrailingObjects(OverloadToken) const { + return NumParsedParameters; } - /// Set the raw chain of attributes. Used for deserialization. - void setRawAttributeChain(DeclAttribute *Chain) { - DeclAttrs = Chain; + IndexSubset *getParameterIndices() const { + return ParameterIndices; + } + void setParameterIndices(IndexSubset *pi) { + ParameterIndices = pi; } - SourceLoc getStartLoc(bool forModifiers = false) const; + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DAK_Transpose; + } }; void simple_display(llvm::raw_ostream &out, const DeclAttribute *attr); diff --git a/include/swift/AST/AutoDiff.h b/include/swift/AST/AutoDiff.h index 09d10b3826730..ab10549fd8fea 100644 --- a/include/swift/AST/AutoDiff.h +++ b/include/swift/AST/AutoDiff.h @@ -1,8 +1,8 @@ -//===--- AutoDiff.h - Swift Differentiable Programming --------------------===// +//===--- AutoDiff.h - Swift Automatic Differentiation ---------------------===// // // 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) 2019 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 @@ -10,15 +10,95 @@ // //===----------------------------------------------------------------------===// // -// SWIFT_ENABLE_TENSORFLOW -// This file defines AST support for the experimental differentiable -// programming feature. +// This file defines AST support for automatic differentiation. // //===----------------------------------------------------------------------===// #ifndef SWIFT_AST_AUTODIFF_H #define SWIFT_AST_AUTODIFF_H +#include + +#include "swift/AST/Identifier.h" +#include "swift/AST/IndexSubset.h" +#include "swift/Basic/SourceLoc.h" +#include "swift/Basic/Range.h" + +namespace swift { + +class ParsedAutoDiffParameter { +public: + enum class Kind { Named, Ordered, Self }; + +private: + SourceLoc loc; + Kind kind; + union Value { + struct { Identifier name; } Named; + struct { unsigned index; } Ordered; + struct {} self; + Value(Identifier name) : Named({name}) {} + Value(unsigned index) : Ordered({index}) {} + Value() {} + } value; + +public: + ParsedAutoDiffParameter(SourceLoc loc, Kind kind, Value value) + : loc(loc), kind(kind), value(value) {} + + ParsedAutoDiffParameter(SourceLoc loc, Kind kind, unsigned index) + : loc(loc), kind(kind), value(index) {} + + static ParsedAutoDiffParameter getNamedParameter(SourceLoc loc, + Identifier name) { + return { loc, Kind::Named, name }; + } + + static ParsedAutoDiffParameter getOrderedParameter(SourceLoc loc, + unsigned index) { + return { loc, Kind::Ordered, index }; + } + + static ParsedAutoDiffParameter getSelfParameter(SourceLoc loc) { + return { loc, Kind::Self, {} }; + } + + Identifier getName() const { + assert(kind == Kind::Named); + return value.Named.name; + } + + unsigned getIndex() const { + return value.Ordered.index; + } + + Kind getKind() const { + return kind; + } + + SourceLoc getLoc() const { + return loc; + } + + bool isEqual(const ParsedAutoDiffParameter &other) const { + if (getKind() != other.getKind()) + return false; + if (getKind() == Kind::Named) + return getName() == other.getName(); + return getKind() == Kind::Self; + } +}; + +enum class DifferentiabilityKind : uint8_t { + NonDifferentiable = 0, + Normal = 1, + Linear = 2 +}; + +} // end namespace swift + +// SWIFT_ENABLE_TENSORFLOW +// Not-yet-upstreamed additions on `tensorflow` branch is below. #include "swift/AST/GenericSignature.h" #include "swift/AST/Identifier.h" #include "swift/AST/IndexSubset.h" @@ -40,12 +120,6 @@ class SILFunctionType; typedef CanTypeWrapper CanSILFunctionType; enum class SILLinkage : uint8_t; -enum class DifferentiabilityKind : uint8_t { - NonDifferentiable = 0, - Normal = 1, - Linear = 2 -}; - /// The kind of an linear map. struct AutoDiffLinearMapKind { enum innerty : uint8_t { @@ -136,69 +210,6 @@ struct LinearDifferentiableFunctionTypeComponent { operator innerty() const { return rawValue; } }; -class ParsedAutoDiffParameter { -public: - enum class Kind { Named, Ordered, Self }; - -private: - SourceLoc loc; - Kind kind; - union Value { - struct { Identifier name; } Named; - struct { unsigned index; } Ordered; - struct {} self; - Value(Identifier name) : Named({name}) {} - Value(unsigned index) : Ordered({index}) {} - Value() {} - } value; - -public: - ParsedAutoDiffParameter(SourceLoc loc, Kind kind, Value value) - : loc(loc), kind(kind), value(value) {} - - ParsedAutoDiffParameter(SourceLoc loc, Kind kind, unsigned index) - : loc(loc), kind(kind), value(index) {} - - static ParsedAutoDiffParameter getNamedParameter(SourceLoc loc, - Identifier name) { - return { loc, Kind::Named, name }; - } - - static ParsedAutoDiffParameter getOrderedParameter(SourceLoc loc, - unsigned index) { - return { loc, Kind::Ordered, index }; - } - - static ParsedAutoDiffParameter getSelfParameter(SourceLoc loc) { - return { loc, Kind::Self, {} }; - } - - Identifier getName() const { - assert(kind == Kind::Named); - return value.Named.name; - } - - unsigned getIndex() const { - return value.Ordered.index; - } - - Kind getKind() const { - return kind; - } - - SourceLoc getLoc() const { - return loc; - } - - bool isEqual(const ParsedAutoDiffParameter &other) const { - if (getKind() != other.getKind()) - return false; - if (getKind() == Kind::Named) - return getName() == other.getName(); - return getKind() == Kind::Self; - } -}; - /// SIL-level automatic differentiation indices. Consists of a source index, /// i.e. index of the dependent result to differentiate from, and parameter /// indices, i.e. index of independent parameters to differentiate with @@ -521,5 +532,6 @@ template<> struct DenseMapInfo { }; } // end namespace llvm +// SWIFT_ENABLE_TENSORFLOW END #endif // SWIFT_AST_AUTODIFF_H diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index fe98077ce7356..39d346c8679bf 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -176,16 +176,6 @@ enum class DescriptiveDeclKind : uint8_t { OpaqueVarType }; -/// Keeps track of stage of circularity checking for the given protocol. -enum class CircularityCheck { - /// Circularity has not yet been checked. - Unchecked, - /// We're currently checking circularity. - Checking, - /// Circularity has already been checked. - Checked -}; - /// Describes which spelling was used in the source for the 'static' or 'class' /// keyword. enum class StaticSpellingKind : uint8_t { @@ -489,7 +479,7 @@ class alignas(1 << DeclAlignInBits) Decl { IsComputingSemanticMembers : 1 ); - SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+2+1+1+8+16, + SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+1+8+16, /// Whether the \c RequiresClass bit is valid. RequiresClassValid : 1, @@ -512,9 +502,6 @@ class alignas(1 << DeclAlignInBits) Decl { /// because they could not be imported from Objective-C). HasMissingRequirements : 1, - /// The stage of the circularity check for this protocol. - Circularity : 2, - /// Whether we've computed the inherited protocols list yet. InheritedProtocolsValid : 1, @@ -531,10 +518,7 @@ class alignas(1 << DeclAlignInBits) Decl { NumRequirementsInSignature : 16 ); - SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 2+1+1+2+1+7+1+1+1+1+1+1, - /// The stage of the inheritance circularity check for this class. - Circularity : 2, - + SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+1+2+1+1+1+1+1+1, /// Whether this class inherits its superclass's convenience initializers. InheritsSuperclassInits : 1, ComputedInheritsSuperclassInits : 1, @@ -562,10 +546,7 @@ class alignas(1 << DeclAlignInBits) Decl { HasUnreferenceableStorage : 1 ); - SWIFT_INLINE_BITFIELD(EnumDecl, NominalTypeDecl, 2+2+1, - /// The stage of the raw type circularity check for this class. - Circularity : 2, - + SWIFT_INLINE_BITFIELD(EnumDecl, NominalTypeDecl, 2+1, /// True if the enum has cases and at least one case has associated values. HasAssociatedValues : 2, /// True if the enum has at least one case that has some availability @@ -3625,16 +3606,9 @@ class EnumDecl final : public NominalTypeDecl { for (auto elt : getAllElements()) elements.insert(elt); } - - /// Retrieve the status of circularity checking for class inheritance. - CircularityCheck getCircularityCheck() const { - return static_cast(Bits.EnumDecl.Circularity); - } - - /// Record the current stage of circularity checking. - void setCircularityCheck(CircularityCheck circularity) { - Bits.EnumDecl.Circularity = static_cast(circularity); - } + + /// Whether this enum has a raw value type that recursively references itself. + bool hasCircularRawValue() const; /// Record that this enum has had all of its raw values computed. void setHasFixedRawValues(); @@ -3893,15 +3867,8 @@ class ClassDecl final : public NominalTypeDecl { /// Set the superclass of this class. void setSuperclass(Type superclass); - /// Retrieve the status of circularity checking for class inheritance. - CircularityCheck getCircularityCheck() const { - return static_cast(Bits.ClassDecl.Circularity); - } - - /// Record the current stage of circularity checking. - void setCircularityCheck(CircularityCheck circularity) { - Bits.ClassDecl.Circularity = static_cast(circularity); - } + /// Whether this class has a circular reference in its inheritance hierarchy. + bool hasCircularInheritance() const; /// Walk this class and all of the superclasses of this class, transitively, /// invoking the callback function for each class. @@ -4372,15 +4339,9 @@ class ProtocolDecl final : public NominalTypeDecl { return false; } - /// Retrieve the status of circularity checking for protocol inheritance. - CircularityCheck getCircularityCheck() const { - return static_cast(Bits.ProtocolDecl.Circularity); - } - - /// Record the current stage of circularity checking. - void setCircularityCheck(CircularityCheck circularity) { - Bits.ProtocolDecl.Circularity = static_cast(circularity); - } + /// Whether this protocol has a circular reference in its list of inherited + /// protocols. + bool hasCircularInheritedProtocols() const; /// Returns true if the protocol has requirements that are not listed in its /// members. @@ -5238,6 +5199,9 @@ enum class ParamSpecifier : uint8_t { /// A function parameter declaration. class ParamDecl : public VarDecl { + friend class DefaultArgumentInitContextRequest; + friend class DefaultArgumentExprRequest; + llvm::PointerIntPair ArgumentNameAndDestructured; SourceLoc ParameterNameLoc; SourceLoc ArgumentNameLoc; @@ -5247,11 +5211,19 @@ class ParamDecl : public VarDecl { struct StoredDefaultArgument { PointerUnion DefaultArg; - Initializer *InitContext = nullptr; + + /// Stores the context for the default argument as well as a bit to + /// indicate whether the default expression has been type-checked. + llvm::PointerIntPair InitContextAndIsTypeChecked; + StringRef StringRepresentation; CaptureInfo Captures; }; + /// Retrieve the cached initializer context for the parameter's default + /// argument without triggering a request. + Optional getCachedDefaultArgumentInitContext() const; + enum class Flags : uint8_t { /// Whether or not this parameter is vargs. IsVariadic = 1 << 0, @@ -5308,8 +5280,27 @@ class ParamDecl : public VarDecl { void setDefaultArgumentKind(DefaultArgumentKind K) { Bits.ParamDecl.defaultArgumentKind = static_cast(K); } - - Expr *getDefaultValue() const { + + /// Whether this parameter has a default argument expression available. + /// + /// Note that this will return false for deserialized declarations, which only + /// have a textual representation of their default expression. + bool hasDefaultExpr() const; + + /// Retrieve the fully type-checked default argument expression for this + /// parameter, or \c nullptr if there is no default expression. + /// + /// Note that while this will produce a type-checked expression for + /// caller-side default arguments such as \c #function, this is done purely to + /// check whether the code is valid. Such default arguments get re-created + /// at the call site in order to have the correct context information. + Expr *getTypeCheckedDefaultExpr() const; + + /// Retrieve the potentially un-type-checked default argument expression for + /// this parameter, which can be queried for information such as its source + /// range and textual representation. Returns \c nullptr if there is no + /// default expression. + Expr *getStructuralDefaultExpr() const { if (auto stored = DefaultValueAndFlags.getPointer()) return stored->DefaultArg.dyn_cast(); return nullptr; @@ -5321,15 +5312,18 @@ class ParamDecl : public VarDecl { return nullptr; } - void setDefaultValue(Expr *E); + /// Sets a new default argument expression for this parameter. This should + /// only be called internally by ParamDecl and AST walkers. + /// + /// \param E The new default argument. + /// \param isTypeChecked Whether this argument should be used as the + /// parameter's fully type-checked default argument. + void setDefaultExpr(Expr *E, bool isTypeChecked); void setStoredProperty(VarDecl *var); - Initializer *getDefaultArgumentInitContext() const { - if (auto stored = DefaultValueAndFlags.getPointer()) - return stored->InitContext; - return nullptr; - } + /// Retrieve the initializer context for the parameter's default argument. + Initializer *getDefaultArgumentInitContext() const; void setDefaultArgumentInitContext(Initializer *initContext); @@ -7353,6 +7347,9 @@ inline EnumElementDecl *EnumDecl::getUniqueElement(bool hasValue) const { return result; } +/// Retrieve the parameter list for a given declaration. +ParameterList *getParameterList(ValueDecl *source); + /// Retrieve parameter declaration from the given source at given index. const ParamDecl *getParameterAt(const ValueDecl *source, unsigned index); diff --git a/include/swift/AST/DiagnosticsClangImporter.def b/include/swift/AST/DiagnosticsClangImporter.def index 4da06a218fb5c..d74022dbb66d4 100644 --- a/include/swift/AST/DiagnosticsClangImporter.def +++ b/include/swift/AST/DiagnosticsClangImporter.def @@ -64,6 +64,12 @@ ERROR(bridging_header_pch_error,Fatal, "failed to emit precompiled header '%0' for bridging header '%1'", (StringRef, StringRef)) +ERROR(emit_pcm_error,Fatal, + "failed to emit precompiled module '%0' for module map '%1'", + (StringRef, StringRef)) +ERROR(dump_pcm_error,Fatal, + "failed to dump precompiled module '%0'", (StringRef)) + WARNING(invalid_swift_name_method,none, "too %select{few|many}0 parameters in swift_name attribute (expected %1; " "got %2)", (bool, unsigned, unsigned)) diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index b171c0f7dd92b..0935b335ce36f 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -71,6 +71,10 @@ ERROR(error_option_requires_sanitizer, none, "option '%0' requires a sanitizer to be enabled. Use -sanitize= to " "enable a sanitizer", (StringRef)) +WARNING(warning_option_requires_specific_sanitizer, none, + "option '%0' has no effect when '%1' sanitizer is disabled. Use -sanitize=%1 to " + "enable the sanitizer", (StringRef, StringRef)) + ERROR(error_option_missing_required_argument, none, "option '%0' is missing a required argument (%1)", (StringRef, StringRef)) @@ -232,6 +236,15 @@ ERROR(error_formatting_invalid_range,none, WARNING(stats_disabled,none, "compiler was not built with support for collecting statistics", ()) +WARNING(tbd_warn_truncating_version,none, + "truncating %select{current|compatibility}0 version '%1' in TBD file " + "to fit in 32-bit space used by old mach-o format", + (unsigned, StringRef)) + +ERROR(tbd_err_invalid_version,none, + "invalid dynamic library %select{current|compatibility}0 version '%1'", + (unsigned, StringRef)) + WARNING(tbd_only_supported_in_whole_module,none, "TBD generation is only supported when the whole module can be seen", ()) diff --git a/include/swift/AST/DiagnosticsModuleDiffer.def b/include/swift/AST/DiagnosticsModuleDiffer.def index 6ec0f78f191c8..df4ddf42b9a89 100644 --- a/include/swift/AST/DiagnosticsModuleDiffer.def +++ b/include/swift/AST/DiagnosticsModuleDiffer.def @@ -80,8 +80,6 @@ ERROR(decl_kind_changed,none,"%0 has been changed to a %1", (StringRef, StringRe ERROR(optional_req_changed,none,"%0 is %select{now|no longer}1 an optional requirement", (StringRef, bool)) -ERROR(var_let_changed,none,"%0 changes from %select{var|let}1 to %select{let|var}1", (StringRef, bool)) - ERROR(no_longer_open,none,"%0 is no longer open for subclassing", (StringRef)) ERROR(func_type_escaping_changed,none,"%0 has %select{removed|added}2 @escaping in %1", (StringRef, StringRef, bool)) diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 859ad405e5383..83f277753dbde 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1546,11 +1546,6 @@ ERROR(attr_implements_expected_member_name,PointsToFirstBadToken, "expected a member name as second parameter in '_implements' attribute", ()) // differentiable -ERROR(differentiable_attribute_expected_rparen,none, - "expected ')' in '@differentiable' attribute", ()) -ERROR(unexpected_argument_differentiable,none, - "unexpected argument '%0' in '@differentiable' attribute", (StringRef)) -// SWIFT_ENABLE_TENSORFLOW ERROR(attr_differentiable_expected_function_name,PointsToFirstBadToken, "expected a %0 function name", (StringRef)) ERROR(attr_differentiable_expected_parameter_list,PointsToFirstBadToken, @@ -1560,6 +1555,17 @@ ERROR(attr_differentiable_use_wrt_not_withrespectto,none, ERROR(attr_differentiable_expected_label,none, "expected either 'wrt:' or a function specifier label, e.g. 'jvp:', " "or 'vjp:'", ()) +ERROR(differentiable_attribute_expected_rparen,none, + "expected ')' in '@differentiable' attribute", ()) +ERROR(unexpected_argument_differentiable,none, + "unexpected argument '%0' in '@differentiable' attribute", (StringRef)) + +// differentiation `wrt` parameters clause +ERROR(expected_colon_after_label,PointsToFirstBadToken, + "expected a colon ':' after '%0'", (StringRef)) +ERROR(diff_params_clause_expected_parameter,PointsToFirstBadToken, + "expected a parameter, which can be a function parameter name, " + "parameter index, or 'self'", ()) // derivative ERROR(attr_derivative_expected_original_name,PointsToFirstBadToken, @@ -1583,13 +1589,6 @@ ERROR(transpose_params_clause_expected_parameter,PointsToFirstBadToken, "expected a parameter, which can be a 'unsigned int' parameter number " "or 'self'", ()) -// differentiation `wrt` parameters clause -ERROR(expected_colon_after_label,PointsToFirstBadToken, - "expected a colon ':' after '%0'", (StringRef)) -ERROR(diff_params_clause_expected_parameter,PointsToFirstBadToken, - "expected a parameter, which can be a function parameter name, " - "parameter index, or 'self'", ()) - // SIL autodiff ERROR(sil_autodiff_expected_lsquare,PointsToFirstBadToken, "expected '[' to start the %0", (StringRef)) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ae3a65e1fe7c0..5191aa59961ff 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -911,8 +911,12 @@ ERROR(invalid_arg_count_for_operator,none, "operators must have one or two arguments", ()) ERROR(operator_in_local_scope,none, "operator functions can only be declared at global or in type scope", ()) -ERROR(nonstatic_operator_in_type,none, - "operator %0 declared in type %1 must be 'static'", (Identifier, Type)) +ERROR(nonstatic_operator_in_nominal,none, + "operator %0 declared in type %1 must be 'static'", + (Identifier, DeclName)) +ERROR(nonstatic_operator_in_extension,none, + "operator %0 declared in extension of %1 must be 'static'", + (Identifier, TypeRepr*)) ERROR(nonfinal_operator_in_class,none, "operator %0 declared in non-final class %1 must be 'final'", (Identifier, Type)) @@ -1493,8 +1497,6 @@ ERROR(indirect_case_without_payload,none, "enum case %0 without associated value cannot be 'indirect'", (Identifier)) ERROR(indirect_case_in_indirect_enum,none, "enum case in 'indirect' enum cannot also be 'indirect'", ()) -WARNING(enum_frozen_nonresilient,none, - "%0 has no effect without -enable-library-evolution", (DeclAttribute)) WARNING(enum_frozen_nonpublic,none, "%0 has no effect on non-public enums", (DeclAttribute)) @@ -3629,9 +3631,9 @@ ERROR(assignment_bang_has_immutable_subcomponent,none, NOTE(change_to_mutating,none, "mark %select{method|accessor}0 'mutating' to make 'self' mutable", (bool)) -NOTE(masked_instance_variable,none, - "add explicit 'self.' to refer to mutable property of %0", - (Type)) +NOTE(masked_mutable_property,none, + "add explicit '%0' to refer to mutable %1 of %2", + (StringRef, DescriptiveDeclKind, Type)) ERROR(assignment_let_property_delegating_init,none, "'let' property %0 may not be initialized directly; use " @@ -3785,8 +3787,6 @@ ERROR(single_tuple_parameter_mismatch_special,none, ERROR(single_tuple_parameter_mismatch_normal,none, "%0 %1 expects a single parameter of type %2%3", (DescriptiveDeclKind, DeclBaseName, Type, StringRef)) -NOTE(note_maybe_forgot_to_form_tuple,none, - "did you mean to pass a tuple?", ()) ERROR(unknown_single_tuple_parameter_mismatch,none, "single parameter of type %0 is expected in call", (Type)) ERROR(cannot_convert_single_tuple_into_multiple_arguments,none, diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 18c4560184eb9..e5a2954cb243c 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -532,17 +532,6 @@ class alignas(8) Expr { /// the parent map. llvm::DenseMap getParentMap(); - /// Produce a mapping from each subexpression to its depth and parent, - /// in the root expression. The root expression has depth 0, its children have - /// depth 1, etc. - llvm::DenseMap> getDepthMap(); - - /// Produce a mapping from each expression to its index according to a - /// preorder traversal of the expressions. The parent has index 0, its first - /// child has index 1, its second child has index 2 if the first child is a - /// leaf node, etc. - llvm::DenseMap getPreorderIndexMap(); - SWIFT_DEBUG_DUMP; void dump(raw_ostream &OS, unsigned Indent = 0) const; void dump(raw_ostream &OS, llvm::function_ref getType, diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 423e5f4f58ee6..6607d38604fe5 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -106,6 +106,9 @@ class IRGenOptions { /// Which sanitizer is turned on. OptionSet Sanitizers; + /// Which sanitizer(s) have recovery instrumentation enabled. + OptionSet SanitizersWithRecoveryInstrumentation; + /// Path prefixes that should be rewritten in debug info. PathRemapper DebugPrefixMap; @@ -239,6 +242,7 @@ class IRGenOptions { : DWARFVersion(2), OutputKind(IRGenOutputKind::LLVMAssembly), Verify(true), OptMode(OptimizationMode::NotSet), Sanitizers(OptionSet()), + SanitizersWithRecoveryInstrumentation(OptionSet()), DebugInfoLevel(IRGenDebugInfoLevel::None), DebugInfoFormat(IRGenDebugInfoFormat::None), DisableClangModuleSkeletonCUs(false), UseJIT(false), diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h index 924ce17f04b6c..4d5cc01853c12 100644 --- a/include/swift/AST/Identifier.h +++ b/include/swift/AST/Identifier.h @@ -428,7 +428,7 @@ class DeclName { // it is simple or compound), or a reference to a compound declaration name. llvm::PointerUnion SimpleOrCompound; - DeclName(void *Opaque) + explicit DeclName(void *Opaque) : SimpleOrCompound(decltype(SimpleOrCompound)::getFromOpaqueValue(Opaque)) {} @@ -571,6 +571,11 @@ class DeclName { return !(lhs == rhs); } + friend llvm::hash_code hash_value(DeclName name) { + using llvm::hash_value; + return hash_value(name.getOpaqueValue()); + } + friend bool operator<(DeclName lhs, DeclName rhs) { return lhs.compare(rhs) < 0; } @@ -615,6 +620,8 @@ class DeclName { SWIFT_DEBUG_DUMP; }; +void simple_display(llvm::raw_ostream &out, DeclName name); + enum class ObjCSelectorFamily : unsigned { None, #define OBJC_SELECTOR_FAMILY(LABEL, PREFIX) LABEL, diff --git a/include/swift/AST/IndexSubset.h b/include/swift/AST/IndexSubset.h index 0bead85fdc98c..4e33bae1d7c3d 100644 --- a/include/swift/AST/IndexSubset.h +++ b/include/swift/AST/IndexSubset.h @@ -93,7 +93,7 @@ class IndexSubset : public llvm::FoldingSetNode { for (auto i : indices.set_bits()) { unsigned bitWordIndex, offset; std::tie(bitWordIndex, offset) = getBitWordIndexAndOffset(i); - getBitWord(bitWordIndex) |= (1 << offset); + getBitWord(bitWordIndex) |= (1ull << offset); } } @@ -181,7 +181,7 @@ class IndexSubset : public llvm::FoldingSetNode { bool contains(unsigned index) const { unsigned bitWordIndex, offset; std::tie(bitWordIndex, offset) = getBitWordIndexAndOffset(index); - return getBitWord(bitWordIndex) & (1 << offset); + return getBitWord(bitWordIndex) & (1ull << offset); } bool isEmpty() const { diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index 05edf1a7f940a..a73ef38940d5f 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -117,61 +117,124 @@ struct LookupResultEntry { ValueDecl *getBaseDecl() const; + friend bool operator ==(const LookupResultEntry &lhs, + const LookupResultEntry &rhs) { + return lhs.BaseDC == rhs.BaseDC && lhs.Value == rhs.Value; + } + void print(llvm::raw_ostream &) const; }; -/// This class implements and represents the result of performing -/// unqualified lookup (i.e. lookup for a plain identifier). -class UnqualifiedLookup { +/// The result of name lookup. +class LookupResult { +private: + /// The set of results found. + SmallVector Results; + size_t IndexOfFirstOuterResult = 0; + public: - enum class Flags { - /// This lookup is known to not affect downstream files. - KnownPrivate = 0x01, - /// This lookup should only return types. - TypeLookup = 0x02, - /// This lookup should consider declarations within protocols to which the - /// context type conforms. - AllowProtocolMembers = 0x04, - /// Don't check access when doing lookup into a type. - IgnoreAccessControl = 0x08, - /// This lookup should include results from outside the innermost scope with - /// results. - IncludeOuterResults = 0x10, - }; - using Options = OptionSet; + LookupResult() {} - /// Lookup an unqualified identifier \p Name in the context. - /// - /// If the current DeclContext is nested in a function body, the SourceLoc - /// is used to determine which declarations in that body are visible. - UnqualifiedLookup(DeclName Name, DeclContext *DC, - SourceLoc Loc = SourceLoc(), Options options = Options()); - - using ResultsVector = SmallVector; - ResultsVector Results; - - /// The index of the first result that isn't from the innermost scope - /// with results. - /// - /// That is, \c makeArrayRef(Results).take_front(IndexOfFirstOuterResults) - /// will be \c Results from the innermost scope that had results, and the - /// remaining elements of Results will be from parent scopes of this one. - /// - /// Allows unqualified name lookup to return results from outer scopes. - /// This is necessary for disambiguating calls to functions like `min` and - /// `max`. - size_t IndexOfFirstOuterResult; + explicit LookupResult(const SmallVectorImpl &Results, + size_t indexOfFirstOuterResult) + : Results(Results.begin(), Results.end()), + IndexOfFirstOuterResult(indexOfFirstOuterResult) {} - /// Return true if anything was found by the name lookup. - bool isSuccess() const { return !Results.empty(); } + using iterator = SmallVectorImpl::iterator; + iterator begin() { return Results.begin(); } + iterator end() { + return Results.begin() + IndexOfFirstOuterResult; + } + unsigned size() const { return innerResults().size(); } + bool empty() const { return innerResults().empty(); } - /// Get the result as a single type, or a null type if that fails. - TypeDecl *getSingleTypeResult() const; + ArrayRef innerResults() const { + return llvm::makeArrayRef(Results).take_front(IndexOfFirstOuterResult); + } + + ArrayRef outerResults() const { + return llvm::makeArrayRef(Results).drop_front(IndexOfFirstOuterResult); + } + + /// \returns An array of both the inner and outer results. + ArrayRef allResults() const { + return llvm::makeArrayRef(Results); + } + + const LookupResultEntry& operator[](unsigned index) const { + return Results[index]; + } + + LookupResultEntry front() const { return innerResults().front(); } + LookupResultEntry back() const { return innerResults().back(); } + + /// \returns The index of the first outer result within \c allResults(). + size_t getIndexOfFirstOuterResult() const { return IndexOfFirstOuterResult; } + + /// Add a result to the set of results. + void add(LookupResultEntry result, bool isOuter) { + Results.push_back(result); + if (!isOuter) { + IndexOfFirstOuterResult++; + assert(IndexOfFirstOuterResult == Results.size() && + "found an outer result before an inner one"); + } else { + assert(IndexOfFirstOuterResult > 0 && + "found outer results without an inner one"); + } + } + + void clear() { Results.clear(); } + + /// Determine whether the result set is nonempty. + explicit operator bool() const { + return !empty(); + } + + TypeDecl *getSingleTypeResult() const { + if (size() != 1) + return nullptr; + + return dyn_cast(front().getValueDecl()); + } + + friend bool operator ==(const LookupResult &lhs, const LookupResult &rhs) { + return lhs.Results == rhs.Results && + lhs.IndexOfFirstOuterResult == rhs.IndexOfFirstOuterResult; + } + + /// Filter out any results that aren't accepted by the given predicate. + void + filter(llvm::function_ref pred); + + /// Shift down results by dropping inner results while keeping outer + /// results (if any), the innermost of which are recogized as inner + /// results afterwards. + void shiftDownResults(); }; -inline UnqualifiedLookup::Options operator|(UnqualifiedLookup::Flags flag1, - UnqualifiedLookup::Flags flag2) { - return UnqualifiedLookup::Options(flag1) | flag2; +enum class UnqualifiedLookupFlags { + /// This lookup is known to not affect downstream files. + KnownPrivate = 0x01, + /// This lookup should only return types. + TypeLookup = 0x02, + /// This lookup should consider declarations within protocols to which the + /// context type conforms. + AllowProtocolMembers = 0x04, + /// Don't check access when doing lookup into a type. + IgnoreAccessControl = 0x08, + /// This lookup should include results from outside the innermost scope with + /// results. + IncludeOuterResults = 0x10, +}; + +using UnqualifiedLookupOptions = OptionSet; + +void simple_display(llvm::raw_ostream &out, UnqualifiedLookupOptions options); + +inline UnqualifiedLookupOptions operator|(UnqualifiedLookupFlags flag1, + UnqualifiedLookupFlags flag2) { + return UnqualifiedLookupOptions(flag1) | flag2; } /// Describes the reason why a certain declaration is visible. diff --git a/include/swift/AST/NameLookupRequests.h b/include/swift/AST/NameLookupRequests.h index 614603c9ef9d6..bf71eec9152a0 100644 --- a/include/swift/AST/NameLookupRequests.h +++ b/include/swift/AST/NameLookupRequests.h @@ -25,11 +25,16 @@ namespace swift { class ClassDecl; +class DeclContext; +class DeclName; class DestructorDecl; class GenericContext; class GenericParamList; +class LookupResult; +class SourceLoc; class TypeAliasDecl; class TypeDecl; +enum class UnqualifiedLookupFlags; namespace ast_scope { class ASTScopeImpl; class ScopeCreator; @@ -302,6 +307,59 @@ class ExpandASTScopeRequest void cacheResult(ast_scope::ASTScopeImpl *) const {} }; +/// The input type for an unqualified lookup request. +class UnqualifiedLookupDescriptor { + using LookupOptions = OptionSet; + +public: + DeclName Name; + DeclContext *DC; + SourceLoc Loc; + LookupOptions Options; + + UnqualifiedLookupDescriptor(DeclName name, DeclContext *dc, + SourceLoc loc = SourceLoc(), + LookupOptions options = {}) + : Name(name), DC(dc), Loc(loc), Options(options) {} + + friend llvm::hash_code hash_value(const UnqualifiedLookupDescriptor &desc) { + return llvm::hash_combine(desc.Name, desc.DC, desc.Loc, + desc.Options.toRaw()); + } + + friend bool operator==(const UnqualifiedLookupDescriptor &lhs, + const UnqualifiedLookupDescriptor &rhs) { + return lhs.Name == rhs.Name && lhs.DC == rhs.DC && lhs.Loc == rhs.Loc && + lhs.Options.toRaw() == rhs.Options.toRaw(); + } + + friend bool operator!=(const UnqualifiedLookupDescriptor &lhs, + const UnqualifiedLookupDescriptor &rhs) { + return !(lhs == rhs); + } +}; + +void simple_display(llvm::raw_ostream &out, + const UnqualifiedLookupDescriptor &desc); + +SourceLoc extractNearestSourceLoc(const UnqualifiedLookupDescriptor &desc); + +/// Performs unqualified lookup for a DeclName from a given context. +class UnqualifiedLookupRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected evaluate(Evaluator &evaluator, + UnqualifiedLookupDescriptor desc) const; +}; + #define SWIFT_TYPEID_ZONE NameLookup #define SWIFT_TYPEID_HEADER "swift/AST/NameLookupTypeIDZone.def" #include "swift/Basic/DefineTypeIDZone.h" diff --git a/include/swift/AST/NameLookupTypeIDZone.def b/include/swift/AST/NameLookupTypeIDZone.def index 5548a96d2aca3..16a4b35ed5646 100644 --- a/include/swift/AST/NameLookupTypeIDZone.def +++ b/include/swift/AST/NameLookupTypeIDZone.def @@ -45,3 +45,6 @@ SWIFT_REQUEST(NameLookup, TypeDeclsFromWhereClauseRequest, SWIFT_REQUEST(NameLookup, UnderlyingTypeDeclsReferencedRequest, DirectlyReferencedTypeDecls(TypeAliasDecl *), Uncached, NoLocationInfo) +SWIFT_REQUEST(NameLookup, UnqualifiedLookupRequest, + LookupResult(UnqualifiedLookupDescriptor), Uncached, + NoLocationInfo) diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index 8ab8382f9ee9d..1c82d1a06aef4 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -270,6 +270,10 @@ struct PrintOptions { /// Whether to skip keywords with a prefix of underscore such as __consuming. bool SkipUnderscoredKeywords = false; + /// Prints type variables and unresolved types in an expanded notation suitable + /// for debugging. + bool PrintTypesForDebugging = false; + /// How to print opaque return types. enum class OpaqueReturnTypePrintingMode { /// 'some P1 & P2'. diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index 761bc797f6291..29d5d0a9c03b1 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -56,6 +56,10 @@ class SILOptions { /// Controls whether the SIL ARC optimizations are run. bool EnableARCOptimizations = true; + /// Controls whether specific OSSA optimizations are run. For benchmarking + /// purposes. + bool EnableOSSAOptimizations = true; + /// Should we run any SIL performance optimizations /// /// Useful when you want to enable -O LLVM opts but not -O SIL opts. @@ -147,7 +151,7 @@ class SILOptions { /// Should the default pass pipelines strip ownership during the diagnostic /// pipeline or after serialization. - bool StripOwnershipAfterSerialization = false; + bool StripOwnershipAfterSerialization = true; /// The name of the file to which the backend should save YAML optimization /// records. diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index f696ad0f26163..2c3c5fa10d9a3 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -147,11 +147,6 @@ class SourceFile final : public FileUnit { /// A set of synthesized declarations that need to be type checked. llvm::SmallVector SynthesizedDecls; - /// We might perform type checking on the same source file more than once, - /// if its the main file or a REPL instance, so keep track of the last - /// checked synthesized declaration to avoid duplicating work. - unsigned LastCheckedSynthesizedDecl = 0; - /// A mapping from Objective-C selectors to the methods that have /// those selectors. llvm::DenseMap> diff --git a/include/swift/AST/SubstitutionMap.h b/include/swift/AST/SubstitutionMap.h index 6d9ce0fb38ace..0ae98500eb524 100644 --- a/include/swift/AST/SubstitutionMap.h +++ b/include/swift/AST/SubstitutionMap.h @@ -20,6 +20,7 @@ #include "swift/AST/GenericSignature.h" #include "swift/AST/ProtocolConformanceRef.h" #include "swift/AST/Type.h" +#include "swift/AST/TypeExpansionContext.h" #include "swift/Basic/Debug.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMapInfo.h" @@ -176,7 +177,13 @@ class SubstitutionMap { SubstitutionMap subst(TypeSubstitutionFn subs, LookupConformanceFn conformances, SubstOptions options=None) const; - + + /// Apply type expansion lowering to all types in the substitution map. Opaque + /// archetypes will be lowered to their underlying types if the type expansion + /// context allows. + SubstitutionMap mapIntoTypeExpansionContext( + TypeExpansionContext context) const; + /// Create a substitution map for a protocol conformance. static SubstitutionMap getProtocolSubstitutions(ProtocolDecl *protocol, diff --git a/include/swift/AST/TypeAlignments.h b/include/swift/AST/TypeAlignments.h index 149b8ae24598d..c67183dd06eec 100644 --- a/include/swift/AST/TypeAlignments.h +++ b/include/swift/AST/TypeAlignments.h @@ -30,6 +30,7 @@ namespace swift { class ArchetypeType; class AssociatedTypeDecl; class ASTContext; + class AttributeBase; class BraceStmt; class Decl; class DeclContext; @@ -52,6 +53,7 @@ namespace swift { class ValueDecl; /// We frequently use three tag bits on all of these types. + constexpr size_t AttrAlignInBits = 3; constexpr size_t DeclAlignInBits = 3; constexpr size_t DeclContextAlignInBits = 3; constexpr size_t ExprAlignInBits = 3; @@ -117,6 +119,8 @@ LLVM_DECLARE_TYPE_ALIGNMENT(swift::Pattern, LLVM_DECLARE_TYPE_ALIGNMENT(swift::SILFunction, swift::SILFunctionAlignInBits) +LLVM_DECLARE_TYPE_ALIGNMENT(swift::AttributeBase, swift::AttrAlignInBits) + static_assert(alignof(void*) >= 2, "pointer alignment is too small"); #endif diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index e1464d28e8e7e..8fb959e648ba7 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1807,6 +1807,117 @@ class PreCheckFunctionBuilderRequest bool isCached() const { return true; } }; +/// Computes whether a class has a circular reference in its inheritance +/// hierarchy. +class HasCircularInheritanceRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected evaluate(Evaluator &evaluator, ClassDecl *decl) const; + +public: + // Cycle handling. + void diagnoseCycle(DiagnosticEngine &diags) const; + void noteCycleStep(DiagnosticEngine &diags) const; + + // Cached. + bool isCached() const { return true; } +}; + +/// Computes whether a protocol has a circular reference in its list of +/// inherited protocols. +class HasCircularInheritedProtocolsRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected evaluate(Evaluator &evaluator, ProtocolDecl *decl) const; + +public: + // Cycle handling. + void diagnoseCycle(DiagnosticEngine &diags) const; + void noteCycleStep(DiagnosticEngine &diags) const; + + // Cached. + bool isCached() const { return true; } +}; + +/// Computes whether an enum's raw value has a circular reference. +class HasCircularRawValueRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected evaluate(Evaluator &evaluator, EnumDecl *decl) const; + +public: + // Cycle handling. + void diagnoseCycle(DiagnosticEngine &diags) const; + void noteCycleStep(DiagnosticEngine &diags) const; + + // Cached. + bool isCached() const { return true; } +}; + +/// Computes an initializer context for a parameter with a default argument. +class DefaultArgumentInitContextRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected evaluate(Evaluator &evaluator, + ParamDecl *param) const; + +public: + // Separate caching. + bool isCached() const { return true; } + Optional getCachedResult() const; + void cacheResult(Initializer *init) const; +}; + +/// Computes the fully type-checked default argument expression for a given +/// parameter. +class DefaultArgumentExprRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected evaluate(Evaluator &evaluator, ParamDecl *param) const; + +public: + // Separate caching. + bool isCached() const { return true; } + Optional getCachedResult() const; + void cacheResult(Expr *expr) const; +}; + // Allow AnyValue to compare two Type values, even though Type doesn't // support ==. template<> diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 7b8828ab559ce..45fd8da709920 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -32,6 +32,10 @@ SWIFT_REQUEST(TypeChecker, ClassAncestryFlagsRequest, SWIFT_REQUEST(TypeChecker, CompareDeclSpecializationRequest, bool (DeclContext *, ValueDecl *, ValueDecl *, bool), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, DefaultArgumentExprRequest, + Expr *(ParamDecl *), SeparatelyCached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, DefaultArgumentInitContextRequest, + Initializer *(ParamDecl *), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, DefaultDefinitionTypeRequest, Type(AssociatedTypeDecl *), Cached, NoLocationInfo) // SWIFT_ENABLE_TENSORFLOW @@ -63,6 +67,12 @@ SWIFT_REQUEST(TypeChecker, FunctionOperatorRequest, OperatorDecl *(FuncDecl *), SWIFT_REQUEST(NameLookup, GenericSignatureRequest, GenericSignature (GenericContext *), SeparatelyCached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, HasCircularInheritanceRequest, + bool(ClassDecl *), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, HasCircularInheritedProtocolsRequest, + bool(ProtocolDecl *), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, HasCircularRawValueRequest, + bool(EnumDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, InferredGenericSignatureRequest, GenericSignature (ModuleDecl *, GenericSignatureImpl *, GenericParamList *, diff --git a/include/swift/AST/TypeExpansionContext.h b/include/swift/AST/TypeExpansionContext.h new file mode 100644 index 0000000000000..761fa53217bd5 --- /dev/null +++ b/include/swift/AST/TypeExpansionContext.h @@ -0,0 +1,145 @@ +//===--- TypeExpansionContext.h - Swift Type Expansion Context --*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypeExpansionContext class. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_TYPEEXPANSIONCONTEXT_H +#define SWIFT_TYPEEXPANSIONCONTEXT_H + +#include "swift/AST/ResilienceExpansion.h" +#include "llvm/ADT/DenseMap.h" + +namespace swift { + class DeclContext; + class SILFunction; + +/// Describes the context in which SIL types should eventually be expanded. +/// Required for lowering resilient types and deciding whether to look through +/// opaque result types to their underlying type. +class TypeExpansionContext { + ResilienceExpansion expansion; + // The context (module, function, ...) we are expanding the type in. + const DeclContext *inContext; + // Is the context in which we are expanding in the whole module. + bool isContextWholeModule; + + // The minimal expansion. + TypeExpansionContext() { + inContext = nullptr; + expansion = ResilienceExpansion::Minimal; + isContextWholeModule = false; + } + +public: + + // Infer the expansion for the SIL function. + TypeExpansionContext(const SILFunction &f); + + TypeExpansionContext(ResilienceExpansion expansion, + const DeclContext *inContext, bool isWholeModuleContext) + : expansion(expansion), inContext(inContext), + isContextWholeModule(isWholeModuleContext) {} + + ResilienceExpansion getResilienceExpansion() const { return expansion; } + + const DeclContext *getContext() const { return inContext; } + + bool isWholeModuleContext() const { return isContextWholeModule; } + + bool shouldLookThroughOpaqueTypeArchetypes() const { + return inContext != nullptr; + } + + bool isMinimal() const { return *this == TypeExpansionContext(); } + + static TypeExpansionContext minimal() { + return TypeExpansionContext(); + } + + static TypeExpansionContext maximal(const DeclContext *inContext, + bool isContextWholeModule) { + return TypeExpansionContext(ResilienceExpansion::Maximal, inContext, + isContextWholeModule); + } + + static TypeExpansionContext maximalResilienceExpansionOnly() { + return maximal(nullptr, false); + } + + static TypeExpansionContext + noOpaqueTypeArchetypesSubstitution(ResilienceExpansion expansion) { + return TypeExpansionContext(expansion, nullptr, false); + } + + bool operator==(const TypeExpansionContext &other) const { + assert(other.inContext != this->inContext || + other.isContextWholeModule == this->isContextWholeModule); + return other.inContext == this->inContext && + other.expansion == this->expansion; + } + + bool operator<(const TypeExpansionContext other) const { + assert(other.inContext != this->inContext || + other.isContextWholeModule == this->isContextWholeModule); + if (this->expansion == other.expansion) + return this->inContext < other.inContext; + return this->expansion < other.expansion; + } + + bool operator>(const TypeExpansionContext other) const { + assert(other.inContext != this->inContext || + other.isContextWholeModule == this->isContextWholeModule); + if (this->expansion == other.expansion) + return this->inContext > other.inContext; + return this->expansion > other.expansion; + } + + uintptr_t getHashKey() const { + uintptr_t key = (uintptr_t)inContext | (uintptr_t)expansion; + return key; + } +}; + +} // namespace swift + +namespace llvm { +template <> struct DenseMapInfo { + using TypeExpansionContext = swift::TypeExpansionContext; + + static TypeExpansionContext getEmptyKey() { + return TypeExpansionContext( + swift::ResilienceExpansion::Minimal, + reinterpret_cast( + DenseMapInfo::getEmptyKey()), + false); + } + static TypeExpansionContext getTombstoneKey() { + return TypeExpansionContext( + swift::ResilienceExpansion::Minimal, + reinterpret_cast( + DenseMapInfo::getTombstoneKey()), + false); + } + + static unsigned getHashValue(TypeExpansionContext val) { + return DenseMapInfo::getHashValue(val.getHashKey()); + } + + static bool isEqual(TypeExpansionContext LHS, TypeExpansionContext RHS) { + return LHS == RHS; + } +}; +} // namespace llvm + +#endif diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 2042833161cea..a33671e37a642 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -17,9 +17,7 @@ #ifndef SWIFT_TYPES_H #define SWIFT_TYPES_H -// SWIFT_ENABLE_TENSORFLOW #include "swift/AST/AutoDiff.h" -#include "swift/AST/Attr.h" #include "swift/AST/DeclContext.h" #include "swift/AST/GenericParamKey.h" #include "swift/AST/Identifier.h" @@ -30,6 +28,7 @@ #include "swift/AST/SubstitutionMap.h" #include "swift/AST/Type.h" #include "swift/AST/TypeAlignments.h" +#include "swift/AST/TypeExpansionContext.h" #include "swift/Basic/ArrayRefView.h" #include "swift/Basic/Debug.h" #include "swift/Basic/InlineBitfield.h" @@ -185,7 +184,7 @@ class RecursiveTypeProperties { /// Does a type with these properties have an unresolved type somewhere in it? bool hasUnresolvedType() const { return Bits & HasUnresolvedType; } - + /// Is a type with these properties an lvalue? bool isLValue() const { return Bits & IsLValue; } @@ -310,7 +309,6 @@ class alignas(1 << TypeAlignInBits) TypeBase { } protected: - // SWIFT_ENABLE_TENSORFLOW enum { NumAFTExtInfoBits = 8 }; enum { NumSILExtInfoBits = 8 }; union { uint64_t OpaqueBits; @@ -358,12 +356,10 @@ class alignas(1 << TypeAlignInBits) TypeBase { NumProtocols : 16 ); - SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 4+32, - : NumPadBits, - + SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 5+32, /// Type variable options. - Options : 4, - + Options : 5, + : NumPadBits, /// The unique number assigned to this type variable. ID : 32 ); @@ -574,7 +570,12 @@ class alignas(1 << TypeAlignInBits) TypeBase { bool hasUnresolvedType() const { return getRecursiveProperties().hasUnresolvedType(); } - + + /// Determine whether this type involves a hole. + bool hasHole() const { + return getRecursiveProperties().hasUnresolvedType(); + } + /// Determine whether the type involves a context-dependent archetype. bool hasArchetype() const { return getRecursiveProperties().hasArchetype(); @@ -593,7 +594,10 @@ class alignas(1 << TypeAlignInBits) TypeBase { bool hasOpaqueArchetype() const { return getRecursiveProperties().hasOpaqueArchetype(); } - + /// Determine whether the type has any stored properties or enum cases that + /// involve an opaque type. + bool hasOpaqueArchetypePropertiesOrCases(); + /// Determine whether the type is an opened existential type. /// /// To determine whether there is an opened existential type @@ -2921,7 +2925,6 @@ class AnyFunctionType : public TypeBase { // If bits are added or removed, then TypeBase::AnyFunctionTypeBits // and NumMaskBits must be updated, and they must match. // - // SWIFT_ENABLE_TENSORFLOW // |representation|noEscape|throws|differentiability| // | 0 .. 3 | 4 | 5 | 6 .. 7 | // @@ -2929,10 +2932,11 @@ class AnyFunctionType : public TypeBase { RepresentationMask = 0xF << 0, NoEscapeMask = 1 << 4, ThrowsMask = 1 << 5, - // SWIFT_ENABLE_TENSORFLOW DifferentiabilityMaskOffset = 6, DifferentiabilityMask = 0x3 << DifferentiabilityMaskOffset, + // SWIFT_ENABLE_TENSORFLOW NumDifferentiabilityMaskBits = 2, + // SWIFT_ENABLE_TENSORFLOW END NumMaskBits = 8 }; @@ -2956,20 +2960,20 @@ class AnyFunctionType : public TypeBase { // Constructor with no defaults. ExtInfo(Representation Rep, bool IsNoEscape, - // SWIFT_ENABLE_TENSORFLOW - bool Throws, DifferentiabilityKind diffKind) + bool Throws, + DifferentiabilityKind DiffKind) : ExtInfo(Rep, Throws) { Bits |= (IsNoEscape ? NoEscapeMask : 0); - // SWIFT_ENABLE_TENSORFLOW - Bits |= ((unsigned)diffKind << DifferentiabilityMaskOffset) - & DifferentiabilityMask; + Bits |= ((unsigned)DiffKind << DifferentiabilityMaskOffset) & + DifferentiabilityMask; } bool isNoEscape() const { return Bits & NoEscapeMask; } bool throws() const { return Bits & ThrowsMask; } - // SWIFT_ENABLE_TENSORFLOW bool isDifferentiable() const { - return getDifferentiabilityKind() >= DifferentiabilityKind::Normal; + // return getDifferentiabilityKind() >= DifferentiabilityKind::Normal; + return getDifferentiabilityKind() > + DifferentiabilityKind::NonDifferentiable; } DifferentiabilityKind getDifferentiabilityKind() const { return DifferentiabilityKind((Bits & DifferentiabilityMask) >> @@ -3174,11 +3178,8 @@ class AnyFunctionType : public TypeBase { bool throws() const { return getExtInfo().throws(); } - - // SWIFT_ENABLE_TENSORFLOW - bool isDifferentiable() const { - return getExtInfo().isDifferentiable(); - } + + bool isDifferentiable() const { return getExtInfo().isDifferentiable(); } DifferentiabilityKind getDifferentiabilityKind() const { return getExtInfo().getDifferentiabilityKind(); } @@ -3836,6 +3837,17 @@ enum class SILCoroutineKind : uint8_t { class SILFunctionConventions; + +CanType substOpaqueTypesWithUnderlyingTypes(CanType type, + TypeExpansionContext context, + bool allowLoweredTypes = false); +ProtocolConformanceRef +substOpaqueTypesWithUnderlyingTypes(ProtocolConformanceRef ref, Type origType, + TypeExpansionContext context); +namespace Lowering { + class TypeConverter; +}; + /// SILFunctionType - The lowered type of a function value, suitable /// for use by SIL. /// @@ -3865,19 +3877,19 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, // If bits are added or removed, then TypeBase::SILFunctionTypeBits // and NumMaskBits must be updated, and they must match. - // SWIFT_ENABLE_TENSORFLOW - // |representation|pseudogeneric|noescape|differentiability| - // | 0 .. 3 | 4 | 5 | 6 .. 7 | + // |representation|pseudogeneric| noescape |differentiability| + // | 0 .. 3 | 4 | 5 | 6 .. 7 | // enum : unsigned { - RepresentationMask = 0xF << 0, - PseudogenericMask = 1 << 4, - NoEscapeMask = 1 << 5, + RepresentationMask = 0xF << 0, + PseudogenericMask = 1 << 4, + NoEscapeMask = 1 << 5, + DifferentiabilityMaskOffset = 6, + DifferentiabilityMask = 0x3 << DifferentiabilityMaskOffset, // SWIFT_ENABLE_TENSORFLOW - DifferentiabilityMaskOffset = 6, - DifferentiabilityMask = 0x3 << DifferentiabilityMaskOffset, NumDifferentiabilityMaskBits = 2, - NumMaskBits = 8 + // SWIFT_ENABLE_TENSORFLOW END + NumMaskBits = 8 }; unsigned Bits; // Naturally sized for speed. @@ -3890,15 +3902,13 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, ExtInfo() : Bits(0) { } // Constructor for polymorphic type. - // SWIFT_ENABLE_TENSORFLOW ExtInfo(Representation rep, bool isPseudogeneric, bool isNoEscape, DifferentiabilityKind diffKind) { Bits = ((unsigned) rep) | (isPseudogeneric ? PseudogenericMask : 0) | - // SWIFT_ENABLE_TENSORFLOW (isNoEscape ? NoEscapeMask : 0) | - (((unsigned)diffKind << DifferentiabilityMaskOffset) - & DifferentiabilityMask); + (((unsigned)diffKind << DifferentiabilityMaskOffset) & + DifferentiabilityMask); } /// Is this function pseudo-generic? A pseudo-generic function @@ -3907,12 +3917,12 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, // Is this function guaranteed to be no-escape by the type system? bool isNoEscape() const { return Bits & NoEscapeMask; } - - // SWIFT_ENABLE_TENSORFLOW + bool isDifferentiable() const { - return getDifferentiabilityKind() >= DifferentiabilityKind::Normal; + return getDifferentiabilityKind() != + DifferentiabilityKind::NonDifferentiable; } - + DifferentiabilityKind getDifferentiabilityKind() const { return DifferentiabilityKind((Bits & DifferentiabilityMask) >> DifferentiabilityMaskOffset); @@ -4354,15 +4364,12 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, getRepresentation() == SILFunctionTypeRepresentation::Thick; } - // SWIFT_ENABLE_TENSORFLOW + bool isDifferentiable() const { return getExtInfo().isDifferentiable(); } + DifferentiabilityKind getDifferentiabilityKind() const { return getExtInfo().getDifferentiabilityKind(); } - bool isDifferentiable() const { - return getExtInfo().isDifferentiable(); - } - bool isNoReturnFunction(SILModule &M) const; // Defined in SILType.cpp /// Create a SILFunctionType with the same parameters, results, and attributes as this one, but with @@ -4414,10 +4421,14 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, SILFunction &context) const; CanSILFunctionType substGenericArgs(SILModule &silModule, - SubstitutionMap subs); + SubstitutionMap subs, + TypeExpansionContext context); CanSILFunctionType substGenericArgs(SILModule &silModule, TypeSubstitutionFn subs, - LookupConformanceFn conformances); + LookupConformanceFn conformances, + TypeExpansionContext context); + CanSILFunctionType substituteOpaqueArchetypes(Lowering::TypeConverter &TC, + TypeExpansionContext context); SILType substInterfaceType(SILModule &M, SILType interfaceType) const; @@ -5172,9 +5183,12 @@ class ReplaceOpaqueTypesWithUnderlyingTypes { public: const DeclContext *inContext; ResilienceExpansion contextExpansion; + bool isContextWholeModule; ReplaceOpaqueTypesWithUnderlyingTypes(const DeclContext *inContext, - ResilienceExpansion contextExpansion) - : inContext(inContext), contextExpansion(contextExpansion) {} + ResilienceExpansion contextExpansion, + bool isWholeModuleContext) + : inContext(inContext), contextExpansion(contextExpansion), + isContextWholeModule(isWholeModuleContext) {} /// TypeSubstitutionFn Type operator()(SubstitutableType *maybeOpaqueType) const; @@ -5965,5 +5979,5 @@ struct DenseMapInfo { }; } - + #endif diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 70758f5a0f07a..1107a3e39374a 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -56,7 +56,7 @@ namespace swift { /// A collection of options that affect the language dialect and /// provide compiler debugging facilities. - class LangOptions { + class LangOptions final { public: /// The target we are building for. @@ -162,64 +162,19 @@ namespace swift { /// Flags for developers /// - /// Whether we are debugging the constraint solver. - /// - /// This option enables verbose debugging output from the constraint - /// solver. - bool DebugConstraintSolver = false; - - /// Specific solution attempt for which the constraint - /// solver should be debugged. - unsigned DebugConstraintSolverAttempt = 0; - - /// Line numbers to activate the constraint solver debugger. - /// Should be stored sorted. - llvm::SmallVector DebugConstraintSolverOnLines; - /// Enable named lazy member loading. bool NamedLazyMemberLoading = true; - - /// Debug the generic signatures computed by the generic signature builder. - bool DebugGenericSignatures = false; - - /// Triggers llvm fatal_error if typechecker tries to typecheck a decl or an - /// identifier reference with the provided prefix name. - /// This is for testing purposes. - std::string DebugForbidTypecheckPrefix; - - /// Whether to dump debug info for request evaluator cycles. - bool DebugDumpCycles = false; - + /// The path to which we should emit GraphViz output for the complete /// request-evaluator graph. std::string RequestEvaluatorGraphVizPath; - - /// The upper bound, in bytes, of temporary data that can be - /// allocated by the constraint solver. - unsigned SolverMemoryThreshold = 512 * 1024 * 1024; - - unsigned SolverBindingThreshold = 1024 * 1024; - - /// The upper bound to number of sub-expressions unsolved - /// before termination of the shrink phrase of the constraint solver. - unsigned SolverShrinkUnsolvedThreshold = 10; - - /// Disable the shrink phase of the expression type checker. - bool SolverDisableShrink = false; - - /// Disable constraint system performance hacks. - bool DisableConstraintSolverPerformanceHacks = false; - - /// Enable experimental operator designated types feature. - bool EnableOperatorDesignatedTypes = false; - + + /// Whether to dump debug info for request evaluator cycles. + bool DebugDumpCycles = false; + /// Enable SIL type lowering bool EnableSubstSILFunctionTypesForFunctionValues = false; - /// Enable constraint solver support for experimental - /// operator protocol designator feature. - bool SolverEnableOperatorDesignatedTypes = false; - /// Whether to diagnose an ephemeral to non-ephemeral conversion as an /// error. bool DiagnoseInvalidEphemeralnessAsError = false; @@ -330,7 +285,7 @@ namespace swift { /// Whether to enable experimental differentiable programming features: /// `@differentiable` declaration attribute, etc. // SWIFT_ENABLE_TENSORFLOW - // Use default value to true on `tensorflow` branch. + // Use default value true on `tensorflow` branch. bool EnableExperimentalDifferentiableProgramming = true; // SWIFT_ENABLE_TENSORFLOW END @@ -469,6 +424,103 @@ namespace swift { PlatformConditionValues; llvm::SmallVector CustomConditionalCompilationFlags; }; + + class TypeCheckerOptions final { + public: + /// If non-zero, warn when a function body takes longer than this many + /// milliseconds to type-check. + /// + /// Intended for debugging purposes only. + unsigned WarnLongFunctionBodies = 0; + + /// If non-zero, warn when type-checking an expression takes longer + /// than this many milliseconds. + /// + /// Intended for debugging purposes only. + unsigned WarnLongExpressionTypeChecking = 0; + + /// If non-zero, abort the expression type checker if it takes more + /// than this many seconds. + unsigned ExpressionTimeoutThreshold = 600; + + /// If non-zero, abort the switch statement exhaustiveness checker if + /// the Space::minus function is called more than this many times. + /// + /// Why this number? Times out in about a second on a 2017 iMac, Retina 5K, + /// 4.2 GHz Intel Core i7. + /// (It's arbitrary, but will keep the compiler from taking too much time.) + unsigned SwitchCheckingInvocationThreshold = 200000; + + /// Whether to delay checking that benefits from having the entire + /// module parsed, e.g., Objective-C method override checking. + bool DelayWholeModuleChecking = false; + + /// If true, the time it takes to type-check each function will be dumped + /// to llvm::errs(). + bool DebugTimeFunctionBodies = false; + + /// If true, the time it takes to type-check each expression will be + /// dumped to llvm::errs(). + bool DebugTimeExpressions = false; + + /// Indicate that the type checker is checking code that will be + /// immediately executed. This will suppress certain warnings + /// when executing scripts. + bool InImmediateMode = false; + + /// Indicate that the type checker should skip type-checking non-inlinable + /// function bodies. + bool SkipNonInlinableFunctionBodies = false; + + /// + /// Flags for developers + /// + + /// Whether we are debugging the constraint solver. + /// + /// This option enables verbose debugging output from the constraint + /// solver. + bool DebugConstraintSolver = false; + + /// Specific solution attempt for which the constraint + /// solver should be debugged. + unsigned DebugConstraintSolverAttempt = 0; + + /// Line numbers to activate the constraint solver debugger. + /// Should be stored sorted. + llvm::SmallVector DebugConstraintSolverOnLines; + + /// Debug the generic signatures computed by the generic signature builder. + bool DebugGenericSignatures = false; + + /// Triggers llvm fatal_error if typechecker tries to typecheck a decl or an + /// identifier reference with the provided prefix name. + /// This is for testing purposes. + std::string DebugForbidTypecheckPrefix; + + /// The upper bound, in bytes, of temporary data that can be + /// allocated by the constraint solver. + unsigned SolverMemoryThreshold = 512 * 1024 * 1024; + + unsigned SolverBindingThreshold = 1024 * 1024; + + /// The upper bound to number of sub-expressions unsolved + /// before termination of the shrink phrase of the constraint solver. + unsigned SolverShrinkUnsolvedThreshold = 10; + + /// Disable the shrink phase of the expression type checker. + bool SolverDisableShrink = false; + + /// Enable experimental operator designated types feature. + bool EnableOperatorDesignatedTypes = false; + + /// Disable constraint system performance hacks. + bool DisableConstraintSolverPerformanceHacks = false; + + /// Enable constraint solver support for experimental + /// operator protocol designator feature. + bool SolverEnableOperatorDesignatedTypes = false; + }; } // end namespace swift #endif // SWIFT_BASIC_LANGOPTIONS_H diff --git a/include/swift/Basic/STLExtras.h b/include/swift/Basic/STLExtras.h index 5c143c1b6f397..96a7c9e6a6334 100644 --- a/include/swift/Basic/STLExtras.h +++ b/include/swift/Basic/STLExtras.h @@ -638,6 +638,16 @@ inline T accumulate(const Container &C, T init, BinaryOperation op) { return std::accumulate(C.begin(), C.end(), init, op); } +template +inline bool binary_search(const Container &C, const T &value) { + return std::binary_search(C.begin(), C.end(), value); +} + +template +inline bool binary_search(const Container &C, const T &value, BinaryOperation op) { + return std::binary_search(C.begin(), C.end(), value, op); +} + /// Returns true if the range defined by \p mainBegin ..< \p mainEnd starts with /// the same elements as the range defined by \p prefixBegin ..< \p prefixEnd. /// diff --git a/include/swift/Basic/Statistics.def b/include/swift/Basic/Statistics.def index 134811bbbf39c..f6a074855e9e6 100644 --- a/include/swift/Basic/Statistics.def +++ b/include/swift/Basic/Statistics.def @@ -153,9 +153,6 @@ FRONTEND_STATISTIC(AST, NumLookupInModule) /// Number of local lookups into a module. FRONTEND_STATISTIC(AST, NumModuleLookupValue) -/// Number of unqualified lookups. -FRONTEND_STATISTIC(AST, NumUnqualifiedLookup) - /// Number of local lookups into a module's class members, for /// AnyObject lookup. FRONTEND_STATISTIC(AST, NumModuleLookupClassMember) diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 61f3225a379e6..4a2766d5a5264 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -112,6 +112,17 @@ class ClangImporter final : public ClangModuleLoader { DependencyTracker *tracker, DWARFImporterDelegate *dwarfImporterDelegate); + /// Creates a clone of Clang importer's compiler instance that has been + /// configured for operations on precompiled outputs (either emitting a + /// precompiled header, emitting a precompiled module, or dumping a + /// precompiled module). + /// + /// The caller of this method should set any action-specific invocation + /// options (like FrontendOptions::ProgramAction, input files, and output + /// paths), then create the appropriate FrontendAction and execute it. + std::unique_ptr + cloneCompilerInstanceForPrecompiling(); + public: /// Create a new Clang importer that can import a suitable Clang /// module into the given ASTContext. @@ -333,6 +344,19 @@ class ClangImporter final : public ClangModuleLoader { /// if we need to persist a PCH for later reuse. bool canReadPCH(StringRef PCHFilename); + /// Makes a temporary replica of the ClangImporter's CompilerInstance, reads a + /// module map into the replica and emits a PCM file for one of the modules it + /// declares. Delegates to clang for everything except construction of the + /// replica. + bool emitPrecompiledModule(StringRef moduleMapPath, StringRef moduleName, + StringRef outputPath); + + /// Makes a temporary replica of the ClangImporter's CompilerInstance and + /// dumps information about a PCM file (assumed to be generated by -emit-pcm + /// or in the Swift module cache). Delegates to clang for everything except + /// construction of the replica. + bool dumpPrecompiledModule(StringRef modulePath, StringRef outputPath); + const clang::Module *getClangOwningModule(ClangNode Node) const; bool hasTypedef(const clang::Decl *typeDecl) const; diff --git a/include/swift/ClangImporter/ClangImporterOptions.h b/include/swift/ClangImporter/ClangImporterOptions.h index 65d58241f1cb5..f329223993f7c 100644 --- a/include/swift/ClangImporter/ClangImporterOptions.h +++ b/include/swift/ClangImporter/ClangImporterOptions.h @@ -62,7 +62,10 @@ class ClangImporterOptions { /// Swift code. Normal, /// Set up Clang for backend compilation only. - EmbedBitcode + EmbedBitcode, + /// Set up Clang to emit a precompiled module from a C/Objective-C module + /// map or dump debugging info about a precompiled module. + PrecompiledModule }; /// Controls how Clang is initially set up. diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index c779245b70358..74ea1328c6699 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -83,6 +83,7 @@ struct ModuleBuffers { /// which manages the actual compiler execution. class CompilerInvocation { LangOptions LangOpts; + TypeCheckerOptions TypeCheckerOpts; FrontendOptions FrontendOpts; ClangImporterOptions ClangImporterOpts; SearchPathOptions SearchPathOpts; @@ -202,6 +203,12 @@ class CompilerInvocation { void setRuntimeResourcePath(StringRef Path); + /// Computes the runtime resource path relative to the given Swift + /// executable. + static void computeRuntimeResourcePathFromExecutablePath( + StringRef mainExecutablePath, + llvm::SmallString<128> &runtimeResourcePath); + void setSDKPath(const std::string &Path); StringRef getSDKPath() const { @@ -215,6 +222,11 @@ class CompilerInvocation { return LangOpts; } + TypeCheckerOptions &getTypeCheckerOptions() { return TypeCheckerOpts; } + const TypeCheckerOptions &getTypeCheckerOptions() const { + return TypeCheckerOpts; + } + FrontendOptions &getFrontendOptions() { return FrontendOpts; } const FrontendOptions &getFrontendOptions() const { return FrontendOpts; } @@ -648,14 +660,11 @@ class CompilerInstance { bool parsePartialModulesAndLibraryFiles(const ImplicitImports &implicitImports); - OptionSet computeTypeCheckingOptions(); - void forEachFileToTypeCheck(llvm::function_ref fn); - void parseAndTypeCheckMainFileUpTo(SourceFile::ASTStage_t LimitStage, - OptionSet TypeCheckOptions); + void parseAndTypeCheckMainFileUpTo(SourceFile::ASTStage_t LimitStage); - void finishTypeChecking(OptionSet TypeCheckOptions); + void finishTypeChecking(); public: const PrimarySpecificPaths & diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index c663d99d79155..14f87e008b375 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -82,28 +82,6 @@ class FrontendOptions { /// Emit index data for imported serialized swift system modules. bool IndexSystemModules = false; - /// If non-zero, warn when a function body takes longer than this many - /// milliseconds to type-check. - /// - /// Intended for debugging purposes only. - unsigned WarnLongFunctionBodies = 0; - - /// If non-zero, warn when type-checking an expression takes longer - /// than this many milliseconds. - /// - /// Intended for debugging purposes only. - unsigned WarnLongExpressionTypeChecking = 0; - - /// If non-zero, overrides the default threshold for how long we let - /// the expression type checker run before we consider an expression - /// too complex. - unsigned SolverExpressionTimeThreshold = 0; - - /// If non-zero, overrides the default threshold for how many times - /// the Space::minus function is called before we consider switch statement - /// exhaustiveness checking to be too complex. - unsigned SwitchCheckingInvocationThreshold = 0; - /// The module for which we should verify all of the generic signatures. std::string VerifyGenericSignaturesInModule; @@ -148,6 +126,9 @@ class FrontendOptions { EmitObject, ///< Emit object file DumpTypeInfo, ///< Dump IRGen type info + + EmitPCM, ///< Emit precompiled Clang module from a module map + DumpPCM, ///< Dump information about a precompiled Clang module }; /// Indicates the action the user requested that the frontend perform. @@ -183,8 +164,6 @@ class FrontendOptions { /// \sa swift::SharedTimer bool DebugTimeCompilation = false; - bool SkipNonInlinableFunctionBodies = false; - /// The path to which we should output statistics files. std::string StatsOutputDir; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index d58c5fb780d67..0a1cb78c14d2b 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -254,6 +254,8 @@ def debugger_support : Flag<["-"], "debugger-support">, def disable_arc_opts : Flag<["-"], "disable-arc-opts">, HelpText<"Don't run SIL ARC optimization passes.">; +def disable_ossa_opts : Flag<["-"], "disable-ossa-opts">, + HelpText<"Don't run SIL OSSA optimization passes.">; def disable_sil_partial_apply : Flag<["-"], "disable-sil-partial-apply">, HelpText<"Disable use of partial_apply in SIL generation">; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index a703542d9390b..22afb18508faa 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -758,6 +758,9 @@ def emit_sibgen : Flag<["-"], "emit-sibgen">, def emit_imported_modules : Flag<["-"], "emit-imported-modules">, HelpText<"Emit a list of the imported modules">, ModeOpt, Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; +def emit_pcm : Flag<["-"], "emit-pcm">, + HelpText<"Emit a precompiled Clang module from a module map">, ModeOpt, + Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; def c : Flag<["-"], "c">, Alias, Flags<[FrontendOption, NoInteractiveOption]>, ModeOpt; @@ -802,6 +805,10 @@ def print_ast : Flag<["-"], "print-ast">, HelpText<"Parse and type-check input file(s) and pretty print AST(s)">, ModeOpt, Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; +def dump_pcm : Flag<["-"], "dump-pcm">, + HelpText<"Dump debugging information about a precompiled Clang module">, + ModeOpt, + Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; // Other Modes def repl : Flag<["-"], "repl">, @@ -899,6 +906,15 @@ def sanitize_EQ : CommaJoined<["-"], "sanitize=">, Flags<[FrontendOption, NoInteractiveOption]>, MetaVarName<"">, HelpText<"Turn on runtime checks for erroneous behavior.">; +def sanitize_recover_EQ + : CommaJoined<["-"], "sanitize-recover=">, + Flags<[FrontendOption, NoInteractiveOption]>, + MetaVarName<"">, + HelpText<"Specify which sanitizer runtime checks (see -sanitize=) will " + "generate instrumentation that allows error recovery. Listed " + "checks should be comma separated. Default behavior is to not " + "allow error recovery.">; + def sanitize_coverage_EQ : CommaJoined<["-"], "sanitize-coverage=">, Flags<[FrontendOption, NoInteractiveOption]>, MetaVarName<"">, diff --git a/include/swift/Option/SanitizerOptions.h b/include/swift/Option/SanitizerOptions.h index f19500c8ac4c0..8a29853e3790d 100644 --- a/include/swift/Option/SanitizerOptions.h +++ b/include/swift/Option/SanitizerOptions.h @@ -36,6 +36,10 @@ OptionSet parseSanitizerArgValues( const llvm::Triple &Triple, DiagnosticEngine &Diag, llvm::function_ref sanitizerRuntimeLibExists); +OptionSet parseSanitizerRecoverArgValues( + const llvm::opt::Arg *A, const OptionSet &enabledSanitizers, + DiagnosticEngine &Diags, bool emitWarnings); + /// Parses a -sanitize-coverage= argument's value. llvm::SanitizerCoverageOptions parseSanitizerCoverageArgValue( const llvm::opt::Arg *A, diff --git a/include/swift/Parse/LocalContext.h b/include/swift/Parse/LocalContext.h index 04af97d82394e..8e4b2b281f5a0 100644 --- a/include/swift/Parse/LocalContext.h +++ b/include/swift/Parse/LocalContext.h @@ -61,12 +61,7 @@ class LocalContext { }; /// Information associated with parsing the top-level context. -class TopLevelContext : public LocalContext { -public: - /// The next auto-closure discriminator. This needs to be preserved - /// across invocations of both the parser and the type-checker. - unsigned NextAutoClosureDiscriminator = 0; -}; +class TopLevelContext : public LocalContext {}; } // end namespace swift diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 642f97c942ae3..cd1784d83b426 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -43,6 +43,7 @@ namespace llvm { namespace swift { class CodeCompletionCallbacks; + class CodeCompletionCallbacksFactory; class DefaultArgumentInitializer; class DiagnosticEngine; class Expr; @@ -801,6 +802,12 @@ class Parser { return parseAnyIdentifier(Result, L, Diagnostic(ID, Args...)); } + /// \brief Parse an unsigned integer and returns it in \p Result. On failure + /// emit the specified error diagnostic, and a note at the specified note + /// location. + bool parseUnsignedInteger(unsigned &Result, SourceLoc &Loc, + const Diagnostic &D); + /// The parser expects that \p K is next token in the input. If so, /// it is consumed and false is returned. /// @@ -823,13 +830,6 @@ class Parser { bool parseMatchingToken(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag, SourceLoc OtherLoc); - /// SWIFT_ENABLE_TENSORFLOW - /// \brief Parse an unsigned integer and returns it in \p Result. On failure - /// emit the specified error diagnostic, and a note at the specified note - /// location. - bool parseUnsignedInteger(unsigned &Result, SourceLoc &Loc, - const Diagnostic &D); - /// Returns the proper location for a missing right brace, parenthesis, etc. SourceLoc getLocForMissingMatchingToken() const; @@ -859,8 +859,6 @@ class Parser { BraceItemListKind::Brace); ParserResult parseBraceItemList(Diag<> ID); - void parseTopLevelCodeDeclDelayed(); - //===--------------------------------------------------------------------===// // Decl Parsing @@ -887,8 +885,6 @@ class Parser { /// Options that control the parsing of declarations. using ParseDeclOptions = OptionSet; - void delayParseFromBeginningToHere(ParserPosition BeginParserPosition, - ParseDeclOptions Flags); void consumeDecl(ParserPosition BeginParserPosition, ParseDeclOptions Flags, bool IsTopLevel); @@ -913,8 +909,6 @@ class Parser { bool IsAtStartOfLineOrPreviousHadSemi, llvm::function_ref Handler); - void parseDeclDelayed(); - std::vector parseDeclListDelayed(IterableDeclContext *IDC); bool parseMemberDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, @@ -985,7 +979,6 @@ class Parser { ParserResult parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc); - /// SWIFT_ENABLE_TENSORFLOW /// Parse the @differentiable attribute. ParserResult parseDifferentiableAttribute(SourceLoc AtLoc, SourceLoc Loc); @@ -1106,7 +1099,6 @@ class Parser { bool HasFuncKeyword = true); void parseAbstractFunctionBody(AbstractFunctionDecl *AFD); BraceStmt *parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD); - void parseAbstractFunctionBodyDelayed(); ParserResult parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes); @@ -1621,6 +1613,16 @@ class Parser { parsePlatformVersionConstraintSpec(); ParserResult parsePlatformAgnosticVersionConstraintSpec(); + + //===--------------------------------------------------------------------===// + // Code completion second pass. + + static void + performCodeCompletionSecondPass(PersistentParserState &ParserState, + CodeCompletionCallbacksFactory &Factory); + + void performCodeCompletionSecondPassImpl( + PersistentParserState::CodeCompletionDelayedDeclState &info); }; /// Describes a parsed declaration name. diff --git a/include/swift/Parse/PersistentParserState.h b/include/swift/Parse/PersistentParserState.h index d15e3b72d7d21..44f53983c6ca6 100644 --- a/include/swift/Parse/PersistentParserState.h +++ b/include/swift/Parse/PersistentParserState.h @@ -17,7 +17,6 @@ #ifndef SWIFT_PARSE_PERSISTENTPARSERSTATE_H #define SWIFT_PARSE_PERSISTENTPARSERSTATE_H -#include "swift/AST/LazyResolver.h" #include "swift/Basic/SourceLoc.h" #include "swift/Parse/LocalContext.h" #include "swift/Parse/ParserPosition.h" @@ -25,7 +24,10 @@ #include "llvm/ADT/DenseMap.h" namespace swift { - class AbstractFunctionDecl; + +class SourceFile; +class DeclContext; +class IterableDeclContext; /// Parser state persistent across multiple parses. class PersistentParserState { @@ -37,32 +39,16 @@ class PersistentParserState { bool isValid() const { return Loc.isValid(); } }; - class FunctionBodyState { - ParserPos BodyPos; - SavedScope Scope; - friend class Parser; - - SavedScope takeScope() { - return std::move(Scope); - } - - public: - FunctionBodyState(SourceRange BodyRange, SourceLoc PreviousLoc, - SavedScope &&Scope) - : BodyPos{BodyRange.Start, PreviousLoc}, Scope(std::move(Scope)) - {} - }; - - enum class DelayedDeclKind { + enum class CodeCompletionDelayedDeclKind { TopLevelCodeDecl, Decl, FunctionBody, }; - class DelayedDeclState { + class CodeCompletionDelayedDeclState { friend class PersistentParserState; friend class Parser; - DelayedDeclKind Kind; + CodeCompletionDelayedDeclKind Kind; unsigned Flags; DeclContext *ParentContext; ParserPos BodyPos; @@ -74,13 +60,13 @@ class PersistentParserState { } public: - DelayedDeclState(DelayedDeclKind Kind, unsigned Flags, - DeclContext *ParentContext, SourceRange BodyRange, - SourceLoc PreviousLoc, SavedScope &&Scope) - : Kind(Kind), Flags(Flags), ParentContext(ParentContext), - BodyPos{BodyRange.Start, PreviousLoc}, - BodyEnd(BodyRange.End), Scope(std::move(Scope)) - {} + CodeCompletionDelayedDeclState(CodeCompletionDelayedDeclKind Kind, + unsigned Flags, DeclContext *ParentContext, + SourceRange BodyRange, SourceLoc PreviousLoc, + SavedScope &&Scope) + : Kind(Kind), Flags(Flags), + ParentContext(ParentContext), BodyPos{BodyRange.Start, PreviousLoc}, + BodyEnd(BodyRange.End), Scope(std::move(Scope)) {} }; bool InPoundLineEnvironment = false; @@ -89,15 +75,11 @@ class PersistentParserState { bool PerformConditionEvaluation = true; private: ScopeInfo ScopeInfo; - using DelayedFunctionBodiesTy = - llvm::DenseMap>; - DelayedFunctionBodiesTy DelayedFunctionBodies; /// Parser sets this if it stopped parsing before the buffer ended. ParserPosition MarkedPos; - std::unique_ptr CodeCompletionDelayedDeclState; + std::unique_ptr CodeCompletionDelayedDeclStat; std::vector DelayedDeclLists; @@ -110,31 +92,24 @@ class PersistentParserState { PersistentParserState(ASTContext &ctx) : PersistentParserState() { } ~PersistentParserState(); - void delayDecl(DelayedDeclKind Kind, unsigned Flags, - DeclContext *ParentContext, - SourceRange BodyRange, SourceLoc PreviousLoc); - - void delayDeclList(IterableDeclContext *D); + void setCodeCompletionDelayedDeclState(CodeCompletionDelayedDeclKind Kind, + unsigned Flags, + DeclContext *ParentContext, + SourceRange BodyRange, + SourceLoc PreviousLoc); - void delayTopLevel(TopLevelCodeDecl *TLCD, SourceRange BodyRange, - SourceLoc PreviousLoc); - - bool hasDelayedDecl() { - return CodeCompletionDelayedDeclState.get() != nullptr; - } - DelayedDeclKind getDelayedDeclKind() { - return CodeCompletionDelayedDeclState->Kind; + bool hasCodeCompletionDelayedDeclState() { + return CodeCompletionDelayedDeclStat.get() != nullptr; } - SourceLoc getDelayedDeclLoc() { - return CodeCompletionDelayedDeclState->BodyPos.Loc; - } - DeclContext *getDelayedDeclContext() { - return CodeCompletionDelayedDeclState->ParentContext; - } - std::unique_ptr takeDelayedDeclState() { - return std::move(CodeCompletionDelayedDeclState); + + std::unique_ptr + takeCodeCompletionDelayedDeclState() { + assert(hasCodeCompletionDelayedDeclState()); + return std::move(CodeCompletionDelayedDeclStat); } + void delayDeclList(IterableDeclContext *D); + void parseAllDelayedDeclLists(); TopLevelContext &getTopLevelContext() { diff --git a/include/swift/SIL/Projection.h b/include/swift/SIL/Projection.h index 1e4324e07b29f..1ccc0fad703bc 100644 --- a/include/swift/SIL/Projection.h +++ b/include/swift/SIL/Projection.h @@ -293,7 +293,8 @@ class Projection { /// /// WARNING: This is not a constant time operation because it is implemented /// in terms of getVarDecl, which requests all BaseType's stored properties. - SILType getType(SILType BaseType, SILModule &M) const; + SILType getType(SILType BaseType, SILModule &M, + TypeExpansionContext context) const; VarDecl *getVarDecl(SILType BaseType) const { assert(isValid()); @@ -402,6 +403,7 @@ class Projection { /// Given a specific SILType, return all first level projections if it is an /// aggregate. static void getFirstLevelProjections(SILType V, SILModule &Mod, + TypeExpansionContext context, llvm::SmallVectorImpl &Out); /// Is this cast which only allows for equality? @@ -584,6 +586,7 @@ class ProjectionPath { /// is a leaf node in the type tree. static void expandTypeIntoLeafProjectionPaths(SILType BaseType, SILModule *Mod, + TypeExpansionContext context, ProjectionPathList &P); /// Return true if the given projection paths in \p CPaths does not cover @@ -626,26 +629,27 @@ class ProjectionPath { SILType getBaseType() const { return BaseType; } /// Returns the most derived type of the projection path. - SILType getMostDerivedType(SILModule &M) { + SILType getMostDerivedType(SILModule &M, TypeExpansionContext context) { if (Path.empty()) return getBaseType(); if (MostDerivedType) return MostDerivedType; - MostDerivedType = getDerivedType(Path.size(), M); + MostDerivedType = getDerivedType(Path.size(), M, context); return MostDerivedType; } /// Returns the ith derived type of the path. This is zero indexed with 0 /// being the base type and n consisting of applying the up to n projections /// to the base type. - SILType getDerivedType(unsigned i, SILModule &M) const { + SILType getDerivedType(unsigned i, SILModule &M, + TypeExpansionContext context) const { assert(i <= Path.size()); SILType IterTy = getBaseType(); if (i == 0) return IterTy; for (unsigned j : range(i)) { auto &Proj = Path[j]; - IterTy = Proj.getType(IterTy, M); + IterTy = Proj.getType(IterTy, M, context); } return IterTy; } @@ -671,10 +675,11 @@ class ProjectionPath { const_reverse_iterator rbegin() const { return Path.rbegin(); } const_reverse_iterator rend() const { return Path.rend(); } - void verify(SILModule &M); + void verify(SILModule &M, TypeExpansionContext context); - raw_ostream &print(raw_ostream &OS, SILModule &M) const; - void dump(SILModule &M) const; + raw_ostream &print(raw_ostream &OS, SILModule &M, + TypeExpansionContext context) const; + void dump(SILModule &M, TypeExpansionContext context) const; }; /// Returns the hashcode for the new projection path. @@ -813,9 +818,11 @@ class ProjectionTreeNode { llvm::SmallVectorImpl &Worklist, SILValue Value); - void createNextLevelChildren(ProjectionTree &Tree); + void createNextLevelChildren(ProjectionTree &Tree, TypeExpansionContext context); - void createNextLevelChildrenForStruct(ProjectionTree &Tree, StructDecl *SD); + void createNextLevelChildrenForStruct(ProjectionTree &Tree, + TypeExpansionContext context, + StructDecl *SD); void createNextLevelChildrenForTuple(ProjectionTree &Tree, TupleType *TT); }; diff --git a/include/swift/SIL/SILBasicBlock.h b/include/swift/SIL/SILBasicBlock.h index d9a4e244527b0..fa3645da1ae60 100644 --- a/include/swift/SIL/SILBasicBlock.h +++ b/include/swift/SIL/SILBasicBlock.h @@ -214,7 +214,8 @@ public llvm::ilist_node, public SILAllocated { /// Allocate a new argument of type \p Ty and append it to the argument /// list. Optionally you can pass in a value decl parameter. SILFunctionArgument *createFunctionArgument(SILType Ty, - const ValueDecl *D = nullptr); + const ValueDecl *D = nullptr, + bool disableEntryBlockVerification = false); SILFunctionArgument *insertFunctionArgument(unsigned Index, SILType Ty, ValueOwnershipKind OwnershipKind, diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index deeb464799708..28dbb5b7b8571 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -197,16 +197,23 @@ class SILBuilder { assert(F && "cannot create this instruction without a function context"); return *F; } + + TypeExpansionContext getTypeExpansionContext() const { + return TypeExpansionContext(getFunction()); + } + SILBuilderContext &getBuilderContext() const { return C; } SILModule &getModule() const { return C.Module; } ASTContext &getASTContext() const { return getModule().getASTContext(); } const Lowering::TypeLowering &getTypeLowering(SILType T) const { - auto expansion = ResilienceExpansion::Maximal; + + auto expansion = TypeExpansionContext::maximal(getModule().getSwiftModule(), + getModule().isWholeModule()); // If there's no current SILFunction, we're inserting into a global // variable initializer. - if (F) - expansion = F->getResilienceExpansion(); - + if (F) { + expansion = TypeExpansionContext(getFunction()); + } return getModule().Types.getTypeLowering(T, expansion); } @@ -336,12 +343,11 @@ class SILBuilder { // Type remapping //===--------------------------------------------------------------------===// - static SILType - getPartialApplyResultType(SILType Ty, unsigned ArgCount, SILModule &M, - SubstitutionMap subs, - ParameterConvention calleeConvention, - PartialApplyInst::OnStackKind onStack = - PartialApplyInst::OnStackKind::NotOnStack); + static SILType getPartialApplyResultType( + TypeExpansionContext context, SILType Ty, unsigned ArgCount, SILModule &M, + SubstitutionMap subs, ParameterConvention calleeConvention, + PartialApplyInst::OnStackKind onStack = + PartialApplyInst::OnStackKind::NotOnStack); //===--------------------------------------------------------------------===// // CFG Manipulation @@ -627,7 +633,8 @@ class SILBuilder { FunctionRefBaseInst *createFunctionRefFor(SILLocation Loc, SILFunction *f) { if (f->isDynamicallyReplaceable()) return createDynamicFunctionRef(Loc, f); - else return createFunctionRef(Loc, f); + else + return createFunctionRef(Loc, f); } FunctionRefBaseInst *createFunctionRef(SILLocation Loc, SILFunction *f, @@ -643,20 +650,20 @@ class SILBuilder { } FunctionRefInst *createFunctionRef(SILLocation Loc, SILFunction *f) { - return insert(new (getModule()) - FunctionRefInst(getSILDebugLocation(Loc), f)); + return insert(new (getModule()) FunctionRefInst(getSILDebugLocation(Loc), f, + getTypeExpansionContext())); } DynamicFunctionRefInst * createDynamicFunctionRef(SILLocation Loc, SILFunction *f) { return insert(new (getModule()) DynamicFunctionRefInst( - getSILDebugLocation(Loc), f)); + getSILDebugLocation(Loc), f, getTypeExpansionContext())); } PreviousDynamicFunctionRefInst * createPreviousDynamicFunctionRef(SILLocation Loc, SILFunction *f) { return insert(new (getModule()) PreviousDynamicFunctionRefInst( - getSILDebugLocation(Loc), f)); + getSILDebugLocation(Loc), f, getTypeExpansionContext())); } AllocGlobalInst *createAllocGlobal(SILLocation Loc, SILGlobalVariable *g) { @@ -664,16 +671,16 @@ class SILBuilder { AllocGlobalInst(getSILDebugLocation(Loc), g)); } GlobalAddrInst *createGlobalAddr(SILLocation Loc, SILGlobalVariable *g) { - return insert(new (getModule()) - GlobalAddrInst(getSILDebugLocation(Loc), g)); + return insert(new (getModule()) GlobalAddrInst(getSILDebugLocation(Loc), g, + getTypeExpansionContext())); } GlobalAddrInst *createGlobalAddr(SILLocation Loc, SILType Ty) { return insert(new (F->getModule()) GlobalAddrInst(getSILDebugLocation(Loc), Ty)); } GlobalValueInst *createGlobalValue(SILLocation Loc, SILGlobalVariable *g) { - return insert(new (getModule()) - GlobalValueInst(getSILDebugLocation(Loc), g)); + return insert(new (getModule()) GlobalValueInst(getSILDebugLocation(Loc), g, + getTypeExpansionContext())); } IntegerLiteralInst *createIntegerLiteral(IntegerLiteralExpr *E); @@ -1338,8 +1345,8 @@ class SILBuilder { UncheckedEnumDataInst *createUncheckedEnumData(SILLocation Loc, SILValue Operand, EnumElementDecl *Element) { - SILType EltType = - Operand->getType().getEnumElementType(Element, getModule()); + SILType EltType = Operand->getType().getEnumElementType( + Element, getModule(), getTypeExpansionContext()); return createUncheckedEnumData(Loc, Operand, Element, EltType); } @@ -1360,8 +1367,8 @@ class SILBuilder { UncheckedTakeEnumDataAddrInst * createUncheckedTakeEnumDataAddr(SILLocation Loc, SILValue Operand, EnumElementDecl *Element) { - SILType EltType = - Operand->getType().getEnumElementType(Element, getModule()); + SILType EltType = Operand->getType().getEnumElementType( + Element, getModule(), getTypeExpansionContext()); return createUncheckedTakeEnumDataAddr(Loc, Operand, Element, EltType); } @@ -1436,7 +1443,8 @@ class SILBuilder { StructExtractInst *createStructExtract(SILLocation Loc, SILValue Operand, VarDecl *Field) { - auto type = Operand->getType().getFieldType(Field, getModule()); + auto type = Operand->getType().getFieldType(Field, getModule(), + getTypeExpansionContext()); return createStructExtract(Loc, Operand, Field, type); } @@ -1450,7 +1458,8 @@ class SILBuilder { StructElementAddrInst * createStructElementAddr(SILLocation Loc, SILValue Operand, VarDecl *Field) { - auto ResultTy = Operand->getType().getFieldType(Field, getModule()); + auto ResultTy = Operand->getType().getFieldType(Field, getModule(), + getTypeExpansionContext()); return createStructElementAddr(Loc, Operand, Field, ResultTy); } @@ -1461,7 +1470,8 @@ class SILBuilder { } RefElementAddrInst *createRefElementAddr(SILLocation Loc, SILValue Operand, VarDecl *Field) { - auto ResultTy = Operand->getType().getFieldType(Field, getModule()); + auto ResultTy = Operand->getType().getFieldType(Field, getModule(), + getTypeExpansionContext()); return createRefElementAddr(Loc, Operand, Field, ResultTy); } @@ -2184,7 +2194,8 @@ class SILBuilder { SILValue emitStructExtract(SILLocation Loc, SILValue Operand, VarDecl *Field) { - auto type = Operand->getType().getFieldType(Field, getModule()); + auto type = Operand->getType().getFieldType(Field, getModule(), + getTypeExpansionContext()); return emitStructExtract(Loc, Operand, Field, type); } diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index bf874364fa038..8410c4f57c7de 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -131,14 +131,15 @@ class SILCloner : protected SILInstructionVisitor { /// blocks. /// /// This is used to clone an entire function and should not mutate the - /// original function. + /// original function except if \p replaceOriginalFunctionInPlace is true. /// /// entryArgs must have a SILValue from the cloned function corresponding to /// each argument in the original function `F`. /// /// Cloned instructions are inserted starting at the end of clonedEntryBB. void cloneFunctionBody(SILFunction *F, SILBasicBlock *clonedEntryBB, - ArrayRef entryArgs); + ArrayRef entryArgs, + bool replaceOriginalFunctionInPlace = false); /// MARK: Callback utilities used from CRTP extensions during cloning. /// These should only be called from within an instruction cloning visitor. @@ -357,8 +358,14 @@ class SILCloner : protected SILInstructionVisitor { SILLocation remapLocation(SILLocation Loc) { return Loc; } const SILDebugScope *remapScope(const SILDebugScope *DS) { return DS; } - SILType remapType(SILType Ty) { return Ty; } - CanType remapASTType(CanType Ty) { return Ty; } + SILType remapType(SILType Ty) { + return Ty; + } + + CanType remapASTType(CanType Ty) { + return Ty; + } + ProtocolConformanceRef remapConformance(Type Ty, ProtocolConformanceRef C) { return C; } @@ -615,9 +622,11 @@ void SILCloner::cloneReachableBlocks( template void SILCloner::cloneFunctionBody(SILFunction *F, SILBasicBlock *clonedEntryBB, - ArrayRef entryArgs) { + ArrayRef entryArgs, + bool replaceOriginalFunctionInPlace) { - assert(F != clonedEntryBB->getParent() && "Must clone into a new function."); + assert((replaceOriginalFunctionInPlace || F != clonedEntryBB->getParent()) && + "Must clone into a new function."); assert(BBMap.empty() && "This API does not allow clients to map blocks."); assert(ValueMap.empty() && "Stale ValueMap."); @@ -1033,9 +1042,9 @@ SILCloner::visitFunctionRefInst(FunctionRefInst *Inst) { getOpLocation(Inst->getLoc()), OpFunction)); } -template -void -SILCloner::visitDynamicFunctionRefInst(DynamicFunctionRefInst *Inst) { +template +void SILCloner::visitDynamicFunctionRefInst( + DynamicFunctionRefInst *Inst) { SILFunction *OpFunction = getOpFunction(Inst->getInitiallyReferencedFunction()); getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); @@ -2110,8 +2119,11 @@ SILCloner::visitWitnessMethodInst(WitnessMethodInst *Inst) { CanType Ty = conformance.getConcrete()->getType()->getCanonicalType(); if (Ty != newLookupType) { - assert(Ty->isExactSuperclassOf(newLookupType) && - "Should only create upcasts for sub class."); + assert( + (Ty->isExactSuperclassOf(newLookupType) || + getBuilder().getModule().Types.getLoweredRValueType( + getBuilder().getTypeExpansionContext(), Ty) == newLookupType) && + "Should only create upcasts for sub class."); // We use the super class as the new look up type. newLookupType = Ty; diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index 1bcad312c5def..8fee4ca79c6bf 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -342,6 +342,14 @@ class SILFunction CanSILFunctionType getLoweredFunctionType() const { return LoweredType; } + CanSILFunctionType + getLoweredFunctionTypeInContext(TypeExpansionContext context) const; + + SILType getLoweredTypeInContext(TypeExpansionContext context) const { + return SILType::getPrimitiveObjectType( + getLoweredFunctionTypeInContext(context)); + } + SILFunctionConventions getConventions() const { return SILFunctionConventions(LoweredType, getModule()); } @@ -491,6 +499,11 @@ class SILFunction : ResilienceExpansion::Maximal); } + // Returns the type expansion context to be used inside this function. + TypeExpansionContext getTypeExpansionContext() const { + return TypeExpansionContext(*this); + } + const Lowering::TypeLowering & getTypeLowering(Lowering::AbstractionPattern orig, Type subst); @@ -502,6 +515,8 @@ class SILFunction SILType getLoweredLoadableType(Type t) const; + SILType getLoweredType(SILType t) const; + const Lowering::TypeLowering &getTypeLowering(SILType type) const; bool isTypeABIAccessible(SILType type) const; diff --git a/include/swift/SIL/SILGlobalVariable.h b/include/swift/SIL/SILGlobalVariable.h index eedc850458e3a..c40ba2c5766a1 100644 --- a/include/swift/SIL/SILGlobalVariable.h +++ b/include/swift/SIL/SILGlobalVariable.h @@ -105,7 +105,12 @@ class SILGlobalVariable CanSILFunctionType getLoweredFunctionType() const { return LoweredType.castTo(); } - + SILType getLoweredTypeInContext(TypeExpansionContext context) const; + CanSILFunctionType + getLoweredFunctionTypeInContext(TypeExpansionContext context) const { + return getLoweredTypeInContext(context).castTo(); + } + StringRef getName() const { return Name; } void setDeclaration(bool isD) { IsDeclaration = isD; } diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 3b9fc77dacab0..9ed013685c404 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -47,6 +47,7 @@ namespace swift { +class AllocationInst; class DeclRefExpr; class FloatLiteralExpr; class FuncDecl; @@ -623,6 +624,15 @@ class SILInstruction return getMemoryBehavior() != MemoryBehavior::None; } + /// Return true if the instruction is "pure" in the sense that it may execute + /// multiple times without affecting behavior. This implies that it can be + /// trivially cloned at multiple use sites without preserving path + /// equivalence. + bool isPure() const { + return !mayReadOrWriteMemory() && !mayTrap() && !isa(this) + && !isa(this); + } + /// Returns true if the result of this instruction is a pointer to stack /// allocated memory. In this case there must be an adjacent deallocating /// instruction. @@ -2396,7 +2406,7 @@ class FunctionRefBaseInst : public LiteralInst { protected: FunctionRefBaseInst(SILInstructionKind Kind, SILDebugLocation DebugLoc, - SILFunction *F); + SILFunction *F, TypeExpansionContext context); public: ~FunctionRefBaseInst(); @@ -2455,7 +2465,9 @@ class FunctionRefInst : public FunctionRefBaseInst { /// /// \param DebugLoc The location of the reference. /// \param F The function being referenced. - FunctionRefInst(SILDebugLocation DebugLoc, SILFunction *F); + /// \param context The type expansion context of the function reference. + FunctionRefInst(SILDebugLocation DebugLoc, SILFunction *F, + TypeExpansionContext context); public: static bool classof(const SILNode *node) { @@ -2473,7 +2485,9 @@ class DynamicFunctionRefInst : public FunctionRefBaseInst { /// /// \param DebugLoc The location of the reference. /// \param F The function being referenced. - DynamicFunctionRefInst(SILDebugLocation DebugLoc, SILFunction *F); + /// \param context The type expansion context of the function reference. + DynamicFunctionRefInst(SILDebugLocation DebugLoc, SILFunction *F, + TypeExpansionContext context); public: static bool classof(const SILNode *node) { @@ -2491,7 +2505,9 @@ class PreviousDynamicFunctionRefInst : public FunctionRefBaseInst { /// /// \param DebugLoc The location of the reference. /// \param F The function being referenced. - PreviousDynamicFunctionRefInst(SILDebugLocation DebugLoc, SILFunction *F); + /// \param context The type expansion context of the function reference. + PreviousDynamicFunctionRefInst(SILDebugLocation DebugLoc, SILFunction *F, + TypeExpansionContext context); public: static bool classof(const SILNode *node) { @@ -3156,14 +3172,16 @@ class GlobalAddrInst GlobalAccessInst> { friend SILBuilder; - GlobalAddrInst(SILDebugLocation DebugLoc, SILGlobalVariable *Global); + GlobalAddrInst(SILDebugLocation DebugLoc, SILGlobalVariable *Global, + TypeExpansionContext context); + public: // FIXME: This constructor should be private but is currently used // in the SILParser. /// Create a placeholder instruction with an unset global reference. GlobalAddrInst(SILDebugLocation DebugLoc, SILType Ty) - : InstructionBase(DebugLoc, Ty, nullptr) { } + : InstructionBase(DebugLoc, Ty, nullptr) {} }; /// Gives the value of a global variable. @@ -3175,7 +3193,8 @@ class GlobalValueInst GlobalAccessInst> { friend SILBuilder; - GlobalValueInst(SILDebugLocation DebugLoc, SILGlobalVariable *Global); + GlobalValueInst(SILDebugLocation DebugLoc, SILGlobalVariable *Global, + TypeExpansionContext context); }; /// IntegerLiteralInst - Encapsulates an integer constant, as defined originally diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index 8d8f91fc969da..0e6c550760b82 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -655,7 +655,7 @@ class SILModule { /// Can value operations (copies and destroys) on the given lowered type /// be performed in this module? bool isTypeABIAccessible(SILType type, - ResilienceExpansion forExpansion); + TypeExpansionContext forExpansion); /// Can type metadata for the given formal type be fetched in /// the given module? diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index 43840ba632d40..7ac95dc529d96 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -244,7 +244,7 @@ class SILType { /// tc.getTypeLowering(type).isAddressOnly(). static bool isAddressOnly(CanType type, Lowering::TypeConverter &tc, CanGenericSignature sig, - ResilienceExpansion expansion); + TypeExpansionContext expansion); /// Return true if this type must be returned indirectly. /// @@ -253,7 +253,7 @@ class SILType { static bool isFormallyReturnedIndirectly(CanType type, Lowering::TypeConverter &tc, CanGenericSignature sig) { - return isAddressOnly(type, tc, sig, ResilienceExpansion::Minimal); + return isAddressOnly(type, tc, sig, TypeExpansionContext::minimal()); } /// Return true if this type must be passed indirectly. @@ -263,7 +263,7 @@ class SILType { static bool isFormallyPassedIndirectly(CanType type, Lowering::TypeConverter &tc, CanGenericSignature sig) { - return isAddressOnly(type, tc, sig, ResilienceExpansion::Minimal); + return isAddressOnly(type, tc, sig, TypeExpansionContext::minimal()); } /// True if the type, or the referenced type of an address type, is loadable. @@ -411,16 +411,20 @@ class SILType { /// the given field. Applies substitutions as necessary. The /// result will be an address type if the base type is an address /// type or a class. - SILType getFieldType(VarDecl *field, Lowering::TypeConverter &TC) const; + SILType getFieldType(VarDecl *field, Lowering::TypeConverter &TC, + TypeExpansionContext context) const; - SILType getFieldType(VarDecl *field, SILModule &M) const; + SILType getFieldType(VarDecl *field, SILModule &M, + TypeExpansionContext context) const; /// Given that this is an enum type, return the lowered type of the /// data for the given element. Applies substitutions as necessary. /// The result will have the same value category as the base type. - SILType getEnumElementType(EnumElementDecl *elt, Lowering::TypeConverter &TC) const; + SILType getEnumElementType(EnumElementDecl *elt, Lowering::TypeConverter &TC, + TypeExpansionContext context) const; - SILType getEnumElementType(EnumElementDecl *elt, SILModule &M) const; + SILType getEnumElementType(EnumElementDecl *elt, SILModule &M, + TypeExpansionContext context) const; /// Given that this is a tuple type, return the lowered type of the /// given tuple element. The result will have the same value @@ -458,11 +462,11 @@ class SILType { /// generic args with the appropriate item from the substitution. /// /// Only call this with function types! - SILType substGenericArgs(Lowering::TypeConverter &TC, - SubstitutionMap SubMap) const; + SILType substGenericArgs(Lowering::TypeConverter &TC, SubstitutionMap SubMap, + TypeExpansionContext context) const; - SILType substGenericArgs(SILModule &M, - SubstitutionMap SubMap) const; + SILType substGenericArgs(SILModule &M, SubstitutionMap SubMap, + TypeExpansionContext context) const; /// If the original type is generic, pass the signature as genericSig. /// @@ -487,8 +491,9 @@ class SILType { bool isHeapObjectReferenceType() const; /// Returns true if this SILType is an aggregate that contains \p Ty - bool aggregateContainsRecord(SILType Ty, SILModule &SILMod) const; - + bool aggregateContainsRecord(SILType Ty, SILModule &SILMod, + TypeExpansionContext context) const; + /// Returns true if this SILType is an aggregate with unreferenceable storage, /// meaning it cannot be fully destructured in SIL. bool aggregateHasUnreferenceableStorage() const; @@ -515,7 +520,8 @@ class SILType { /// Returns true if this SILType could be potentially a lowering of the given /// formal type. Meant for verification purposes/assertions. - bool isLoweringOf(SILModule &M, CanType formalType); + bool isLoweringOf(TypeExpansionContext context, SILModule &M, + CanType formalType); // SWIFT_ENABLE_TENSORFLOW /// Returns true if this SILType is a differentiable type. @@ -593,8 +599,9 @@ NON_SIL_TYPE(LValue) #undef NON_SIL_TYPE CanSILFunctionType getNativeSILFunctionType( - Lowering::TypeConverter &TC, Lowering::AbstractionPattern origType, - CanAnyFunctionType substType, Optional origConstant = None, + Lowering::TypeConverter &TC, TypeExpansionContext context, + Lowering::AbstractionPattern origType, CanAnyFunctionType substType, + Optional origConstant = None, Optional constant = None, Optional reqtSubs = None, ProtocolConformanceRef witnessMethodConformance = ProtocolConformanceRef()); @@ -620,15 +627,15 @@ inline SILType SILField::getObjectType() const { return SILType::getPrimitiveObjectType(getLoweredType()); } -CanType getSILBoxFieldLoweredType(SILBoxType *type, - Lowering::TypeConverter &TC, +CanType getSILBoxFieldLoweredType(TypeExpansionContext context, + SILBoxType *type, Lowering::TypeConverter &TC, unsigned index); -inline SILType getSILBoxFieldType(SILBoxType *type, - Lowering::TypeConverter &TC, +inline SILType getSILBoxFieldType(TypeExpansionContext context, + SILBoxType *type, Lowering::TypeConverter &TC, unsigned index) { return SILType::getPrimitiveAddressType( - getSILBoxFieldLoweredType(type, TC, index)); + getSILBoxFieldLoweredType(context, type, TC, index)); } } // end swift namespace diff --git a/include/swift/SIL/TypeLowering.h b/include/swift/SIL/TypeLowering.h index 1a856f8af390d..fa3d4adedf953 100644 --- a/include/swift/SIL/TypeLowering.h +++ b/include/swift/SIL/TypeLowering.h @@ -15,6 +15,7 @@ #include "swift/ABI/MetadataValues.h" #include "swift/AST/CaptureInfo.h" +#include "swift/AST/Module.h" #include "swift/SIL/AbstractionPattern.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILInstruction.h" @@ -227,11 +228,12 @@ class TypeLowering { SILType LoweredType; RecursiveProperties Properties; - unsigned ReferenceCounted : 1; /// The resilience expansion for this type lowering. /// If the type is not resilient at all, this is always Minimal. - unsigned ForExpansion : 1; + TypeExpansionContext expansionContext; + + unsigned ReferenceCounted : 1; /// A single linked list of lowerings for different resilience expansions. /// The first lowering is always for ResilientExpansion::Minimal. @@ -240,10 +242,9 @@ class TypeLowering { protected: TypeLowering(SILType type, RecursiveProperties properties, IsReferenceCounted_t isRefCounted, - ResilienceExpansion forExpansion) - : LoweredType(type), Properties(properties), - ReferenceCounted(isRefCounted), - ForExpansion(unsigned(forExpansion)) {} + TypeExpansionContext expansionContext) + : LoweredType(type), Properties(properties), + expansionContext(expansionContext), ReferenceCounted(isRefCounted) {} public: TypeLowering(const TypeLowering &) = delete; @@ -257,27 +258,6 @@ class TypeLowering { /// Dump out the internal state of this type lowering to llvm::dbgs(). SWIFT_DEBUG_DUMP; - /// Are r-values of this type passed as arguments indirectly by formal - /// convention? - /// - /// This is independent of whether the SIL argument is address type. - bool isFormallyPassedIndirectly() const { - assert(!isResilient() || - getResilienceExpansion() == ResilienceExpansion::Minimal && - "calling convention uses minimal resilience expansion"); - return isAddressOnly(); - } - - /// Are r-values of this type returned indirectly by formal convention? - /// - /// This is independent of whether the SIL result is address type. - bool isFormallyReturnedIndirectly() const { - assert(!isResilient() || - getResilienceExpansion() == ResilienceExpansion::Minimal && - "calling convention uses minimal resilience expansion"); - return isAddressOnly(); - } - RecursiveProperties getRecursiveProperties() const { return Properties; } @@ -331,7 +311,11 @@ class TypeLowering { } ResilienceExpansion getResilienceExpansion() const { - return ResilienceExpansion(ForExpansion); + return expansionContext.getResilienceExpansion(); + } + + TypeExpansionContext getExpansionContext() const { + return expansionContext; } /// Produce an exact copy of the value in the given address as a @@ -595,12 +579,13 @@ class TypeConverter { CanGenericSignature Sig; AbstractionPattern::CachingKey OrigType; CanType SubstType; + TypeExpansionContext expansionContext; friend bool operator==(const CachingTypeKey &lhs, const CachingTypeKey &rhs) { - return lhs.Sig == rhs.Sig - && lhs.OrigType == rhs.OrigType - && lhs.SubstType == rhs.SubstType; + return lhs.Sig == rhs.Sig && lhs.OrigType == rhs.OrigType && + lhs.SubstType == rhs.SubstType && + lhs.expansionContext == rhs.expansionContext; } friend bool operator!=(const CachingTypeKey &lhs, const CachingTypeKey &rhs) { @@ -616,13 +601,16 @@ class TypeConverter { /// should be used in the lowered type. CanType SubstType; + TypeExpansionContext expansionContext; + CachingTypeKey getCachingKey() const { assert(isCacheable()); return { (OrigType.hasGenericSignature() ? OrigType.getGenericSignature() : nullptr), OrigType.getCachingKey(), - SubstType }; + SubstType, + expansionContext }; } bool isCacheable() const { @@ -634,14 +622,18 @@ class TypeConverter { return IsDependent; return IsNotDependent; } + TypeKey getKeyForMinimalExpansion() const { + return {OrigType, SubstType, TypeExpansionContext::minimal()}; + } }; friend struct llvm::DenseMapInfo; - - TypeKey getTypeKey(AbstractionPattern origTy, CanType substTy) { - return {origTy, substTy}; + + TypeKey getTypeKey(AbstractionPattern origTy, CanType substTy, + TypeExpansionContext context) { + return {origTy, substTy, context}; } - + struct OverrideKey { SILDeclRef derived; SILDeclRef base; @@ -664,7 +656,11 @@ class TypeConverter { const TypeLowering *find(TypeKey k); /// Insert a mapping into the cache. void insert(TypeKey k, const TypeLowering *tl); - +#ifndef NDEBUG + /// Remove the nullptr entry from the type map. + void removeNullEntry(TypeKey k); +#endif + /// Mapping for types independent on contextual generic parameters. llvm::DenseMap IndependentTypes; @@ -685,12 +681,15 @@ class TypeConverter { llvm::SmallVector DependentTypes; - llvm::DenseMap ConstantTypes; - + llvm::DenseMap, SILConstantInfo *> + ConstantTypes; + llvm::DenseMap ConstantOverrideTypes; llvm::DenseMap LoweredCaptures; + llvm::DenseMap opaqueArchetypeFields; + /// Cache of loadable SILType to number of (estimated) fields /// /// Second element is a ResilienceExpansion. @@ -705,12 +704,14 @@ class TypeConverter { const TypeLowering & getTypeLoweringForLoweredType(TypeKey key, - ResilienceExpansion forExpansion); + TypeExpansionContext forExpansion, + bool origHadOpaqueTypeArchetype); const TypeLowering * getTypeLoweringForExpansion(TypeKey key, - ResilienceExpansion forExpansion, - const TypeLowering *lowering); + TypeExpansionContext forExpansion, + const TypeLowering *lowering, + bool origHadOpaqueTypeArchetype); public: ModuleDecl &M; @@ -723,7 +724,7 @@ class TypeConverter { /// Return the CaptureKind to use when capturing a decl. CaptureKind getDeclCaptureKind(CapturedValue capture, - ResilienceExpansion expansion); + TypeExpansionContext expansion); /// Return a most-general-possible abstraction pattern. AbstractionPattern getMostGeneralAbstraction() { @@ -748,7 +749,7 @@ class TypeConverter { static ProtocolDispatchStrategy getProtocolDispatchStrategy(ProtocolDecl *P); /// Count the total number of fields inside the given SIL Type - unsigned countNumberOfFields(SILType Ty, ResilienceExpansion expansion); + unsigned countNumberOfFields(SILType Ty, TypeExpansionContext expansion); /// True if a protocol uses witness tables for dynamic dispatch. static bool protocolRequiresWitnessTable(ProtocolDecl *P) { @@ -774,7 +775,7 @@ class TypeConverter { /// Lowers a Swift type to a SILType, and returns the SIL TypeLowering /// for that type. const TypeLowering & - getTypeLowering(Type t, ResilienceExpansion forExpansion) { + getTypeLowering(Type t, TypeExpansionContext forExpansion) { AbstractionPattern pattern(getCurGenericContext(), t->getCanonicalType()); return getTypeLowering(pattern, t, forExpansion); } @@ -783,28 +784,28 @@ class TypeConverter { /// patterns of the given original type. const TypeLowering &getTypeLowering(AbstractionPattern origType, Type substType, - ResilienceExpansion forExpansion); + TypeExpansionContext forExpansion); /// Returns the SIL TypeLowering for an already lowered SILType. If the /// SILType is an address, returns the TypeLowering for the pointed-to /// type. const TypeLowering & - getTypeLowering(SILType t, ResilienceExpansion forExpansion); + getTypeLowering(SILType t, TypeExpansionContext forExpansion); // Returns the lowered SIL type for a Swift type. - SILType getLoweredType(Type t, ResilienceExpansion forExpansion) { + SILType getLoweredType(Type t, TypeExpansionContext forExpansion) { return getTypeLowering(t, forExpansion).getLoweredType(); } // Returns the lowered SIL type for a Swift type. SILType getLoweredType(AbstractionPattern origType, Type substType, - ResilienceExpansion forExpansion) { + TypeExpansionContext forExpansion) { return getTypeLowering(origType, substType, forExpansion) .getLoweredType(); } SILType getLoweredLoadableType(Type t, - ResilienceExpansion forExpansion, + TypeExpansionContext forExpansion, SILModule &M) { const TypeLowering &ti = getTypeLowering(t, forExpansion); assert( @@ -813,17 +814,13 @@ class TypeConverter { return ti.getLoweredType(); } - CanType getLoweredRValueType(Type t) { - // We're ignoring the category (object vs address), so the resilience - // expansion does not matter. - return getLoweredType(t, ResilienceExpansion::Minimal).getASTType(); + CanType getLoweredRValueType(TypeExpansionContext context, Type t) { + return getLoweredType(t, context).getASTType(); } - CanType getLoweredRValueType(AbstractionPattern origType, Type substType) { - // We're ignoring the category (object vs address), so the resilience - // expansion does not matter. - return getLoweredType(origType, substType, - ResilienceExpansion::Minimal).getASTType(); + CanType getLoweredRValueType(TypeExpansionContext context, + AbstractionPattern origType, Type substType) { + return getLoweredType(origType, substType, context).getASTType(); } AbstractionPattern getAbstractionPattern(AbstractStorageDecl *storage, @@ -836,14 +833,18 @@ class TypeConverter { CanType getLoweredTypeOfGlobal(VarDecl *var); + bool hasOpaqueArchetypeOrPropertiesOrCases(CanType ty); + /// Return the SILFunctionType for a native function value of the /// given type. - CanSILFunctionType getSILFunctionType(AbstractionPattern origType, + CanSILFunctionType getSILFunctionType(TypeExpansionContext context, + AbstractionPattern origType, CanFunctionType substFnType); /// Returns the formal type, lowered AST type, and SILFunctionType /// for a constant reference. - const SILConstantInfo &getConstantInfo(SILDeclRef constant); + const SILConstantInfo &getConstantInfo(TypeExpansionContext context, + SILDeclRef constant); /// Get the generic environment for a constant. GenericSignature getConstantGenericSignature(SILDeclRef constant); @@ -852,26 +853,29 @@ class TypeConverter { GenericEnvironment *getConstantGenericEnvironment(SILDeclRef constant); /// Returns the SIL type of a constant reference. - SILType getConstantType(SILDeclRef constant) { - return getConstantInfo(constant).getSILType(); + SILType getConstantType(TypeExpansionContext context, SILDeclRef constant) { + return getConstantInfo(context, constant).getSILType(); } /// Returns the SILFunctionType for the given declaration. - CanSILFunctionType getConstantFunctionType(SILDeclRef constant) { - return getConstantInfo(constant).SILFnType; + CanSILFunctionType getConstantFunctionType(TypeExpansionContext context, + SILDeclRef constant) { + return getConstantInfo(context, constant).SILFnType; } /// Returns the SILParameterInfo for the given declaration's `self` parameter. /// `constant` must refer to a method. - SILParameterInfo getConstantSelfParameter(SILDeclRef constant); + SILParameterInfo getConstantSelfParameter(TypeExpansionContext context, + SILDeclRef constant); /// Returns the SILFunctionType that must be used to perform a vtable dispatch /// to the given declaration. /// /// Will be the same as getConstantFunctionType() if the declaration does not /// override anything. - CanSILFunctionType getConstantOverrideType(SILDeclRef constant) { - return getConstantOverrideInfo(constant).SILFnType; + CanSILFunctionType getConstantOverrideType(TypeExpansionContext context, + SILDeclRef constant) { + return getConstantOverrideInfo(context, constant).SILFnType; } /// Returns the SILConstantInfo that must be used to perform a vtable dispatch @@ -879,17 +883,19 @@ class TypeConverter { /// /// Will be the same as getConstantInfo() if the declaration does not /// override anything. - const SILConstantInfo &getConstantOverrideInfo(SILDeclRef constant) { + const SILConstantInfo &getConstantOverrideInfo(TypeExpansionContext context, + SILDeclRef constant) { // Fast path if the constant does not override anything. auto next = constant.getNextOverriddenVTableEntry(); if (next.isNull()) - return getConstantInfo(constant); + return getConstantInfo(context, constant); auto base = constant.getOverriddenVTableEntry(); - return getConstantOverrideInfo(constant, base); + return getConstantOverrideInfo(context, constant, base); } - const SILConstantInfo &getConstantOverrideInfo(SILDeclRef constant, + const SILConstantInfo &getConstantOverrideInfo(TypeExpansionContext context, + SILDeclRef constant, SILDeclRef base); /// Get the empty tuple type as a SILType. @@ -939,7 +945,8 @@ class TypeConverter { /// type of the storage of the value. /// /// \return - always an address type - SILType getSubstitutedStorageType(AbstractStorageDecl *value, + SILType getSubstitutedStorageType(TypeExpansionContext context, + AbstractStorageDecl *value, Type lvalueType); /// Push a generic function context. See GenericContextScope for an RAII @@ -1022,9 +1029,10 @@ class TypeConverter { /// \p constant. The result is not cached as part of the constant's normal /// ConstantInfo. CanSILFunctionType - getUncachedSILFunctionTypeForConstant(SILDeclRef constant, - CanAnyFunctionType origInterfaceType); - + getUncachedSILFunctionTypeForConstant(TypeExpansionContext expansion, + SILDeclRef constant, + CanAnyFunctionType origInterfaceType); + /// Get the boxed interface type to use for a capture of the given decl. CanSILBoxType getInterfaceBoxTypeForCapture(ValueDecl *captured, @@ -1038,11 +1046,13 @@ class TypeConverter { GenericEnvironment *env, bool isMutable); - CanSILBoxType getBoxTypeForEnumElement(SILType enumType, + CanSILBoxType getBoxTypeForEnumElement(TypeExpansionContext context, + SILType enumType, EnumElementDecl *elt); private: - CanType computeLoweredRValueType(AbstractionPattern origType, + CanType computeLoweredRValueType(TypeExpansionContext context, + AbstractionPattern origType, CanType substType); Type getLoweredCBridgedType(AbstractionPattern pattern, Type t, @@ -1103,10 +1113,12 @@ namespace llvm { // Use the second field because the first field can validly be null. static CachingTypeKey getEmptyKey() { - return {nullptr, APCachingKey(), CanTypeInfo::getEmptyKey()}; + return {nullptr, APCachingKey(), CanTypeInfo::getEmptyKey(), + swift::TypeExpansionContext::minimal()}; } static CachingTypeKey getTombstoneKey() { - return {nullptr, APCachingKey(), CanTypeInfo::getTombstoneKey()}; + return {nullptr, APCachingKey(), CanTypeInfo::getTombstoneKey(), + swift::TypeExpansionContext::minimal()}; } static unsigned getHashValue(CachingTypeKey val) { auto hashSig = @@ -1115,7 +1127,10 @@ namespace llvm { CachingKeyInfo::getHashValue(val.OrigType); auto hashSubst = DenseMapInfo::getHashValue(val.SubstType); - return hash_combine(hashSig, hashOrig, hashSubst); + auto hashContext = + DenseMapInfo::getHashValue( + val.expansionContext); + return hash_combine(hashSig, hashOrig, hashSubst, hashContext); } static bool isEqual(CachingTypeKey LHS, CachingTypeKey RHS) { return LHS == RHS; diff --git a/include/swift/SIL/TypeSubstCloner.h b/include/swift/SIL/TypeSubstCloner.h index f450827afa47f..22b8dfb679256 100644 --- a/include/swift/SIL/TypeSubstCloner.h +++ b/include/swift/SIL/TypeSubstCloner.h @@ -90,7 +90,8 @@ class TypeSubstCloner : public SILClonerWithScopes { // Use the new set of substitutions to compute the new // substituted callee type. RecursiveSubstCalleeSILType = LoweredFnTy->substGenericArgs( - AI.getModule(), RecursiveSubs); + AI.getModule(), RecursiveSubs, + Builder.getTypeExpansionContext()); } // The specialized recursive function may have different calling @@ -109,7 +110,8 @@ class TypeSubstCloner : public SILClonerWithScopes { assert(Subs.empty() || SubstCalleeSILType == - Callee->getType().substGenericArgs(AI.getModule(), Subs)); + Callee->getType().substGenericArgs( + AI.getModule(), Subs, Builder.getTypeExpansionContext())); } ArrayRef getArguments() const { @@ -168,17 +170,40 @@ class TypeSubstCloner : public SILClonerWithScopes { SILType &Sty = TypeCache[Ty]; if (!Sty) { Sty = Ty.subst(Original.getModule(), SubsMap); + if (!Sty.getASTType()->hasOpaqueArchetype() || + !getBuilder() + .getTypeExpansionContext() + .shouldLookThroughOpaqueTypeArchetypes()) + return Sty; + // Remap types containing opaque result types in the current context. + Sty = getBuilder().getTypeLowering(Sty).getLoweredType().getCategoryType( + Sty.getCategory()); } return Sty; } CanType remapASTType(CanType ty) { - return ty.subst(SubsMap)->getCanonicalType(); + auto substTy = ty.subst(SubsMap)->getCanonicalType(); + if (!substTy->hasOpaqueArchetype() || + !getBuilder().getTypeExpansionContext() + .shouldLookThroughOpaqueTypeArchetypes()) + return substTy; + // Remap types containing opaque result types in the current context. + return getBuilder().getModule().Types.getLoweredRValueType( + TypeExpansionContext(getBuilder().getFunction()), substTy); } - ProtocolConformanceRef remapConformance(Type type, + ProtocolConformanceRef remapConformance(Type ty, ProtocolConformanceRef conf) { - return conf.subst(type, SubsMap); + auto conformance = conf.subst(ty, SubsMap); + auto substTy = ty.subst(SubsMap)->getCanonicalType(); + auto context = getBuilder().getTypeExpansionContext(); + if (substTy->hasOpaqueArchetype() && + context.shouldLookThroughOpaqueTypeArchetypes()) { + conformance = + substOpaqueTypesWithUnderlyingTypes(conformance, substTy, context); + } + return conformance; } SubstitutionMap remapSubstitutionMap(SubstitutionMap Subs) { diff --git a/include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h b/include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h index 1c19552cd5f5f..e71b6c58fea36 100644 --- a/include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h @@ -62,7 +62,8 @@ class AccessSummaryAnalysis : public BottomUpIPAnalysis { /// Returns a description of the summary. For debugging and testing /// purposes. - std::string getDescription(SILType BaseType, SILModule &M) const; + std::string getDescription(SILType BaseType, SILModule &M, + TypeExpansionContext context) const; }; typedef llvm::SmallDenseMap @@ -85,7 +86,8 @@ class AccessSummaryAnalysis : public BottomUpIPAnalysis { /// Returns a description of the summary. For debugging and testing /// purposes. - std::string getDescription(SILType BaseType, SILModule &M) const; + std::string getDescription(SILType BaseType, SILModule &M, + TypeExpansionContext context) const; /// Returns the accesses that the function performs to subpaths of the /// argument. @@ -208,7 +210,8 @@ class AccessSummaryAnalysis : public BottomUpIPAnalysis { /// The base type must be the type of the root of the path. static std::string getSubPathDescription(SILType BaseType, const IndexTrieNode *SubPath, - SILModule &M); + SILModule &M, + TypeExpansionContext context); /// Performs a lexicographic comparison of two subpaths, first by path length /// and then by index of the last path component. Returns true when lhs diff --git a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h index 732cb08754df5..60822d94f171f 100644 --- a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h @@ -305,13 +305,19 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// True if the merge is finished (see mergeTo). In this state this node /// is completely unlinked from the graph, bool isMerged = false; - + + /// True if this is a content node that owns a reference count. Such a + /// content node necessarilly keeps alive all content it points to until it + /// is released. This can be conservatively false. + bool hasRC = false; + /// The type of the node (mainly distinguishes between content and value /// nodes). NodeType Type; /// The constructor. - CGNode(ValueBase *V, NodeType Type) : V(V), UsePoints(0), Type(Type) { + CGNode(ValueBase *V, NodeType Type, bool hasRC) + : V(V), UsePoints(0), hasRC(hasRC), Type(Type) { switch (Type) { case NodeType::Argument: case NodeType::Value: @@ -403,17 +409,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// Checks an invariant of the connection graph: The points-to nodes of /// the defer-successors must match with the points-to of this node. - bool matchPointToOfDefers() const { - for (CGNode *Def : defersTo) { - if (pointsTo != Def->pointsTo) - return false; - } - /// A defer-path in the graph must not end without the specified points-to - /// node. - if (pointsTo && !pointsToIsEdge && defersTo.empty()) - return false; - return true; - } + bool matchPointToOfDefers(bool allowMerge = false) const; friend class CGNodeMap; friend class ConnectionGraph; @@ -434,6 +430,12 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// Return true if this node represents content. bool isContent() const { return Type == NodeType::Content; } + + /// Return true if this node represents an entire reference counted object. + bool hasRefCount() const { return hasRC; } + + void setRefCount() { hasRC = true; } + /// Returns the escape state. EscapeState getEscapeState() const { return State; } @@ -480,7 +482,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { llvm_unreachable("Unhandled EscapeState in switch."); } - /// Returns the content node if of this node if it exists in the graph. + /// Returns the content node of this node if it exists in the graph. CGNode *getContentNodeOrNull() const { return pointsTo; } @@ -575,10 +577,14 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// Removes all nodes from the graph. void clear(); - + /// Allocates a node of a given type. - CGNode *allocNode(ValueBase *V, NodeType Type) { - CGNode *Node = new (NodeAllocator.Allocate()) CGNode(V, Type); + /// + /// hasRC is set for Content nodes based on the type and origin of + /// the pointer. + CGNode *allocNode(ValueBase *V, NodeType Type, bool hasRC = false) { + assert(Type == NodeType::Content || !hasRC); + CGNode *Node = new (NodeAllocator.Allocate()) CGNode(V, Type, hasRC); Nodes.push_back(Node); return Node; } @@ -603,14 +609,25 @@ class EscapeAnalysis : public BottomUpIPAnalysis { } } + /// Initialize the 'pointsTo' fields of all nodes in the defer web of \p + /// initialiNode. + /// + /// If \p createEdge is true, a proper pointsTo edge will be created from \p + /// initialNode to \p pointsTo. + void initializePointsTo(CGNode *initialNode, CGNode *newPointsTo, + bool createEdge = false); + + void initializePointsToEdge(CGNode *initialNode, CGNode *newPointsTo) { + initializePointsTo(initialNode, newPointsTo, true); + } + /// Merges all nodes which are added to the ToMerge list. void mergeAllScheduledNodes(); - /// Transitively updates pointsTo of all nodes in the defer-edge web, - /// starting at \p InitialNode. - /// If a node in the web already points to another content node, the other - /// content node is scheduled to be merged with \p pointsTo. - void updatePointsTo(CGNode *InitialNode, CGNode *pointsTo); + /// Transitively update pointsTo of all nodes in the defer-edge web, + /// reaching and reachable from \p initialNode. All nodes in this defer web + /// must already have an initialized `pointsTo`. + void mergePointsTo(CGNode *initialNode, CGNode *pointsTo); /// Utility function to clear the isInWorkList flags of all nodes in /// \p WorkList. @@ -627,12 +644,20 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// Returns null, if V is not a "pointer". CGNode *getNode(ValueBase *V, bool createIfNeeded = true); - /// Gets or creates a content node to which \a AddrNode points to during - /// initial graph construction. This may not be called after defer edges - /// have been created. Doing so would break the invariant that all - /// non-content nodes ultimately have a pointsTo edge to a single content - /// node. - CGNode *getContentNode(CGNode *AddrNode); + /// Helper to create a content node and update the pointsTo graph. \p + /// addrNode will point to the new content node. The new content node is + /// directly initialized with the remaining function arguments. + CGNode *createContentNode(CGNode *addrNode, SILValue addrVal, bool hasRC); + + /// Create a new content node based on an existing content node to support + /// graph merging. + /// + /// \p destAddrNode will point to to new content. The content's initial + /// state will be initialized based on the \p srcContent node. + CGNode *createMergedContent(CGNode *destAddrNode, CGNode *srcContent); + + /// Get a node represnting the field data within the given RC node. + CGNode *getFieldContent(CGNode *rcNode); /// Get or creates a pseudo node for the function return value. CGNode *getReturnNode() { @@ -679,31 +704,21 @@ class EscapeAnalysis : public BottomUpIPAnalysis { return Idx; } - /// Specifies that the node's value escapes to global or unidentified - /// memory. - void setEscapesGlobal(CGNode *Node) { - Node->mergeEscapeState(EscapeState::Global); - - // Make sure to have a content node. Otherwise we may end up not merging - // the global-escape state into a caller graph (only content nodes are - // merged). Either the node itself is a content node or we let the node - // point to one. - if (Node->Type != NodeType::Content) - getContentNode(Node); + void escapeContentsOf(CGNode *Node) { + CGNode *escapedContent = Node->getContentNodeOrNull(); + if (!escapedContent) { + escapedContent = createContentNode(Node, Node->V, /*hasRC=*/false); + } + escapedContent->markEscaping(); } /// Creates a defer-edge between \p From and \p To. /// This may trigger node merges to keep the graph invariance 4). /// Returns the \p From node or its merge-target in case \p From was merged /// during adding the edge. - /// The \p EdgeAdded is set to true if there was no defer-edge between - /// \p From and \p To, yet. - CGNode *defer(CGNode *From, CGNode *To, bool &EdgeAdded) { - if (addDeferEdge(From, To)) - EdgeAdded = true; - mergeAllScheduledNodes(); - return From->getMergeTarget(); - } + /// \p Changed is set to true if a defer edge was added or any nodes were + /// merged. + CGNode *defer(CGNode *From, CGNode *To, bool &Changed); /// Creates a defer-edge between \p From and \p To. /// This may trigger node merges to keep the graph invariance 4). @@ -802,7 +817,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { void dumpCG() const; /// Checks if the graph is OK. - void verify() const; + void verify(bool allowMerge = false) const; /// Just verifies the graph structure. This function can also be called /// during the graph is modified, e.g. in mergeAllScheduledNodes(). @@ -889,9 +904,22 @@ class EscapeAnalysis : public BottomUpIPAnalysis { SILValue getPointerRoot(SILValue value) const; /// If \p pointer is a pointer, set it to global escaping. - void setEscapesGlobal(ConnectionGraph *ConGraph, ValueBase *pointer) { - if (CGNode *Node = ConGraph->getNode(pointer)) - ConGraph->setEscapesGlobal(Node); + void setEscapesGlobal(ConnectionGraph *conGraph, ValueBase *pointer) { + CGNode *Node = conGraph->getNode(pointer); + if (!Node) + return; + + if (Node->isContent()) { + Node->markEscaping(); + return; + } + Node->mergeEscapeState(EscapeState::Global); + + // Make sure to have a content node. Otherwise we may end up not merging + // the global-escape state into a caller graph (only content nodes are + // merged). Either the node itself is a content node or we let the node + // point to one. + conGraph->escapeContentsOf(Node); } /// Gets or creates FunctionEffects for \p F. @@ -902,6 +930,15 @@ class EscapeAnalysis : public BottomUpIPAnalysis { return FInfo; } + /// Get or create the node representing the memory pointed to by \p + /// addrVal. If \p addrVal is an address, then return the content node for the + /// variable's memory. Otherwise, \p addrVal may contain a reference, so + /// return the content node for the referenced heap object. + /// + /// Note that \p addrVal cannot be an address within a heap object, such as + /// an address from ref_element_addr or project_box. + CGNode *getValueContent(ConnectionGraph *conGraph, SILValue addrVal); + /// Build a connection graph for reach callee from the callee list. bool buildConnectionGraphForCallees(SILInstruction *Caller, CalleeList Callees, diff --git a/include/swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h b/include/swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h index bc70dd7a31292..69c0b7718e1cc 100644 --- a/include/swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h @@ -12,6 +12,7 @@ #ifndef SWIFT_SILOPTIMIZER_ANALYSIS_TYPEEXPANSIONANALYSIS_H #define SWIFT_SILOPTIMIZER_ANALYSIS_TYPEEXPANSIONANALYSIS_H +#include "swift/AST/TypeExpansionContext.h" #include "swift/SIL/Projection.h" #include "swift/SIL/SILType.h" #include "swift/SIL/SILValue.h" @@ -22,7 +23,9 @@ namespace swift { /// This analysis determines memory effects during destruction. class TypeExpansionAnalysis : public SILAnalysis { - llvm::DenseMap ExpansionCache; + llvm::DenseMap, ProjectionPathList> + ExpansionCache; + public: TypeExpansionAnalysis(SILModule *M) : SILAnalysis(SILAnalysisKind::TypeExpansion) {} @@ -32,7 +35,8 @@ class TypeExpansionAnalysis : public SILAnalysis { } /// Return ProjectionPath to every leaf or intermediate node of the given type. - const ProjectionPathList &getTypeExpansion(SILType B, SILModule *Mod); + const ProjectionPathList &getTypeExpansion(SILType B, SILModule *Mod, + TypeExpansionContext context); /// Invalidate all information in this analysis. virtual void invalidate() override { diff --git a/include/swift/SILOptimizer/Analysis/ValueTracking.h b/include/swift/SILOptimizer/Analysis/ValueTracking.h index 2a3e39eafb9a5..cb13571026b4d 100644 --- a/include/swift/SILOptimizer/Analysis/ValueTracking.h +++ b/include/swift/SILOptimizer/Analysis/ValueTracking.h @@ -47,7 +47,7 @@ bool pointsToLocalObject(SILValue V); /// allocated object). /// /// - an address projection based on an exclusive argument with no levels of -/// indirection. +/// indirection (e.g. ref_element_addr, project_box, etc.). inline bool isUniquelyIdentified(SILValue V) { return pointsToLocalObject(V) || isExclusiveArgument(getUnderlyingAddressRoot(V)); diff --git a/include/swift/SILOptimizer/PassManager/PassPipeline.def b/include/swift/SILOptimizer/PassManager/PassPipeline.def index 005943e86582b..12132e4d180bb 100644 --- a/include/swift/SILOptimizer/PassManager/PassPipeline.def +++ b/include/swift/SILOptimizer/PassManager/PassPipeline.def @@ -30,6 +30,7 @@ PASSPIPELINE(Onone, "Passes run at -Onone") PASSPIPELINE(InstCount, "Utility pipeline to just run the inst count pass") PASSPIPELINE(Lowering, "SIL Address Lowering") PASSPIPELINE(IRGenPrepare, "Pipeline to run during IRGen") +PASSPIPELINE(SerializeSIL, "Utility pipeline that just runs SerializeSILPass ") #undef PASSPIPELINE_WITH_OPTIONS #undef PASSPIPELINE diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index 4796abde148e8..62813d894fe0a 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -233,8 +233,6 @@ PASS(NoReturnFolding, "noreturn-folding", "Prune Control Flow at No-Return Calls Using SIL unreachable") PASS(ObjectOutliner, "object-outliner", "Outlining of Global Objects") -PASS(OpaqueArchetypeSpecializer, "opaque-archetype-specializer", - "Opaque archetype specializer") PASS(Outliner, "outliner", "Function Outlining Optimization") PASS(OwnershipModelEliminator, "ownership-model-eliminator", diff --git a/include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h b/include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h index 2d0bb0e457892..77e5e4b0e2780 100644 --- a/include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h +++ b/include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h @@ -22,9 +22,10 @@ #ifndef SWIFT_SILOPTIMIZER_UTILS_BASICBLOCKOPTUTILS_H #define SWIFT_SILOPTIMIZER_UTILS_BASICBLOCKOPTUTILS_H -#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILCloner.h" +#include "swift/SIL/SILInstruction.h" +#include "swift/SILOptimizer/Utils/InstOptUtils.h" namespace swift { @@ -61,12 +62,65 @@ bool rotateLoop(SILLoop *loop, DominanceInfo *domInfo, SILLoopInfo *loopInfo, bool rotateSingleBlockLoops, SILBasicBlock *upToBB, bool shouldVerify); -/// Helper function to perform SSA updates in case of jump threading. -void updateSSAAfterCloning(BasicBlockCloner &cloner, SILBasicBlock *srcBB, - SILBasicBlock *destBB); +/// Sink address projections to their out-of-block uses. This is +/// required after cloning a block and before calling +/// updateSSAAfterCloning to avoid address-type phis. +/// +/// This clones address projections at their use points, but does not +/// mutate the block containing the projections. +/// +/// BasicBlockCloner handles this internally. +class SinkAddressProjections { + // Projections ordered from last to first in the chain. + SmallVector projections; + SmallSetVector inBlockDefs; + + // Transient per-projection data for use during cloning. + SmallVector usesToReplace; + llvm::SmallDenseMap firstBlockUse; + +public: + /// Check for an address projection chain ending at \p inst. Return true if + /// the given instruction is successfully analyzed. + /// + /// If \p inst does not produce an address, then return + /// true. getInBlockDefs() will contain \p inst if any of its + /// (non-address) values are used outside its block. + /// + /// If \p inst does produce an address, return true only of the + /// chain of address projections within this block is clonable at + /// their use sites. getInBlockDefs will return all non-address + /// operands in the chain that are also defined in this block. These + /// may require phis after cloning the projections. + bool analyzeAddressProjections(SILInstruction *inst); + + /// After analyzing projections, returns the list of (non-address) values + /// defined in the same block as the projections which will have uses outside + /// the block after cloning. + ArrayRef getInBlockDefs() const { + return inBlockDefs.getArrayRef(); + } + /// Clone the chain of projections at their use sites. + /// + /// Return true if anything was done. + /// + /// getInBlockProjectionOperandValues() can be called before or after cloning. + bool cloneProjections(); +}; /// Clone a single basic block and any required successor edges within the same /// function. +/// +/// Before cloning, call either canCloneBlock or call canCloneInstruction for +/// every instruction in the original block. +/// +/// To clone just the block, call cloneBlock. To also update the original +/// block's branch to jump to the newly cloned block, call cloneBranchTarget +/// instead. +/// +/// After cloning, call splitCriticalEdges, then updateSSAAfterCloning. This is +/// decoupled from cloning becaused some clients perform CFG edges updates after +/// cloning but before splitting CFG edges. class BasicBlockCloner : public SILCloner { using SuperTy = SILCloner; friend class SILCloner; @@ -75,18 +129,56 @@ class BasicBlockCloner : public SILCloner { /// The original block to be cloned. SILBasicBlock *origBB; + /// Will cloning require an SSA update? + bool needsSSAUpdate = false; + + /// Transient object for analyzing a single address projction chain. It's + /// state is reset each time analyzeAddressProjections is called. + SinkAddressProjections sinkProj; + public: /// An ordered list of old to new available value pairs. /// /// updateSSAAfterCloning() expects this public field to hold values that may /// be remapped in the cloned block and live out. - SmallVector, 16> AvailVals; + SmallVector, 16> availVals; // Clone blocks starting at `origBB`, within the same function. BasicBlockCloner(SILBasicBlock *origBB) : SILCloner(*origBB->getParent()), origBB(origBB) {} + bool canCloneBlock() { + for (auto &inst : *origBB) { + if (!canCloneInstruction(&inst)) + return false; + } + return true; + } + + /// Returns true if \p inst can be cloned. + /// + /// If canCloneBlock is not called, then this must be called for every + /// instruction in origBB, both to ensure clonability and to handle internal + /// book-keeping (needsSSAUpdate). + bool canCloneInstruction(SILInstruction *inst) { + assert(inst->getParent() == origBB); + + if (!inst->isTriviallyDuplicatable()) + return false; + + if (!sinkProj.analyzeAddressProjections(inst)) + return false; + + // Check if any of the non-address defs in the cloned block (including the + // current instruction) will still have uses outside the block after sinking + // address projections. + needsSSAUpdate |= !sinkProj.getInBlockDefs().empty(); + return true; + } + void cloneBlock(SILBasicBlock *insertAfterBB = nullptr) { + sinkAddressProjections(); + SmallVector successorBBs; successorBBs.reserve(origBB->getSuccessors().size()); llvm::copy(origBB->getSuccessors(), std::back_inserter(successorBBs)); @@ -95,6 +187,9 @@ class BasicBlockCloner : public SILCloner { /// Clone the given branch instruction's destination block, splitting /// its successors, and rewrite the branch instruction. + /// + /// Return false if the branch's destination block cannot be cloned. When + /// false is returned, no changes have been made. void cloneBranchTarget(BranchInst *bi) { assert(origBB == bi->getDestBB()); @@ -110,10 +205,16 @@ class BasicBlockCloner : public SILCloner { return remapBasicBlock(origBB); } + bool wasCloned() { return isBlockCloned(origBB); } + /// Call this after processing all instructions to fix the control flow /// graph. The branch cloner may have left critical edges. bool splitCriticalEdges(DominanceInfo *domInfo, SILLoopInfo *loopInfo); + /// Helper function to perform SSA updates after calling both + /// cloneBranchTarget and splitCriticalEdges. + void updateSSAAfterCloning(); + protected: // MARK: CRTP overrides. @@ -137,8 +238,10 @@ class BasicBlockCloner : public SILCloner { void mapValue(SILValue origValue, SILValue mappedValue) { SuperTy::mapValue(origValue, mappedValue); - AvailVals.emplace_back(origValue, mappedValue); + availVals.emplace_back(origValue, mappedValue); } + + void sinkAddressProjections(); }; // Helper class that provides a callback that can be used in @@ -173,46 +276,6 @@ class CloneCollector { } }; -/// Sink address projections to their out-of-block uses. This is -/// required after cloning a block and before calling -/// updateSSAAfterCloning to avoid address-type phis. -/// -/// This clones address projections at their use points, but does not -/// mutate the block containing the projections. -class SinkAddressProjections { - // Projections ordered from last to first in the chain. - SmallVector projections; - SmallSetVector inBlockDefs; - -public: - /// Check for an address projection chain ending at \p inst. Return true if - /// the given instruction is successfully analyzed. - /// - /// If \p inst does not produce an address, then return - /// true. getInBlockDefs() will contain \p inst if any of its - /// (non-address) values are used outside its block. - /// - /// If \p inst does produce an address, return true only of the - /// chain of address projections within this block is clonable at - /// their use sites. getInBlockDefs will return all non-address - /// operands in the chain that are also defined in this block. These - /// may require phis after cloning the projections. - bool analyzeAddressProjections(SILInstruction *inst); - - /// After analyzing projections, returns the list of (non-address) values - /// defined in the same block as the projections which will have uses outside - /// the block after cloning. - ArrayRef getInBlockDefs() const { - return inBlockDefs.getArrayRef(); - } - /// Clone the chain of projections at their use sites. - /// - /// Return true if anything was done. - /// - /// getInBlockProjectionOperandValues() can be called before or after cloning. - bool cloneProjections(); -}; - /// Utility class for cloning init values into the static initializer of a /// SILGlobalVariable. class StaticInitCloner : public SILCloner { diff --git a/include/swift/SILOptimizer/Utils/Generics.h b/include/swift/SILOptimizer/Utils/Generics.h index 50c80b51578d3..d4c3f3d325040 100644 --- a/include/swift/SILOptimizer/Utils/Generics.h +++ b/include/swift/SILOptimizer/Utils/Generics.h @@ -100,6 +100,11 @@ class ReabstractionInfo { // Reference to the original generic non-specialized callee function. SILFunction *Callee; + // The module the specialization is created in. + ModuleDecl *TargetModule = nullptr; + + bool isWholeModule = false; + // The apply site which invokes the generic function. ApplySite Apply; @@ -140,7 +145,9 @@ class ReabstractionInfo { /// substitutions \p ParamSubs. /// If specialization is not possible getSpecializedType() will return an /// invalid type. - ReabstractionInfo(ApplySite Apply, SILFunction *Callee, + ReabstractionInfo(ModuleDecl *targetModule, + bool isModuleWholeModule, + ApplySite Apply, SILFunction *Callee, SubstitutionMap ParamSubs, IsSerialized_t Serialized, bool ConvertIndirectToDirect = true, @@ -148,16 +155,17 @@ class ReabstractionInfo { /// Constructs the ReabstractionInfo for generic function \p Callee with /// a specialization signature. - ReabstractionInfo(SILFunction *Callee, GenericSignature SpecializedSig); + ReabstractionInfo(ModuleDecl *targetModule, bool isModuleWholeModule, + SILFunction *Callee, GenericSignature SpecializedSig); IsSerialized_t isSerialized() const { return Serialized; } - ResilienceExpansion getResilienceExpansion() const { - return (Serialized - ? ResilienceExpansion::Minimal - : ResilienceExpansion::Maximal); + TypeExpansionContext getResilienceExpansion() const { + auto resilience = (Serialized ? ResilienceExpansion::Minimal + : ResilienceExpansion::Maximal); + return TypeExpansionContext(resilience, TargetModule, isWholeModule); } /// Returns true if the \p ParamIdx'th (non-result) formal parameter is diff --git a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h index f11fbcd3042af..5a25557693b06 100644 --- a/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h +++ b/include/swift/SILOptimizer/Utils/LoadStoreOptUtils.h @@ -169,12 +169,15 @@ class LSBase { } /// Print the LSBase. - virtual void print(llvm::raw_ostream &os, SILModule *Mod) { + virtual void print(llvm::raw_ostream &os, SILModule *Mod, + TypeExpansionContext context) { os << Base; - Path.getValue().print(os, *Mod); + Path.getValue().print(os, *Mod, context); } - virtual void dump(SILModule *Mod) { print(llvm::dbgs(), Mod); } + virtual void dump(SILModule *Mod, TypeExpansionContext context) { + print(llvm::dbgs(), Mod, context); + } }; static inline llvm::hash_code hash_value(const LSBase &S) { @@ -257,16 +260,18 @@ class LSValue : public LSBase { return Path.getValue().createExtract(Base, Inst, true); } - void print(llvm::raw_ostream &os, SILModule *Mod) { + void print(llvm::raw_ostream &os, SILModule *Mod, + TypeExpansionContext context) { if (CoveringValue) { os << "Covering Value"; return; } - LSBase::print(os, Mod); + LSBase::print(os, Mod, context); } /// Expand this SILValue to all individual fields it contains. - static void expand(SILValue Base, SILModule *Mod, LSValueList &Vals, + static void expand(SILValue Base, SILModule *Mod, + TypeExpansionContext context, LSValueList &Vals, TypeExpansionAnalysis *TE); /// Given a memory location and a map between the expansions of the location @@ -329,13 +334,14 @@ class LSLocation : public LSBase { } /// Returns the type of the object the LSLocation represents. - SILType getType(SILModule *M) { - return Path.getValue().getMostDerivedType(*M); + SILType getType(SILModule *M, TypeExpansionContext context) { + return Path.getValue().getMostDerivedType(*M, context); } /// Get the first level locations based on this location's first level /// projection. - void getNextLevelLSLocations(LSLocationList &Locs, SILModule *Mod); + void getNextLevelLSLocations(LSLocationList &Locs, SILModule *Mod, + TypeExpansionContext context); /// Check whether the 2 LSLocations may alias each other or not. bool isMayAliasLSLocation(const LSLocation &RHS, AliasAnalysis *AA); @@ -351,15 +357,18 @@ class LSLocation : public LSBase { /// In SIL, we can have a store to an aggregate and loads from its individual /// fields. Therefore, we expand all the operations on aggregates onto /// individual fields and process them separately. - static void expand(LSLocation Base, SILModule *Mod, LSLocationList &Locs, + static void expand(LSLocation Base, SILModule *Mod, + TypeExpansionContext context, LSLocationList &Locs, TypeExpansionAnalysis *TE); /// Given a set of locations derived from the same base, try to merge/reduce /// them into smallest number of LSLocations possible. - static void reduce(LSLocation Base, SILModule *Mod, LSLocationList &Locs); + static void reduce(LSLocation Base, SILModule *Mod, + TypeExpansionContext context, LSLocationList &Locs); /// Enumerate the given Mem LSLocation. - static void enumerateLSLocation(SILModule *M, SILValue Mem, + static void enumerateLSLocation(TypeExpansionContext context, SILModule *M, + SILValue Mem, std::vector &LSLocationVault, LSLocationIndexMap &LocToBit, LSLocationBaseMap &BaseToLoc, diff --git a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h index 7d84920cffc01..f222f2309cc79 100644 --- a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h +++ b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h @@ -133,8 +133,10 @@ class UseWrapper { /// reconstruct the use. UseWrapper(Operand *Use); + Operand *getOperand(); + /// Return the operand we wrap. Reconstructing branch operands. - operator Operand*(); + operator Operand*() { return getOperand(); } }; } // end namespace swift diff --git a/include/swift/Subsystems.h b/include/swift/Subsystems.h index 8422e9b75b73e..eeb360d2e7827 100644 --- a/include/swift/Subsystems.h +++ b/include/swift/Subsystems.h @@ -66,6 +66,7 @@ namespace swift { class Token; class TopLevelContext; class TypeChecker; + class TypeCheckerOptions; struct TypeLoc; class UnifiedStatsReporter; enum class SourceFileKind; @@ -167,31 +168,7 @@ namespace swift { /// Once parsing and name-binding are complete this optionally walks the ASTs /// to add calls to externally provided functions that simulate /// "program counter"-like debugging events. - void performPCMacro(SourceFile &SF, TopLevelContext &TLC); - - /// Flags used to control type checking. - enum class TypeCheckingFlags : unsigned { - /// Whether to delay checking that benefits from having the entire - /// module parsed, e.g., Objective-C method override checking. - DelayWholeModuleChecking = 1 << 0, - - /// If set, dumps wall time taken to check each function body to - /// llvm::errs(). - DebugTimeFunctionBodies = 1 << 1, - - /// Indicates that the type checker is checking code that will be - /// immediately executed. - ForImmediateMode = 1 << 2, - - /// If set, dumps wall time taken to type check each expression to - /// llvm::errs(). - DebugTimeExpressions = 1 << 3, - - /// If set, the typechecker will skip typechecking non-inlinable function - /// bodies. Set this if you're trying to quickly emit a module or module - /// interface without a full compilation. - SkipNonInlinableFunctionBodies = 1 << 4, - }; + void performPCMacro(SourceFile &SF); /// Creates a type checker instance on the given AST context, if it /// doesn't already have one. @@ -199,21 +176,15 @@ namespace swift { /// \returns a reference to the type checker instance. TypeChecker &createTypeChecker(ASTContext &Ctx); + /// Bind all 'extension' visible from \p SF to the extended nominal. + void bindExtensions(SourceFile &SF); + /// Once parsing and name-binding are complete, this walks the AST to resolve /// types and diagnose problems therein. /// /// \param StartElem Where to start for incremental type-checking in the main /// source file. - /// - /// \param WarnLongFunctionBodies If non-zero, warn when a function body takes - /// longer than this many milliseconds to type-check - void performTypeChecking(SourceFile &SF, TopLevelContext &TLC, - OptionSet Options, - unsigned StartElem = 0, - unsigned WarnLongFunctionBodies = 0, - unsigned WarnLongExpressionTypeChecking = 0, - unsigned ExpressionTimeoutThreshold = 0, - unsigned SwitchCheckingInvocationThreshold = 0); + void performTypeChecking(SourceFile &SF, unsigned StartElem = 0); /// Now that we have type-checked an entire module, perform any type /// checking that requires the full module, e.g., Objective-C method @@ -232,9 +203,6 @@ namespace swift { /// of declarations in the module. void checkInconsistentImplementationOnlyImports(ModuleDecl *M); - /// Incrementally type-check only added external definitions. - void typeCheckExternalDefinitions(SourceFile &SF); - /// Recursively validate the specified type. /// /// This is used when dealing with partial source files (e.g. SIL parsing, @@ -259,8 +227,7 @@ namespace swift { bool ProduceDiagnostics = true); /// Expose TypeChecker's handling of GenericParamList to SIL parsing. - GenericEnvironment *handleSILGenericParams(ASTContext &Ctx, - GenericParamList *genericParams, + GenericEnvironment *handleSILGenericParams(GenericParamList *genericParams, DeclContext *DC); /// Turn the given module into SIL IR. @@ -386,7 +353,8 @@ namespace swift { class ParserUnit { public: ParserUnit(SourceManager &SM, SourceFileKind SFKind, unsigned BufferID, - const LangOptions &LangOpts, StringRef ModuleName, + const LangOptions &LangOpts, const TypeCheckerOptions &TyOpts, + StringRef ModuleName, std::shared_ptr spActions = nullptr, SyntaxParsingCache *SyntaxCache = nullptr); ParserUnit(SourceManager &SM, SourceFileKind SFKind, unsigned BufferID); diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h index 2d0f0f8867b82..c78803ff58e38 100644 --- a/include/swift/TBDGen/TBDGen.h +++ b/include/swift/TBDGen/TBDGen.h @@ -40,12 +40,12 @@ struct TBDGenOptions { std::string ModuleLinkName; /// The current project version to use in the generated TBD file. Defaults - /// to None. - llvm::Optional CurrentVersion = None; + /// to empty string if not provided. + std::string CurrentVersion; /// The dylib compatibility-version to use in the generated TBD file. Defaults - /// to None. - llvm::Optional CompatibilityVersion = None; + /// to empty string if not provided. + std::string CompatibilityVersion; }; void enumeratePublicSymbols(FileUnit *module, llvm::StringSet<> &symbols, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 5ebb3ba2eef47..1d057d5f3d6a6 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -528,6 +528,7 @@ void ASTContext::operator delete(void *Data) throw() { } ASTContext *ASTContext::get(LangOptions &langOpts, + TypeCheckerOptions &typeckOpts, SearchPathOptions &SearchPathOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags) { @@ -540,15 +541,16 @@ ASTContext *ASTContext::get(LangOptions &langOpts, auto impl = reinterpret_cast((char*)mem + sizeof(ASTContext)); impl = reinterpret_cast(llvm::alignAddr(impl,alignof(Implementation))); new (impl) Implementation(); - return new (mem) ASTContext(langOpts, SearchPathOpts, SourceMgr, Diags); + return new (mem) + ASTContext(langOpts, typeckOpts, SearchPathOpts, SourceMgr, Diags); } -ASTContext::ASTContext(LangOptions &langOpts, SearchPathOptions &SearchPathOpts, +ASTContext::ASTContext(LangOptions &langOpts, TypeCheckerOptions &typeckOpts, + SearchPathOptions &SearchPathOpts, SourceManager &SourceMgr, DiagnosticEngine &Diags) : LangOpts(langOpts), - SearchPathOpts(SearchPathOpts), - SourceMgr(SourceMgr), - Diags(Diags), + TypeCheckerOpts(typeckOpts), + SearchPathOpts(SearchPathOpts), SourceMgr(SourceMgr), Diags(Diags), evaluator(Diags, langOpts.DebugDumpCycles), TheBuiltinModule(createBuiltinModule(*this)), StdlibModuleName(getIdentifier(STDLIB_NAME)), @@ -1543,12 +1545,6 @@ bool ASTContext::hasArrayLiteralIntrinsics() const { && getDeallocateUninitializedArray(); } -void ASTContext::addSynthesizedDecl(Decl *decl) { - auto *fileUnit = decl->getDeclContext()->getModuleScopeContext(); - if (auto *sf = dyn_cast(fileUnit)) - sf->SynthesizedDecls.push_back(decl); -} - void ASTContext::addCleanup(std::function cleanup) { getImpl().Cleanups.push_back(std::move(cleanup)); } @@ -4548,42 +4544,28 @@ ASTContext::getOverrideGenericSignature(const ValueDecl *base, auto derivedGenericCtx = derived->getAsGenericContext(); auto &ctx = base->getASTContext(); - if (!baseGenericCtx) { + if (!baseGenericCtx || !derivedGenericCtx) return nullptr; - } auto baseClass = base->getDeclContext()->getSelfClassDecl(); - - if (!baseClass) { + if (!baseClass) return nullptr; - } auto derivedClass = derived->getDeclContext()->getSelfClassDecl(); - auto baseClassSig = baseClass->getGenericSignature(); - - if (!derivedClass) { + if (!derivedClass) return nullptr; - } - if (derivedClass->getSuperclass().isNull()) { + if (derivedClass->getSuperclass().isNull()) return nullptr; - } - if (!derivedGenericCtx || !derivedGenericCtx->isGeneric()) { + if (baseGenericCtx->getGenericSignature().isNull() || + derivedGenericCtx->getGenericSignature().isNull()) return nullptr; - } - - if (derivedClass->getGenericSignature().isNull() && - !baseGenericCtx->isGeneric()) { - return nullptr; - } + auto baseClassSig = baseClass->getGenericSignature(); auto subMap = derivedClass->getSuperclass()->getContextSubstitutionMap( derivedClass->getModuleContext(), baseClass); - if (baseGenericCtx->getGenericSignature().isNull()) { - return nullptr; - } unsigned derivedDepth = 0; auto key = OverrideSignatureKey(baseGenericCtx->getGenericSignature(), @@ -4599,9 +4581,11 @@ ASTContext::getOverrideGenericSignature(const ValueDecl *base, derivedDepth = derivedSig->getGenericParams().back()->getDepth() + 1; SmallVector addedGenericParams; - for (auto gp : *derivedGenericCtx->getGenericParams()) { - addedGenericParams.push_back( - gp->getDeclaredInterfaceType()->castTo()); + if (auto *gpList = derivedGenericCtx->getGenericParams()) { + for (auto gp : *gpList) { + addedGenericParams.push_back( + gp->getDeclaredInterfaceType()->castTo()); + } } unsigned baseDepth = 0; diff --git a/lib/AST/ASTDemangler.cpp b/lib/AST/ASTDemangler.cpp index 320b4bab28bbb..993eb1edbe521 100644 --- a/lib/AST/ASTDemangler.cpp +++ b/lib/AST/ASTDemangler.cpp @@ -495,11 +495,9 @@ Type ASTBuilder::createImplFunctionType( break; } - auto einfo = SILFunctionType::ExtInfo(representation, - flags.isPseudogeneric(), - !flags.isEscaping(), - DifferentiabilityKind:: - NonDifferentiable); + auto einfo = SILFunctionType::ExtInfo( + representation, flags.isPseudogeneric(), !flags.isEscaping(), + DifferentiabilityKind::NonDifferentiable); llvm::SmallVector funcParams; llvm::SmallVector funcYields; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 58e73501b2825..e7f5c69d19c14 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -996,14 +996,14 @@ namespace { getDefaultArgumentKindString(P->getDefaultArgumentKind())); } - if (P->getDefaultValue() && - !P->getDefaultArgumentCaptureInfo().isTrivial()) { + if (P->hasDefaultExpr() && + !P->getDefaultArgumentCaptureInfo().isTrivial()) { OS << " "; P->getDefaultArgumentCaptureInfo().print( PrintWithColorRAII(OS, CapturesColor).getOS()); } - if (auto init = P->getDefaultValue()) { + if (auto init = P->getStructuralDefaultExpr()) { OS << " expression=\n"; printRec(init); } @@ -1262,15 +1262,6 @@ void ParameterList::dump() const { } void ParameterList::dump(raw_ostream &OS, unsigned Indent) const { - llvm::Optional> X; - - // Make sure to print type variables if we can get to ASTContext. - if (size() != 0 && get(0)) { - auto &ctx = get(0)->getASTContext(); - X.emplace(llvm::SaveAndRestore(ctx.LangOpts.DebugConstraintSolver, - true)); - } - PrintDecl(OS, Indent).printParameterList(this); llvm::errs() << '\n'; } @@ -1293,9 +1284,6 @@ void Decl::dump(const char *filename) const { } void Decl::dump(raw_ostream &OS, unsigned Indent) const { - // Make sure to print type variables. - llvm::SaveAndRestore X(getASTContext().LangOpts.DebugConstraintSolver, - true); PrintDecl(OS, Indent).visit(const_cast(this)); OS << '\n'; } @@ -1407,8 +1395,6 @@ void SourceFile::dump() const { } void SourceFile::dump(llvm::raw_ostream &OS) const { - llvm::SaveAndRestore X(getASTContext().LangOpts.DebugConstraintSolver, - true); PrintDecl(OS).visitSourceFile(*this); llvm::errs() << '\n'; } @@ -1826,13 +1812,17 @@ class PrintExpr : public ExprVisitor { } raw_ostream &printCommon(Expr *E, const char *C) { + PrintOptions PO; + PO.PrintTypesForDebugging = true; + OS.indent(Indent); PrintWithColorRAII(OS, ParenthesisColor) << '('; PrintWithColorRAII(OS, ExprColor) << C; if (E->isImplicit()) PrintWithColorRAII(OS, ExprModifierColor) << " implicit"; - PrintWithColorRAII(OS, TypeColor) << " type='" << GetTypeOfExpr(E) << '\''; + PrintWithColorRAII(OS, TypeColor) << " type='"; + PrintWithColorRAII(OS, TypeColor) << GetTypeOfExpr(E).getString(PO) << '\''; // If we have a source range and an ASTContext, print the source range. if (auto Ty = GetTypeOfExpr(E)) { @@ -3807,14 +3797,10 @@ namespace { } // end anonymous namespace void Type::dump() const { - // Make sure to print type variables. dump(llvm::errs()); } void Type::dump(raw_ostream &os, unsigned indent) const { - // Make sure to print type variables. - llvm::SaveAndRestore X(getPointer()->getASTContext().LangOpts. - DebugConstraintSolver, true); PrintType(os, indent).visit(*this, ""); os << "\n"; } @@ -3825,10 +3811,6 @@ void TypeBase::dump() const { } void TypeBase::dump(raw_ostream &os, unsigned indent) const { - auto &ctx = const_cast(this)->getASTContext(); - - // Make sure to print type variables. - llvm::SaveAndRestore X(ctx.LangOpts.DebugConstraintSolver, true); Type(const_cast(this)).dump(os, indent); } diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index afccfac8ab7b9..305d65c7a338c 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -196,7 +196,13 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr) { // the default to 'public' and mark the 'internal' things. result.PrintAccess = true; - result.ExcludeAttrList = {DAK_AccessControl, DAK_SetterAccess, DAK_Lazy}; + result.ExcludeAttrList = { + DAK_AccessControl, + DAK_SetterAccess, + DAK_Lazy, + DAK_StaticInitializeObjCMetadata, + DAK_RestatedObjCConformance + }; return result; } @@ -2523,26 +2529,26 @@ void PrintAST::visitVarDecl(VarDecl *decl) { [&]{ Printer.printName(decl->getName(), getTypeMemberPrintNameContext(decl)); }); - if (auto type = decl->getInterfaceType()) { - Printer << ": "; - TypeLoc tyLoc; - if (auto *repr = decl->getTypeReprOrParentPatternTypeRepr()) - tyLoc = TypeLoc(repr, type); - else - tyLoc = TypeLoc::withoutLoc(type); - Printer.printDeclResultTypePre(decl, tyLoc); + auto type = decl->getInterfaceType(); + Printer << ": "; + TypeLoc tyLoc; + if (auto *repr = decl->getTypeReprOrParentPatternTypeRepr()) + tyLoc = TypeLoc(repr, type); + else + tyLoc = TypeLoc::withoutLoc(type); - // HACK: When printing result types for vars with opaque result types, - // always print them using the `some` keyword instead of printing - // the full stable reference. - llvm::SaveAndRestore - x(Options.OpaqueReturnTypePrinting, - PrintOptions::OpaqueReturnTypePrintingMode::WithOpaqueKeyword); + Printer.printDeclResultTypePre(decl, tyLoc); - printTypeLocForImplicitlyUnwrappedOptional( - tyLoc, decl->isImplicitlyUnwrappedOptional()); - } + // HACK: When printing result types for vars with opaque result types, + // always print them using the `some` keyword instead of printing + // the full stable reference. + llvm::SaveAndRestore + x(Options.OpaqueReturnTypePrinting, + PrintOptions::OpaqueReturnTypePrintingMode::WithOpaqueKeyword); + + printTypeLocForImplicitlyUnwrappedOptional( + tyLoc, decl->isImplicitlyUnwrappedOptional()); printAccessors(decl); } @@ -2565,7 +2571,7 @@ void PrintAST::printOneParameter(const ParamDecl *param, auto BodyName = param->getName(); switch (Options.ArgAndParamPrinting) { case PrintOptions::ArgAndParamPrintingMode::EnumElement: - if (ArgName.empty() && BodyName.empty() && !param->getDefaultValue()) { + if (ArgName.empty() && BodyName.empty() && !param->hasDefaultExpr()) { // Don't print anything, in the style of a tuple element. return; } @@ -2671,18 +2677,13 @@ void PrintAST::printFunctionParameters(AbstractFunctionDecl *AFD) { auto curTy = AFD->getInterfaceType(); // Skip over the implicit 'self'. - if (AFD->hasImplicitSelfDecl()) { - if (curTy) - if (auto funTy = curTy->getAs()) - curTy = funTy->getResult(); - } + if (AFD->hasImplicitSelfDecl()) + if (auto funTy = curTy->getAs()) + curTy = funTy->getResult(); ArrayRef parameterListTypes; - if (curTy) { - if (auto funTy = curTy->getAs()) { - parameterListTypes = funTy->getParams(); - } - } + if (auto funTy = curTy->getAs()) + parameterListTypes = funTy->getParams(); printParameterList(BodyParams, parameterListTypes, AFD->argumentNameIsAPIByDefault()); @@ -2875,15 +2876,14 @@ void PrintAST::printEnumElement(EnumElementDecl *elt) { auto params = ArrayRef(); - if (auto type = elt->getInterfaceType()) { - if (!elt->isInvalid()) { - // Walk to the params of the associated values. - // (EnumMetaType) -> (AssocValues) -> Enum - params = type->castTo() - ->getResult() - ->castTo() - ->getParams(); - } + if (!elt->isInvalid()) { + // Walk to the params of the associated values. + // (EnumMetaType) -> (AssocValues) -> Enum + auto type = elt->getInterfaceType(); + params = type->castTo() + ->getResult() + ->castTo() + ->getParams(); } // @escaping is not valid in enum element position, even though the @@ -2974,11 +2974,10 @@ void PrintAST::visitSubscriptDecl(SubscriptDecl *decl) { }, [&] { // Parameters printGenericDeclGenericParams(decl); auto params = ArrayRef(); - if (auto type = decl->getInterfaceType()) { - if (!decl->isInvalid()) { - // Walk to the params of the subscript's indices. - params = type->castTo()->getParams(); - } + if (!decl->isInvalid()) { + // Walk to the params of the subscript's indices. + auto type = decl->getInterfaceType(); + params = type->castTo()->getParams(); } printParameterList(decl->getIndices(), params, /*isAPINameByDefault*/false); @@ -3615,7 +3614,7 @@ class TypePrinter : public TypeVisitor { } void visitUnresolvedType(UnresolvedType *T) { - if (T->getASTContext().LangOpts.DebugConstraintSolver) + if (Options.PrintTypesForDebugging) Printer << "<>"; else Printer << "_"; @@ -3802,8 +3801,8 @@ class TypePrinter : public TypeVisitor { if (Options.SkipAttributes) return; - // SWIFT_ENABLE_TENSORFLOW - if (!Options.excludeAttrKind(TAK_differentiable) && info.isDifferentiable()) { + if (!Options.excludeAttrKind(TAK_differentiable) && + info.isDifferentiable()) { if (info.getDifferentiabilityKind() == DifferentiabilityKind::Linear) { Printer << "@differentiable(linear) "; } else { @@ -3854,8 +3853,8 @@ class TypePrinter : public TypeVisitor { if (Options.SkipAttributes) return; - // SWIFT_ENABLE_TENSORFLOW - if (!Options.excludeAttrKind(TAK_differentiable) && info.isDifferentiable()) { + if (!Options.excludeAttrKind(TAK_differentiable) && + info.isDifferentiable()) { if (info.getDifferentiabilityKind() == DifferentiabilityKind::Linear) { Printer << "@differentiable(linear) "; } else { @@ -4351,7 +4350,7 @@ class TypePrinter : public TypeVisitor { #include "swift/AST/ReferenceStorage.def" void visitTypeVariableType(TypeVariableType *T) { - if (T->getASTContext().LangOpts.DebugConstraintSolver) { + if (Options.PrintTypesForDebugging) { Printer << "$T" << T->getID(); return; } diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index 1c8ff358dfb12..ef6e179273587 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -1260,7 +1260,7 @@ ParameterListScope::expandAScopeThatCreatesANewInsertionPoint( // Unlike generic parameters or pattern initializers, it cannot refer to a // previous parameter. for (ParamDecl *pd : params->getArray()) { - if (pd->getDefaultValue()) + if (pd->hasDefaultExpr()) scopeCreator .constructExpandAndInsertUncheckable( this, pd); @@ -1594,7 +1594,7 @@ void ClosureBodyScope::expandAScopeThatDoesNotCreateANewInsertionPoint( void DefaultArgumentInitializerScope:: expandAScopeThatDoesNotCreateANewInsertionPoint( ScopeCreator &scopeCreator) { - auto *initExpr = decl->getDefaultValue(); + auto *initExpr = decl->getStructuralDefaultExpr(); ASTScopeAssert(initExpr, "Default argument initializer must have an initializer."); scopeCreator.addToScopeTree(initExpr, this); diff --git a/lib/AST/ASTScopeSourceRange.cpp b/lib/AST/ASTScopeSourceRange.cpp index 7f3260b7d8cf0..c4173d29c617f 100644 --- a/lib/AST/ASTScopeSourceRange.cpp +++ b/lib/AST/ASTScopeSourceRange.cpp @@ -232,7 +232,7 @@ SourceRange AbstractStmtScope::getSourceRangeOfThisASTNode( SourceRange DefaultArgumentInitializerScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { - if (auto *dv = decl->getDefaultValue()) + if (auto *dv = decl->getStructuralDefaultExpr()) return dv->getSourceRange(); return SourceRange(); } diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp index 6b2ff5d2976e2..2fe478a3ecfc4 100644 --- a/lib/AST/ASTVerifier.cpp +++ b/lib/AST/ASTVerifier.cpp @@ -2866,15 +2866,6 @@ class Verifier : public ASTWalker { void verifyParsed(ConstructorDecl *CD) { PrettyStackTraceDecl debugStack("verifying ConstructorDecl", CD); - - auto *DC = CD->getDeclContext(); - if (!isa(DC) && !isa(DC) && - !CD->isInvalid()) { - Out << "ConstructorDecls outside nominal types and extensions " - "should be marked invalid"; - abort(); - } - verifyParsedBase(CD); } @@ -2955,15 +2946,6 @@ class Verifier : public ASTWalker { Out << "DestructorDecl cannot be generic"; abort(); } - - auto *DC = DD->getDeclContext(); - if (!isa(DC) && !isa(DC) && - !DD->isInvalid()) { - Out << "DestructorDecls outside nominal types and extensions " - "should be marked invalid"; - abort(); - } - verifyParsedBase(DD); } diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 9c10ce8e21e9f..a4850b9b3af9e 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -1193,10 +1193,10 @@ class Traversal : public ASTVisitorgetDefaultValue()) { + if (auto *E = P->getStructuralDefaultExpr()) { auto res = doIt(E); if (!res) return true; - P->setDefaultValue(res); + P->setDefaultExpr(res, /*isTypeChecked*/ (bool)res->getType()); } } diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index a6984f21321f4..16dfd34342e55 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -22,12 +22,14 @@ #include "swift/AST/GenericEnvironment.h" // SWIFT_ENABLE_TENSORFLOW #include "swift/AST/GenericSignatureBuilder.h" +// SWIFT_ENABLE_TENSORFLOW END +#include "swift/AST/IndexSubset.h" #include "swift/AST/Module.h" #include "swift/AST/TypeRepr.h" // SWIFT_ENABLE_TENSORFLOW #include "swift/AST/TypeCheckRequests.h" +// SWIFT_ENABLE_TENSORFLOW END #include "swift/AST/Types.h" -// SWIFT_ENABLE_TENSORFLOW #include "swift/AST/ParameterList.h" #include "swift/Basic/Defer.h" #include "llvm/ADT/SmallString.h" @@ -405,8 +407,7 @@ static std::string getDifferentiationParametersClauseString( case ParsedAutoDiffParameter::Kind::Ordered: auto *paramList = function->getParameters(); assert(param.getIndex() <= paramList->size() && - "'wrt:' parameter index should be less than the number " - "of parameters"); + "wrt parameter is out of range"); auto *funcParam = paramList->get(param.getIndex()); printer << funcParam->getNameStr(); break; @@ -511,7 +512,7 @@ static void printDifferentiableAttrArguments( } stream << ", "; }; - + // Print if the function is marked as linear. if (attr->isLinear()) { isLeadingClause = false; @@ -550,16 +551,14 @@ static void printDifferentiableAttrArguments( ArrayRef derivativeRequirements; if (auto derivativeGenSig = attr->getDerivativeGenericSignature()) derivativeRequirements = derivativeGenSig->getRequirements(); - llvm::SmallVector requirementsToPrint; - std::copy_if(derivativeRequirements.begin(), derivativeRequirements.end(), - std::back_inserter(requirementsToPrint), - [&](Requirement req) { - if (auto originalGenSig = original->getGenericSignature()) - if (originalGenSig->isRequirementSatisfied(req)) - return false; - return true; - }); - if (!requirementsToPrint.empty()) { + auto requirementsToPrint = + llvm::make_filter_range(derivativeRequirements, [&](Requirement req) { + if (const auto &originalGenSig = original->getGenericSignature()) + if (originalGenSig->isRequirementSatisfied(req)) + return false; + return true; + }); + if (!llvm::empty(requirementsToPrint)) { if (!isLeadingClause) stream << ' '; stream << "where "; @@ -576,7 +575,7 @@ static void printDifferentiableAttrArguments( }; } interleave(requirementsToPrint, [&](Requirement req) { - if (auto originalGenSig = original->getGenericSignature()) + if (const auto &originalGenSig = original->getGenericSignature()) if (originalGenSig->isRequirementSatisfied(req)) return; auto FirstTy = getInterfaceType(req.getFirstType()); @@ -912,7 +911,31 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, break; } - // SWIFT_ENABLE_TENSORFLOW + case DAK_DynamicReplacement: { + Printer.printAttrName("@_dynamicReplacement"); + Printer << "(for: \""; + auto *attr = cast(this); + Printer << attr->getReplacedFunctionName() << "\")"; + break; + } + + case DAK_Custom: { + Printer.printAttrName("@"); + const TypeLoc &typeLoc = cast(this)->getTypeLoc(); + if (auto type = typeLoc.getType()) + type->print(Printer, Options); + else + typeLoc.getTypeRepr()->print(Printer, Options); + break; + } + + case DAK_ProjectedValueProperty: + Printer.printAttrName("@_projectedValueProperty"); + Printer << "("; + Printer << cast(this)->ProjectionPropertyName; + Printer << ")"; + break; + case DAK_Differentiable: { Printer.printAttrName("@differentiable"); auto *attr = cast(this); @@ -950,31 +973,6 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, break; } - case DAK_DynamicReplacement: { - Printer.printAttrName("@_dynamicReplacement"); - Printer << "(for: \""; - auto *attr = cast(this); - Printer << attr->getReplacedFunctionName() << "\")"; - break; - } - - case DAK_Custom: { - Printer.printAttrName("@"); - const TypeLoc &typeLoc = cast(this)->getTypeLoc(); - if (auto type = typeLoc.getType()) - type->print(Printer, Options); - else - typeLoc.getTypeRepr()->print(Printer, Options); - break; - } - - case DAK_ProjectedValueProperty: - Printer.printAttrName("@_projectedValueProperty"); - Printer << "("; - Printer << cast(this)->ProjectionPropertyName; - Printer << ")"; - break; - case DAK_Count: llvm_unreachable("exceed declaration attribute kinds"); @@ -1105,9 +1103,9 @@ StringRef DeclAttribute::getAttrName() const { return "<>"; case DAK_ProjectedValueProperty: return "_projectedValueProperty"; - // SWIFT_ENABLE_TENSORFLOW case DAK_Differentiable: return "differentiable"; + // SWIFT_ENABLE_TENSORFLOW case DAK_Derivative: return "derivative"; case DAK_Transpose: @@ -1452,8 +1450,6 @@ SpecializeAttr *SpecializeAttr::create(ASTContext &Ctx, SourceLoc atLoc, specializedSignature); } - -// SWIFT_ENABLE_TENSORFLOW DifferentiableAttr::DifferentiableAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, bool linear, ArrayRef params, @@ -1509,6 +1505,7 @@ DifferentiableAttr::create(Decl *original, bool implicit, SourceLoc atLoc, std::move(vjp), derivativeGenSig); } +// SWIFT_ENABLE_TENSORFLOW void DifferentiableAttr::setOriginalDeclaration(Decl *decl) { assert(decl && "Original declaration must be non-null"); assert(!OriginalDeclaration && @@ -1540,6 +1537,7 @@ void DifferentiableAttr::setParameterIndices(IndexSubset *paramIndices) { const_cast(this), getOriginalDeclaration()}, std::move(paramIndices)); } +// SWIFT_ENABLE_TENSORFLOW END void DifferentiableAttr::setJVPFunction(FuncDecl *decl) { JVPFunction = decl; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 907f9733ae473..d43caf2e06a8d 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1232,16 +1232,21 @@ bool ExtensionDecl::hasValidParent() const { } bool ExtensionDecl::isConstrainedExtension() const { - // Non-generic extension. - if (!getGenericSignature()) + auto nominal = getExtendedNominal(); + if (!nominal) return false; - auto nominal = getExtendedNominal(); - assert(nominal); + auto typeSig = nominal->getGenericSignature(); + if (!typeSig) + return false; + + auto extSig = getGenericSignature(); + if (!extSig) + return false; // If the generic signature differs from that of the nominal type, it's a // constrained extension. - return !getGenericSignature()->isEqual(nominal->getGenericSignature()); + return !typeSig->isEqual(extSig); } bool ExtensionDecl::isEquivalentToExtendedContext() const { @@ -3437,11 +3442,7 @@ Type TypeDecl::getDeclaredInterfaceType() const { selfTy, const_cast(ATD)); } - Type interfaceType = getInterfaceType(); - if (!interfaceType) - return ErrorType::get(getASTContext()); - - return interfaceType->getMetatypeInstanceType(); + return getInterfaceType()->getMetatypeInstanceType(); } int TypeDecl::compare(const TypeDecl *type1, const TypeDecl *type2) { @@ -3972,8 +3973,6 @@ EnumDecl::EnumDecl(SourceLoc EnumLoc, GenericParams), EnumLoc(EnumLoc) { - Bits.EnumDecl.Circularity - = static_cast(CircularityCheck::Unchecked); Bits.EnumDecl.HasAssociatedValues = static_cast(AssociatedValueCheck::Unchecked); Bits.EnumDecl.HasAnyUnavailableValues @@ -4081,14 +4080,19 @@ void NominalTypeDecl::synthesizeSemanticMembersIfNeeded(DeclName member) { } } +bool ClassDecl::hasCircularInheritance() const { + auto &ctx = getASTContext(); + auto *mutableThis = const_cast(this); + return evaluateOrDefault(ctx.evaluator, + HasCircularInheritanceRequest{mutableThis}, true); +} + ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc, MutableArrayRef Inherited, GenericParamList *GenericParams, DeclContext *Parent) : NominalTypeDecl(DeclKind::Class, Parent, Name, NameLoc, Inherited, GenericParams), ClassLoc(ClassLoc) { - Bits.ClassDecl.Circularity - = static_cast(CircularityCheck::Unchecked); Bits.ClassDecl.InheritsSuperclassInits = 0; Bits.ClassDecl.ComputedInheritsSuperclassInits = 0; Bits.ClassDecl.RawForeignKind = 0; @@ -4561,6 +4565,13 @@ void EnumDecl::setHasFixedRawValues() { LazySemanticInfo.RawTypeAndFlags.setInt(flags); } +bool EnumDecl::hasCircularRawValue() const { + auto &ctx = getASTContext(); + auto *mutableThis = const_cast(this); + return evaluateOrDefault(ctx.evaluator, + HasCircularRawValueRequest{mutableThis}, true); +} + ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc, SourceLoc NameLoc, Identifier Name, MutableArrayRef Inherited, @@ -4572,8 +4583,6 @@ ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc, Bits.ProtocolDecl.RequiresClass = false; Bits.ProtocolDecl.ExistentialConformsToSelfValid = false; Bits.ProtocolDecl.ExistentialConformsToSelf = false; - Bits.ProtocolDecl.Circularity - = static_cast(CircularityCheck::Unchecked); Bits.ProtocolDecl.InheritedProtocolsValid = 0; Bits.ProtocolDecl.NumRequirementsInSignature = 0; Bits.ProtocolDecl.HasMissingRequirements = false; @@ -4847,10 +4856,6 @@ ProtocolDecl::findProtocolSelfReferences(const ValueDecl *value, auto type = value->getInterfaceType(); - // FIXME: Deal with broken recursion. - if (!type) - return SelfReferenceKind::None(); - // Skip invalid declarations. if (type->hasError()) return SelfReferenceKind::None(); @@ -5002,6 +5007,12 @@ void ProtocolDecl::computeKnownProtocolKind() const { const_cast(this)->Bits.ProtocolDecl.KnownProtocol = value; } +bool ProtocolDecl::hasCircularInheritedProtocols() const { + auto &ctx = getASTContext(); + auto *mutableThis = const_cast(this); + return evaluateOrDefault( + ctx.evaluator, HasCircularInheritedProtocolsRequest{mutableThis}, true); +} StorageImplInfo AbstractStorageDecl::getImplInfo() const { ASTContext &ctx = getASTContext(); @@ -6071,7 +6082,7 @@ SourceRange ParamDecl::getSourceRange() const { // It would be nice to extend the front of the range to show where inout is, // but we don't have that location info. Extend the back of the range to the // location of the default argument, or the typeloc if they are valid. - if (auto expr = getDefaultValue()) { + if (auto expr = getStructuralDefaultExpr()) { auto endLoc = expr->getEndLoc(); if (endLoc.isValid()) return SourceRange(startLoc, endLoc); @@ -6120,7 +6131,63 @@ AnyFunctionType::Param ParamDecl::toFunctionParam(Type type) const { return AnyFunctionType::Param(type, label, flags); } -void ParamDecl::setDefaultValue(Expr *E) { +Optional ParamDecl::getCachedDefaultArgumentInitContext() const { + if (auto *defaultInfo = DefaultValueAndFlags.getPointer()) + if (auto *init = defaultInfo->InitContextAndIsTypeChecked.getPointer()) + return init; + + return None; +} + +Initializer *ParamDecl::getDefaultArgumentInitContext() const { + // If this param doesn't need a context, don't bother kicking off a request. + if (!hasDefaultExpr() && !getStoredProperty()) + return nullptr; + + auto &ctx = getASTContext(); + auto *mutableThis = const_cast(this); + return evaluateOrDefault( + ctx.evaluator, DefaultArgumentInitContextRequest{mutableThis}, nullptr); +} + +bool ParamDecl::hasDefaultExpr() const { + switch (getDefaultArgumentKind()) { + case DefaultArgumentKind::None: + case DefaultArgumentKind::Inherited: + case DefaultArgumentKind::StoredProperty: + return false; + case DefaultArgumentKind::Normal: + case DefaultArgumentKind::File: + case DefaultArgumentKind::Line: + case DefaultArgumentKind::Column: + case DefaultArgumentKind::Function: + case DefaultArgumentKind::DSOHandle: + case DefaultArgumentKind::NilLiteral: + case DefaultArgumentKind::EmptyArray: + case DefaultArgumentKind::EmptyDictionary: + // Check if we have a structural default expr. This ensures we return false + // for deserialized decls. + return getStructuralDefaultExpr(); + } + llvm_unreachable("Unhandled case in switch"); +} + +Expr *ParamDecl::getTypeCheckedDefaultExpr() const { + // Don't kick off a request if we know there's no default expr. The only + // exception is for inherited default args which we need to perform a couple + // of semantic checks for. + if (!hasDefaultExpr() && + getDefaultArgumentKind() != DefaultArgumentKind::Inherited) { + return nullptr; + } + + auto &ctx = getASTContext(); + return evaluateOrDefault( + ctx.evaluator, DefaultArgumentExprRequest{const_cast(this)}, + new (ctx) ErrorExpr(getSourceRange(), ErrorType::get(ctx))); +} + +void ParamDecl::setDefaultExpr(Expr *E, bool isTypeChecked) { if (!DefaultValueAndFlags.getPointer()) { if (!E) return; @@ -6128,7 +6195,16 @@ void ParamDecl::setDefaultValue(Expr *E) { getASTContext().Allocate()); } - DefaultValueAndFlags.getPointer()->DefaultArg = E; + auto *defaultInfo = DefaultValueAndFlags.getPointer(); + assert(defaultInfo->DefaultArg.isNull() || + defaultInfo->DefaultArg.is()); + + if (!isTypeChecked) { + assert(!defaultInfo->InitContextAndIsTypeChecked.getInt() && + "Can't overwrite type-checked default with un-type-checked default"); + } + defaultInfo->DefaultArg = E; + defaultInfo->InitContextAndIsTypeChecked.setInt(isTypeChecked); } void ParamDecl::setStoredProperty(VarDecl *var) { @@ -6139,7 +6215,10 @@ void ParamDecl::setStoredProperty(VarDecl *var) { getASTContext().Allocate()); } - DefaultValueAndFlags.getPointer()->DefaultArg = var; + auto *defaultInfo = DefaultValueAndFlags.getPointer(); + assert(defaultInfo->DefaultArg.isNull() || + defaultInfo->DefaultArg.is()); + defaultInfo->DefaultArg = var; } Type ValueDecl::getFunctionBuilderType() const { @@ -6167,8 +6246,13 @@ CustomAttr *ValueDecl::getAttachedFunctionBuilder() const { } void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) { - assert(DefaultValueAndFlags.getPointer()); - DefaultValueAndFlags.getPointer()->InitContext = initContext; + auto oldContext = getCachedDefaultArgumentInitContext(); + assert((!oldContext || oldContext == initContext) && + "Cannot change init context after setting"); + + auto *defaultInfo = DefaultValueAndFlags.getPointer(); + assert(defaultInfo); + defaultInfo->InitContextAndIsTypeChecked.setPointer(initContext); } void ParamDecl::setDefaultArgumentCaptureInfo(CaptureInfo captures) { @@ -6316,10 +6400,10 @@ ParamDecl::getDefaultValueStringRepresentation( if (!existing.empty()) return existing; - assert(getDefaultValue() + assert(hasDefaultExpr() && "Normal default argument with no default expression?!"); - return extractInlinableText(getASTContext().SourceMgr, getDefaultValue(), - scratch); + return extractInlinableText(getASTContext().SourceMgr, + getStructuralDefaultExpr(), scratch); } case DefaultArgumentKind::StoredProperty: { assert(DefaultValueAndFlags.getPointer() && @@ -6419,7 +6503,7 @@ void DefaultArgumentInitializer::changeFunction( } auto param = paramList->get(getIndex()); - if (param->getDefaultValue() || param->getStoredProperty()) + if (param->hasDefaultExpr() || param->getStoredProperty()) param->setDefaultArgumentInitContext(this); } @@ -6539,17 +6623,19 @@ DeclName AbstractFunctionDecl::getEffectiveFullName() const { return DeclName(); } -const ParamDecl *swift::getParameterAt(const ValueDecl *source, unsigned index) { - const ParameterList *paramList; +ParameterList *swift::getParameterList(ValueDecl *source) { if (auto *AFD = dyn_cast(source)) { - paramList = AFD->getParameters(); + return AFD->getParameters(); } else if (auto *EED = dyn_cast(source)) { - paramList = EED->getParameterList(); + return EED->getParameterList(); } else { - paramList = cast(source)->getIndices(); + return cast(source)->getIndices(); } +} - return paramList->get(index); +const ParamDecl *swift::getParameterAt(const ValueDecl *source, + unsigned index) { + return getParameterList(const_cast(source))->get(index); } Type AbstractFunctionDecl::getMethodInterfaceType() const { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 3ef97eb50907c..e72cdc5c1fc4f 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -741,56 +741,6 @@ llvm::DenseMap Expr::getParentMap() { return parentMap; } -llvm::DenseMap> Expr::getDepthMap() { - class RecordingTraversal : public ASTWalker { - public: - llvm::DenseMap> &DepthMap; - unsigned Depth = 0; - - explicit RecordingTraversal( - llvm::DenseMap> &depthMap) - : DepthMap(depthMap) {} - - std::pair walkToExprPre(Expr *E) override { - DepthMap[E] = {Depth, Parent.getAsExpr()}; - Depth++; - return { true, E }; - } - - Expr *walkToExprPost(Expr *E) override { - Depth--; - return E; - } - }; - - llvm::DenseMap> depthMap; - RecordingTraversal traversal(depthMap); - walk(traversal); - return depthMap; -} - -llvm::DenseMap Expr::getPreorderIndexMap() { - class RecordingTraversal : public ASTWalker { - public: - llvm::DenseMap &IndexMap; - unsigned Index = 0; - - explicit RecordingTraversal(llvm::DenseMap &indexMap) - : IndexMap(indexMap) { } - - std::pair walkToExprPre(Expr *E) override { - IndexMap[E] = Index; - Index++; - return { true, E }; - } - }; - - llvm::DenseMap indexMap; - RecordingTraversal traversal(indexMap); - walk(traversal); - return indexMap; -} - //===----------------------------------------------------------------------===// // Support methods for Exprs. //===----------------------------------------------------------------------===// diff --git a/lib/AST/Identifier.cpp b/lib/AST/Identifier.cpp index 8fbf7e20416ea..880ab05241ce9 100644 --- a/lib/AST/Identifier.cpp +++ b/lib/AST/Identifier.cpp @@ -47,6 +47,10 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, DeclName I) { return OS; } +void swift::simple_display(llvm::raw_ostream &out, DeclName name) { + out << "'" << name << "'"; +} + raw_ostream &llvm::operator<<(raw_ostream &OS, swift::ObjCSelector S) { unsigned n = S.getNumArgs(); if (n == 0) { diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index cb4ba6cb5f774..1384e778aeb51 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -65,6 +65,68 @@ ValueDecl *LookupResultEntry::getBaseDecl() const { return nominalDecl; } +void LookupResult::filter( + llvm::function_ref pred) { + size_t index = 0; + size_t originalFirstOuter = IndexOfFirstOuterResult; + Results.erase(std::remove_if(Results.begin(), Results.end(), + [&](LookupResultEntry result) -> bool { + auto isInner = index < originalFirstOuter; + index++; + if (pred(result, !isInner)) + return false; + + // Need to remove this, which means, if it is + // an inner result, the outer results need to + // shift down. + if (isInner) + IndexOfFirstOuterResult--; + return true; + }), + Results.end()); +} + +void LookupResult::shiftDownResults() { + // Remove inner results. + Results.erase(Results.begin(), Results.begin() + IndexOfFirstOuterResult); + IndexOfFirstOuterResult = 0; + + if (Results.empty()) + return; + + // Compute IndexOfFirstOuterResult. + const DeclContext *dcInner = Results.front().getValueDecl()->getDeclContext(); + for (auto &&result : Results) { + const DeclContext *dc = result.getValueDecl()->getDeclContext(); + if (dc == dcInner || + (dc->isModuleScopeContext() && dcInner->isModuleScopeContext())) + ++IndexOfFirstOuterResult; + else + break; + } +} + +void swift::simple_display(llvm::raw_ostream &out, + UnqualifiedLookupOptions options) { + using Flag = std::pair; + Flag possibleFlags[] = { + {UnqualifiedLookupFlags::AllowProtocolMembers, "AllowProtocolMembers"}, + {UnqualifiedLookupFlags::IgnoreAccessControl, "IgnoreAccessControl"}, + {UnqualifiedLookupFlags::IncludeOuterResults, "IncludeOuterResults"}, + {UnqualifiedLookupFlags::KnownPrivate, "KnownPrivate"}, + {UnqualifiedLookupFlags::TypeLookup, "TypeLookup"}, + }; + + auto flagsToPrint = llvm::make_filter_range( + possibleFlags, [&](Flag flag) { return options.contains(flag.first); }); + + out << "{ "; + interleave( + flagsToPrint, [&](Flag flag) { out << flag.second; }, + [&] { out << ", "; }); + out << " }"; +} + void DebuggerClient::anchor() {} void AccessFilteringDeclConsumer::foundDecl( @@ -1913,14 +1975,17 @@ directReferencesForUnqualifiedTypeLookup(DeclName name, SourceLoc loc, DeclContext *dc, LookupOuterResults lookupOuter) { DirectlyReferencedTypeDecls results; - UnqualifiedLookup::Options options = - UnqualifiedLookup::Flags::TypeLookup | - UnqualifiedLookup::Flags::AllowProtocolMembers; + UnqualifiedLookupOptions options = + UnqualifiedLookupFlags::TypeLookup | + UnqualifiedLookupFlags::AllowProtocolMembers; if (lookupOuter == LookupOuterResults::Included) - options |= UnqualifiedLookup::Flags::IncludeOuterResults; + options |= UnqualifiedLookupFlags::IncludeOuterResults; - UnqualifiedLookup lookup(name, dc, loc, options); - for (const auto &result : lookup.Results) { + auto &ctx = dc->getASTContext(); + auto descriptor = UnqualifiedLookupDescriptor(name, dc, loc, options); + auto lookup = evaluateOrDefault(ctx.evaluator, + UnqualifiedLookupRequest{descriptor}, {}); + for (const auto &result : lookup.allResults()) { if (auto typeDecl = dyn_cast(result.getValueDecl())) results.push_back(typeDecl); } diff --git a/lib/AST/NameLookupRequests.cpp b/lib/AST/NameLookupRequests.cpp index 6641e32797777..5eb06e0bafa6d 100644 --- a/lib/AST/NameLookupRequests.cpp +++ b/lib/AST/NameLookupRequests.cpp @@ -128,6 +128,25 @@ void GenericParamListRequest::cacheResult(GenericParamList *params) const { context->GenericParamsAndBit.setPointerAndInt(params, true); } +//----------------------------------------------------------------------------// +// UnqualifiedLookupRequest computation. +//----------------------------------------------------------------------------// + +void swift::simple_display(llvm::raw_ostream &out, + const UnqualifiedLookupDescriptor &desc) { + out << "looking up "; + simple_display(out, desc.Name); + out << " from "; + simple_display(out, desc.DC); + out << " with options "; + simple_display(out, desc.Options); +} + +SourceLoc +swift::extractNearestSourceLoc(const UnqualifiedLookupDescriptor &desc) { + return extractNearestSourceLoc(desc.DC); +} + // Define request evaluation functions for each of the name lookup requests. static AbstractRequestFunction *nameLookupRequestFunctions[] = { #define SWIFT_REQUEST(Zone, Name, Sig, Caching, LocOptions) \ diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index 3f74f9a42a6ba..38e17b36aed58 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -715,3 +715,11 @@ bool SubstitutionMap::isIdentity() const { return !hasNonIdentityReplacement; } + +SubstitutionMap SubstitutionMap::mapIntoTypeExpansionContext( + TypeExpansionContext context) const { + ReplaceOpaqueTypesWithUnderlyingTypes replacer( + context.getContext(), context.getResilienceExpansion(), + context.isWholeModuleContext()); + return this->subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes); +} diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 36738ccf320b3..542de902a67a0 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2670,8 +2670,10 @@ ReplaceOpaqueTypesWithUnderlyingTypes::shouldPerformSubstitution( static Type substOpaqueTypesWithUnderlyingTypes(Type ty, const DeclContext *inContext, - ResilienceExpansion contextExpansion) { - ReplaceOpaqueTypesWithUnderlyingTypes replacer(inContext, contextExpansion); + ResilienceExpansion contextExpansion, + bool isWholeModuleContext) { + ReplaceOpaqueTypesWithUnderlyingTypes replacer(inContext, contextExpansion, + isWholeModuleContext); return ty.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes); } @@ -2682,7 +2684,8 @@ substOpaqueTypesWithUnderlyingTypes(Type ty, const DeclContext *inContext, /// will be accessible. It's not intended to enforce any rules about what /// opaque substitutions are or are not allowed. static bool canSubstituteTypeInto(Type ty, const DeclContext *dc, - OpaqueSubstitutionKind kind) { + OpaqueSubstitutionKind kind, + bool isContextWholeModule) { auto nominal = ty->getAnyNominal(); if (!nominal) return true; @@ -2695,6 +2698,10 @@ static bool canSubstituteTypeInto(Type ty, const DeclContext *dc, return true; case OpaqueSubstitutionKind::SubstituteSameModuleMaximalResilience: + // In whole module compilation private types are okay. + if (isContextWholeModule) + return true; + // In the same file any visibility is okay. if (!dc->isModuleContext() && nominal->getDeclContext()->getParentSourceFile() == @@ -2739,27 +2746,39 @@ operator()(SubstitutableType *maybeOpaqueType) const { // Check that we are allowed to substitute the underlying type into the // context. auto inContext = this->inContext; - if (substTy.findIf([inContext, substitutionKind](Type t) -> bool { - if (!canSubstituteTypeInto(t, inContext, substitutionKind)) - return true; - return false; - })) + auto isContextWholeModule = this->isContextWholeModule; + if (substTy.findIf( + [inContext, substitutionKind, isContextWholeModule](Type t) -> bool { + if (!canSubstituteTypeInto(t, inContext, substitutionKind, + isContextWholeModule)) + return true; + return false; + })) return maybeOpaqueType; // If the type still contains opaque types, recur. if (substTy->hasOpaqueArchetype()) { - return substOpaqueTypesWithUnderlyingTypes(substTy, inContext, - contextExpansion); + return ::substOpaqueTypesWithUnderlyingTypes( + substTy, inContext, contextExpansion, isContextWholeModule); } return substTy; } -static ProtocolConformanceRef -substOpaqueTypesWithUnderlyingTypes(ProtocolConformanceRef ref, Type origType, - const DeclContext *inContext, - ResilienceExpansion contextExpansion) { - ReplaceOpaqueTypesWithUnderlyingTypes replacer(inContext, contextExpansion); +static ProtocolConformanceRef substOpaqueTypesWithUnderlyingTypes( + ProtocolConformanceRef ref, Type origType, const DeclContext *inContext, + ResilienceExpansion contextExpansion, bool isWholeModuleContext) { + ReplaceOpaqueTypesWithUnderlyingTypes replacer(inContext, contextExpansion, + isWholeModuleContext); + return ref.subst(origType, replacer, replacer, + SubstFlags::SubstituteOpaqueArchetypes); +} + +ProtocolConformanceRef swift::substOpaqueTypesWithUnderlyingTypes( + ProtocolConformanceRef ref, Type origType, TypeExpansionContext context) { + ReplaceOpaqueTypesWithUnderlyingTypes replacer( + context.getContext(), context.getResilienceExpansion(), + context.isWholeModuleContext()); return ref.subst(origType, replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes); } @@ -2804,11 +2823,14 @@ operator()(CanType maybeOpaqueType, Type replacementType, // Check that we are allowed to substitute the underlying type into the // context. auto inContext = this->inContext; - if (substTy.findIf([inContext, substitutionKind](Type t) -> bool { - if (!canSubstituteTypeInto(t, inContext, substitutionKind)) - return true; - return false; - })) + auto isContextWholeModule = this->isContextWholeModule; + if (substTy.findIf( + [inContext, substitutionKind, isContextWholeModule](Type t) -> bool { + if (!canSubstituteTypeInto(t, inContext, substitutionKind, + isContextWholeModule)) + return true; + return false; + })) return abstractRef; auto substRef = @@ -2816,8 +2838,8 @@ operator()(CanType maybeOpaqueType, Type replacementType, // If the type still contains opaque types, recur. if (substTy->hasOpaqueArchetype()) { - return substOpaqueTypesWithUnderlyingTypes(substRef, substTy, inContext, - contextExpansion); + return ::substOpaqueTypesWithUnderlyingTypes( + substRef, substTy, inContext, contextExpansion, isContextWholeModule); } return substRef; } @@ -3436,6 +3458,11 @@ static Type substType(Type derivedType, // If we have a substitution for this type, use it. if (auto known = substitutions(substOrig)) { + if (options.contains(SubstFlags::SubstituteOpaqueArchetypes) && + isa(substOrig) && + known->getCanonicalType() == substOrig->getCanonicalType()) + return None; // Recursively process the substitutions of the opaque type + // archetype. return known; } @@ -4479,9 +4506,12 @@ ReferenceCounting TypeBase::getReferenceCounting() { ASTContext &ctx = type->getASTContext(); // In the absence of Objective-C interoperability, everything uses native - // reference counting. - if (!ctx.LangOpts.EnableObjCInterop) - return ReferenceCounting::Native; + // reference counting or is the builtin BridgeObject. + if (!ctx.LangOpts.EnableObjCInterop) { + return type->getKind() == TypeKind::BuiltinBridgeObject + ? ReferenceCounting::Bridge + : ReferenceCounting::Native; + } switch (type->getKind()) { #define SUGARED_TYPE(id, parent) case TypeKind::id: @@ -4857,6 +4887,44 @@ AnyFunctionType::getAutoDiffOriginalFunctionType() { return originalType; } +bool TypeBase::hasOpaqueArchetypePropertiesOrCases() { + if (auto *structDecl = getStructOrBoundGenericStruct()) { + for (auto *field : structDecl->getStoredProperties()) { + auto fieldTy = field->getInterfaceType()->getCanonicalType(); + if (fieldTy->hasOpaqueArchetype() || + fieldTy->hasOpaqueArchetypePropertiesOrCases()) + return true; + } + } + + if (auto *enumDecl = getEnumOrBoundGenericEnum()) { + for (auto *elt : enumDecl->getAllElements()) { + auto eltType = elt->getInterfaceType(); + if (eltType->hasOpaqueArchetype() || + eltType->getCanonicalType()->hasOpaqueArchetypePropertiesOrCases()) + return true; + } + } + return false; +} + +CanType swift::substOpaqueTypesWithUnderlyingTypes(CanType ty, + TypeExpansionContext context, + bool allowLoweredTypes) { + if (!context.shouldLookThroughOpaqueTypeArchetypes() || + !ty->hasOpaqueArchetype()) + return ty; + + ReplaceOpaqueTypesWithUnderlyingTypes replacer( + context.getContext(), context.getResilienceExpansion(), + context.isWholeModuleContext()); + SubstOptions flags = SubstFlags::SubstituteOpaqueArchetypes; + if (allowLoweredTypes) + flags = + SubstFlags::SubstituteOpaqueArchetypes | SubstFlags::AllowLoweredTypes; + return ty.subst(replacer, replacer, flags)->getCanonicalType(); +} + // SWIFT_ENABLE_TENSORFLOW static AnyFunctionType * makeFunctionType(ArrayRef params, Type retTy, @@ -4973,3 +5041,4 @@ AnyFunctionType *AnyFunctionType::getWithoutDifferentiability() const { return GenericFunctionType::get(getOptGenericSignature(), newParams, getResult(), nonDiffExtInfo); } +// SWIFT_ENABLE_TENSORFLOW END diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 867cead48d89f..7fc5117485a42 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -13,6 +13,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsCommon.h" #include "swift/AST/DiagnosticsSema.h" +#include "swift/AST/Initializer.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/PropertyWrappers.h" @@ -1161,3 +1162,88 @@ void swift::simple_display(llvm::raw_ostream &out, break; } } + +//----------------------------------------------------------------------------// +// HasCircularInheritanceRequest computation. +//----------------------------------------------------------------------------// + +void HasCircularInheritanceRequest::diagnoseCycle( + DiagnosticEngine &diags) const { + auto *decl = std::get<0>(getStorage()); + diags.diagnose(decl, diag::circular_class_inheritance, decl->getName()); +} + +void HasCircularInheritanceRequest::noteCycleStep( + DiagnosticEngine &diags) const { + auto *decl = std::get<0>(getStorage()); + diags.diagnose(decl, diag::kind_declname_declared_here, + decl->getDescriptiveKind(), decl->getName()); +} + +//----------------------------------------------------------------------------// +// HasCircularInheritedProtocolsRequest computation. +//----------------------------------------------------------------------------// + +void HasCircularInheritedProtocolsRequest::diagnoseCycle( + DiagnosticEngine &diags) const { + auto *decl = std::get<0>(getStorage()); + diags.diagnose(decl, diag::circular_protocol_def, decl->getName()); +} + +void HasCircularInheritedProtocolsRequest::noteCycleStep( + DiagnosticEngine &diags) const { + auto *decl = std::get<0>(getStorage()); + diags.diagnose(decl, diag::kind_declname_declared_here, + decl->getDescriptiveKind(), decl->getName()); +} + +//----------------------------------------------------------------------------// +// HasCircularRawValueRequest computation. +//----------------------------------------------------------------------------// + +void HasCircularRawValueRequest::diagnoseCycle(DiagnosticEngine &diags) const { + auto *decl = std::get<0>(getStorage()); + diags.diagnose(decl, diag::circular_enum_inheritance, decl->getName()); +} + +void HasCircularRawValueRequest::noteCycleStep(DiagnosticEngine &diags) const { + auto *decl = std::get<0>(getStorage()); + diags.diagnose(decl, diag::kind_declname_declared_here, + decl->getDescriptiveKind(), decl->getName()); +} + +//----------------------------------------------------------------------------// +// DefaultArgumentInitContextRequest computation. +//----------------------------------------------------------------------------// + +Optional +DefaultArgumentInitContextRequest::getCachedResult() const { + auto *param = std::get<0>(getStorage()); + return param->getCachedDefaultArgumentInitContext(); +} + +void DefaultArgumentInitContextRequest::cacheResult(Initializer *init) const { + auto *param = std::get<0>(getStorage()); + param->setDefaultArgumentInitContext(init); +} + +//----------------------------------------------------------------------------// +// DefaultArgumentExprRequest computation. +//----------------------------------------------------------------------------// + +Optional DefaultArgumentExprRequest::getCachedResult() const { + auto *param = std::get<0>(getStorage()); + auto *defaultInfo = param->DefaultValueAndFlags.getPointer(); + if (!defaultInfo) + return None; + + if (!defaultInfo->InitContextAndIsTypeChecked.getInt()) + return None; + + return defaultInfo->DefaultArg.get(); +} + +void DefaultArgumentExprRequest::cacheResult(Expr *expr) const { + auto *param = std::get<0>(getStorage()); + param->setDefaultExpr(expr, /*isTypeChecked*/ true); +} diff --git a/lib/AST/USRGeneration.cpp b/lib/AST/USRGeneration.cpp index cf9d7895f71b9..db298ab702686 100644 --- a/lib/AST/USRGeneration.cpp +++ b/lib/AST/USRGeneration.cpp @@ -242,8 +242,6 @@ swift::USRGenerationRequest::evaluate(Evaluator &evaluator, } auto declIFaceTy = D->getInterfaceType(); - if (!declIFaceTy) - return std::string(); // Invalid code. if (declIFaceTy.findIf([](Type t) -> bool { diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 60c2964d8adbf..057b86335b8d4 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// /// -/// This file implements the construction of an UnqualifiedLookup, which entails -/// performing the lookup. +/// This file implements unqualified lookup, which searches for an identifier +/// from a given context. /// //===----------------------------------------------------------------------===// @@ -81,18 +81,14 @@ namespace { } // end anonymous namespace namespace { - /// Because UnqualifiedLookup does all of its work in the constructor, - /// a factory class is needed to hold all of the inputs and outputs so - /// that the construction code can be decomposed into bite-sized pieces. - class UnqualifiedLookupFactory { friend class ASTScopeDeclConsumerForUnqualifiedLookup; public: - using Flags = UnqualifiedLookup::Flags; - using Options = UnqualifiedLookup::Options; - using ResultsVector = UnqualifiedLookup::ResultsVector; + using Flags = UnqualifiedLookupFlags; + using Options = UnqualifiedLookupOptions; + using ResultsVector = SmallVector; private: struct ContextAndResolvedIsCascadingUse { @@ -203,12 +199,6 @@ namespace { public: // clang-format off - UnqualifiedLookupFactory(DeclName Name, - DeclContext *const DC, - SourceLoc Loc, - Options options, - UnqualifiedLookup &lookupToBeCreated); - UnqualifiedLookupFactory(DeclName Name, DeclContext *const DC, SourceLoc Loc, @@ -342,7 +332,7 @@ namespace { #pragma mark common helper declarations static NLOptions - computeBaseNLOptions(const UnqualifiedLookup::Options options, + computeBaseNLOptions(const UnqualifiedLookupOptions options, const bool isOriginallyTypeLookup); Optional getInitialIsCascadingUse() const { @@ -433,18 +423,6 @@ class ASTScopeDeclConsumerForUnqualifiedLookup #pragma mark UnqualifiedLookupFactory functions // clang-format off -UnqualifiedLookupFactory::UnqualifiedLookupFactory( - DeclName Name, - DeclContext *const DC, - SourceLoc Loc, - Options options, - UnqualifiedLookup &lookupToBeCreated) -: UnqualifiedLookupFactory(Name, DC, Loc, options, - lookupToBeCreated.Results, - lookupToBeCreated.IndexOfFirstOuterResult) - -{} - UnqualifiedLookupFactory::UnqualifiedLookupFactory( DeclName Name, DeclContext *const DC, @@ -1065,7 +1043,7 @@ void UnqualifiedLookupFactory::findResultsAndSaveUnavailables( NLOptions UnqualifiedLookupFactory::computeBaseNLOptions( - const UnqualifiedLookup::Options options, + const UnqualifiedLookupOptions options, const bool isOriginallyTypeLookup) { NLOptions baseNLOptions = NL_UnqualifiedDefault; if (options.contains(Flags::AllowProtocolMembers)) @@ -1209,29 +1187,15 @@ bool ASTScopeDeclConsumerForUnqualifiedLookup::lookInMembers( return factory.isFirstResultEnough(); } - -#pragma mark UnqualifiedLookup functions - -// clang-format off -UnqualifiedLookup::UnqualifiedLookup(DeclName Name, - DeclContext *const DC, - SourceLoc Loc, - Options options) - // clang-format on - : IndexOfFirstOuterResult(0) { - - auto *stats = DC->getASTContext().Stats; - if (stats) - stats->getFrontendCounters().NumUnqualifiedLookup++; - - UnqualifiedLookupFactory factory(Name, DC, Loc, options, *this); +llvm::Expected +UnqualifiedLookupRequest::evaluate(Evaluator &evaluator, + UnqualifiedLookupDescriptor desc) const { + SmallVector results; + size_t indexOfFirstOuterResult = 0; + UnqualifiedLookupFactory factory(desc.Name, desc.DC, desc.Loc, desc.Options, + results, indexOfFirstOuterResult); factory.performUnqualifiedLookup(); -} - -TypeDecl *UnqualifiedLookup::getSingleTypeResult() const { - if (Results.size() != 1) - return nullptr; - return dyn_cast(Results.back().getValueDecl()); + return LookupResult(results, indexOfFirstOuterResult); } #pragma mark debugging diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index cb7cb8afbada8..a2ebbe6e2bf19 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -916,6 +916,7 @@ ClangImporter::create(ASTContext &ctx, const ClangImporterOptions &importerOpts, invocationArgStrs.push_back("clang"); switch (importerOpts.Mode) { case ClangImporterOptions::Modes::Normal: + case ClangImporterOptions::Modes::PrecompiledModule: getNormalInvocationArguments(invocationArgStrs, ctx, importerOpts); break; case ClangImporterOptions::Modes::EmbedBitcode: @@ -1088,7 +1089,17 @@ ClangImporter::create(ASTContext &ctx, const ClangImporterOptions &importerOpts, if (importerOpts.Mode == ClangImporterOptions::Modes::EmbedBitcode) return importer; + // ClangImporter always sets this in Normal mode, so we need to make sure to + // set it before bailing out early when configuring ClangImporter for + // precompiled modules. This is not a benign langopt, so forgetting this (for + // example, if we combined the early exit below with the one above) would make + // the compiler instance used to emit PCMs incompatible with the one used to + // read them later. instance.getLangOpts().NeededByPCHOrCompilationUsesPCH = true; + + if (importerOpts.Mode == ClangImporterOptions::Modes::PrecompiledModule) + return importer; + bool canBegin = action->BeginSourceFile(instance, instance.getFrontendOpts().Inputs[0]); if (!canBegin) @@ -1472,43 +1483,82 @@ std::string ClangImporter::getBridgingHeaderContents(StringRef headerPath, return result; } -bool -ClangImporter::emitBridgingPCH(StringRef headerPath, - StringRef outputPCHPath) { +/// Returns the appropriate source input language based on language options. +static clang::Language getLanguageFromOptions( + const clang::LangOptions *LangOpts) { + if (LangOpts->OpenCL) + return clang::Language::OpenCL; + if (LangOpts->CUDA) + return clang::Language::CUDA; + if (LangOpts->ObjC) + return LangOpts->CPlusPlus ? + clang::Language::ObjCXX : clang::Language::ObjC; + return LangOpts->CPlusPlus ? clang::Language::CXX : clang::Language::C; +} + +/// Wraps the given frontend action in an index data recording action if the +/// frontend options have an index store path specified. +static +std::unique_ptr wrapActionForIndexingIfEnabled( + const clang::FrontendOptions &FrontendOpts, + std::unique_ptr action) { + if (!FrontendOpts.IndexStorePath.empty()) { + return clang::index::createIndexDataRecordingAction( + FrontendOpts, std::move(action)); + } + return action; +} + +std::unique_ptr +ClangImporter::cloneCompilerInstanceForPrecompiling() { auto invocation = std::make_shared(*Impl.Invocation); - invocation->getFrontendOpts().DisableFree = false; - invocation->getFrontendOpts().Inputs.clear(); - invocation->getFrontendOpts().Inputs.push_back( - clang::FrontendInputFile(headerPath, clang::Language::ObjC)); - invocation->getFrontendOpts().OutputFile = outputPCHPath; - invocation->getFrontendOpts().ProgramAction = clang::frontend::GeneratePCH; - invocation->getPreprocessorOpts().resetNonModularOptions(); - invocation->getLangOpts()->NeededByPCHOrCompilationUsesPCH = true; - invocation->getLangOpts()->CacheGeneratedPCH = true; - clang::CompilerInstance emitInstance( + auto &PPOpts = invocation->getPreprocessorOpts(); + PPOpts.resetNonModularOptions(); + + auto &FrontendOpts = invocation->getFrontendOpts(); + FrontendOpts.DisableFree = false; + FrontendOpts.Inputs.clear(); + + auto clonedInstance = llvm::make_unique( Impl.Instance->getPCHContainerOperations(), &Impl.Instance->getModuleCache()); - emitInstance.setInvocation(std::move(invocation)); - emitInstance.createDiagnostics(&Impl.Instance->getDiagnosticClient(), - /*ShouldOwnClient=*/false); + clonedInstance->setInvocation(std::move(invocation)); + clonedInstance->createDiagnostics(&Impl.Instance->getDiagnosticClient(), + /*ShouldOwnClient=*/false); clang::FileManager &fileManager = Impl.Instance->getFileManager(); - emitInstance.setFileManager(&fileManager); - emitInstance.createSourceManager(fileManager); - emitInstance.setTarget(&Impl.Instance->getTarget()); + clonedInstance->setFileManager(&fileManager); + clonedInstance->createSourceManager(fileManager); + clonedInstance->setTarget(&Impl.Instance->getTarget()); - std::unique_ptr action; - action.reset(new clang::GeneratePCHAction()); - if (!emitInstance.getFrontendOpts().IndexStorePath.empty()) { - action = clang::index:: - createIndexDataRecordingAction(emitInstance.getFrontendOpts(), - std::move(action)); - } - emitInstance.ExecuteAction(*action); + return clonedInstance; +} + +bool +ClangImporter::emitBridgingPCH(StringRef headerPath, + StringRef outputPCHPath) { + auto emitInstance = cloneCompilerInstanceForPrecompiling(); + auto &invocation = emitInstance->getInvocation(); + + auto LangOpts = invocation.getLangOpts(); + LangOpts->NeededByPCHOrCompilationUsesPCH = true; + LangOpts->CacheGeneratedPCH = true; + + auto language = getLanguageFromOptions(LangOpts); + auto inputFile = clang::FrontendInputFile(headerPath, language); + + auto &FrontendOpts = invocation.getFrontendOpts(); + FrontendOpts.Inputs = {inputFile}; + FrontendOpts.OutputFile = outputPCHPath; + FrontendOpts.ProgramAction = clang::frontend::GeneratePCH; - if (emitInstance.getDiagnostics().hasErrorOccurred()) { + auto action = wrapActionForIndexingIfEnabled( + FrontendOpts, llvm::make_unique()); + emitInstance->ExecuteAction(*action); + + if (emitInstance->getDiagnostics().hasErrorOccurred()) { Impl.SwiftContext.Diags.diagnose({}, diag::bridging_header_pch_error, outputPCHPath, headerPath); @@ -1517,6 +1567,65 @@ ClangImporter::emitBridgingPCH(StringRef headerPath, return false; } +bool ClangImporter::emitPrecompiledModule(StringRef moduleMapPath, + StringRef moduleName, + StringRef outputPath) { + auto emitInstance = cloneCompilerInstanceForPrecompiling(); + auto &invocation = emitInstance->getInvocation(); + + auto LangOpts = invocation.getLangOpts(); + LangOpts->setCompilingModule(clang::LangOptions::CMK_ModuleMap); + LangOpts->ModuleName = moduleName; + LangOpts->CurrentModule = LangOpts->ModuleName; + + auto language = getLanguageFromOptions(LangOpts); + auto inputFile = clang::FrontendInputFile( + moduleMapPath, clang::InputKind( + language, clang::InputKind::ModuleMap, false)); + + auto &FrontendOpts = invocation.getFrontendOpts(); + FrontendOpts.Inputs = {inputFile}; + FrontendOpts.OriginalModuleMap = moduleMapPath; + FrontendOpts.OutputFile = outputPath; + FrontendOpts.ProgramAction = clang::frontend::GenerateModule; + + auto action = wrapActionForIndexingIfEnabled( + FrontendOpts, + llvm::make_unique()); + emitInstance->ExecuteAction(*action); + + if (emitInstance->getDiagnostics().hasErrorOccurred()) { + Impl.SwiftContext.Diags.diagnose({}, + diag::emit_pcm_error, + outputPath, moduleMapPath); + return true; + } + return false; +} + +bool ClangImporter::dumpPrecompiledModule(StringRef modulePath, + StringRef outputPath) { + auto dumpInstance = cloneCompilerInstanceForPrecompiling(); + auto &invocation = dumpInstance->getInvocation(); + + auto inputFile = clang::FrontendInputFile( + modulePath, clang::InputKind( + clang::Language::Unknown, clang::InputKind::Precompiled, false)); + + auto &FrontendOpts = invocation.getFrontendOpts(); + FrontendOpts.Inputs = {inputFile}; + FrontendOpts.OutputFile = outputPath; + + auto action = llvm::make_unique(); + dumpInstance->ExecuteAction(*action); + + if (dumpInstance->getDiagnostics().hasErrorOccurred()) { + Impl.SwiftContext.Diags.diagnose({}, diag::dump_pcm_error, modulePath); + return true; + } + return false; +} + void ClangImporter::collectVisibleTopLevelModuleNames( SmallVectorImpl &names) const { SmallVector Modules; diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index e2afb39811320..cc4c30f932086 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -4705,8 +4705,6 @@ namespace { Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result; - result->setCircularityCheck(CircularityCheck::Checked); - // Import protocols this protocol conforms to. SmallVector inheritedTypes; importObjCProtocols(result, decl->getReferencedProtocols(), @@ -4742,7 +4740,6 @@ namespace { SourceLoc(), None, nullptr, dc); Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result; - result->setCircularityCheck(CircularityCheck::Checked); result->setSuperclass(Type()); result->setAddedImplicitInitializers(); // suppress all initializers result->setHasMissingVTableEntries(false); @@ -4848,7 +4845,6 @@ namespace { } Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result; - result->setCircularityCheck(CircularityCheck::Checked); addObjCAttribute(result, Impl.importIdentifier(decl->getIdentifier())); if (declaredNative) @@ -5325,7 +5321,6 @@ SwiftDeclConverter::importCFClassType(const clang::TypedefNameDecl *decl, auto theClass = Impl.createDeclWithClangNode( decl, AccessLevel::Public, SourceLoc(), className, SourceLoc(), None, nullptr, dc); - theClass->setCircularityCheck(CircularityCheck::Checked); theClass->setSuperclass(superclass); theClass->setAddedImplicitInitializers(); // suppress all initializers theClass->setHasMissingVTableEntries(false); diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index 7c8535a346f02..632edc4527a0e 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -30,9 +30,9 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Bitcode/RecordLayout.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Support/DJB.h" #include "llvm/Support/OnDiskHashTable.h" @@ -1482,7 +1482,13 @@ SwiftLookupTableReader::create(clang::ModuleFileExtension *extension, // Look for the base name -> entities table record. SmallVector scratch; auto cursor = stream; - auto next = cursor.advance(); + llvm::Expected maybeNext = cursor.advance(); + if (!maybeNext) { + // FIXME this drops the error on the floor. + consumeError(maybeNext.takeError()); + return nullptr; + } + llvm::BitstreamEntry next = maybeNext.get(); std::unique_ptr serializedTable; std::unique_ptr globalsAsMembersTable; ArrayRef categories; @@ -1495,14 +1501,27 @@ SwiftLookupTableReader::create(clang::ModuleFileExtension *extension, // API notes format. if (cursor.SkipBlock()) return nullptr; - - next = cursor.advance(); + + maybeNext = cursor.advance(); + if (!maybeNext) { + // FIXME this drops the error on the floor. + consumeError(maybeNext.takeError()); + return nullptr; + } + next = maybeNext.get(); continue; } scratch.clear(); StringRef blobData; - unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); + llvm::Expected maybeKind = + cursor.readRecord(next.ID, scratch, &blobData); + if (!maybeKind) { + // FIXME this drops the error on the floor. + consumeError(maybeNext.takeError()); + return nullptr; + } + unsigned kind = maybeKind.get(); switch (kind) { case BASE_NAME_TO_ENTITIES_RECORD_ID: { // Already saw base name -> entities table. @@ -1554,7 +1573,13 @@ SwiftLookupTableReader::create(clang::ModuleFileExtension *extension, break; } - next = cursor.advance(); + maybeNext = cursor.advance(); + if (!maybeNext) { + // FIXME this drops the error on the floor. + consumeError(maybeNext.takeError()); + return nullptr; + } + next = maybeNext.get(); } if (!serializedTable) return nullptr; diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 3b9c98c6b0fb3..d4c20ecc22c08 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -2345,7 +2345,7 @@ std::string Demangler::demangleBridgedMethodParams() { while (!nextIf('_')) { auto c = nextChar(); - if (!c && c != 'n' && c != 'b') + if (c != 'n' && c != 'b') return std::string(); Str.push_back(c); } diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index c696ac204bf93..76b9e1d14b43e 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -1410,6 +1410,11 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, OI.CompilerOutputType = file_types::TY_PCH; break; + case options::OPT_emit_pcm: + OI.CompilerMode = OutputInfo::Mode::SingleCompile; + OI.CompilerOutputType = file_types::TY_ClangModuleFile; + break; + case options::OPT_emit_imported_modules: OI.CompilerOutputType = file_types::TY_ImportedModules; // We want the imported modules from the module as a whole, not individual @@ -1442,6 +1447,11 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, OI.CompilerOutputType = file_types::TY_Nothing; break; + case options::OPT_dump_pcm: + OI.CompilerMode = OutputInfo::Mode::SingleCompile; + OI.CompilerOutputType = file_types::TY_Nothing; + break; + case options::OPT_i: // Keep the default output/mode; this flag was removed and should already // have been diagnosed above. @@ -1636,6 +1646,14 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, return TC.sanitizerRuntimeLibExists(Args, sanitizerName, shared); }); + if (const Arg *A = Args.getLastArg(options::OPT_sanitize_recover_EQ)) { + // Just validate the args. The frontend will parse these again and actually + // use them. To avoid emitting warnings multiple times we surpress warnings + // here but not in the frontend. + (void)parseSanitizerRecoverArgValues(A, OI.SelectedSanitizers, Diags, + /*emitWarnings=*/false); + } + if (const Arg *A = Args.getLastArg(options::OPT_sanitize_coverage_EQ)) { // Check that the sanitizer coverage flags are supported if supplied. @@ -1842,6 +1860,11 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, } case OutputInfo::Mode::SingleCompile: { if (Inputs.empty()) break; + if (Args.hasArg(options::OPT_emit_pcm) && Inputs.size() != 1) { + // -emit-pcm mode requires exactly one input (the module map). + Diags.diagnose(SourceLoc(), diag::error_mode_requires_one_input_file); + return; + } if (Args.hasArg(options::OPT_embed_bitcode)) { // Make sure we can handle the inputs. bool HandledHere = true; diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index d8a3548a40b05..c32d380eab4db 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -214,6 +214,7 @@ static void addCommonFrontendArgs(const ToolChain &TC, const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_profile_coverage_mapping); inputArgs.AddLastArg(arguments, options::OPT_warnings_as_errors); inputArgs.AddLastArg(arguments, options::OPT_sanitize_EQ); + inputArgs.AddLastArg(arguments, options::OPT_sanitize_recover_EQ); inputArgs.AddLastArg(arguments, options::OPT_sanitize_coverage_EQ); inputArgs.AddLastArg(arguments, options::OPT_static); inputArgs.AddLastArg(arguments, options::OPT_swift_version); @@ -505,6 +506,8 @@ const char *ToolChain::JobContext::computeFrontendModeForCompile() const { return "-emit-ir"; case file_types::TY_LLVM_BC: return "-emit-bc"; + case file_types::TY_ClangModuleFile: + return "-emit-pcm"; case file_types::TY_Assembly: return "-S"; case file_types::TY_SwiftModuleFile: @@ -528,7 +531,6 @@ const char *ToolChain::JobContext::computeFrontendModeForCompile() const { case file_types::TY_AutolinkFile: case file_types::TY_Dependencies: case file_types::TY_SwiftModuleDocFile: - case file_types::TY_ClangModuleFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ObjCHeader: case file_types::TY_Image: @@ -764,6 +766,7 @@ ToolChain::constructInvocation(const BackendJobAction &job, case file_types::TY_SIL: case file_types::TY_SIB: case file_types::TY_PCH: + case file_types::TY_ClangModuleFile: case file_types::TY_IndexData: llvm_unreachable("Cannot be output from backend job"); case file_types::TY_Swift: @@ -771,7 +774,6 @@ ToolChain::constructInvocation(const BackendJobAction &job, case file_types::TY_AutolinkFile: case file_types::TY_Dependencies: case file_types::TY_SwiftModuleDocFile: - case file_types::TY_ClangModuleFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ObjCHeader: case file_types::TY_Image: diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 96a36172c22c0..15917137f9a20 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -90,15 +90,6 @@ bool ArgsToFrontendOptionsConverter::convert( computeDebugTimeOptions(); computeTBDOptions(); - setUnsignedIntegerArgument(OPT_warn_long_function_bodies, 10, - Opts.WarnLongFunctionBodies); - setUnsignedIntegerArgument(OPT_warn_long_expression_type_checking, 10, - Opts.WarnLongExpressionTypeChecking); - setUnsignedIntegerArgument(OPT_solver_expression_time_threshold_EQ, 10, - Opts.SolverExpressionTimeThreshold); - setUnsignedIntegerArgument(OPT_switch_checking_invocation_threshold_EQ, 10, - Opts.SwitchCheckingInvocationThreshold); - Opts.CheckOnoneSupportCompleteness = Args.hasArg(OPT_check_onone_completeness); Opts.DebuggerTestingTransform = Args.hasArg(OPT_debugger_testing_transform); @@ -163,7 +154,7 @@ bool ArgsToFrontendOptionsConverter::convert( return true; if (FrontendOptions::doesActionGenerateIR(Opts.RequestedAction) - && Opts.SkipNonInlinableFunctionBodies) { + && Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies)) { Diags.diagnose(SourceLoc(), diag::cannot_emit_ir_skipping_function_bodies); return true; } @@ -222,17 +213,7 @@ void ArgsToFrontendOptionsConverter::computePrintStatsOptions() { void ArgsToFrontendOptionsConverter::computeDebugTimeOptions() { using namespace options; - Opts.DebugTimeFunctionBodies |= Args.hasArg(OPT_debug_time_function_bodies); - Opts.DebugTimeExpressionTypeChecking |= - Args.hasArg(OPT_debug_time_expression_type_checking); Opts.DebugTimeCompilation |= Args.hasArg(OPT_debug_time_compilation); - Opts.SkipNonInlinableFunctionBodies |= - Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies); - - // If asked to perform InstallAPI, go ahead and enable non-inlinable function - // body skipping. - Opts.SkipNonInlinableFunctionBodies |= - Args.hasArg(OPT_tbd_is_installapi); if (const Arg *A = Args.getLastArg(OPT_stats_output_dir)) { Opts.StatsOutputDir = A->getValue(); @@ -266,19 +247,6 @@ void ArgsToFrontendOptionsConverter::computeTBDOptions() { } } -void ArgsToFrontendOptionsConverter::setUnsignedIntegerArgument( - options::ID optionID, unsigned radix, unsigned &valueToSet) { - if (const Arg *A = Args.getLastArg(optionID)) { - unsigned attempt; - if (StringRef(A->getValue()).getAsInteger(radix, attempt)) { - Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, - A->getAsString(Args), A->getValue()); - } else { - valueToSet = attempt; - } - } -} - void ArgsToFrontendOptionsConverter::computePlaygroundOptions() { using namespace options; Opts.PlaygroundTransform |= Args.hasArg(OPT_playground); @@ -393,6 +361,10 @@ ArgsToFrontendOptionsConverter::determineRequestedAction(const ArgList &args) { return FrontendOptions::ActionType::DumpTypeInfo; if (Opt.matches(OPT_print_ast)) return FrontendOptions::ActionType::PrintAST; + if (Opt.matches(OPT_emit_pcm)) + return FrontendOptions::ActionType::EmitPCM; + if (Opt.matches(OPT_dump_pcm)) + return FrontendOptions::ActionType::DumpPCM; if (Opt.matches(OPT_repl) || Opt.matches(OPT_deprecated_integrated_repl)) return FrontendOptions::ActionType::REPL; diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.h b/lib/Frontend/ArgsToFrontendOptionsConverter.h index ebf09b6d3153e..8431ac4c0090b 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.h +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.h @@ -47,9 +47,6 @@ class ArgsToFrontendOptionsConverter { void computePrintStatsOptions(); void computeTBDOptions(); - void setUnsignedIntegerArgument(options::ID optionID, unsigned radix, - unsigned &valueToSet); - bool setUpInputKindAndImmediateArgs(); bool checkUnusedSupplementaryOutputPaths() const; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index f42f020c3f2bc..24cdd13d386a2 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -38,11 +38,17 @@ swift::CompilerInvocation::CompilerInvocation() { setTargetTriple(llvm::sys::getDefaultTargetTriple()); } +void CompilerInvocation::computeRuntimeResourcePathFromExecutablePath( + StringRef mainExecutablePath, llvm::SmallString<128> &runtimeResourcePath) { + runtimeResourcePath.assign(mainExecutablePath); + llvm::sys::path::remove_filename(runtimeResourcePath); // Remove /swift + llvm::sys::path::remove_filename(runtimeResourcePath); // Remove /bin + llvm::sys::path::append(runtimeResourcePath, "lib", "swift"); +} + void CompilerInvocation::setMainExecutablePath(StringRef Path) { - llvm::SmallString<128> LibPath(Path); - llvm::sys::path::remove_filename(LibPath); // Remove /swift - llvm::sys::path::remove_filename(LibPath); // Remove /bin - llvm::sys::path::append(LibPath, "lib", "swift"); + llvm::SmallString<128> LibPath; + computeRuntimeResourcePathFromExecutablePath(Path, LibPath); setRuntimeResourcePath(LibPath.str()); llvm::SmallString<128> DiagnosticDocsPath(Path); @@ -284,18 +290,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.EnableSubstSILFunctionTypesForFunctionValues |= Args.hasArg(OPT_enable_subst_sil_function_types_for_function_values); - Opts.EnableOperatorDesignatedTypes |= - Args.hasArg(OPT_enable_operator_designated_types); - Opts.DiagnoseInvalidEphemeralnessAsError |= Args.hasArg(OPT_enable_invalid_ephemeralness_as_error); - // Always enable operator designated types for the standard library. - Opts.EnableOperatorDesignatedTypes |= FrontendOpts.ParseStdlib; - - Opts.SolverEnableOperatorDesignatedTypes |= - Args.hasArg(OPT_solver_enable_operator_designated_types); - if (auto A = Args.getLastArg(OPT_enable_deserialization_recovery, OPT_disable_deserialization_recovery)) { Opts.EnableDeserializationRecovery @@ -353,9 +350,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.WarnIfASTScopeLookup |= Args.hasArg(OPT_warn_if_astscope_lookup); Opts.LazyASTScopes |= Args.hasArg(OPT_lazy_astscopes); - Opts.DebugConstraintSolver |= Args.hasArg(OPT_debug_constraints); Opts.NamedLazyMemberLoading &= !Args.hasArg(OPT_disable_named_lazy_member_loading); - Opts.DebugGenericSignatures |= Args.hasArg(OPT_debug_generic_signatures); if (Args.hasArg(OPT_verify_syntax_tree)) { Opts.BuildSyntaxTree = true; @@ -396,34 +391,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.EnableTestableAttrRequiresTestableModule = A->getOption().matches(OPT_enable_testable_attr_requires_testable_module); } - - if (const Arg *A = Args.getLastArg(OPT_debug_constraints_attempt)) { - unsigned attempt; - if (StringRef(A->getValue()).getAsInteger(10, attempt)) { - Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, - A->getAsString(Args), A->getValue()); - HadError = true; - } else { - Opts.DebugConstraintSolverAttempt = attempt; - } - } - - for (const Arg *A : Args.filtered(OPT_debug_constraints_on_line)) { - unsigned line; - if (StringRef(A->getValue()).getAsInteger(10, line)) { - Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, - A->getAsString(Args), A->getValue()); - HadError = true; - } else { - Opts.DebugConstraintSolverOnLines.push_back(line); - } - } - llvm::sort(Opts.DebugConstraintSolverOnLines); - if (const Arg *A = Args.getLastArg(OPT_debug_forbid_typecheck_prefix)) { - Opts.DebugForbidTypecheckPrefix = A->getValue(); - } - if (Args.getLastArg(OPT_debug_cycles)) Opts.DebugDumpCycles = true; @@ -438,31 +406,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, } } - if (const Arg *A = Args.getLastArg(OPT_solver_memory_threshold)) { - unsigned threshold; - if (StringRef(A->getValue()).getAsInteger(10, threshold)) { - Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, - A->getAsString(Args), A->getValue()); - HadError = true; - } else { - Opts.SolverMemoryThreshold = threshold; - } - } - - if (const Arg *A = Args.getLastArg(OPT_solver_shrink_unsolved_threshold)) { - unsigned threshold; - if (StringRef(A->getValue()).getAsInteger(10, threshold)) { - Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, - A->getAsString(Args), A->getValue()); - HadError = true; - } else { - Opts.SolverShrinkUnsolvedThreshold = threshold; - } - } - - if (Args.getLastArg(OPT_solver_disable_shrink)) - Opts.SolverDisableShrink = true; - if (const Arg *A = Args.getLastArg(OPT_value_recursion_threshold)) { unsigned threshold; if (StringRef(A->getValue()).getAsInteger(10, threshold)) { @@ -534,9 +477,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, (Target.isTvOS() && Target.isOSVersionLT(12, 2)) || (Target.isWatchOS() && Target.isOSVersionLT(5, 2)); - Opts.DisableConstraintSolverPerformanceHacks |= - Args.hasArg(OPT_disable_constraint_solver_performance_hacks); - // Must be processed after any other language options that could affect // platform conditions. bool UnsupportedOS, UnsupportedArch; @@ -558,6 +498,88 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, return HadError || UnsupportedOS || UnsupportedArch; } +static bool ParseTypeCheckerArgs(TypeCheckerOptions &Opts, ArgList &Args, + DiagnosticEngine &Diags, + const FrontendOptions &FrontendOpts) { + using namespace options; + + bool HadError = false; + auto setUnsignedIntegerArgument = + [&Args, &Diags, &HadError](options::ID optionID, unsigned &valueToSet) { + if (const Arg *A = Args.getLastArg(optionID)) { + unsigned attempt; + if (StringRef(A->getValue()).getAsInteger(/*radix*/ 10, attempt)) { + Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, + A->getAsString(Args), A->getValue()); + HadError = true; + } else { + valueToSet = attempt; + } + } + }; + + setUnsignedIntegerArgument(OPT_warn_long_function_bodies, + Opts.WarnLongFunctionBodies); + setUnsignedIntegerArgument(OPT_warn_long_expression_type_checking, + Opts.WarnLongExpressionTypeChecking); + setUnsignedIntegerArgument(OPT_solver_expression_time_threshold_EQ, + Opts.ExpressionTimeoutThreshold); + setUnsignedIntegerArgument(OPT_switch_checking_invocation_threshold_EQ, + Opts.SwitchCheckingInvocationThreshold); + setUnsignedIntegerArgument(OPT_debug_constraints_attempt, + Opts.DebugConstraintSolverAttempt); + setUnsignedIntegerArgument(OPT_solver_memory_threshold, + Opts.SolverMemoryThreshold); + setUnsignedIntegerArgument(OPT_solver_shrink_unsolved_threshold, + Opts.SolverShrinkUnsolvedThreshold); + + Opts.DebugTimeFunctionBodies |= Args.hasArg(OPT_debug_time_function_bodies); + Opts.DebugTimeExpressions |= + Args.hasArg(OPT_debug_time_expression_type_checking); + Opts.SkipNonInlinableFunctionBodies |= + Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies); + + // If asked to perform InstallAPI, go ahead and enable non-inlinable function + // body skipping. + Opts.SkipNonInlinableFunctionBodies |= Args.hasArg(OPT_tbd_is_installapi); + + Opts.DisableConstraintSolverPerformanceHacks |= + Args.hasArg(OPT_disable_constraint_solver_performance_hacks); + + Opts.EnableOperatorDesignatedTypes |= + Args.hasArg(OPT_enable_operator_designated_types); + + // Always enable operator designated types for the standard library. + Opts.EnableOperatorDesignatedTypes |= FrontendOpts.ParseStdlib; + + Opts.SolverEnableOperatorDesignatedTypes |= + Args.hasArg(OPT_solver_enable_operator_designated_types); + + Opts.DebugConstraintSolver |= Args.hasArg(OPT_debug_constraints); + Opts.DebugGenericSignatures |= Args.hasArg(OPT_debug_generic_signatures); + + for (const Arg *A : Args.filtered(OPT_debug_constraints_on_line)) { + unsigned line; + if (StringRef(A->getValue()).getAsInteger(/*radix*/ 10, line)) { + Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, + A->getAsString(Args), A->getValue()); + HadError = true; + } else { + Opts.DebugConstraintSolverOnLines.push_back(line); + } + } + llvm::sort(Opts.DebugConstraintSolverOnLines); + + if (const Arg *A = Args.getLastArg(OPT_debug_forbid_typecheck_prefix)) { + Opts.DebugForbidTypecheckPrefix = A->getValue(); + } + + if (Args.getLastArg(OPT_solver_disable_shrink)) + Opts.SolverDisableShrink = true; + + return HadError; +} + static bool ParseClangImporterArgs(ClangImporterOptions &Opts, ArgList &Args, DiagnosticEngine &Diags, @@ -602,6 +624,9 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts, if (Args.hasArg(OPT_embed_bitcode)) Opts.Mode = ClangImporterOptions::Modes::EmbedBitcode; + else if (Args.hasArg(OPT_emit_pcm) || Args.hasArg(OPT_dump_pcm)) + Opts.Mode = ClangImporterOptions::Modes::PrecompiledModule; + if (auto *A = Args.getLastArg(OPT_import_objc_header)) Opts.BridgingHeader = A->getValue(); Opts.DisableSwiftBridgeAttr |= Args.hasArg(OPT_disable_swift_bridge_attr); @@ -852,7 +877,8 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, // -Ounchecked might also set removal of runtime asserts (cond_fail). Opts.RemoveRuntimeAsserts |= Args.hasArg(OPT_RemoveRuntimeAsserts); - Opts.EnableARCOptimizations |= !Args.hasArg(OPT_disable_arc_opts); + Opts.EnableARCOptimizations &= !Args.hasArg(OPT_disable_arc_opts); + Opts.EnableOSSAOptimizations &= !Args.hasArg(OPT_disable_ossa_opts); Opts.DisableSILPerfOptimizations |= Args.hasArg(OPT_disable_sil_perf_optzns); Opts.VerifyAll |= Args.hasArg(OPT_sil_verify_all); Opts.DebugSerialization |= Args.hasArg(OPT_sil_debug_serialization); @@ -900,6 +926,12 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, IRGenOpts.Sanitizers = Opts.Sanitizers; } + if (const Arg *A = Args.getLastArg(options::OPT_sanitize_recover_EQ)) { + IRGenOpts.SanitizersWithRecoveryInstrumentation = + parseSanitizerRecoverArgValues(A, Opts.Sanitizers, Diags, + /*emitWarnings=*/true); + } + if (auto A = Args.getLastArg(OPT_enable_verify_exclusivity, OPT_disable_verify_exclusivity)) { Opts.VerifyExclusivity @@ -970,16 +1002,11 @@ static bool ParseTBDGenArgs(TBDGenOptions &Opts, ArgList &Args, Opts.IsInstallAPI = Args.hasArg(OPT_tbd_is_installapi); if (const Arg *A = Args.getLastArg(OPT_tbd_compatibility_version)) { - if (auto vers = version::Version::parseVersionString( - A->getValue(), SourceLoc(), &Diags)) { - Opts.CompatibilityVersion = *vers; - } + Opts.CompatibilityVersion = A->getValue(); } + if (const Arg *A = Args.getLastArg(OPT_tbd_current_version)) { - if (auto vers = version::Version::parseVersionString( - A->getValue(), SourceLoc(), &Diags)) { - Opts.CurrentVersion = *vers; - } + Opts.CurrentVersion = A->getValue(); } return false; } @@ -1398,6 +1425,10 @@ bool CompilerInvocation::parseArgs( return true; } + if (ParseTypeCheckerArgs(TypeCheckerOpts, ParsedArgs, Diags, FrontendOpts)) { + return true; + } + if (ParseClangImporterArgs(ClangImporterOpts, ParsedArgs, Diags, workingDirectory)) { return true; diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index fac2d1af8ad73..d97bdd8572ea3 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -190,9 +190,9 @@ bool CompilerInstance::setUpASTContextIfNeeded() { return false; } - Context.reset(ASTContext::get(Invocation.getLangOptions(), - Invocation.getSearchPathOptions(), SourceMgr, - Diagnostics)); + Context.reset(ASTContext::get( + Invocation.getLangOptions(), Invocation.getTypeCheckerOptions(), + Invocation.getSearchPathOptions(), SourceMgr, Diagnostics)); registerParseRequestFunctions(Context->evaluator); registerTypeCheckerRequestFunctions(Context->evaluator); @@ -222,17 +222,28 @@ bool CompilerInstance::setup(const CompilerInvocation &Invok) { setUpLLVMArguments(); setUpDiagnosticOptions(); + const auto &frontendOpts = Invocation.getFrontendOptions(); + // If we are asked to emit a module documentation file, configure lexing and // parsing to remember comments. - if (Invocation.getFrontendOptions().InputsAndOutputs.hasModuleDocOutputPath()) + if (frontendOpts.InputsAndOutputs.hasModuleDocOutputPath()) Invocation.getLangOptions().AttachCommentsToDecls = true; // If we are doing index-while-building, configure lexing and parsing to // remember comments. - if (!Invocation.getFrontendOptions().IndexStorePath.empty()) { + if (!frontendOpts.IndexStorePath.empty()) { Invocation.getLangOptions().AttachCommentsToDecls = true; } + // Set up the type checker options. + auto &typeCkOpts = Invocation.getTypeCheckerOptions(); + if (isWholeModuleCompilation()) { + typeCkOpts.DelayWholeModuleChecking = true; + } + if (FrontendOptions::isActionImmediate(frontendOpts.RequestedAction)) { + typeCkOpts.InImmediateMode = true; + } + assert(Lexer::isIdentifier(Invocation.getModuleName())); if (isInSILMode()) @@ -825,14 +836,12 @@ void CompilerInstance::parseAndCheckTypesUpTo( if (hadLoadError) return; - OptionSet TypeCheckOptions = computeTypeCheckingOptions(); - // Type-check main file after parsing all other files so that // it can use declarations from other files. // In addition, the main file has parsing and type-checking // interwined. if (MainBufferID != NO_SUCH_BUFFER) { - parseAndTypeCheckMainFileUpTo(limitStage, TypeCheckOptions); + parseAndTypeCheckMainFileUpTo(limitStage); } assert(llvm::all_of(MainModule->getFiles(), [](const FileUnit *File) -> bool { @@ -843,22 +852,16 @@ void CompilerInstance::parseAndCheckTypesUpTo( }) && "some files have not yet had their imports resolved"); MainModule->setHasResolvedImports(); - // If the limiting AST stage is name binding, we're done. - if (limitStage <= SourceFile::NameBound) { - return; - } - - const auto &options = Invocation.getFrontendOptions(); forEachFileToTypeCheck([&](SourceFile &SF) { - performTypeChecking(SF, PersistentState->getTopLevelContext(), - TypeCheckOptions, /*curElem*/ 0, - options.WarnLongFunctionBodies, - options.WarnLongExpressionTypeChecking, - options.SolverExpressionTimeThreshold, - options.SwitchCheckingInvocationThreshold); + if (limitStage == SourceFile::NameBound) { + bindExtensions(SF); + return; + } + + performTypeChecking(SF); if (!Context->hadError() && Invocation.getFrontendOptions().PCMacro) { - performPCMacro(SF, PersistentState->getTopLevelContext()); + performPCMacro(SF); } // Playground transform knows to look out for PCMacro's changes and not @@ -871,10 +874,17 @@ void CompilerInstance::parseAndCheckTypesUpTo( }); if (Invocation.isCodeCompletion()) { + assert(limitStage == SourceFile::NameBound); performCodeCompletionSecondPass(*PersistentState.get(), *Invocation.getCodeCompletionFactory()); } - finishTypeChecking(TypeCheckOptions); + + // If the limiting AST stage is name binding, we're done. + if (limitStage <= SourceFile::NameBound) { + return; + } + + finishTypeChecking(); } void CompilerInstance::parseLibraryFile( @@ -905,27 +915,6 @@ void CompilerInstance::parseLibraryFile( performNameBinding(*NextInput); } -OptionSet CompilerInstance::computeTypeCheckingOptions() { - OptionSet TypeCheckOptions; - if (isWholeModuleCompilation()) { - TypeCheckOptions |= TypeCheckingFlags::DelayWholeModuleChecking; - } - const auto &options = Invocation.getFrontendOptions(); - if (options.DebugTimeFunctionBodies) { - TypeCheckOptions |= TypeCheckingFlags::DebugTimeFunctionBodies; - } - if (FrontendOptions::isActionImmediate(options.RequestedAction)) { - TypeCheckOptions |= TypeCheckingFlags::ForImmediateMode; - } - if (options.DebugTimeExpressionTypeChecking) { - TypeCheckOptions |= TypeCheckingFlags::DebugTimeExpressions; - } - if (options.SkipNonInlinableFunctionBodies) { - TypeCheckOptions |= TypeCheckingFlags::SkipNonInlinableFunctionBodies; - } - return TypeCheckOptions; -} - bool CompilerInstance::parsePartialModulesAndLibraryFiles( const ImplicitImports &implicitImports) { FrontendStatsTracer tracer(Context->Stats, @@ -951,8 +940,7 @@ bool CompilerInstance::parsePartialModulesAndLibraryFiles( } void CompilerInstance::parseAndTypeCheckMainFileUpTo( - SourceFile::ASTStage_t LimitStage, - OptionSet TypeCheckOptions) { + SourceFile::ASTStage_t LimitStage) { FrontendStatsTracer tracer(Context->Stats, "parse-and-typecheck-main-file"); bool mainIsPrimary = @@ -987,13 +975,7 @@ void CompilerInstance::parseAndTypeCheckMainFileUpTo( performNameBinding(MainFile, CurTUElem); break; case SourceFile::TypeChecked: - const auto &options = Invocation.getFrontendOptions(); - performTypeChecking(MainFile, PersistentState->getTopLevelContext(), - TypeCheckOptions, CurTUElem, - options.WarnLongFunctionBodies, - options.WarnLongExpressionTypeChecking, - options.SolverExpressionTimeThreshold, - options.SwitchCheckingInvocationThreshold); + performTypeChecking(MainFile, CurTUElem); break; } } @@ -1033,9 +1015,8 @@ void CompilerInstance::forEachFileToTypeCheck( } } -void CompilerInstance::finishTypeChecking( - OptionSet TypeCheckOptions) { - if (TypeCheckOptions & TypeCheckingFlags::DelayWholeModuleChecking) { +void CompilerInstance::finishTypeChecking() { + if (getASTContext().TypeCheckerOpts.DelayWholeModuleChecking) { forEachSourceFileIn(MainModule, [&](SourceFile &SF) { performWholeModuleTypeChecking(SF); }); @@ -1158,7 +1139,8 @@ static bool performMandatorySILPasses(CompilerInvocation &Invocation, /// These may change across compiler versions. static void performSILOptimizations(CompilerInvocation &Invocation, SILModule *SM) { - SharedTimer timer("SIL optimization"); + FrontendStatsTracer tracer(SM->getASTContext().Stats, + "SIL optimization"); if (Invocation.getFrontendOptions().RequestedAction == FrontendOptions::ActionType::MergeModules || !Invocation.getSILOptions().shouldOptimize()) { @@ -1201,7 +1183,8 @@ bool CompilerInstance::performSILProcessing(SILModule *silModule, return true; { - SharedTimer timer("SIL verification, pre-optimization"); + FrontendStatsTracer tracer(silModule->getASTContext().Stats, + "SIL verification, pre-optimization"); silModule->verify(); } @@ -1211,7 +1194,8 @@ bool CompilerInstance::performSILProcessing(SILModule *silModule, countStatsPostSILOpt(*stats, *silModule); { - SharedTimer timer("SIL verification, post-optimization"); + FrontendStatsTracer tracer(silModule->getASTContext().Stats, + "SIL verification, post-optimization"); silModule->verify(); } diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 46e60edfb27c6..dd21f74b00dfb 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -40,6 +40,7 @@ bool FrontendOptions::needsProperModuleName(ActionType action) { case ActionType::PrintAST: case ActionType::DumpScopeMaps: case ActionType::DumpTypeRefinementContexts: + case ActionType::DumpPCM: return false; case ActionType::EmitPCH: case ActionType::EmitSILGen: @@ -59,6 +60,7 @@ bool FrontendOptions::needsProperModuleName(ActionType action) { case ActionType::EmitObject: case ActionType::EmitImportedModules: case ActionType::DumpTypeInfo: + case ActionType::EmitPCM: return true; } llvm_unreachable("Unknown ActionType"); @@ -95,6 +97,8 @@ bool FrontendOptions::isActionImmediate(ActionType action) { case ActionType::EmitObject: case ActionType::EmitImportedModules: case ActionType::DumpTypeInfo: + case ActionType::EmitPCM: + case ActionType::DumpPCM: return false; } llvm_unreachable("Unknown ActionType"); @@ -154,6 +158,7 @@ FrontendOptions::formatForPrincipalOutputFileForAction(ActionType action) { case ActionType::DumpScopeMaps: case ActionType::DumpTypeRefinementContexts: case ActionType::DumpTypeInfo: + case ActionType::DumpPCM: return TY_Nothing; case ActionType::EmitPCH: @@ -195,6 +200,9 @@ FrontendOptions::formatForPrincipalOutputFileForAction(ActionType action) { case ActionType::EmitImportedModules: return TY_ImportedModules; + + case ActionType::EmitPCM: + return TY_ClangModuleFile; } llvm_unreachable("unhandled action"); } @@ -214,6 +222,7 @@ bool FrontendOptions::canActionEmitDependencies(ActionType action) { case ActionType::CompileModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: + case ActionType::DumpPCM: return false; case ActionType::ResolveImports: case ActionType::Typecheck: @@ -229,6 +238,7 @@ bool FrontendOptions::canActionEmitDependencies(ActionType action) { case ActionType::EmitAssembly: case ActionType::EmitObject: case ActionType::EmitImportedModules: + case ActionType::EmitPCM: return true; } llvm_unreachable("unhandled action"); @@ -250,6 +260,8 @@ bool FrontendOptions::canActionEmitReferenceDependencies(ActionType action) { case ActionType::CompileModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: + case ActionType::EmitPCM: + case ActionType::DumpPCM: return false; case ActionType::Typecheck: case ActionType::MergeModules: @@ -286,6 +298,8 @@ bool FrontendOptions::canActionEmitObjCHeader(ActionType action) { case ActionType::CompileModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: + case ActionType::EmitPCM: + case ActionType::DumpPCM: return false; case ActionType::Typecheck: case ActionType::MergeModules: @@ -319,6 +333,8 @@ bool FrontendOptions::canActionEmitLoadedModuleTrace(ActionType action) { case ActionType::CompileModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: + case ActionType::EmitPCM: + case ActionType::DumpPCM: return false; case ActionType::ResolveImports: case ActionType::Typecheck: @@ -358,6 +374,8 @@ bool FrontendOptions::canActionEmitModule(ActionType action) { case ActionType::CompileModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: + case ActionType::EmitPCM: + case ActionType::DumpPCM: return false; case ActionType::MergeModules: case ActionType::EmitModuleOnly: @@ -398,6 +416,8 @@ bool FrontendOptions::canActionEmitInterface(ActionType action) { case ActionType::CompileModuleFromInterface: case ActionType::Immediate: case ActionType::REPL: + case ActionType::EmitPCM: + case ActionType::DumpPCM: return false; case ActionType::Typecheck: case ActionType::MergeModules: @@ -439,6 +459,8 @@ bool FrontendOptions::doesActionProduceOutput(ActionType action) { case ActionType::MergeModules: case ActionType::CompileModuleFromInterface: case ActionType::DumpTypeInfo: + case ActionType::EmitPCM: + case ActionType::DumpPCM: return true; case ActionType::NoneAction: @@ -462,6 +484,7 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) { case ActionType::EmitObject: case ActionType::Immediate: case ActionType::REPL: + case ActionType::EmitPCM: return false; case ActionType::Parse: @@ -480,6 +503,7 @@ bool FrontendOptions::doesActionProduceTextualOutput(ActionType action) { case ActionType::EmitAssembly: case ActionType::EmitIR: case ActionType::DumpTypeInfo: + case ActionType::DumpPCM: return true; } llvm_unreachable("unhandled action"); @@ -501,6 +525,8 @@ bool FrontendOptions::doesActionGenerateSIL(ActionType action) { case ActionType::EmitImportedModules: case ActionType::EmitPCH: case ActionType::CompileModuleFromInterface: + case ActionType::EmitPCM: + case ActionType::DumpPCM: return false; case ActionType::EmitSILGen: case ActionType::EmitSIBGen: @@ -543,6 +569,8 @@ bool FrontendOptions::doesActionGenerateIR(ActionType action) { case ActionType::EmitSIBGen: case ActionType::EmitSIB: case ActionType::EmitImportedModules: + case ActionType::EmitPCM: + case ActionType::DumpPCM: return false; case ActionType::Immediate: case ActionType::REPL: diff --git a/lib/Frontend/SerializedDiagnosticConsumer.cpp b/lib/Frontend/SerializedDiagnosticConsumer.cpp index 6b1346bae2935..001063e817f90 100644 --- a/lib/Frontend/SerializedDiagnosticConsumer.cpp +++ b/lib/Frontend/SerializedDiagnosticConsumer.cpp @@ -28,7 +28,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitstream/BitstreamWriter.h" // For constant values only. #include "clang/Frontend/SerializedDiagnosticPrinter.h" diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 7cb57df324d3a..44629ad48987c 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -764,6 +764,29 @@ static bool precompileBridgingHeader(CompilerInvocation &Invocation, .InputsAndOutputs.getSingleOutputFilename()); } +static bool precompileClangModule(CompilerInvocation &Invocation, + CompilerInstance &Instance) { + auto clangImporter = static_cast( + Instance.getASTContext().getClangModuleLoader()); + return clangImporter->emitPrecompiledModule( + Invocation.getFrontendOptions() + .InputsAndOutputs.getFilenameOfFirstInput(), + Invocation.getFrontendOptions().ModuleName, + Invocation.getFrontendOptions() + .InputsAndOutputs.getSingleOutputFilename()); +} + +static bool dumpPrecompiledClangModule(CompilerInvocation &Invocation, + CompilerInstance &Instance) { + auto clangImporter = static_cast( + Instance.getASTContext().getClangModuleLoader()); + return clangImporter->dumpPrecompiledModule( + Invocation.getFrontendOptions() + .InputsAndOutputs.getFilenameOfFirstInput(), + Invocation.getFrontendOptions() + .InputsAndOutputs.getSingleOutputFilename()); +} + static bool buildModuleFromInterface(CompilerInvocation &Invocation, CompilerInstance &Instance) { const FrontendOptions &FEOpts = Invocation.getFrontendOptions(); @@ -1133,10 +1156,14 @@ static bool performCompile(CompilerInstance &Instance, Instance.getASTContext().LangOpts.VerifySyntaxTree = true; } - // We've been asked to precompile a bridging header; we want to + // We've been asked to precompile a bridging header or module; we want to // avoid touching any other inputs and just parse, emit and exit. if (Action == FrontendOptions::ActionType::EmitPCH) return precompileBridgingHeader(Invocation, Instance); + if (Action == FrontendOptions::ActionType::EmitPCM) + return precompileClangModule(Invocation, Instance); + if (Action == FrontendOptions::ActionType::DumpPCM) + return dumpPrecompiledClangModule(Invocation, Instance); if (Action == FrontendOptions::ActionType::CompileModuleFromInterface) return buildModuleFromInterface(Invocation, Instance); diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 63cc2ab67b4b7..5a74c4d786b85 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -4144,10 +4144,42 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer { void addAccessControl(const ValueDecl *VD, CodeCompletionResultBuilder &Builder) { - assert(CurrDeclContext->getSelfNominalTypeDecl()); - auto AccessOfContext = - CurrDeclContext->getSelfNominalTypeDecl()->getFormalAccess(); - auto Access = std::min(VD->getFormalAccess(), AccessOfContext); + auto CurrentNominal = CurrDeclContext->getSelfNominalTypeDecl(); + assert(CurrentNominal); + + auto AccessOfContext = CurrentNominal->getFormalAccess(); + if (AccessOfContext < AccessLevel::Public) + return; + + auto Access = VD->getFormalAccess(); + // Use the greater access between the protocol requirement and the witness. + // In case of: + // + // public protocol P { func foo() } + // public class B { func foo() {} } + // public class C: B, P { + // + // } + // + // 'VD' is 'B.foo()' which is implicitly 'internal'. But as the overriding + // declaration, the user needs to write both 'public' and 'override': + // + // public class C: B { + // public override func foo() {} + // } + if (Access < AccessLevel::Public && + !isa(VD->getDeclContext())) { + for (auto Conformance : CurrentNominal->getAllConformances()) { + Conformance->getRootConformance()->forEachValueWitness( + [&](ValueDecl *req, Witness witness) { + if (witness.getDecl() == VD) + Access = std::max( + Access, Conformance->getProtocol()->getFormalAccess()); + }); + } + } + + Access = std::min(Access, AccessOfContext); // Only emit 'public', not needed otherwise. if (Access >= AccessLevel::Public) Builder.addAccessControlKeyword(Access); @@ -4370,9 +4402,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer { if (D->shouldHideFromEditor()) return; - if (D->isFinal() || - // A 'class' member with an initial value cannot be overriden either. - (D->isStatic() && D->getAttrs().hasAttribute())) + if (D->isFinal()) return; bool hasIntroducer = hasFuncIntroducer || @@ -4961,13 +4991,16 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink, case CompletionKind::TypeIdentifierWithoutDot: break; - case CompletionKind::TypeDeclResultBeginning: - if (!isa(CurDeclContext)) - if (CurDeclContext->isTypeContext() || - (ParsedDecl && isa(ParsedDecl))) + case CompletionKind::TypeDeclResultBeginning: { + auto DC = CurDeclContext; + if (ParsedDecl && ParsedDecl == CurDeclContext->getAsDecl()) + DC = ParsedDecl->getDeclContext(); + if (!isa(DC)) + if (DC->isTypeContext() || (ParsedDecl && isa(ParsedDecl))) addOpaqueTypeKeyword(Sink); LLVM_FALLTHROUGH; + } case CompletionKind::TypeSimpleBeginning: addAnyTypeKeyword(Sink); break; @@ -5136,8 +5169,6 @@ void CodeCompletionCallbacksImpl::doneParsing() { CD->getContextKind() == DeclContextKind::TopLevelCodeDecl) MaybeFuncBody = false; } - // Add keywords even if type checking fails completely. - addKeywords(CompletionContext.getResultSink(), MaybeFuncBody); if (auto *DC = dyn_cast_or_null(ParsedDecl)) { if (DC->isChildContextOf(CurDeclContext)) @@ -5148,6 +5179,9 @@ void CodeCompletionCallbacksImpl::doneParsing() { CurDeclContext, CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc()); + // Add keywords even if type checking fails completely. + addKeywords(CompletionContext.getResultSink(), MaybeFuncBody); + Optional ExprType; ConcreteDeclRef ReferencedDecl = nullptr; if (ParsedExpr) { diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index 5bafb15f05d4e..f5ee2b6db3377 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -22,6 +22,7 @@ #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" +#include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/Type.h" #include "swift/AST/Types.h" @@ -61,10 +62,9 @@ void typeCheckContextImpl(DeclContext *DC, SourceLoc Loc) { if (auto *patternInit = dyn_cast(DC)) { if (auto *PBD = patternInit->getBinding()) { auto i = patternInit->getBindingIndex(); + PBD->getPattern(i)->forEachVariable( + [](VarDecl *VD) { (void)VD->getInterfaceType(); }); if (PBD->getInit(i)) { - PBD->getPattern(i)->forEachVariable([](VarDecl *VD) { - (void) VD->getInterfaceType(); - }); if (!PBD->isInitializerChecked(i)) typeCheckPatternBinding(PBD, i); } @@ -91,15 +91,29 @@ void typeCheckContextImpl(DeclContext *DC, SourceLoc Loc) { } // anonymous namespace void swift::ide::typeCheckContextUntil(DeclContext *DC, SourceLoc Loc) { - // The only time we have to explicitly check a TopLevelCodeDecl - // is when we're directly inside of one. In this case, - // performTypeChecking() did not type check it for us. while (isa(DC)) DC = DC->getParent(); - if (auto *TLCD = dyn_cast(DC)) - typeCheckTopLevelCodeDecl(TLCD); - else + + if (auto *TLCD = dyn_cast(DC)) { + // Typecheck all 'TopLevelCodeDecl's up to the target one. + // In theory, this is not needed, but it fails to resolve the type of + // 'guard'ed variable. e.g. + // + // guard value = something() else { fatalError() } + // + // Here, 'value' is '' unless we explicitly typecheck the + // 'guard' statement. + SourceFile *SF = DC->getParentSourceFile(); + for (auto *D : SF->Decls) { + if (auto Code = dyn_cast(D)) { + typeCheckTopLevelCodeDecl(Code); + if (Code == TLCD) + break; + } + } + } else { typeCheckContextImpl(DC, Loc); + } } //===----------------------------------------------------------------------===// @@ -274,9 +288,6 @@ static void collectPossibleCalleesByQualifiedLookup( if (!isMemberDeclApplied(&DC, baseTy->getMetatypeInstanceType(), VD)) continue; Type declaredMemberType = VD->getInterfaceType(); - if (!declaredMemberType) { - continue; - } if (!declaredMemberType->is()) continue; if (VD->getDeclContext()->isTypeContext()) { diff --git a/lib/IDE/REPLCodeCompletion.cpp b/lib/IDE/REPLCodeCompletion.cpp index c63b76c02dbd4..4d3356c440687 100644 --- a/lib/IDE/REPLCodeCompletion.cpp +++ b/lib/IDE/REPLCodeCompletion.cpp @@ -212,8 +212,7 @@ doCodeCompletion(SourceFile &SF, StringRef EnteredCode, unsigned *BufferID, do { parseIntoSourceFile(SF, *BufferID, &Done, nullptr, &PersistentState); } while (!Done); - performTypeChecking(SF, PersistentState.getTopLevelContext(), None, - OriginalDeclCount); + performTypeChecking(SF, OriginalDeclCount); performCodeCompletionSecondPass(PersistentState, *CompletionCallbacksFactory); diff --git a/lib/IDE/Refactoring.cpp b/lib/IDE/Refactoring.cpp index 88d4ef3650fbf..b148785f6d070 100644 --- a/lib/IDE/Refactoring.cpp +++ b/lib/IDE/Refactoring.cpp @@ -2939,30 +2939,36 @@ static NumberLiteralExpr *getTrailingNumberLiteral(ResolvedCursorInfo Tok) { // This cursor must point to the start of an expression. if (Tok.Kind != CursorInfoKind::ExprStart) return nullptr; - Expr *Parent = Tok.TrailingExpr; - assert(Parent); - - // Check if an expression is a number literal. - auto IsLiteralNumber = [&](Expr *E) -> NumberLiteralExpr* { - if (auto *NL = dyn_cast(E)) { - - // The sub-expression must have the same start loc with the outermost - // expression, i.e. the cursor position. - if (Parent->getStartLoc().getOpaquePointerValue() == - E->getStartLoc().getOpaquePointerValue()) { - return NL; - } - } - return nullptr; - }; + // For every sub-expression, try to find the literal expression that matches // our criteria. - for (auto Pair: Parent->getDepthMap()) { - if (auto Result = IsLiteralNumber(Pair.getFirst())) { - return Result; + class FindLiteralNumber : public ASTWalker { + Expr * const parent; + + public: + NumberLiteralExpr *found = nullptr; + + explicit FindLiteralNumber(Expr *parent) : parent(parent) { } + + std::pair walkToExprPre(Expr *expr) override { + if (auto *literal = dyn_cast(expr)) { + // The sub-expression must have the same start loc with the outermost + // expression, i.e. the cursor position. + if (!found && + parent->getStartLoc().getOpaquePointerValue() == + expr->getStartLoc().getOpaquePointerValue()) { + found = literal; + } + } + + return { found == nullptr, expr }; } - } - return nullptr; + }; + + auto parent = Tok.TrailingExpr; + FindLiteralNumber finder(parent); + parent->walk(finder); + return finder.found; } static std::string insertUnderscore(StringRef Text) { diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 37fa1f0051c22..c3f7aad6a8a31 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -904,10 +904,6 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) { pushStructureNode(SN, NTD); } else if (auto *ED = dyn_cast(D)) { - // Normally bindExtension() would take care of computing the extended - // nominal. It must be done before asking for generic parameters. - if (!inInactiveClause || ASTScope::areInactiveIfConfigClausesSupported()) - ED->computeExtendedNominal(); SyntaxStructureNode SN; setDecl(SN, D); SN.Kind = SyntaxStructureKind::Extension; diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index cd663e30c02e3..c305bfe603ef0 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -3346,10 +3346,43 @@ Explosion NativeConventionSchema::mapIntoNative(IRGenModule &IGM, return nativeExplosion; } -void IRGenFunction::emitScalarReturn(SILType resultType, Explosion &result, +Explosion IRGenFunction::coerceValueTo(SILType fromTy, Explosion &from, + SILType toTy) { + if (fromTy == toTy) + return std::move(from); + + auto &fromTI = cast(IGM.getTypeInfo(fromTy)); + auto &toTI = cast(IGM.getTypeInfo(toTy)); + + Explosion result; + if (fromTI.getStorageType()->isPointerTy() && + toTI.getStorageType()->isPointerTy()) { + auto ptr = from.claimNext(); + ptr = Builder.CreateBitCast(ptr, toTI.getStorageType()); + result.add(ptr); + return result; + } + + auto temporary = toTI.allocateStack(*this, toTy, "coerce.temp"); + + auto addr = + Address(Builder.CreateBitCast(temporary.getAddressPointer(), + fromTI.getStorageType()->getPointerTo()), + temporary.getAlignment()); + fromTI.initialize(*this, from, addr, false); + + toTI.loadAsTake(*this, temporary.getAddress(), result); + toTI.deallocateStack(*this, temporary, toTy); + return result; +} + +void IRGenFunction::emitScalarReturn(SILType returnResultType, + SILType funcResultType, Explosion &result, bool isSwiftCCReturn, bool isOutlined) { if (result.empty()) { - assert(IGM.getTypeInfo(resultType).nativeReturnValueSchema(IGM).empty() && + assert(IGM.getTypeInfo(returnResultType) + .nativeReturnValueSchema(IGM) + .empty() && "Empty explosion must match the native calling convention"); Builder.CreateRetVoid(); @@ -3358,12 +3391,13 @@ void IRGenFunction::emitScalarReturn(SILType resultType, Explosion &result, // In the native case no coercion is needed. if (isSwiftCCReturn) { + result = coerceValueTo(returnResultType, result, funcResultType); auto &nativeSchema = - IGM.getTypeInfo(resultType).nativeReturnValueSchema(IGM); + IGM.getTypeInfo(funcResultType).nativeReturnValueSchema(IGM); assert(!nativeSchema.requiresIndirect()); - Explosion native = - nativeSchema.mapIntoNative(IGM, *this, result, resultType, isOutlined); + Explosion native = nativeSchema.mapIntoNative(IGM, *this, result, + funcResultType, isOutlined); if (native.size() == 1) { Builder.CreateRet(native.claimNext()); return; @@ -3390,7 +3424,7 @@ void IRGenFunction::emitScalarReturn(SILType resultType, Explosion &result, return; } - auto &resultTI = IGM.getTypeInfo(resultType); + auto &resultTI = IGM.getTypeInfo(returnResultType); auto schema = resultTI.getSchema(); auto *bodyType = schema.getScalarResultType(IGM); diff --git a/lib/IRGen/GenClangType.cpp b/lib/IRGen/GenClangType.cpp index 37ec09bf81935..74aeedc3bb8f7 100644 --- a/lib/IRGen/GenClangType.cpp +++ b/lib/IRGen/GenClangType.cpp @@ -324,7 +324,9 @@ ClangTypeConverter::reverseBuiltinTypeMapping(IRGenModule &IGM, // On 64-bit Windows, no C type is imported as an Int or UInt; CLong is // imported as an Int32 and CLongLong as an Int64. Therefore, manually // add mappings to C for Int and UInt. - if (IGM.Triple.isOSWindows() && IGM.Triple.isArch64Bit()) { + // On 64-bit Cygwin, no manual mapping is required. + if (IGM.Triple.isOSWindows() && !IGM.Triple.isWindowsCygwinEnvironment() && + IGM.Triple.isArch64Bit()) { // Map UInt to uintptr_t auto swiftUIntType = getNamedSwiftType(stdlib, "UInt"); auto clangUIntPtrType = ctx.getCanonicalType(ctx.getUIntPtrType()); diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index e5a379f927d4a..f120032ca8901 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -297,7 +297,8 @@ namespace { SILType classType, bool superclass) { for (VarDecl *var : theClass->getStoredProperties()) { - SILType type = classType.getFieldType(var, IGM.getSILModule()); + SILType type = classType.getFieldType(var, IGM.getSILModule(), + TypeExpansionContext::minimal()); // Lower the field type. auto *eltType = &IGM.getTypeInfo(type); @@ -500,23 +501,20 @@ Address IRGenFunction::emitByteOffsetGEP(llvm::Value *base, } /// Emit a field l-value by applying the given offset to the given base. -static OwnedAddress emitAddressAtOffset(IRGenFunction &IGF, - SILType baseType, - llvm::Value *base, - llvm::Value *offset, +static OwnedAddress emitAddressAtOffset(IRGenFunction &IGF, SILType baseType, + llvm::Value *base, llvm::Value *offset, VarDecl *field) { - auto &fieldTI = - IGF.getTypeInfo(baseType.getFieldType(field, IGF.getSILModule())); + auto &fieldTI = IGF.getTypeInfo(baseType.getFieldType( + field, IGF.getSILModule(), IGF.IGM.getMaximalTypeExpansionContext())); auto addr = IGF.emitByteOffsetGEP(base, offset, fieldTI, base->getName() + "." + field->getName().str()); return OwnedAddress(addr, base); } -llvm::Constant * -irgen::tryEmitConstantClassFragilePhysicalMemberOffset(IRGenModule &IGM, - SILType baseType, - VarDecl *field) { - auto fieldType = baseType.getFieldType(field, IGM.getSILModule()); +llvm::Constant *irgen::tryEmitConstantClassFragilePhysicalMemberOffset( + IRGenModule &IGM, SILType baseType, VarDecl *field) { + auto fieldType = baseType.getFieldType(field, IGM.getSILModule(), + IGM.getMaximalTypeExpansionContext()); // If the field is empty, its address doesn't matter. auto &fieldTI = IGM.getTypeInfo(fieldType); if (fieldTI.isKnownEmpty(ResilienceExpansion::Maximal)) { @@ -2423,12 +2421,13 @@ FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF, return FunctionPointer(fnPtr, signature); } -FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF, - llvm::Value *base, - SILType baseType, - SILDeclRef method, - CanSILFunctionType methodType, - bool useSuperVTable) { +FunctionPointer +irgen::emitVirtualMethodValue(IRGenFunction &IGF, + llvm::Value *base, + SILType baseType, + SILDeclRef method, + CanSILFunctionType methodType, + bool useSuperVTable) { // Find the metadata. llvm::Value *metadata; if (useSuperVTable) { diff --git a/lib/IRGen/GenClass.h b/lib/IRGen/GenClass.h index b7fdf7f758d87..66018fbfb7b8d 100644 --- a/lib/IRGen/GenClass.h +++ b/lib/IRGen/GenClass.h @@ -50,12 +50,10 @@ namespace irgen { enum class ClassDeallocationKind : unsigned char; enum class FieldAccess : uint8_t; - - OwnedAddress projectPhysicalClassMemberAddress(IRGenFunction &IGF, - llvm::Value *base, - SILType baseType, - SILType fieldType, - VarDecl *field); + + OwnedAddress projectPhysicalClassMemberAddress( + IRGenFunction &IGF, llvm::Value *base, + SILType baseType, SILType fieldType, VarDecl *field); /// Return a strategy for accessing the given stored class property. /// @@ -180,11 +178,9 @@ namespace irgen { /// Emit the constant fragile offset of the given property inside an instance /// of the class. - llvm::Constant * - tryEmitConstantClassFragilePhysicalMemberOffset(IRGenModule &IGM, - SILType baseType, - VarDecl *field); - + llvm::Constant *tryEmitConstantClassFragilePhysicalMemberOffset( + IRGenModule &IGM, SILType baseType, VarDecl *field); + FieldAccess getClassFieldAccess(IRGenModule &IGM, SILType baseType, VarDecl *field); @@ -208,10 +204,8 @@ namespace irgen { /// Given an instance pointer (or, for a static method, a class /// pointer), emit the callee for the given method. - FunctionPointer emitVirtualMethodValue(IRGenFunction &IGF, - llvm::Value *base, - SILType baseType, - SILDeclRef method, + FunctionPointer emitVirtualMethodValue(IRGenFunction &IGF, llvm::Value *base, + SILType baseType, SILDeclRef method, CanSILFunctionType methodType, bool useSuperVTable); diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 72283ab27c56b..9cf8fcaad0f8b 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1281,6 +1281,17 @@ void IRGenerator::noteUseOfTypeGlobals(NominalTypeDecl *type, if (!hasLazyMetadata(type)) return; + // If the type can be generated in several TU with weak linkage we don't know + // which one will be picked up so we have to require the metadata. Otherwise, + // the situation can arise where one TU contains a type descriptor with a null + // metadata access function and the other TU which requires metadata has a + // type descriptor with a valid metadata access function but the linker picks + // the first one. + if (isAccessorLazilyGenerated(getTypeMetadataAccessStrategy( + type->getDeclaredType()->getCanonicalType()))) { + requireMetadata = RequireMetadata; + } + // Try to create a new record of the fact that we used this type. auto insertResult = LazyTypeGlobals.try_emplace(type); auto &entry = insertResult.first->second; diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index 674a22ab0c052..c6e07d16b6c57 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -315,9 +315,10 @@ namespace { SILType getSingletonType(IRGenModule &IGM, SILType T) const { assert(!ElementsWithPayload.empty()); - + return T.getEnumElementType(ElementsWithPayload[0].decl, - IGM.getSILModule()); + IGM.getSILModule(), + IGM.getMaximalTypeExpansionContext()); } public: @@ -614,8 +615,9 @@ namespace { assert(ElementsWithPayload.size() == 1 && "empty singleton enum should not be dynamic!"); - auto payloadTy = T.getEnumElementType(ElementsWithPayload[0].decl, - IGM.getSILModule()); + auto payloadTy = T.getEnumElementType( + ElementsWithPayload[0].decl, IGM.getSILModule(), + IGM.getMaximalTypeExpansionContext()); auto payloadLayout = emitTypeLayoutRef(IGF, payloadTy, collector); auto flags = emitEnumLayoutFlags(IGF.IGM, isVWTMutable); IGF.Builder.CreateCall( @@ -1567,7 +1569,8 @@ namespace { SILType getPayloadType(IRGenModule &IGM, SILType T) const { return T.getEnumElementType(ElementsWithPayload[0].decl, - IGM.getSILModule()); + IGM.getSILModule(), + IGM.getMaximalTypeExpansionContext()); } const TypeInfo &getPayloadTypeInfo() const { @@ -2957,8 +2960,9 @@ namespace { // Ask the runtime to do our layout using the payload metadata and number // of empty cases. - auto payloadTy = T.getEnumElementType(ElementsWithPayload[0].decl, - IGM.getSILModule()); + auto payloadTy = + T.getEnumElementType(ElementsWithPayload[0].decl, IGM.getSILModule(), + IGM.getMaximalTypeExpansionContext()); auto payloadLayout = emitTypeLayoutRef(IGF, payloadTy, collector); auto emptyCasesVal = llvm::ConstantInt::get(IGM.Int32Ty, ElementsWithNoPayload.size()); @@ -4575,8 +4579,9 @@ namespace { unsigned tagIndex = 0; for (auto &payloadCasePair : ElementsWithPayload) { - SILType PayloadT = T.getEnumElementType(payloadCasePair.decl, - IGF.getSILModule()); + SILType PayloadT = + T.getEnumElementType(payloadCasePair.decl, IGF.getSILModule(), + IGF.IGM.getMaximalTypeExpansionContext()); auto &payloadTI = *payloadCasePair.ti; // Trivial and, in the case of a take, bitwise-takable payloads, // can all share the default path. @@ -4692,9 +4697,9 @@ namespace { } for (auto &payloadCasePair : ElementsWithPayload) { - SILType payloadT = - T.getEnumElementType(payloadCasePair.decl, - collector.IGF.getSILModule()); + SILType payloadT = T.getEnumElementType( + payloadCasePair.decl, collector.IGF.getSILModule(), + collector.IGF.IGM.getMaximalTypeExpansionContext()); auto &payloadTI = *payloadCasePair.ti; payloadTI.collectMetadataForOutlining(collector, payloadT); } @@ -4737,8 +4742,9 @@ namespace { // Destroy the data. Address dataAddr = IGF.Builder.CreateBitCast( addr, elt.ti->getStorageType()->getPointerTo()); - SILType payloadT = - T.getEnumElementType(elt.decl, IGF.getSILModule()); + SILType payloadT = T.getEnumElementType( + elt.decl, IGF.getSILModule(), + IGF.IGM.getMaximalTypeExpansionContext()); elt.ti->destroy(IGF, dataAddr, payloadT, true /*isOutlined*/); }); return; @@ -4977,9 +4983,11 @@ namespace { Address eltAddr = IGF.Builder.CreateStructGEP(metadataBuffer, i, IGM.getPointerSize() * i); if (i == 0) firstAddr = eltAddr.getAddress(); - - auto payloadTy = T.getEnumElementType(elt.decl, IGF.getSILModule()); - + + auto payloadTy = + T.getEnumElementType(elt.decl, IGF.getSILModule(), + IGF.IGM.getMaximalTypeExpansionContext()); + auto metadata = emitTypeLayoutRef(IGF, payloadTy, collector); IGF.Builder.CreateStore(metadata, eltAddr); @@ -5809,7 +5817,8 @@ EnumImplStrategy::get(TypeConverter &TC, SILType type, EnumDecl *theEnum) { // *Now* apply the substitutions and get the type info for the instance's // payload type, since we know this case carries an apparent payload in // the generic case. - SILType fieldTy = type.getEnumElementType(elt, TC.IGM.getSILModule()); + SILType fieldTy = type.getEnumElementType( + elt, TC.IGM.getSILModule(), TC.IGM.getMaximalTypeExpansionContext()); auto *substArgTI = &TC.IGM.getTypeInfo(fieldTy); elementsWithPayload.push_back({elt, substArgTI, origArgTI}); diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp index e5f71d7a35e9e..7121029b5f285 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -1160,8 +1160,11 @@ static llvm::Function *emitPartialApplicationForwarder(IRGenModule &IGM, FunctionPointer fnPtr = [&]() -> FunctionPointer { // If we found a function pointer statically, great. if (staticFnPtr) { - assert(staticFnPtr->getPointer()->getType() == fnTy && - "static function type mismatch?!"); + if (staticFnPtr->getPointer()->getType() != fnTy) { + auto fnPtr = staticFnPtr->getPointer(); + fnPtr = subIGF.Builder.CreateBitCast(fnPtr, fnTy); + return FunctionPointer(fnPtr, origSig); + } return *staticFnPtr; } diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp index d3dc107dd68e5..9bb4ecbd0ccbb 100644 --- a/lib/IRGen/GenHeap.cpp +++ b/lib/IRGen/GenHeap.cpp @@ -1528,8 +1528,8 @@ const TypeInfo *TypeConverter::convertBoxType(SILBoxType *T) { // TODO: Multi-field boxes assert(T->getLayout()->getFields().size() == 1 && "multi-field boxes not implemented yet"); - auto &eltTI = IGM.getTypeInfoForLowered( - getSILBoxFieldLoweredType(T, IGM.getSILModule().Types, 0)); + auto &eltTI = IGM.getTypeInfoForLowered(getSILBoxFieldLoweredType( + IGM.getMaximalTypeExpansionContext(), T, IGM.getSILModule().Types, 0)); if (!eltTI.isFixedSize()) { if (!NonFixedBoxTI) NonFixedBoxTI = new NonFixedBoxTypeInfo(IGM); @@ -1577,8 +1577,9 @@ const TypeInfo *TypeConverter::convertBoxType(SILBoxType *T) { // Produce a tailored box metadata for the type. assert(T->getLayout()->getFields().size() == 1 && "multi-field boxes not implemented yet"); - return new FixedBoxTypeInfo(IGM, - getSILBoxFieldType(T, IGM.getSILModule().Types, 0)); + return new FixedBoxTypeInfo( + IGM, getSILBoxFieldType(IGM.getMaximalTypeExpansionContext(), + T, IGM.getSILModule().Types, 0)); } OwnedAddress @@ -1588,9 +1589,12 @@ irgen::emitAllocateBox(IRGenFunction &IGF, CanSILBoxType boxType, auto &boxTI = IGF.getTypeInfoForLowered(boxType).as(); assert(boxType->getLayout()->getFields().size() == 1 && "multi-field boxes not implemented yet"); - return boxTI.allocate(IGF, - getSILBoxFieldType(boxType, IGF.IGM.getSILModule().Types, 0), - env, name); + return boxTI.allocate( + IGF, + getSILBoxFieldType( + IGF.IGM.getMaximalTypeExpansionContext(), + boxType, IGF.IGM.getSILModule().Types, 0), + env, name); } void irgen::emitDeallocateBox(IRGenFunction &IGF, @@ -1599,8 +1603,10 @@ void irgen::emitDeallocateBox(IRGenFunction &IGF, auto &boxTI = IGF.getTypeInfoForLowered(boxType).as(); assert(boxType->getLayout()->getFields().size() == 1 && "multi-field boxes not implemented yet"); - return boxTI.deallocate(IGF, box, - getSILBoxFieldType(boxType, IGF.IGM.getSILModule().Types, 0)); + return boxTI.deallocate( + IGF, box, + getSILBoxFieldType(IGF.IGM.getMaximalTypeExpansionContext(), boxType, + IGF.IGM.getSILModule().Types, 0)); } Address irgen::emitProjectBox(IRGenFunction &IGF, @@ -1609,8 +1615,10 @@ Address irgen::emitProjectBox(IRGenFunction &IGF, auto &boxTI = IGF.getTypeInfoForLowered(boxType).as(); assert(boxType->getLayout()->getFields().size() == 1 && "multi-field boxes not implemented yet"); - return boxTI.project(IGF, box, - getSILBoxFieldType(boxType, IGF.IGM.getSILModule().Types, 0)); + return boxTI.project( + IGF, box, + getSILBoxFieldType(IGF.IGM.getMaximalTypeExpansionContext(), boxType, + IGF.IGM.getSILModule().Types, 0)); } Address irgen::emitAllocateExistentialBoxInBuffer( diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index f5eb1d120a201..9952ceb1df6c4 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -790,9 +790,8 @@ emitKeyPathComponent(IRGenModule &IGM, switch (getClassFieldAccess(IGM, loweredBaseContextTy, property)) { case FieldAccess::ConstantDirect: { // Known constant fixed offset. - auto offset = tryEmitConstantClassFragilePhysicalMemberOffset(IGM, - loweredClassTy, - property); + auto offset = tryEmitConstantClassFragilePhysicalMemberOffset( + IGM, loweredClassTy, property); assert(offset && "no constant offset for ConstantDirect field?!"); addFixedOffset(/*struct*/ false, property->isLet(), offset); break; diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index c62ca4b472e4b..00cd6db8fd14a 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -1939,7 +1939,8 @@ static void emitInitializeFieldOffsetVector(IRGenFunction &IGF, unsigned index = 0; for (auto prop : storedProperties) { - auto propTy = T.getFieldType(prop, IGF.getSILModule()); + auto propTy = T.getFieldType(prop, IGF.getSILModule(), + TypeExpansionContext::minimal()); llvm::Value *metadata = emitTypeLayoutRef(IGF, propTy, collector); Address field = IGF.Builder.CreateConstArrayGEP(fields, index, IGM.getPointerSize()); @@ -3606,8 +3607,10 @@ namespace { B.add(offset); return; } - assert(IGM.getTypeInfo(Type.getFieldType(field, IGM.getSILModule())) - .isKnownEmpty(ResilienceExpansion::Maximal)); + assert(IGM.getTypeInfo( + Type.getFieldType(field, IGM.getSILModule(), + TypeExpansionContext::minimal())) + .isKnownEmpty(ResilienceExpansion::Maximal)); B.addInt32(0); } diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp index e4b3d5f288241..bb65387cfb82e 100644 --- a/lib/IRGen/GenObjC.cpp +++ b/lib/IRGen/GenObjC.cpp @@ -858,8 +858,8 @@ static llvm::Function *emitObjCPartialApplicationForwarder(IRGenModule &IGM, auto &callee = emission.getCallee(); auto resultType = callee.getOrigFunctionType()->getDirectFormalResultsType(IGM.getSILModule()); - subIGF.emitScalarReturn(resultType, result, true /*isSwiftCCReturn*/, - false); + subIGF.emitScalarReturn(resultType, resultType, result, + true /*isSwiftCCReturn*/, false); } return fwd; @@ -1018,8 +1018,9 @@ static SILDeclRef getObjCMethodRef(AbstractFunctionDecl *method) { } static CanSILFunctionType getObjCMethodType(IRGenModule &IGM, - AbstractFunctionDecl *method) { - return IGM.getSILTypes().getConstantFunctionType(getObjCMethodRef(method)); + AbstractFunctionDecl *method) { + return IGM.getSILTypes().getConstantFunctionType( + TypeExpansionContext::minimal(), getObjCMethodRef(method)); } static clang::CanQualType getObjCPropertyType(IRGenModule &IGM, diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index e7fa291f37ef2..7fe09ffeda407 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -3186,10 +3186,9 @@ void irgen::expandTrailingWitnessSignature(IRGenModule &IGM, out.push_back(IGM.WitnessTablePtrTy); } -FunctionPointer -irgen::emitWitnessMethodValue(IRGenFunction &IGF, - llvm::Value *wtable, - SILDeclRef member) { +FunctionPointer irgen::emitWitnessMethodValue(IRGenFunction &IGF, + llvm::Value *wtable, + SILDeclRef member) { auto *fn = cast(member.getDecl()); auto proto = cast(fn->getDeclContext()); @@ -3203,7 +3202,8 @@ irgen::emitWitnessMethodValue(IRGenFunction &IGF, emitInvariantLoadOfOpaqueWitness(IGF, wtable, index.forProtocolWitnessTable()); - auto fnType = IGF.IGM.getSILTypes().getConstantFunctionType(member); + auto fnType = IGF.IGM.getSILTypes().getConstantFunctionType( + IGF.IGM.getMaximalTypeExpansionContext(), member); Signature signature = IGF.IGM.getSignature(fnType); witnessFnPtr = IGF.Builder.CreateBitCast(witnessFnPtr, signature.getType()->getPointerTo()); @@ -3211,12 +3211,9 @@ irgen::emitWitnessMethodValue(IRGenFunction &IGF, return FunctionPointer(witnessFnPtr, signature); } -FunctionPointer -irgen::emitWitnessMethodValue(IRGenFunction &IGF, - CanType baseTy, - llvm::Value **baseMetadataCache, - SILDeclRef member, - ProtocolConformanceRef conformance) { +FunctionPointer irgen::emitWitnessMethodValue( + IRGenFunction &IGF, CanType baseTy, llvm::Value **baseMetadataCache, + SILDeclRef member, ProtocolConformanceRef conformance) { llvm::Value *wtable = emitWitnessTableRef(IGF, baseTy, baseMetadataCache, conformance); diff --git a/lib/IRGen/GenProto.h b/lib/IRGen/GenProto.h index 7d602cc80b291..f91b802841c85 100644 --- a/lib/IRGen/GenProto.h +++ b/lib/IRGen/GenProto.h @@ -64,8 +64,7 @@ namespace irgen { /// Extract the method pointer from an archetype's witness table /// as a function value. - FunctionPointer emitWitnessMethodValue(IRGenFunction &IGF, - CanType baseTy, + FunctionPointer emitWitnessMethodValue(IRGenFunction &IGF, CanType baseTy, llvm::Value **baseMetadataCache, SILDeclRef member, ProtocolConformanceRef conformance); diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index bd273beda33aa..c6eceff88c938 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -74,7 +74,8 @@ namespace { } SILType getType(IRGenModule &IGM, SILType T) const { - return T.getFieldType(Field, IGM.getSILModule()); + return T.getFieldType(Field, IGM.getSILModule(), + IGM.getMaximalTypeExpansionContext()); } }; @@ -95,7 +96,8 @@ namespace { SILType getType(IRGenModule &IGM, SILType T) const { if (Field) - return T.getFieldType(Field, IGM.getSILModule()); + return T.getFieldType(Field, IGM.getSILModule(), + IGM.getMaximalTypeExpansionContext()); // The Swift-field-less cases use opaque storage, which is // guaranteed to ignore the type passed to it. @@ -592,7 +594,9 @@ namespace { SILType getType(VarDecl *field) { assert(field->getDeclContext() == TheStruct->getAnyNominal()); auto silType = SILType::getPrimitiveAddressType(TheStruct); - return silType.getFieldType(field, IGM.getSILModule()); + return silType.getFieldType( + field, IGM.getSILModule(), + IGM.getMaximalTypeExpansionContext()); } StructLayout performLayout(ArrayRef fieldTypes) { @@ -733,8 +737,9 @@ class ClangRecordLowering { // If we have a Swift import of this type, use our lowered information. if (swiftField) { - auto &fieldTI = cast( - IGM.getTypeInfo(SwiftType.getFieldType(swiftField, IGM.getSILModule()))); + auto &fieldTI = cast(IGM.getTypeInfo( + SwiftType.getFieldType(swiftField, IGM.getSILModule(), + IGM.getMaximalTypeExpansionContext()))); addField(swiftField, offset, fieldTI); return; } diff --git a/lib/IRGen/GenThunk.cpp b/lib/IRGen/GenThunk.cpp index cdc9ffa7c8e84..db4d67356ac81 100644 --- a/lib/IRGen/GenThunk.cpp +++ b/lib/IRGen/GenThunk.cpp @@ -46,7 +46,8 @@ IRGenModule::getAddrOfDispatchThunk(SILDeclRef declRef, return entry; } - auto fnType = getSILModule().Types.getConstantFunctionType(declRef); + auto fnType = getSILModule().Types.getConstantFunctionType( + getMaximalTypeExpansionContext(), declRef); Signature signature = getSignature(fnType); LinkInfo link = LinkInfo::get(*this, entity, forDefinition); @@ -54,8 +55,8 @@ IRGenModule::getAddrOfDispatchThunk(SILDeclRef declRef, return entry; } -static FunctionPointer lookupMethod(IRGenFunction &IGF, - SILDeclRef declRef) { +static FunctionPointer lookupMethod(IRGenFunction &IGF, SILDeclRef declRef) { + auto expansionContext = IGF.IGM.getMaximalTypeExpansionContext(); auto *decl = cast(declRef.getDecl()); // Protocol case. @@ -68,7 +69,8 @@ static FunctionPointer lookupMethod(IRGenFunction &IGF, } // Class case. - auto funcTy = IGF.IGM.getSILModule().Types.getConstantFunctionType(declRef); + auto funcTy = IGF.IGM.getSILModule().Types.getConstantFunctionType( + expansionContext, declRef); // Load the metadata, or use the 'self' value if we have a static method. llvm::Value *self; diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index 4ba497af06556..6798b24bb23dc 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -1466,25 +1466,25 @@ const TypeInfo &IRGenFunction::getTypeInfo(SILType T) { /// Return the SIL-lowering of the given type. SILType IRGenModule::getLoweredType(AbstractionPattern orig, Type subst) const { - return getSILTypes().getLoweredType(orig, subst, - ResilienceExpansion::Maximal); + return getSILTypes().getLoweredType( + orig, subst, TypeExpansionContext::maximalResilienceExpansionOnly()); } /// Return the SIL-lowering of the given type. SILType IRGenModule::getLoweredType(Type subst) const { - return getSILTypes().getLoweredType(subst, - ResilienceExpansion::Maximal); + return getSILTypes().getLoweredType( + subst, TypeExpansionContext::maximalResilienceExpansionOnly()); } /// Return the SIL-lowering of the given type. const Lowering::TypeLowering &IRGenModule::getTypeLowering(SILType type) const { - return getSILTypes().getTypeLowering(type, - ResilienceExpansion::Maximal); + return getSILTypes().getTypeLowering( + type, TypeExpansionContext::maximalResilienceExpansionOnly()); } bool IRGenModule::isTypeABIAccessible(SILType type) const { - return getSILModule().isTypeABIAccessible(type, - ResilienceExpansion::Maximal); + return getSILModule().isTypeABIAccessible( + type, TypeExpansionContext::maximalResilienceExpansionOnly()); } /// Get a pointer to the storage type for the given type. Note that, @@ -2307,7 +2307,10 @@ SILType irgen::getSingletonAggregateFieldType(IRGenModule &IGM, SILType t, auto allFields = structDecl->getStoredProperties(); if (allFields.size() == 1) { - auto fieldTy = t.getFieldType(allFields[0], IGM.getSILModule()); + auto fieldTy = t.getFieldType( + allFields[0], IGM.getSILModule(), + TypeExpansionContext(expansion, IGM.getSwiftModule(), + IGM.getSILModule().isWholeModule())); if (!IGM.isTypeABIAccessible(fieldTy)) return SILType(); return fieldTy; @@ -2327,7 +2330,10 @@ SILType irgen::getSingletonAggregateFieldType(IRGenModule &IGM, SILType t, auto theCase = allCases.begin(); if (!allCases.empty() && std::next(theCase) == allCases.end() && (*theCase)->hasAssociatedValues()) { - auto enumEltTy = t.getEnumElementType(*theCase, IGM.getSILModule()); + auto enumEltTy = t.getEnumElementType( + *theCase, IGM.getSILModule(), + TypeExpansionContext(expansion, IGM.getSwiftModule(), + IGM.getSILModule().isWholeModule())); if (!IGM.isTypeABIAccessible(enumEltTy)) return SILType(); return enumEltTy; diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index a7f3fc0643fbe..35cb5ea6a46a8 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -126,8 +126,14 @@ static void addSwiftMergeFunctionsPass(const PassManagerBuilder &Builder, static void addAddressSanitizerPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { - PM.add(createAddressSanitizerFunctionPass()); - PM.add(createModuleAddressSanitizerLegacyPassPass()); + auto &BuilderWrapper = + static_cast(Builder); + auto recover = + bool(BuilderWrapper.IRGOpts.SanitizersWithRecoveryInstrumentation & + SanitizerKind::Address); + PM.add(createAddressSanitizerFunctionPass(/*CompileKernel=*/false, recover)); + PM.add(createModuleAddressSanitizerLegacyPassPass(/*CompileKernel=*/false, + recover)); } static void addThreadSanitizerPass(const PassManagerBuilder &Builder, @@ -670,10 +676,17 @@ swift::createTargetMachine(IRGenOptions &Opts, ASTContext &Ctx) { } + // On Cygwin 64 bit, dlls are loaded above the max address for 32 bits. + // This means that the default CodeModel causes generated code to segfault + // when run. + Optional cmodel = None; + if (EffectiveTriple.isArch64Bit() && EffectiveTriple.isWindowsCygwinEnvironment()) + cmodel = CodeModel::Large; + // Create a target machine. llvm::TargetMachine *TargetMachine = Target->createTargetMachine( EffectiveTriple.str(), CPU, targetFeatures, TargetOpts, Reloc::PIC_, - None, OptLevel); + cmodel, OptLevel); if (!TargetMachine) { Ctx.Diags.diagnose(SourceLoc(), diag::no_llvm_target, EffectiveTriple.str(), "no LLVM target machine"); @@ -864,7 +877,7 @@ performIRGeneration(IRGenOptions &Opts, ModuleDecl *M, runIRGenPreparePasses(*SILMod, IGM); { - SharedTimer timer("IRGen"); + FrontendStatsTracer tracer(Ctx.Stats, "IRGen"); // Emit the module contents. irgen.emitGlobalTopLevel(); @@ -935,7 +948,7 @@ performIRGeneration(IRGenOptions &Opts, ModuleDecl *M, if (outModuleHash) { *outModuleHash = IGM.ModuleHash; } else { - SharedTimer timer("LLVM pipeline"); + FrontendStatsTracer tracer(Ctx.Stats, "LLVM pipeline"); // Since no out module hash was set, we need to performLLVM. if (performLLVM(Opts, &IGM.Context.Diags, nullptr, IGM.ModuleHash, @@ -1223,7 +1236,7 @@ static void performParallelIRGeneration( // Bail out if there are any errors. if (Ctx.hadError()) return; - SharedTimer timer("LLVM pipeline"); + FrontendStatsTracer tracer(Ctx.Stats, "LLVM pipeline"); llvm::sys::Mutex DiagMutex; diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h index 3ef32d7c19674..0a1affaf92acb 100644 --- a/lib/IRGen/IRGenFunction.h +++ b/lib/IRGen/IRGenFunction.h @@ -92,8 +92,9 @@ class IRGenFunction { //--- Function prologue and epilogue ------------------------------------------- public: Explosion collectParameters(); - void emitScalarReturn(SILType resultTy, Explosion &scalars, - bool isSwiftCCReturn, bool isOutlined); + void emitScalarReturn(SILType returnResultType, SILType funcResultType, + Explosion &scalars, bool isSwiftCCReturn, + bool isOutlined); void emitScalarReturn(llvm::Type *resultTy, Explosion &scalars); void emitBBForReturn(); @@ -280,6 +281,7 @@ class IRGenFunction { const SILDebugScope *getDebugScope() const { return DbgScope; } llvm::Value *coerceValue(llvm::Value *value, llvm::Type *toTy, const llvm::DataLayout &); + Explosion coerceValueTo(SILType fromTy, Explosion &from, SILType toTy); /// Mark a load as invariant. void setInvariantLoad(llvm::LoadInst *load); diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index d089cb385c07b..9f388dadc6c0b 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -1392,3 +1392,8 @@ const llvm::DataLayout &IRGenerator::getClangDataLayout() { ->getTargetInfo() .getDataLayout(); } + +TypeExpansionContext IRGenModule::getMaximalTypeExpansionContext() const { + return TypeExpansionContext::maximal(getSwiftModule(), + getSILModule().isWholeModule()); +} diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 9a8a3975960df..33d840e36e44e 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -842,6 +842,8 @@ class IRGenModule { ResilienceExpansion getResilienceExpansionForLayout(NominalTypeDecl *decl); ResilienceExpansion getResilienceExpansionForLayout(SILGlobalVariable *var); + TypeExpansionContext getMaximalTypeExpansionContext() const; + bool isResilientConformance(const NormalProtocolConformance *conformance); bool isResilientConformance(const RootProtocolConformance *root); bool isDependentConformance(const RootProtocolConformance *conformance); diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 1ee8058e39425..18433a2ed8e94 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -623,6 +623,16 @@ class IRGenSILFunction : return foundBB->second; } + TypeExpansionContext getExpansionContext() { + return TypeExpansionContext(*CurSILFn); + } + + SILType getLoweredTypeInContext(SILType ty) { + return CurSILFn->getModule() + .Types.getLoweredType(ty.getASTType(), getExpansionContext()) + .getCategoryType(ty.getCategory()); + } + StringRef getOrCreateAnonymousVarName(VarDecl *Decl) { llvm::SmallString<4> &Name = AnonymousVariables[Decl]; if (Name.empty()) { @@ -1354,41 +1364,72 @@ static ArrayRef emitEntryPointIndirectReturn( SILType directResultType = IGF.CurSILFn->mapTypeIntoContext(fnConv.getSILResultType()); if (requiresIndirectResult(directResultType)) { - auto &retTI = IGF.IGM.getTypeInfo(directResultType); - IGF.IndirectReturn = retTI.getAddressForPointer(params.claimNext()); + auto ¶mTI = IGF.IGM.getTypeInfo(directResultType); + auto &retTI = + IGF.IGM.getTypeInfo(IGF.getLoweredTypeInContext(directResultType)); + auto ptr = params.claimNext(); + if (paramTI.getStorageType() != retTI.getStorageType()) { + assert(directResultType.getASTType()->hasOpaqueArchetype()); + ptr = IGF.Builder.CreateBitCast(ptr, + retTI.getStorageType()->getPointerTo()); + } + IGF.IndirectReturn = retTI.getAddressForPointer(ptr); } auto bbargs = entry->getArguments(); // Map the indirect returns if present. unsigned numIndirectResults = fnConv.getNumIndirectSILResults(); - for (unsigned i = 0; i != numIndirectResults; ++i) { - SILArgument *ret = bbargs[i]; - auto &retTI = IGF.IGM.getTypeInfo(ret->getType()); - IGF.setLoweredAddress(ret, retTI.getAddressForPointer(params.claimNext())); - } + unsigned idx = 0; + for (auto indirectResultType : fnConv.getIndirectSILResultTypes()) { + SILArgument *ret = bbargs[idx]; + auto inContextResultType = + IGF.CurSILFn->mapTypeIntoContext(indirectResultType); + auto &retTI = IGF.IGM.getTypeInfo(ret->getType()); + // The parameter's type might be different due to looking through opaque + // archetypes. + auto ptr = params.claimNext(); + auto ¶mTI = IGF.IGM.getTypeInfo(inContextResultType); + if (paramTI.getStorageType() != retTI.getStorageType()) { + assert(inContextResultType.getASTType()->hasOpaqueArchetype()); + ptr = IGF.Builder.CreateBitCast(ptr, + retTI.getStorageType()->getPointerTo()); + } + auto addr = retTI.getAddressForPointer(ptr); + IGF.setLoweredAddress(ret, addr); + ++idx; + } + assert(numIndirectResults == idx); return bbargs.slice(numIndirectResults); } static void bindParameter(IRGenSILFunction &IGF, SILArgument *param, + SILType paramTy, Explosion &allParamValues) { // Pull out the parameter value and its formal type. - auto ¶mTI = IGF.getTypeInfo(param->getType()); + auto ¶mTI = IGF.getTypeInfo(IGF.CurSILFn->mapTypeIntoContext(paramTy)); + auto &argTI = IGF.getTypeInfo(param->getType()); // If the SIL parameter isn't passed indirectly, we need to map it // to an explosion. if (param->getType().isObject()) { Explosion paramValues; - auto &loadableTI = cast(paramTI); + auto &loadableParamTI = cast(paramTI); + auto &loadableArgTI = cast(paramTI); // If the explosion must be passed indirectly, load the value from the // indirect address. - auto &nativeSchema = paramTI.nativeParameterValueSchema(IGF.IGM); + auto &nativeSchema = argTI.nativeParameterValueSchema(IGF.IGM); if (nativeSchema.requiresIndirect()) { - Address paramAddr - = loadableTI.getAddressForPointer(allParamValues.claimNext()); - loadableTI.loadAsTake(IGF, paramAddr, paramValues); + Address paramAddr = + loadableParamTI.getAddressForPointer(allParamValues.claimNext()); + if (paramTI.getStorageType() != argTI.getStorageType()) + paramAddr = + loadableArgTI.getAddressForPointer(IGF.Builder.CreateBitCast( + paramAddr.getAddress(), + loadableArgTI.getStorageType()->getPointerTo())); + loadableArgTI.loadAsTake(IGF, paramAddr, paramValues); } else { if (!nativeSchema.empty()) { // Otherwise, we map from the native convention to the type's explosion @@ -1410,8 +1451,12 @@ static void bindParameter(IRGenSILFunction &IGF, // FIXME: that doesn't mean we should physically pass it // indirectly at this resilience expansion. An @in or @in_guaranteed parameter // could be passed by value in the right resilience domain. - Address paramAddr - = paramTI.getAddressForPointer(allParamValues.claimNext()); + auto ptr = allParamValues.claimNext(); + if (paramTI.getStorageType() != argTI.getStorageType()) { + ptr = + IGF.Builder.CreateBitCast(ptr, argTI.getStorageType()->getPointerTo()); + } + Address paramAddr = argTI.getAddressForPointer(ptr); IGF.setLoweredAddress(param, paramAddr); } @@ -1441,7 +1486,6 @@ static void emitEntryPointArgumentsNativeCC(IRGenSILFunction &IGF, if (funcTy->hasErrorResult()) { IGF.setErrorResultSlot(allParamValues.takeLast()); } - // The coroutine context should be the first parameter. switch (funcTy->getCoroutineKind()) { case SILCoroutineKind::None: @@ -1454,6 +1498,8 @@ static void emitEntryPointArgumentsNativeCC(IRGenSILFunction &IGF, break; } + SILFunctionConventions conv(funcTy, IGF.getSILModule()); + // The 'self' argument might be in the context position, which is // now the end of the parameter list. Bind it now. if (hasSelfContextParameter(funcTy)) { @@ -1462,10 +1508,12 @@ static void emitEntryPointArgumentsNativeCC(IRGenSILFunction &IGF, Explosion selfTemp; selfTemp.add(allParamValues.takeLast()); - bindParameter(IGF, selfParam, selfTemp); + bindParameter(IGF, selfParam, + conv.getSILArgumentType(conv.getNumSILArguments() - 1), + selfTemp); - // Even if we don't have a 'self', if we have an error result, we - // should have a placeholder argument here. + // Even if we don't have a 'self', if we have an error result, we + // should have a placeholder argument here. } else if (funcTy->hasErrorResult() || funcTy->getRepresentation() == SILFunctionTypeRepresentation::Thick) { @@ -1474,8 +1522,11 @@ static void emitEntryPointArgumentsNativeCC(IRGenSILFunction &IGF, } // Map the remaining SIL parameters to LLVM parameters. + unsigned i = 0; for (SILArgument *param : params) { - bindParameter(IGF, param, allParamValues); + auto argIdx = conv.getSILArgIndexOfFirstParam() + i; + bindParameter(IGF, param, conv.getSILArgumentType(argIdx), allParamValues); + ++i; } // Bind polymorphic arguments. This can only be done after binding @@ -2012,7 +2063,7 @@ void IRGenSILFunction::visitAllocGlobalInst(AllocGlobalInst *i) { void IRGenSILFunction::visitGlobalAddrInst(GlobalAddrInst *i) { SILGlobalVariable *var = i->getReferencedGlobal(); - SILType loweredTy = var->getLoweredType(); + SILType loweredTy = var->getLoweredTypeInContext(getExpansionContext()); assert(loweredTy == i->getType().getObjectType()); auto &ti = getTypeInfo(loweredTy); @@ -2756,7 +2807,12 @@ static void emitReturnInst(IRGenSILFunction &IGF, auto swiftCCReturn = funcLang == SILFunctionLanguage::Swift; assert(swiftCCReturn || funcLang == SILFunctionLanguage::C && "Need to handle all cases"); - IGF.emitScalarReturn(resultTy, result, swiftCCReturn, false); + SILFunctionConventions conv(IGF.CurSILFn->getLoweredFunctionType(), + IGF.getSILModule()); + auto funcResultType = + IGF.CurSILFn->mapTypeIntoContext(conv.getSILResultType()); + IGF.emitScalarReturn(resultTy, funcResultType, result, swiftCCReturn, + false); } } @@ -3680,12 +3736,9 @@ void IRGenSILFunction::visitRefElementAddrInst(swift::RefElementAddrInst *i) { llvm::Value *value = base.claimNext(); SILType baseTy = i->getOperand()->getType(); - Address field = projectPhysicalClassMemberAddress(*this, - value, - baseTy, - i->getType(), - i->getField()) - .getAddress(); + Address field = projectPhysicalClassMemberAddress(*this, value, baseTy, + i->getType(), i->getField()) + .getAddress(); setLoweredAddress(i, field); } @@ -4307,7 +4360,8 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) { assert(i->getBoxType()->getLayout()->getFields().size() == 1 && "multi field boxes not implemented yet"); const TypeInfo &type = getTypeInfo( - getSILBoxFieldType(i->getBoxType(), IGM.getSILModule().Types, 0)); + getSILBoxFieldType(IGM.getMaximalTypeExpansionContext(), i->getBoxType(), + IGM.getSILModule().Types, 0)); // Derive name from SIL location. bool IsAnonymous = false; @@ -4345,7 +4399,9 @@ void IRGenSILFunction::visitAllocBoxInst(swift::AllocBoxInst *i) { assert(i->getBoxType()->getLayout()->getFields().size() == 1 && "box for a local variable should only have one field"); - auto SILTy = getSILBoxFieldType(i->getBoxType(), IGM.getSILModule().Types, 0); + auto SILTy = getSILBoxFieldType( + IGM.getMaximalTypeExpansionContext(), + i->getBoxType(), IGM.getSILModule().Types, 0); auto RealType = SILTy.getASTType(); auto DbgTy = DebugTypeInfo::getLocalVariable(Decl, RealType, type); @@ -5531,7 +5587,8 @@ void IRGenSILFunction::visitWitnessMethodInst(swift::WitnessMethodInst *i) { if (IGM.isResilient(conformance.getRequirement(), ResilienceExpansion::Maximal)) { auto *fnPtr = IGM.getAddrOfDispatchThunk(member, NotForDefinition); - auto fnType = IGM.getSILTypes().getConstantFunctionType(member); + auto fnType = IGM.getSILTypes().getConstantFunctionType( + IGM.getMaximalTypeExpansionContext(), member); auto sig = IGM.getSignature(fnType); auto fn = FunctionPointer::forDirect(fnPtr, sig); @@ -5542,9 +5599,9 @@ void IRGenSILFunction::visitWitnessMethodInst(swift::WitnessMethodInst *i) { // It would be nice if this weren't discarded. llvm::Value *baseMetadataCache = nullptr; - auto fn = emitWitnessMethodValue(*this, baseTy, &baseMetadataCache, - member, conformance); - + auto fn = emitWitnessMethodValue(*this, baseTy, &baseMetadataCache, member, + conformance); + setLoweredFunctionPointer(i, fn); } @@ -5701,9 +5758,9 @@ void IRGenSILFunction::visitSuperMethodInst(swift::SuperMethodInst *i) { // Non-resilient case. - auto fn = emitVirtualMethodValue(*this, baseValue, baseType, - method, methodType, - /*useSuperVTable*/ true); + auto fn = + emitVirtualMethodValue(*this, baseValue, baseType, method, methodType, + /*useSuperVTable*/ true); setLoweredFunctionPointer(i, fn); } @@ -5737,10 +5794,9 @@ void IRGenSILFunction::visitClassMethodInst(swift::ClassMethodInst *i) { // For Swift classes, get the method implementation from the vtable. // FIXME: better explosion kind, map as static. - FunctionPointer fn = emitVirtualMethodValue(*this, baseValue, - i->getOperand()->getType(), - method, methodType, - /*useSuperVTable*/ false); + FunctionPointer fn = emitVirtualMethodValue( + *this, baseValue, i->getOperand()->getType(), method, methodType, + /*useSuperVTable*/ false); setLoweredFunctionPointer(i, fn); } diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp index 23ecfcd9f2ff2..6ed49d16b3e3b 100644 --- a/lib/IRGen/LoadableByAddress.cpp +++ b/lib/IRGen/LoadableByAddress.cpp @@ -2605,7 +2605,7 @@ bool LoadableByAddress::recreateUncheckedEnumDataInstr( GenericEnvironment *genEnv = F->getGenericEnvironment(); SILType newType = MapperCache.getNewSILType(genEnv, origType, *currIRMod); auto caseTy = enumInstr->getOperand()->getType().getEnumElementType( - enumInstr->getElement(), F->getModule()); + enumInstr->getElement(), F->getModule(), TypeExpansionContext(*F)); SingleValueInstruction *newInstr = nullptr; if (newType.isAddress()) { newType = newType.getObjectType(); @@ -2638,7 +2638,7 @@ bool LoadableByAddress::recreateUncheckedTakeEnumDataAddrInst( GenericEnvironment *genEnv = F->getGenericEnvironment(); SILType newType = MapperCache.getNewSILType(genEnv, origType, *currIRMod); auto caseTy = enumInstr->getOperand()->getType().getEnumElementType( - enumInstr->getElement(), F->getModule()); + enumInstr->getElement(), F->getModule(), TypeExpansionContext(*F)); SingleValueInstruction *newInstr = nullptr; if (caseTy != origType.getObjectType()) { auto *takeEnum = enumBuilder.createUncheckedTakeEnumDataAddr( diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index a1d3130e5cfa7..afddbbd78a974 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -516,8 +516,9 @@ CanType IRGenModule::substOpaqueTypesWithUnderlyingTypes(CanType type) { // Substitute away opaque types whose underlying types we're allowed to // assume are constant. if (type->hasOpaqueArchetype()) { - ReplaceOpaqueTypesWithUnderlyingTypes replacer(getSwiftModule(), - ResilienceExpansion::Maximal); + ReplaceOpaqueTypesWithUnderlyingTypes replacer( + getSwiftModule(), ResilienceExpansion::Maximal, + getSILModule().isWholeModule()); auto underlyingTy = type.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes) ->getCanonicalType(); @@ -532,8 +533,9 @@ SILType IRGenModule::substOpaqueTypesWithUnderlyingTypes( // Substitute away opaque types whose underlying types we're allowed to // assume are constant. if (type.getASTType()->hasOpaqueArchetype()) { - ReplaceOpaqueTypesWithUnderlyingTypes replacer(getSwiftModule(), - ResilienceExpansion::Maximal); + ReplaceOpaqueTypesWithUnderlyingTypes replacer( + getSwiftModule(), ResilienceExpansion::Maximal, + getSILModule().isWholeModule()); auto underlyingTy = type.subst(getSILModule(), replacer, replacer, genericSig, /*substitute opaque*/ true); @@ -549,8 +551,9 @@ IRGenModule::substOpaqueTypesWithUnderlyingTypes(CanType type, // Substitute away opaque types whose underlying types we're allowed to // assume are constant. if (type->hasOpaqueArchetype()) { - ReplaceOpaqueTypesWithUnderlyingTypes replacer(getSwiftModule(), - ResilienceExpansion::Maximal); + ReplaceOpaqueTypesWithUnderlyingTypes replacer( + getSwiftModule(), ResilienceExpansion::Maximal, + getSILModule().isWholeModule()); auto substConformance = conformance.subst( type, replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes); auto underlyingTy = diff --git a/lib/Immediate/REPL.cpp b/lib/Immediate/REPL.cpp index 5d55c9f633c25..b973616a09f74 100644 --- a/lib/Immediate/REPL.cpp +++ b/lib/Immediate/REPL.cpp @@ -20,6 +20,7 @@ #include "swift/AST/IRGenOptions.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/NameLookupRequests.h" #include "swift/Basic/LLVMContext.h" #include "swift/Frontend/Frontend.h" #include "swift/IDE/REPLCodeCompletion.h" @@ -193,8 +194,7 @@ typeCheckREPLInput(ModuleDecl *MostRecentModule, StringRef Name, parseIntoSourceFile(REPLInputFile, BufferID, &Done, nullptr, &PersistentState); } while (!Done); - performTypeChecking(REPLInputFile, PersistentState.getTopLevelContext(), - /*Options*/None); + performTypeChecking(REPLInputFile); return REPLModule; } @@ -1092,8 +1092,11 @@ class REPLEnvironment { ASTContext &ctx = CI.getASTContext(); SourceFile &SF = MostRecentModule->getMainSourceFile(SourceFileKind::REPL); - UnqualifiedLookup lookup(ctx.getIdentifier(Tok.getText()), &SF); - for (auto result : lookup.Results) { + auto name = ctx.getIdentifier(Tok.getText()); + auto descriptor = UnqualifiedLookupDescriptor(name, &SF); + auto lookup = evaluateOrDefault( + ctx.evaluator, UnqualifiedLookupRequest{descriptor}, {}); + for (auto result : lookup) { printOrDumpDecl(result.getValueDecl(), doPrint); if (auto typeDecl = dyn_cast(result.getValueDecl())) { @@ -1163,9 +1166,9 @@ class REPLEnvironment { if (Tok.getText() == "debug") { L.lex(Tok); if (Tok.getText() == "on") { - CI.getASTContext().LangOpts.DebugConstraintSolver = true; + CI.getASTContext().TypeCheckerOpts.DebugConstraintSolver = true; } else if (Tok.getText() == "off") { - CI.getASTContext().LangOpts.DebugConstraintSolver = false; + CI.getASTContext().TypeCheckerOpts.DebugConstraintSolver = false; } else { llvm::outs() << "Unknown :constraints debug command; try :help\n"; } diff --git a/lib/Option/SanitizerOptions.cpp b/lib/Option/SanitizerOptions.cpp index 781427f004677..45f11d04ec257 100644 --- a/lib/Option/SanitizerOptions.cpp +++ b/lib/Option/SanitizerOptions.cpp @@ -185,6 +185,49 @@ OptionSet swift::parseSanitizerArgValues( return sanitizerSet; } +OptionSet swift::parseSanitizerRecoverArgValues( + const llvm::opt::Arg *A, const OptionSet &enabledSanitizers, + DiagnosticEngine &Diags, bool emitWarnings) { + OptionSet sanitizerRecoverSet; + + // Find the sanitizer kind. + for (const char *arg : A->getValues()) { + Optional optKind = parse(arg); + + // Unrecognized sanitizer option + if (!optKind.hasValue()) { + Diags.diagnose(SourceLoc(), diag::error_unsupported_option_argument, + A->getOption().getPrefixedName(), arg); + continue; + } + SanitizerKind kind = optKind.getValue(); + + // Only support ASan for now. + if (kind != SanitizerKind::Address) { + Diags.diagnose(SourceLoc(), diag::error_unsupported_option_argument, + A->getOption().getPrefixedName(), arg); + continue; + } + + // Check that the sanitizer is enabled. + if (!(enabledSanitizers & kind)) { + SmallString<128> b; + if (emitWarnings) { + Diags.diagnose(SourceLoc(), + diag::warning_option_requires_specific_sanitizer, + (A->getOption().getPrefixedName() + toStringRef(kind)) + .toStringRef(b), + toStringRef(kind)); + } + continue; + } + + sanitizerRecoverSet |= kind; + } + + return sanitizerRecoverSet; +} + std::string swift::getSanitizerList(const OptionSet &Set) { std::string list; #define SANITIZER(_, kind, name, file) \ diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2223d0d66dd6b..cb1e0439e2599 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -804,7 +804,6 @@ Parser::parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc) { ProtocolType.get(), MemberName, MemberNameLoc)); } -/// SWIFT_ENABLE_TENSORFLOW ParserResult Parser::parseDifferentiableAttribute(SourceLoc atLoc, SourceLoc loc) { StringRef AttrName = "differentiable"; @@ -929,6 +928,7 @@ bool Parser::parseDifferentiationParametersClause( return false; } +// SWIFT_ENABLE_TENSORFLOW bool Parser::parseTransposedParametersClause( SmallVectorImpl ¶ms, StringRef attrName) { SyntaxParsingContext TransposeParamsClauseContext( @@ -995,6 +995,7 @@ bool Parser::parseTransposedParametersClause( } return false; } +// SWIFT_ENABLE_TENSORFLOW END bool Parser::parseDifferentiableAttributeArguments( bool &linear, SmallVectorImpl ¶ms, @@ -1257,8 +1258,9 @@ Parser::parseDifferentiatingAttribute(SourceLoc atLoc, SourceLoc loc) { DerivativeAttr::create(Context, /*implicit*/ false, atLoc, SourceRange(loc, rParenLoc), original, params)); } +// SWIFT_ENABLE_TENSORFLOW END -/// SWIFT_ENABLE_TENSORFLOW +// SWIFT_ENABLE_TENSORFLOW /// Helper function that parses 'type-identifier' for `parseQualifiedDeclName`. /// Returns true on error. Sets `baseType` to the parsed type, if present, or to /// `nullptr` if not. A missing base type is not considered an error. @@ -1281,8 +1283,9 @@ static bool parseBaseTypeForQualifiedDeclName(Parser &P, TypeRepr *&baseType) { baseType = result.getPtrOrNull(); return false; } +// SWIFT_ENABLE_TENSORFLOW END -/// SWIFT_ENABLE_TENSORFLOW +// SWIFT_ENABLE_TENSORFLOW /// parseQualifiedDeclName /// /// qualified-decl-name: @@ -1309,7 +1312,9 @@ bool parseQualifiedDeclName(Parser &P, Diag<> nameParseError, // If name could not be parsed, return true for error. return !original.Name; } +// SWIFT_ENABLE_TENSORFLOW END +// SWIFT_ENABLE_TENSORFLOW ParserResult Parser::parseTransposeAttribute(SourceLoc atLoc, SourceLoc loc) { StringRef AttrName = "transpose"; @@ -1377,7 +1382,9 @@ ParserResult Parser::parseTransposeAttribute(SourceLoc atLoc, Context, /*implicit*/ false, atLoc, SourceRange(loc, rParenLoc), baseType, original, params)); } +// SWIFT_ENABLE_TENSORFLOW END +// SWIFT_ENABLE_TENSORFLOW ParserResult Parser::parseQuotedAttribute(SourceLoc atLoc, SourceLoc loc) { if (Context.LangOpts.EnableExperimentalQuasiquotes) { @@ -1388,6 +1395,7 @@ ParserResult Parser::parseQuotedAttribute(SourceLoc atLoc, return makeParserError(); } } +// SWIFT_ENABLE_TENSORFLOW END void Parser::parseObjCSelector(SmallVector &Names, SmallVector &NameLocs, @@ -2188,7 +2196,6 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc, break; } - // SWIFT_ENABLE_TENSORFLOW case DAK_Differentiable: { auto Attr = parseDifferentiableAttribute(AtLoc, Loc); if (Attr.isNonNull()) @@ -3394,9 +3401,10 @@ void Parser::consumeDecl(ParserPosition BeginParserPosition, backtrackToPosition(BeginParserPosition); SourceLoc BeginLoc = Tok.getLoc(); - State->delayDecl(PersistentParserState::DelayedDeclKind::Decl, Flags.toRaw(), - CurDeclContext, {BeginLoc, EndLoc}, - BeginParserPosition.PreviousLoc); + State->setCodeCompletionDelayedDeclState( + PersistentParserState::CodeCompletionDelayedDeclKind::Decl, + Flags.toRaw(), CurDeclContext, {BeginLoc, EndLoc}, + BeginParserPosition.PreviousLoc); while (SourceMgr.isBeforeInBuffer(Tok.getLoc(), CurrentLoc)) consumeToken(); @@ -3431,21 +3439,6 @@ void Parser::setLocalDiscriminatorToParamList(ParameterList *PL) { } } -void Parser::delayParseFromBeginningToHere(ParserPosition BeginParserPosition, - ParseDeclOptions Flags) { - auto CurLoc = Tok.getLoc(); - backtrackToPosition(BeginParserPosition); - SourceLoc BeginLoc = Tok.getLoc(); - SourceLoc EndLoc = CurLoc; - State->delayDecl(PersistentParserState::DelayedDeclKind::Decl, - Flags.toRaw(), - CurDeclContext, {BeginLoc, EndLoc}, - BeginParserPosition.PreviousLoc); - - while (Tok.isNot(tok::eof)) - consumeToken(); -} - // SWIFT_ENABLE_TENSORFLOW static void setOriginalFunctionInDifferentiableAttributes( DeclAttributes Attributes, Decl *D) { @@ -3823,26 +3816,23 @@ Parser::parseDecl(ParseDeclOptions Flags, consumeToken(tok::code_complete); } - if (AttrStatus.hasCodeCompletion()) { - if (CodeCompletion) { + if (AttrStatus.hasCodeCompletion() || DeclResult.hasCodeCompletion()) { + if (isCodeCompletionFirstPass() && + !CurDeclContext->isModuleScopeContext() && + !isa(CurDeclContext) && + !isa(CurDeclContext)) { + // Only consume non-toplevel decls. + consumeDecl(BeginParserPosition, Flags, /*IsTopLevel=*/false); + + return makeParserError(); + } + if (AttrStatus.hasCodeCompletion() && CodeCompletion) { Optional DK; if (DeclResult.isNonNull()) DK = DeclResult.get()->getKind(); CodeCompletion->setAttrTargetDeclKind(DK); - } else { - delayParseFromBeginningToHere(BeginParserPosition, Flags); - return makeParserError(); } - } - - if (DeclResult.hasCodeCompletion() && isCodeCompletionFirstPass() && - !CurDeclContext->isModuleScopeContext() && - !isa(CurDeclContext) && - !isa(CurDeclContext)) { - // Only consume non-toplevel decls. - consumeDecl(BeginParserPosition, Flags, /*IsTopLevel=*/false); - - return makeParserError(); + DeclResult.setHasCodeCompletion(); } if (auto SF = CurDeclContext->getParentSourceFile()) { @@ -4031,48 +4021,6 @@ std::vector Parser::parseDeclListDelayed(IterableDeclContext *IDC) { return parseDeclList(LBLoc, RBLoc, Id, Options, IDC, hadError); } -void Parser::parseDeclDelayed() { - auto DelayedState = State->takeDelayedDeclState(); - assert(DelayedState.get() && "should have delayed state"); - - auto BeginParserPosition = getParserPosition(DelayedState->BodyPos); - auto EndLexerState = L->getStateForEndOfTokenLoc(DelayedState->BodyEnd); - - // ParserPositionRAII needs a primed parser to restore to. - if (Tok.is(tok::NUM_TOKENS)) - consumeTokenWithoutFeedingReceiver(); - - // Ensure that we restore the parser state at exit. - ParserPositionRAII PPR(*this); - - // Create a lexer that cannot go past the end state. - Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState); - - // Temporarily swap out the parser's current lexer with our new one. - llvm::SaveAndRestore T(L, &LocalLex); - - // Rewind to the beginning of the decl. - restoreParserPosition(BeginParserPosition); - - // Re-enter the lexical scope. - Scope S(this, DelayedState->takeScope()); - ContextChange CC(*this, DelayedState->ParentContext); - - parseDecl(ParseDeclOptions(DelayedState->Flags), - /*IsAtStartOfLineOrPreviousHadSemi=*/true, - [&](Decl *D) { - if (auto *parent = DelayedState->ParentContext) { - if (auto *NTD = dyn_cast(parent)) { - NTD->addMember(D); - } else if (auto *ED = dyn_cast(parent)) { - ED->addMember(D); - } else if (auto *SF = dyn_cast(parent)) { - SF->Decls.push_back(D); - } - } - }); -} - /// Parse an 'import' declaration, doing no token skipping on error. /// /// \verbatim @@ -6107,9 +6055,9 @@ void Parser::consumeAbstractFunctionBody(AbstractFunctionDecl *AFD, if (isCodeCompletionFirstPass()) { if (SourceMgr.rangeContainsCodeCompletionLoc(BodyRange)) { - State->delayDecl(PersistentParserState::DelayedDeclKind::FunctionBody, - PD_Default, AFD, BodyRange, - BeginParserPosition.PreviousLoc); + State->setCodeCompletionDelayedDeclState( + PersistentParserState::CodeCompletionDelayedDeclKind::FunctionBody, + PD_Default, AFD, BodyRange, BeginParserPosition.PreviousLoc); } else { AFD->setBodySkipped(BodyRange); } @@ -6424,20 +6372,6 @@ BraceStmt *Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) { return parseBraceItemList(diag::func_decl_without_brace).getPtrOrNull(); } -/// Parse a delayed function body from the 'PersistentParserState'. -void Parser::parseAbstractFunctionBodyDelayed() { - auto DelayedState = State->takeDelayedDeclState(); - assert(DelayedState.get() && "should have delayed state"); - auto CD = DelayedState->ParentContext->getAsDecl(); - auto AFD = cast(CD); - - // Eagarly parse local decls or nested function bodies inside the body. - llvm::SaveAndRestore DisableDelayedBody(DelayBodyParsing, false); - - auto body = parseAbstractFunctionBodyDelayed(AFD); - AFD->setBodyParsed(body); -} - /// Parse a 'enum' declaration, returning true (and doing no token /// skipping) on error. /// @@ -7456,7 +7390,7 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name, return makeParserCodeCompletionResult(); } - if (Context.LangOpts.EnableOperatorDesignatedTypes) { + if (Context.TypeCheckerOpts.EnableOperatorDesignatedTypes) { if (Tok.is(tok::identifier)) { SyntaxParsingContext GroupCtxt(SyntaxContext, SyntaxKind::IdentifierList); diff --git a/lib/Parse/ParsePattern.cpp b/lib/Parse/ParsePattern.cpp index 1c94c419cdda0..d0cd5536ee1ce 100644 --- a/lib/Parse/ParsePattern.cpp +++ b/lib/Parse/ParsePattern.cpp @@ -654,7 +654,7 @@ mapParsedParameters(Parser &parser, if (param.DefaultArg) { DefaultArgumentKind kind = getDefaultArgKind(param.DefaultArg); result->setDefaultArgumentKind(kind); - result->setDefaultValue(param.DefaultArg); + result->setDefaultExpr(param.DefaultArg, /*isTypeChecked*/ false); } else if (param.hasInheritedDefaultArg) { result->setDefaultArgumentKind(DefaultArgumentKind::Inherited); } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 70f7f6db8a358..9b66714cf07fa 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -256,8 +256,9 @@ void Parser::consumeTopLevelDecl(ParserPosition BeginParserPosition, SourceLoc EndLoc = PreviousLoc; backtrackToPosition(BeginParserPosition); SourceLoc BeginLoc = Tok.getLoc(); - State->delayTopLevel(TLCD, {BeginLoc, EndLoc}, - BeginParserPosition.PreviousLoc); + State->setCodeCompletionDelayedDeclState( + PersistentParserState::CodeCompletionDelayedDeclKind::TopLevelCodeDecl, + PD_Default, TLCD, {BeginLoc, EndLoc}, BeginParserPosition.PreviousLoc); // Skip the rest of the file to prevent the parser from constructing the AST // for it. Forward references are not allowed at the top level. @@ -522,53 +523,6 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl &Entries, return BraceItemsStatus; } -void Parser::parseTopLevelCodeDeclDelayed() { - auto DelayedState = State->takeDelayedDeclState(); - assert(DelayedState.get() && "should have delayed state"); - - auto BeginParserPosition = getParserPosition(DelayedState->BodyPos); - auto EndLexerState = L->getStateForEndOfTokenLoc(DelayedState->BodyEnd); - - // ParserPositionRAII needs a primed parser to restore to. - if (Tok.is(tok::NUM_TOKENS)) - consumeTokenWithoutFeedingReceiver(); - - // Ensure that we restore the parser state at exit. - ParserPositionRAII PPR(*this); - - // Create a lexer that cannot go past the end state. - Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState); - - // Temporarily swap out the parser's current lexer with our new one. - llvm::SaveAndRestore T(L, &LocalLex); - - // Rewind to the beginning of the top-level code. - restoreParserPosition(BeginParserPosition); - - // Re-enter the lexical scope. - Scope S(this, DelayedState->takeScope()); - - // Re-enter the top-level decl context. - // FIXME: this can issue discriminators out-of-order? - auto *TLCD = cast(DelayedState->ParentContext); - ContextChange CC(*this, TLCD, &State->getTopLevelContext()); - - SourceLoc StartLoc = Tok.getLoc(); - ASTNode Result; - - // Expressions can't begin with a closure literal at statement position. This - // prevents potential ambiguities with trailing closure syntax. - if (Tok.is(tok::l_brace)) { - diagnose(Tok, diag::statement_begins_with_closure); - } - - parseExprOrStmt(Result); - if (!Result.isNull()) { - auto Brace = BraceStmt::create(Context, StartLoc, Result, Tok.getLoc()); - TLCD->setBody(Brace); - } -} - /// Recover from a 'case' or 'default' outside of a 'switch' by consuming up to /// the next ':'. static ParserResult recoverFromInvalidCase(Parser &P) { diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 5c05e1a1fbfce..8b1601b5b5af9 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -113,37 +113,113 @@ void SILParserTUStateBase::anchor() { } void swift::performCodeCompletionSecondPass( PersistentParserState &ParserState, CodeCompletionCallbacksFactory &Factory) { - SharedTimer timer("CodeCompletionSecondPass"); - if (!ParserState.hasDelayedDecl()) + Parser::performCodeCompletionSecondPass(ParserState, Factory); +} + +void Parser::performCodeCompletionSecondPass( + PersistentParserState &ParserState, + CodeCompletionCallbacksFactory &Factory) { + if (!ParserState.hasCodeCompletionDelayedDeclState()) return; - auto &SF = *ParserState.getDelayedDeclContext()->getParentSourceFile(); - auto &SM = SF.getASTContext().SourceMgr; - auto BufferID = SM.findBufferContainingLoc(ParserState.getDelayedDeclLoc()); - Parser TheParser(BufferID, SF, nullptr, &ParserState, nullptr); + auto state = ParserState.takeCodeCompletionDelayedDeclState(); + auto &SF = *state->ParentContext->getParentSourceFile(); + auto &Ctx = SF.getASTContext(); - // Disable libSyntax creation in the delayed parsing. - TheParser.SyntaxContext->disable(); + FrontendStatsTracer tracer(Ctx.Stats, "CodeCompletionSecondPass"); + + auto BufferID = Ctx.SourceMgr.findBufferContainingLoc(state->BodyPos.Loc); + Parser TheParser(BufferID, SF, nullptr, &ParserState, nullptr); std::unique_ptr CodeCompletion( Factory.createCodeCompletionCallbacks(TheParser)); TheParser.setCodeCompletionCallbacks(CodeCompletion.get()); - switch (ParserState.getDelayedDeclKind()) { - case PersistentParserState::DelayedDeclKind::TopLevelCodeDecl: - TheParser.parseTopLevelCodeDeclDelayed(); + TheParser.performCodeCompletionSecondPassImpl(*state); +} + +void Parser::performCodeCompletionSecondPassImpl( + PersistentParserState::CodeCompletionDelayedDeclState &info) { + // Disable libSyntax creation in the delayed parsing. + SyntaxContext->disable(); + + auto BeginParserPosition = getParserPosition(info.BodyPos); + auto EndLexerState = L->getStateForEndOfTokenLoc(info.BodyEnd); + + // ParserPositionRAII needs a primed parser to restore to. + if (Tok.is(tok::NUM_TOKENS)) + consumeTokenWithoutFeedingReceiver(); + + // Ensure that we restore the parser state at exit. + ParserPositionRAII PPR(*this); + + // Create a lexer that cannot go past the end state. + Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState); + + // Temporarily swap out the parser's current lexer with our new one. + llvm::SaveAndRestore T(L, &LocalLex); + + // Rewind to the beginning of the top-level code. + restoreParserPosition(BeginParserPosition); + + // Do not delay parsing in the second pass. + llvm::SaveAndRestore DisableDelayedBody(DelayBodyParsing, false); + + // Re-enter the lexical scope. + Scope S(this, info.takeScope()); + + DeclContext *DC = info.ParentContext; + + switch (info.Kind) { + case PersistentParserState::CodeCompletionDelayedDeclKind::TopLevelCodeDecl: { + // Re-enter the top-level code decl context. + // FIXME: this can issue discriminators out-of-order? + auto *TLCD = cast(DC); + ContextChange CC(*this, TLCD, &State->getTopLevelContext()); + + SourceLoc StartLoc = Tok.getLoc(); + ASTNode Result; + parseExprOrStmt(Result); + if (!Result.isNull()) { + auto Brace = BraceStmt::create(Context, StartLoc, Result, Tok.getLoc()); + TLCD->setBody(Brace); + } break; + } - case PersistentParserState::DelayedDeclKind::Decl: - TheParser.parseDeclDelayed(); + case PersistentParserState::CodeCompletionDelayedDeclKind::Decl: { + assert((DC->isTypeContext() || DC->isModuleScopeContext()) && + "Delayed decl must be a type member or a top-level decl"); + ContextChange CC(*this, DC); + + parseDecl(ParseDeclOptions(info.Flags), + /*IsAtStartOfLineOrPreviousHadSemi=*/true, [&](Decl *D) { + if (auto *NTD = dyn_cast(DC)) { + NTD->addMember(D); + } else if (auto *ED = dyn_cast(DC)) { + ED->addMember(D); + } else if (auto *SF = dyn_cast(DC)) { + SF->Decls.push_back(D); + } else { + llvm_unreachable("invalid decl context kind"); + } + }); break; + } - case PersistentParserState::DelayedDeclKind::FunctionBody: { - TheParser.parseAbstractFunctionBodyDelayed(); + case PersistentParserState::CodeCompletionDelayedDeclKind::FunctionBody: { + auto *AFD = cast(DC); + ParseFunctionBody CC(*this, AFD); + setLocalDiscriminatorToParamList(AFD->getParameters()); + + auto result = parseBraceItemList(diag::func_decl_without_brace); + AFD->setBody(result.getPtrOrNull()); break; } } - assert(!ParserState.hasDelayedDecl()); + + assert(!State->hasCodeCompletionDelayedDeclState() && + "Second pass should not set any code completion info"); CodeCompletion->doneParsing(); } @@ -907,7 +983,6 @@ bool Parser::parseMatchingToken(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag, return false; } -// SWIFT_ENABLE_TENSORFLOW bool Parser::parseUnsignedInteger(unsigned &Result, SourceLoc &Loc, const Diagnostic &D) { auto IntTok = Tok; @@ -1088,6 +1163,7 @@ Parser::getStringLiteralIfNotInterpolated(SourceLoc Loc, struct ParserUnit::Implementation { std::shared_ptr SPActions; LangOptions LangOpts; + TypeCheckerOptions TypeCheckerOpts; SearchPathOptions SearchPathOpts; DiagnosticEngine Diags; ASTContext &Ctx; @@ -1095,19 +1171,16 @@ struct ParserUnit::Implementation { std::unique_ptr TheParser; Implementation(SourceManager &SM, SourceFileKind SFKind, unsigned BufferID, - const LangOptions &Opts, StringRef ModuleName, + const LangOptions &Opts, const TypeCheckerOptions &TyOpts, + StringRef ModuleName, std::shared_ptr spActions) - : SPActions(std::move(spActions)), - LangOpts(Opts), - Diags(SM), - Ctx(*ASTContext::get(LangOpts, SearchPathOpts, SM, Diags)), - SF(new (Ctx) SourceFile( - *ModuleDecl::create(Ctx.getIdentifier(ModuleName), Ctx), - SFKind, BufferID, - SourceFile::ImplicitModuleImportKind::None, - Opts.CollectParsedToken, - Opts.BuildSyntaxTree)) { - } + : SPActions(std::move(spActions)), + LangOpts(Opts), TypeCheckerOpts(TyOpts), Diags(SM), + Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SearchPathOpts, SM, Diags)), + SF(new (Ctx) SourceFile( + *ModuleDecl::create(Ctx.getIdentifier(ModuleName), Ctx), SFKind, + BufferID, SourceFile::ImplicitModuleImportKind::None, + Opts.CollectParsedToken, Opts.BuildSyntaxTree)) {} ~Implementation() { // We need to delete the parser before the context so that it can finalize @@ -1118,15 +1191,18 @@ struct ParserUnit::Implementation { }; ParserUnit::ParserUnit(SourceManager &SM, SourceFileKind SFKind, unsigned BufferID) - : ParserUnit(SM, SFKind, BufferID, LangOptions(), "input") { + : ParserUnit(SM, SFKind, BufferID, + LangOptions(), TypeCheckerOptions(), "input") { } ParserUnit::ParserUnit(SourceManager &SM, SourceFileKind SFKind, unsigned BufferID, - const LangOptions &LangOpts, StringRef ModuleName, + const LangOptions &LangOpts, + const TypeCheckerOptions &TypeCheckOpts, + StringRef ModuleName, std::shared_ptr spActions, SyntaxParsingCache *SyntaxCache) - : Impl(*new Implementation(SM, SFKind, BufferID, LangOpts, ModuleName, - std::move(spActions))) { + : Impl(*new Implementation(SM, SFKind, BufferID, LangOpts, TypeCheckOpts, + ModuleName, std::move(spActions))) { Impl.SF->SyntaxParsingCache = SyntaxCache; Impl.TheParser.reset(new Parser(BufferID, *Impl.SF, /*SIL=*/nullptr, @@ -1136,8 +1212,8 @@ ParserUnit::ParserUnit(SourceManager &SM, SourceFileKind SFKind, unsigned Buffer ParserUnit::ParserUnit(SourceManager &SM, SourceFileKind SFKind, unsigned BufferID, unsigned Offset, unsigned EndOffset) - : Impl(*new Implementation(SM, SFKind, BufferID, LangOptions(), "input", - nullptr)) { + : Impl(*new Implementation(SM, SFKind, BufferID, LangOptions(), + TypeCheckerOptions(), "input", nullptr)) { std::unique_ptr Lex; Lex.reset(new Lexer(Impl.LangOpts, SM, diff --git a/lib/Parse/PersistentParserState.cpp b/lib/Parse/PersistentParserState.cpp index 89d700847d2b6..5244697ecba2d 100644 --- a/lib/Parse/PersistentParserState.cpp +++ b/lib/Parse/PersistentParserState.cpp @@ -25,14 +25,12 @@ PersistentParserState::PersistentParserState() { } PersistentParserState::~PersistentParserState() { } -void PersistentParserState::delayDecl(DelayedDeclKind Kind, - unsigned Flags, - DeclContext *ParentContext, - SourceRange BodyRange, - SourceLoc PreviousLoc) { - assert(!CodeCompletionDelayedDeclState.get() && +void PersistentParserState::setCodeCompletionDelayedDeclState( + CodeCompletionDelayedDeclKind Kind, unsigned Flags, + DeclContext *ParentContext, SourceRange BodyRange, SourceLoc PreviousLoc) { + assert(!CodeCompletionDelayedDeclStat.get() && "only one decl can be delayed for code completion"); - CodeCompletionDelayedDeclState.reset(new DelayedDeclState( + CodeCompletionDelayedDeclStat.reset(new CodeCompletionDelayedDeclState( Kind, Flags, ParentContext, BodyRange, PreviousLoc, ScopeInfo.saveCurrentScope())); } @@ -45,10 +43,3 @@ void PersistentParserState::parseAllDelayedDeclLists() { for (auto IDC : DelayedDeclLists) IDC->loadAllMembers(); } - -void PersistentParserState::delayTopLevel(TopLevelCodeDecl *TLCD, - SourceRange BodyRange, - SourceLoc PreviousLoc) { - delayDecl(DelayedDeclKind::TopLevelCodeDecl, 0U, TLCD, BodyRange, - PreviousLoc); -} diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index 1dc8226f89dd9..5cdd62ec2fe73 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -17,6 +17,7 @@ #include "swift/AST/ExistentialLayout.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/NameLookupRequests.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" @@ -145,7 +146,7 @@ static bool parseIntoSourceFileImpl(SourceFile &SF, if (SIL) DelayBodyParsing = false; - SharedTimer timer("Parsing"); + FrontendStatsTracer tracer(SF.getASTContext().Stats, "Parsing"); Parser P(BufferID, SF, SIL ? SIL->Impl.get() : nullptr, PersistentState, STreeCreator, DelayBodyParsing); PrettyStackTraceParser StackTrace(P); @@ -1196,14 +1197,16 @@ lookupTopDecl(Parser &P, DeclBaseName Name, bool typeLookup) { llvm::SaveAndRestore ASTStage(P.SF.ASTStage, SourceFile::Parsed); - UnqualifiedLookup::Options options; + UnqualifiedLookupOptions options; if (typeLookup) - options |= UnqualifiedLookup::Flags::TypeLookup; - - UnqualifiedLookup DeclLookup(Name, &P.SF, SourceLoc(), options); - assert(DeclLookup.isSuccess() && DeclLookup.Results.size() == 1); - ValueDecl *VD = DeclLookup.Results.back().getValueDecl(); - return VD; + options |= UnqualifiedLookupFlags::TypeLookup; + + auto &ctx = P.SF.getASTContext(); + auto descriptor = UnqualifiedLookupDescriptor(Name, &P.SF); + auto lookup = evaluateOrDefault(ctx.evaluator, + UnqualifiedLookupRequest{descriptor}, {}); + assert(lookup.size() == 1); + return lookup.back().getValueDecl(); } /// Find the ValueDecl given an interface type and a member name. @@ -1296,24 +1299,20 @@ bool SILParser::parseSILType(SILType &Result, // Resolve the generic environments for parsed generic function and box types. class HandleSILGenericParamsWalker : public ASTWalker { - ASTContext &C; SourceFile *SF; public: - HandleSILGenericParamsWalker(ASTContext &C, - SourceFile *SF) - : C(C), SF(SF) - {} - + HandleSILGenericParamsWalker(SourceFile *SF) : SF(SF) {} + bool walkToTypeReprPre(TypeRepr *T) override { if (auto fnType = dyn_cast(T)) { if (auto generics = fnType->getGenericParams()) { - auto env = handleSILGenericParams(C, generics, SF); + auto env = handleSILGenericParams(generics, SF); fnType->setGenericEnvironment(env); } } if (auto boxType = dyn_cast(T)) { if (auto generics = boxType->getGenericParams()) { - auto env = handleSILGenericParams(C, generics, SF); + auto env = handleSILGenericParams(generics, SF); boxType->setGenericEnvironment(env); } } @@ -1321,9 +1320,8 @@ bool SILParser::parseSILType(SILType &Result, } }; - TyR.get() - ->walk(HandleSILGenericParamsWalker(P.Context, &P.SF)); - + TyR.get()->walk(HandleSILGenericParamsWalker(&P.SF)); + // Save the top-level function generic environment if there was one. if (auto fnType = dyn_cast(TyR.get())) if (auto env = fnType->getGenericEnvironment()) @@ -2117,8 +2115,7 @@ parseSILDifferentiabilityWitnessConfigAndFunction(Parser &P, SILParser &SP, Scope genericsScope(&P, ScopeKind::Generics); auto *genericParams = P.maybeParseGenericParams().getPtrOrNull(); if (genericParams) { - auto *witnessGenEnv = - handleSILGenericParams(P.Context, genericParams, &P.SF); + auto *witnessGenEnv = handleSILGenericParams(genericParams, &P.SF); witnessGenSig = witnessGenEnv->getGenericSignature(); } } @@ -2202,7 +2199,7 @@ bool SILParser::parseSILDeclRef(SILDeclRef &Member, bool FnTypeRequired) { if (auto generics = fnType->getGenericParams()) { assert(!Ty.wasValidated() && Ty.getType().isNull()); - genericEnv = handleSILGenericParams(P.Context, generics, &P.SF); + genericEnv = handleSILGenericParams(generics, &P.SF); fnType->setGenericEnvironment(genericEnv); } } @@ -3483,8 +3480,8 @@ bool SILParser::parseSILInstruction(SILBuilder &B) { { Scope genericsScope(&P, ScopeKind::Generics); generics = P.maybeParseGenericParams().getPtrOrNull(); - patternEnv = handleSILGenericParams(P.Context, generics, &P.SF); - + patternEnv = handleSILGenericParams(generics, &P.SF); + if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(")) return true; @@ -4457,8 +4454,9 @@ bool SILParser::parseSILInstruction(SILBuilder &B) { return true; EnumElementDecl *Elt = cast(EltRef.getDecl()); - auto ResultTy = Operand->getType().getEnumElementType(Elt, SILMod); - + auto ResultTy = Operand->getType().getEnumElementType( + Elt, SILMod, B.getTypeExpansionContext()); + switch (Opcode) { case swift::SILInstructionKind::InitEnumDataAddrInst: ResultVal = B.createInitEnumDataAddr(InstLoc, Operand, Elt, ResultTy); @@ -4806,7 +4804,8 @@ bool SILParser::parseSILInstruction(SILBuilder &B) { // FIXME: substitution means this type should be explicit to improve // performance. - auto ResultTy = Val->getType().getFieldType(Field, SILMod); + auto ResultTy = + Val->getType().getFieldType(Field, SILMod, B.getTypeExpansionContext()); if (Opcode == SILInstructionKind::StructElementAddrInst) ResultVal = B.createStructElementAddr(InstLoc, Val, Field, ResultTy.getAddressType()); @@ -4828,7 +4827,8 @@ bool SILParser::parseSILInstruction(SILBuilder &B) { return true; } VarDecl *Field = cast(FieldV); - auto ResultTy = Val->getType().getFieldType(Field, SILMod); + auto ResultTy = + Val->getType().getFieldType(Field, SILMod, B.getTypeExpansionContext()); ResultVal = B.createRefElementAddr(InstLoc, Val, Field, ResultTy); break; } @@ -5511,8 +5511,8 @@ bool SILParser::parseCallInstruction(SILLocation InstLoc, CanSILFunctionType substFTI = FTI; if (!subs.empty()) { auto silFnTy = FnTy.castTo(); - substFTI - = silFnTy->substGenericArgs(SILMod, subs); + substFTI = + silFnTy->substGenericArgs(SILMod, subs, B.getTypeExpansionContext()); FnTy = SILType::getPrimitiveObjectType(substFTI); } SILFunctionConventions substConv(substFTI, B.getModule()); @@ -6089,8 +6089,8 @@ bool SILParserTUState::parseSILProperty(Parser &P) { Scope toplevelScope(&P, ScopeKind::TopLevel); Scope genericsScope(&P, ScopeKind::Generics); generics = P.maybeParseGenericParams().getPtrOrNull(); - patternEnv = handleSILGenericParams(P.Context, generics, &P.SF); - + patternEnv = handleSILGenericParams(generics, &P.SF); + if (patternEnv) { if (patternEnv->getGenericSignature()->getCanonicalSignature() != VD->getInnermostDeclContext()->getGenericSignatureOfContext() @@ -6400,7 +6400,7 @@ ProtocolConformanceRef SILParser::parseProtocolConformance( auto *genericParams = P.maybeParseGenericParams().getPtrOrNull(); if (genericParams) { - genericEnv = handleSILGenericParams(P.Context, genericParams, &P.SF); + genericEnv = handleSILGenericParams(genericParams, &P.SF); } auto retVal = parseProtocolConformanceHelper(proto, genericEnv, context, diff --git a/lib/SIL/AbstractionPattern.cpp b/lib/SIL/AbstractionPattern.cpp index ff1b499c68120..ed058b3a899e8 100644 --- a/lib/SIL/AbstractionPattern.cpp +++ b/lib/SIL/AbstractionPattern.cpp @@ -596,6 +596,8 @@ AbstractionPattern AbstractionPattern::getOptionalObjectType() const { case Kind::Type: if (isTypeParameter()) return AbstractionPattern::getOpaque(); + if (isa(getType())) + return AbstractionPattern::getOpaque(); return AbstractionPattern(getGenericSignature(), ::getOptionalObjectType(getType())); diff --git a/lib/SIL/Bridging.cpp b/lib/SIL/Bridging.cpp index ab2fc6bab7aef..c5760f1805eda 100644 --- a/lib/SIL/Bridging.cpp +++ b/lib/SIL/Bridging.cpp @@ -33,7 +33,8 @@ using namespace swift::Lowering; CanType TypeConverter::getLoweredTypeOfGlobal(VarDecl *var) { AbstractionPattern origType = getAbstractionPattern(var); assert(!origType.isTypeParameter()); - return getLoweredRValueType(origType, origType.getType()); + return getLoweredRValueType(TypeExpansionContext::minimal(), origType, + origType.getType()); } AnyFunctionType::Param diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp index 3f83785d1bbbb..f294dddecb59b 100644 --- a/lib/SIL/DynamicCasts.cpp +++ b/lib/SIL/DynamicCasts.cpp @@ -918,7 +918,8 @@ namespace { auto sourceSomeDecl = Ctx.getOptionalSomeDecl(); SILType loweredSourceObjectType = - source.Value->getType().getEnumElementType(sourceSomeDecl, M); + source.Value->getType().getEnumElementType( + sourceSomeDecl, M, B.getTypeExpansionContext()); // Form the target for the optional object. EmitSomeState state; @@ -991,8 +992,8 @@ namespace { auto someDecl = Ctx.getOptionalSomeDecl(); state.SomeDecl = someDecl; - SILType loweredObjectType = - target.LoweredType.getEnumElementType(someDecl, M); + SILType loweredObjectType = target.LoweredType.getEnumElementType( + someDecl, M, B.getTypeExpansionContext()); if (target.isAddress()) { SILValue objectAddr = diff --git a/lib/SIL/LoopInfo.cpp b/lib/SIL/LoopInfo.cpp index 84f55ef1d4116..72defd29eb7bc 100644 --- a/lib/SIL/LoopInfo.cpp +++ b/lib/SIL/LoopInfo.cpp @@ -47,6 +47,18 @@ bool SILLoop::canDuplicate(SILInstruction *I) const { } return true; } + if (I->isDeallocatingStack()) { + SILInstruction *alloc = nullptr; + if (auto *dealloc = dyn_cast(I)) { + SILValue address = dealloc->getOperand(); + if (isa(address) || isa(address)) + alloc = cast(address); + } + if (auto *dealloc = dyn_cast(I)) + alloc = dyn_cast(dealloc->getOperand()); + + return alloc && contains(alloc); + } // CodeGen can't build ssa for objc methods. if (auto *Method = dyn_cast(I)) { @@ -71,13 +83,17 @@ bool SILLoop::canDuplicate(SILInstruction *I) const { return true; } - if (auto *Dealloc = dyn_cast(I)) { - // The matching alloc_stack must be in the loop. - if (auto *Alloc = dyn_cast(Dealloc->getOperand())) - return contains(Alloc->getParent()); + if (isa(I)) return false; - } + // The entire access must be within the loop. + if (auto BAI = dyn_cast(I)) { + for (auto *UI : BAI->getUses()) { + if (!contains(UI->getUser())) + return false; + } + return true; + } // The entire coroutine execution must be within the loop. // Note that we don't have to worry about the reverse --- a loop which // contains an end_apply or abort_apply of an external begin_apply --- @@ -92,18 +108,11 @@ bool SILLoop::canDuplicate(SILInstruction *I) const { return true; } - if (isa(I)) - return false; - - if (isa(I)) - return false; - if (isa(I)) return false; - if (auto *PA = dyn_cast(I)) - return !PA->isOnStack(); - + // Some special cases above that aren't considered isTriviallyDuplicatable + // return true early. assert(I->isTriviallyDuplicatable() && "Code here must match isTriviallyDuplicatable in SILInstruction"); return true; diff --git a/lib/SIL/MemoryLifetime.cpp b/lib/SIL/MemoryLifetime.cpp index 8c8688086b0ca..39af8027f878f 100644 --- a/lib/SIL/MemoryLifetime.cpp +++ b/lib/SIL/MemoryLifetime.cpp @@ -374,7 +374,8 @@ void MemoryLocations::initFieldsCounter(Location &loc) { } SILModule &module = function->getModule(); for (VarDecl *field : decl->getStoredProperties()) { - loc.updateFieldCounters(ty.getFieldType(field, module), +1); + loc.updateFieldCounters( + ty.getFieldType(field, module, TypeExpansionContext(*function)), +1); } return; } diff --git a/lib/SIL/OwnershipUtils.cpp b/lib/SIL/OwnershipUtils.cpp index 33f65dac5c71a..da53ef1536b56 100644 --- a/lib/SIL/OwnershipUtils.cpp +++ b/lib/SIL/OwnershipUtils.cpp @@ -171,6 +171,13 @@ bool swift::getUnderlyingBorrowIntroducingValues( continue; } + // If v produces .none ownership, then we can ignore it. It is important + // that we put this before checking for guaranteed forwarding instructions, + // since we want to ignore guaranteed forwarding instructions that in this + // specific case produce a .none value. + if (v.getOwnershipKind() == ValueOwnershipKind::None) + continue; + // Otherwise if v is an ownership forwarding value, add its defining // instruction if (isGuaranteedForwardingValue(v)) { @@ -181,10 +188,9 @@ bool swift::getUnderlyingBorrowIntroducingValues( continue; } - // If v produces any ownership, then we can ignore it. Otherwise, we need to - // return false since this is an introducer we do not understand. - if (v.getOwnershipKind() != ValueOwnershipKind::None) - return false; + // Otherwise, this is an introducer we do not understand. Bail and return + // false. + return false; } return true; diff --git a/lib/SIL/Projection.cpp b/lib/SIL/Projection.cpp index 3e090189a21bf..2881469102ea1 100644 --- a/lib/SIL/Projection.cpp +++ b/lib/SIL/Projection.cpp @@ -177,17 +177,18 @@ Projection::Projection(SingleValueInstruction *I) : Value() { /// /// WARNING: This is not a constant time operation because it is implemented /// in terms of getVarDecl, which requests all BaseType's stored properties. -SILType Projection::getType(SILType BaseType, SILModule &M) const { +SILType Projection::getType(SILType BaseType, SILModule &M, + TypeExpansionContext context) const { assert(isValid()); switch (getKind()) { case ProjectionKind::Struct: case ProjectionKind::Class: - return BaseType.getFieldType(getVarDecl(BaseType), M); + return BaseType.getFieldType(getVarDecl(BaseType), M, context); case ProjectionKind::Enum: - return BaseType.getEnumElementType(getEnumElementDecl(BaseType), M); + return BaseType.getEnumElementType(getEnumElementDecl(BaseType), M, context); case ProjectionKind::Box: - return getSILBoxFieldType(BaseType.castTo(), - M.Types, getIndex()); + return getSILBoxFieldType(context, BaseType.castTo(), M.Types, + getIndex()); case ProjectionKind::Tuple: return BaseType.getTupleElementType(getIndex()); case ProjectionKind::Upcast: @@ -285,18 +286,20 @@ Projection::createAddressProjection(SILBuilder &B, SILLocation Loc, llvm_unreachable("Unhandled ProjectionKind in switch."); } -void Projection::getFirstLevelProjections(SILType Ty, SILModule &Mod, - llvm::SmallVectorImpl &Out) { +void Projection::getFirstLevelProjections( + SILType Ty, SILModule &Mod, TypeExpansionContext context, + llvm::SmallVectorImpl &Out) { if (auto *S = Ty.getStructOrBoundGenericStruct()) { unsigned Count = 0; for (auto *VDecl : S->getStoredProperties()) { (void) VDecl; Projection P(ProjectionKind::Struct, Count++); LLVM_DEBUG(ProjectionPath X(Ty); - assert(X.getMostDerivedType(Mod) == Ty); + assert(X.getMostDerivedType(Mod, context) == Ty); X.append(P); - assert(X.getMostDerivedType(Mod)==Ty.getFieldType(VDecl, Mod)); - X.verify(Mod);); + assert(X.getMostDerivedType(Mod, context) == + Ty.getFieldType(VDecl, Mod, context)); + X.verify(Mod, context);); Out.push_back(P); } return; @@ -306,10 +309,11 @@ void Projection::getFirstLevelProjections(SILType Ty, SILModule &Mod, for (unsigned i = 0, e = TT->getNumElements(); i != e; ++i) { Projection P(ProjectionKind::Tuple, i); LLVM_DEBUG(ProjectionPath X(Ty); - assert(X.getMostDerivedType(Mod) == Ty); + assert(X.getMostDerivedType(Mod, context) == Ty); X.append(P); - assert(X.getMostDerivedType(Mod) == Ty.getTupleElementType(i)); - X.verify(Mod);); + assert(X.getMostDerivedType(Mod, context) == + Ty.getTupleElementType(i)); + X.verify(Mod, context);); Out.push_back(P); } return; @@ -321,10 +325,11 @@ void Projection::getFirstLevelProjections(SILType Ty, SILModule &Mod, (void) VDecl; Projection P(ProjectionKind::Class, Count++); LLVM_DEBUG(ProjectionPath X(Ty); - assert(X.getMostDerivedType(Mod) == Ty); + assert(X.getMostDerivedType(Mod, context) == Ty); X.append(P); - assert(X.getMostDerivedType(Mod)==Ty.getFieldType(VDecl, Mod)); - X.verify(Mod);); + assert(X.getMostDerivedType(Mod, context) == + Ty.getFieldType(VDecl, Mod, context)); + X.verify(Mod, context);); Out.push_back(P); } return; @@ -334,11 +339,10 @@ void Projection::getFirstLevelProjections(SILType Ty, SILModule &Mod, for (unsigned field : indices(Box->getLayout()->getFields())) { Projection P(ProjectionKind::Box, field); LLVM_DEBUG(ProjectionPath X(Ty); - assert(X.getMostDerivedType(Mod) == Ty); - X.append(P); - assert(X.getMostDerivedType(Mod) - == getSILBoxFieldType(Box, Mod.Types, field)); - X.verify(Mod);); + assert(X.getMostDerivedType(Mod, context) == Ty); X.append(P); + assert(X.getMostDerivedType(Mod, context) == + getSILBoxFieldType(context, Box, Mod.Types, field)); + X.verify(Mod, context);); (void)Box; Out.push_back(P); } @@ -580,12 +584,13 @@ void Projection::print(raw_ostream &os, SILType baseType) const { os << ""; } -raw_ostream &ProjectionPath::print(raw_ostream &os, SILModule &M) const { +raw_ostream &ProjectionPath::print(raw_ostream &os, SILModule &M, + TypeExpansionContext context) const { os << "Projection Path ["; SILType IterType = getBaseType(); for (const Projection &IterProj : Path) { SILType BaseType = IterType; - IterType = IterProj.getType(IterType, M); + IterType = IterProj.getType(IterType, M, context); os << BaseType.getAddressType() << "\n "; @@ -596,16 +601,16 @@ raw_ostream &ProjectionPath::print(raw_ostream &os, SILModule &M) const { return os; } -void ProjectionPath::dump(SILModule &M) const { - print(llvm::dbgs(), M); +void ProjectionPath::dump(SILModule &M, TypeExpansionContext context) const { + print(llvm::dbgs(), M, context); } -void ProjectionPath::verify(SILModule &M) { +void ProjectionPath::verify(SILModule &M, TypeExpansionContext context) { #ifndef NDEBUG SILType IterTy = getBaseType(); assert(IterTy); for (auto &Proj : Path) { - IterTy = Proj.getType(IterTy, M); + IterTy = Proj.getType(IterTy, M, context); assert(IterTy); } #endif @@ -613,6 +618,7 @@ void ProjectionPath::verify(SILModule &M) { void ProjectionPath::expandTypeIntoLeafProjectionPaths(SILType B, SILModule *Mod, + TypeExpansionContext context, ProjectionPathList &Paths) { // Perform a BFS to expand the given type into projectionpath each of // which contains 1 field from the type. @@ -626,7 +632,7 @@ ProjectionPath::expandTypeIntoLeafProjectionPaths(SILType B, SILModule *Mod, // Get the next level projections based on current projection's type. ProjectionPath PP = Worklist.pop_back_val(); // Get the current type to process. - SILType Ty = PP.getMostDerivedType(*Mod); + SILType Ty = PP.getMostDerivedType(*Mod, context); LLVM_DEBUG(llvm::dbgs() << "Visiting type: " << Ty << "\n"); @@ -655,7 +661,7 @@ ProjectionPath::expandTypeIntoLeafProjectionPaths(SILType B, SILModule *Mod, // Get the first level projection of the current type. Projections.clear(); - Projection::getFirstLevelProjections(Ty, *Mod, Projections); + Projection::getFirstLevelProjections(Ty, *Mod, context, Projections); // Reached the end of the projection tree, this field can not be expanded // anymore. @@ -695,11 +701,12 @@ bool ProjectionPath::hasUncoveredNonTrivials(SILType B, const SILFunction &F, continue; // Get the current type to process. - SILType Ty = PP.getMostDerivedType(Mod); + SILType Ty = PP.getMostDerivedType(Mod, F.getTypeExpansionContext()); // Get the first level projection of the current type. llvm::SmallVector Projections; - Projection::getFirstLevelProjections(Ty, Mod, Projections); + Projection::getFirstLevelProjections(Ty, Mod, F.getTypeExpansionContext(), + Projections); // Reached the end of the projection tree, this field can not be expanded // anymore. @@ -719,7 +726,8 @@ bool ProjectionPath::hasUncoveredNonTrivials(SILType B, const SILFunction &F, for (auto &P : Projections) { ProjectionPath X(B); X.append(PP); - assert(PP.getMostDerivedType(Mod) == X.getMostDerivedType(Mod)); + assert(PP.getMostDerivedType(Mod, F.getTypeExpansionContext()) == + X.getMostDerivedType(Mod, F.getTypeExpansionContext())); X.append(P); Worklist.push_back(X); } @@ -728,8 +736,8 @@ bool ProjectionPath::hasUncoveredNonTrivials(SILType B, const SILFunction &F, // Check whether any path leads to a non-trivial type. for (auto &X : Paths) { - if (!X.getMostDerivedType(Mod).isTrivial(F)) - return true; + if (!X.getMostDerivedType(Mod, F.getTypeExpansionContext()).isTrivial(F)) + return true; } return false; } @@ -937,7 +945,8 @@ processUsersOfValue(ProjectionTree &Tree, // we have a projection to the next level children, create the next // level children nodes lazily. if (!Initialized) - createNextLevelChildren(Tree); + createNextLevelChildren( + Tree, TypeExpansionContext(*projectionInst->getFunction())); // Look up the Node for this projection add {User, ChildNode} to the // worklist. @@ -962,15 +971,14 @@ processUsersOfValue(ProjectionTree &Tree, } } -void -ProjectionTreeNode:: -createNextLevelChildrenForStruct(ProjectionTree &Tree, StructDecl *SD) { +void ProjectionTreeNode::createNextLevelChildrenForStruct( + ProjectionTree &Tree, TypeExpansionContext context, StructDecl *SD) { SILModule &Mod = Tree.getModule(); unsigned ChildIndex = 0; SILType Ty = getType(); for (VarDecl *VD : SD->getStoredProperties()) { assert(Tree.getNode(Index) == this && "Node is not mapped to itself?"); - SILType NodeTy = Ty.getFieldType(VD, Mod); + SILType NodeTy = Ty.getFieldType(VD, Mod, context); auto *Node = Tree.createChildForStruct(this, NodeTy, VD, ChildIndex++); LLVM_DEBUG(llvm::dbgs() << " Creating child for: " < elts) { return createTuple(loc, tupleType, elts); } -SILType SILBuilder::getPartialApplyResultType(SILType origTy, unsigned argCount, - SILModule &M, - SubstitutionMap subs, - ParameterConvention calleeConvention, - PartialApplyInst::OnStackKind onStack) { +SILType SILBuilder::getPartialApplyResultType( + TypeExpansionContext context, SILType origTy, unsigned argCount, + SILModule &M, SubstitutionMap subs, ParameterConvention calleeConvention, + PartialApplyInst::OnStackKind onStack) { CanSILFunctionType FTI = origTy.castTo(); if (!subs.empty()) - FTI = FTI->substGenericArgs(M, subs); - + FTI = FTI->substGenericArgs(M, subs, context); + assert(!FTI->isPolymorphic() && "must provide substitutions for generic partial_apply"); auto params = FTI->getParameters(); @@ -104,7 +103,8 @@ ProjectBoxInst *SILBuilder::createProjectBox(SILLocation Loc, SILValue boxOperand, unsigned index) { auto boxTy = boxOperand->getType().castTo(); - auto fieldTy = getSILBoxFieldType(boxTy, getModule().Types, index); + auto fieldTy = getSILBoxFieldType(getTypeExpansionContext(), boxTy, + getModule().Types, index); return insert(new (getModule()) ProjectBoxInst( getSILDebugLocation(Loc), boxOperand, index, fieldTy)); @@ -511,11 +511,11 @@ void SILBuilder::addOpenedArchetypeOperands(SILInstruction *I) { ValueMetatypeInst *SILBuilder::createValueMetatype(SILLocation Loc, SILType MetatypeTy, SILValue Base) { - assert( - Base->getType().isLoweringOf( - getModule(), MetatypeTy.castTo().getInstanceType()) && - "value_metatype result must be formal metatype of the lowered operand " - "type"); + assert(Base->getType().isLoweringOf( + getTypeExpansionContext(), getModule(), + MetatypeTy.castTo().getInstanceType()) && + "value_metatype result must be formal metatype of the lowered operand " + "type"); return insert(new (getModule()) ValueMetatypeInst(getSILDebugLocation(Loc), MetatypeTy, Base)); } @@ -541,7 +541,8 @@ void SILBuilder::emitDestructureValueOperation( // In non qualified ownership SIL, drop back to using projection code. SmallVector projections; - Projection::getFirstLevelProjections(v->getType(), getModule(), projections); + Projection::getFirstLevelProjections(v->getType(), getModule(), + getTypeExpansionContext(), projections); llvm::transform(projections, std::back_inserter(results), [&](const Projection &p) -> SILValue { return p.createObjectProjection(*this, loc, v).get(); @@ -562,7 +563,8 @@ void SILBuilder::emitDestructureAddressOperation( } SmallVector projections; - Projection::getFirstLevelProjections(v->getType(), getModule(), projections); + Projection::getFirstLevelProjections(v->getType(), getModule(), + getTypeExpansionContext(), projections); llvm::transform(projections, std::back_inserter(results), [&](const Projection &p) -> SILValue { return p.createAddressProjection(*this, loc, v).get(); diff --git a/lib/SIL/SILFunction.cpp b/lib/SIL/SILFunction.cpp index 947ef19def276..a9b76b58653a1 100644 --- a/lib/SIL/SILFunction.cpp +++ b/lib/SIL/SILFunction.cpp @@ -243,34 +243,37 @@ bool SILFunction::isNoReturnFunction() const { const TypeLowering & SILFunction::getTypeLowering(AbstractionPattern orig, Type subst) { return getModule().Types.getTypeLowering(orig, subst, - getResilienceExpansion()); + TypeExpansionContext(*this)); } const TypeLowering &SILFunction::getTypeLowering(Type t) const { - return getModule().Types.getTypeLowering(t, getResilienceExpansion()); + return getModule().Types.getTypeLowering(t, TypeExpansionContext(*this)); } SILType SILFunction::getLoweredType(AbstractionPattern orig, Type subst) const { return getModule().Types.getLoweredType(orig, subst, - getResilienceExpansion()); + TypeExpansionContext(*this)); } SILType SILFunction::getLoweredType(Type t) const { - return getModule().Types.getLoweredType(t, getResilienceExpansion()); + return getModule().Types.getLoweredType(t, TypeExpansionContext(*this)); } SILType SILFunction::getLoweredLoadableType(Type t) const { auto &M = getModule(); - return M.Types.getLoweredLoadableType(t, getResilienceExpansion(), M); + return M.Types.getLoweredLoadableType(t, TypeExpansionContext(*this), M); } const TypeLowering &SILFunction::getTypeLowering(SILType type) const { - return getModule().Types.getTypeLowering(type, getResilienceExpansion()); + return getModule().Types.getTypeLowering(type, TypeExpansionContext(*this)); } +SILType SILFunction::getLoweredType(SILType t) const { + return getTypeLowering(t).getLoweredType().getCategoryType(t.getCategory()); +} bool SILFunction::isTypeABIAccessible(SILType type) const { - return getModule().isTypeABIAccessible(type, getResilienceExpansion()); + return getModule().isTypeABIAccessible(type, TypeExpansionContext(*this)); } bool SILFunction::isWeakImported() const { diff --git a/lib/SIL/SILFunctionBuilder.cpp b/lib/SIL/SILFunctionBuilder.cpp index d465d51fb9fa1..66e0d0416578a 100644 --- a/lib/SIL/SILFunctionBuilder.cpp +++ b/lib/SIL/SILFunctionBuilder.cpp @@ -132,7 +132,8 @@ SILFunctionBuilder::getOrCreateFunction(SILLocation loc, SILDeclRef constant, ForDefinition_t forDefinition, ProfileCounter entryCount) { auto nameTmp = constant.mangle(); - auto constantType = mod.Types.getConstantFunctionType(constant); + auto constantType = mod.Types.getConstantFunctionType( + TypeExpansionContext::minimal(), constant); SILLinkage linkage = constant.getLinkage(forDefinition); if (auto fn = mod.lookUpFunction(nameTmp)) { diff --git a/lib/SIL/SILFunctionType.cpp b/lib/SIL/SILFunctionType.cpp index aa0d91496ac60..02bd60fad2a9b 100644 --- a/lib/SIL/SILFunctionType.cpp +++ b/lib/SIL/SILFunctionType.cpp @@ -246,7 +246,7 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( // Given a type, returns its formal SIL parameter info. auto getTangentParameterInfoForOriginalResult = [&]( CanType tanType, ResultConvention origResConv) -> SILParameterInfo { - auto &tl = TC.getTypeLowering(tanType, ResilienceExpansion::Minimal); + auto &tl = TC.getTypeLowering(tanType, TypeExpansionContext::minimal()); ParameterConvention conv; switch (origResConv) { case ResultConvention::Owned: @@ -269,7 +269,8 @@ CanSILFunctionType SILFunctionType::getAutoDiffDerivativeFunctionType( // Given a type, returns its formal SIL result info. auto getTangentResultInfoForOriginalParameter = [&]( CanType tanType, ParameterConvention origParamConv) -> SILResultInfo { - auto &tl = TC.getTypeLowering(tanType, ResilienceExpansion::Minimal); + auto &tl = + TC.getTypeLowering(tanType, TypeExpansionContext::minimal()); ResultConvention conv; switch (origParamConv) { case ParameterConvention::Direct_Owned: @@ -370,7 +371,7 @@ CanSILFunctionType SILFunctionType::getAutoDiffTransposeFunctionType( auto getParameterInfoForOriginalResult = [&]( const SILResultInfo &result) -> SILParameterInfo { auto &tl = TC.getTypeLowering( - result.getInterfaceType(), ResilienceExpansion::Minimal); + result.getInterfaceType(), TypeExpansionContext::minimal()); ParameterConvention newConv; switch (result.getConvention()) { case ResultConvention::Owned: @@ -394,7 +395,7 @@ CanSILFunctionType SILFunctionType::getAutoDiffTransposeFunctionType( auto getResultInfoForOriginalParameter = [&]( const SILParameterInfo ¶m) -> SILResultInfo { auto &tl = TC.getTypeLowering( - param.getInterfaceType(), ResilienceExpansion::Minimal); + param.getInterfaceType(), TypeExpansionContext::minimal()); ResultConvention newConv; switch (param.getConvention()) { case ParameterConvention::Direct_Owned: @@ -636,10 +637,13 @@ class DestructureResults { TypeConverter &TC; const Conventions &Convs; SmallVectorImpl &Results; + TypeExpansionContext context; + public: - DestructureResults(TypeConverter &TC, const Conventions &conventions, + DestructureResults(TypeExpansionContext context, TypeConverter &TC, + const Conventions &conventions, SmallVectorImpl &results) - : TC(TC), Convs(conventions), Results(results) {} + : TC(TC), Convs(conventions), Results(results), context(context) {} void destructure(AbstractionPattern origType, CanType substType) { // Recurse into tuples. @@ -654,15 +658,19 @@ class DestructureResults { return; } + auto &substResultTLForConvention = TC.getTypeLowering( + origType, substType, TypeExpansionContext::minimal()); auto &substResultTL = TC.getTypeLowering(origType, substType, - ResilienceExpansion::Minimal); + context); + // Determine the result convention. ResultConvention convention; - if (isFormallyReturnedIndirectly(origType, substType, substResultTL)) { + if (isFormallyReturnedIndirectly(origType, substType, + substResultTLForConvention)) { convention = ResultConvention::Indirect; } else { - convention = Convs.getResult(substResultTL); + convention = Convs.getResult(substResultTLForConvention); // Reduce conventions for trivial types to an unowned convention. if (substResultTL.isTrivial()) { @@ -805,6 +813,7 @@ static bool isFormallyPassedIndirectly(TypeConverter &TC, /// /// See the comment in AbstractionPattern.h for details. class DestructureInputs { + TypeExpansionContext expansion; TypeConverter &TC; const Conventions &Convs; const ForeignInfo &Foreign; @@ -812,10 +821,11 @@ class DestructureInputs { SmallVectorImpl &Inputs; unsigned NextOrigParamIndex = 0; public: - DestructureInputs(TypeConverter &TC, const Conventions &conventions, - const ForeignInfo &foreign, + DestructureInputs(TypeExpansionContext expansion, TypeConverter &TC, + const Conventions &conventions, const ForeignInfo &foreign, SmallVectorImpl &inputs) - : TC(TC), Convs(conventions), Foreign(foreign), Inputs(inputs) {} + : expansion(expansion), TC(TC), Convs(conventions), Foreign(foreign), + Inputs(inputs) {} void destructure(AbstractionPattern origType, CanAnyFunctionType::CanParamArrayRef params, @@ -929,20 +939,21 @@ class DestructureInputs { unsigned origParamIndex = NextOrigParamIndex++; - auto &substTL = TC.getTypeLowering(origType, substType, - ResilienceExpansion::Minimal); + auto &substTLConv = TC.getTypeLowering(origType, substType, + TypeExpansionContext::minimal()); + auto &substTL = TC.getTypeLowering(origType, substType, expansion); ParameterConvention convention; if (ownership == ValueOwnership::InOut) { convention = ParameterConvention::Indirect_Inout; - } else if (isFormallyPassedIndirectly(origType, substType, substTL)) { + } else if (isFormallyPassedIndirectly(origType, substType, substTLConv)) { convention = Convs.getIndirect(ownership, forSelf, origParamIndex, - origType, substTL); + origType, substTLConv); assert(isIndirectFormalParameter(convention)); } else if (substTL.isTrivial()) { convention = ParameterConvention::Direct_Unowned; } else { convention = Convs.getDirect(ownership, forSelf, origParamIndex, origType, - substTL); + substTLConv); assert(!isIndirectFormalParameter(convention)); } auto loweredType = substTL.getLoweredType().getASTType(); @@ -971,8 +982,8 @@ class DestructureInputs { NextOrigParamIndex != Foreign.Error->getErrorParameterIndex()) return false; - auto foreignErrorTy = - TC.getLoweredRValueType(Foreign.Error->getErrorParameterType()); + auto foreignErrorTy = TC.getLoweredRValueType( + expansion, Foreign.Error->getErrorParameterType()); // Assume the error parameter doesn't have interesting lowering. Inputs.push_back(SILParameterInfo(foreignErrorTy, @@ -1061,7 +1072,7 @@ static std::pair updateResultTypeForForeignError( static void lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, CanGenericSignature genericSig, - ResilienceExpansion expansion, + TypeExpansionContext expansion, SmallVectorImpl &inputs) { // NB: The generic signature may be elided from the lowered function type @@ -1133,9 +1144,14 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, break; } case CaptureKind::Box: { + // The type in the box is lowered in the minimal context. + auto minimalLoweredTy = + TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType, + TypeExpansionContext::minimal()) + .getLoweredType(); // Lvalues are captured as a box that owns the captured value. auto boxTy = TC.getInterfaceBoxTypeForCapture( - VD, loweredTy.getASTType(), + VD, minimalLoweredTy.getASTType(), /*mutable*/ true); auto convention = ParameterConvention::Direct_Guaranteed; auto param = SILParameterInfo(boxTy, convention); @@ -1156,6 +1172,7 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function, } static void destructureYieldsForReadAccessor(TypeConverter &TC, + TypeExpansionContext expansion, AbstractionPattern origType, CanType valueType, SmallVectorImpl &yields) { @@ -1165,17 +1182,20 @@ static void destructureYieldsForReadAccessor(TypeConverter &TC, for (auto i : indices(valueTupleType.getElementTypes())) { auto origEltType = origType.getTupleElementType(i); auto valueEltType = valueTupleType.getElementType(i); - destructureYieldsForReadAccessor(TC, origEltType, valueEltType, yields); + destructureYieldsForReadAccessor(TC, expansion, origEltType, valueEltType, + yields); } return; } - auto &tl = TC.getTypeLowering(origType, valueType, - ResilienceExpansion::Minimal); + auto &tlConv = + TC.getTypeLowering(origType, valueType, TypeExpansionContext::minimal()); + auto &tl = + TC.getTypeLowering(origType, valueType, expansion); auto convention = [&] { - if (isFormallyPassedIndirectly(TC, origType, valueType, tl)) + if (isFormallyPassedIndirectly(TC, origType, valueType, tlConv)) return ParameterConvention::Indirect_In_Guaranteed; - if (tl.isTrivial()) + if (tlConv.isTrivial()) return ParameterConvention::Direct_Unowned; return ParameterConvention::Direct_Guaranteed; }(); @@ -1184,6 +1204,7 @@ static void destructureYieldsForReadAccessor(TypeConverter &TC, } static void destructureYieldsForCoroutine(TypeConverter &TC, + TypeExpansionContext expansion, Optional origConstant, Optional constant, Optional reqtSubs, @@ -1222,7 +1243,8 @@ static void destructureYieldsForCoroutine(TypeConverter &TC, // 'modify' yields an inout of the target type. if (accessor->getAccessorKind() == AccessorKind::Modify) { - auto loweredValueTy = TC.getLoweredRValueType(origType, canValueType); + auto loweredValueTy = + TC.getLoweredRValueType(expansion, origType, canValueType); yields.push_back(SILYieldInfo(loweredValueTy, ParameterConvention::Indirect_Inout)); return; @@ -1231,7 +1253,8 @@ static void destructureYieldsForCoroutine(TypeConverter &TC, // 'read' yields a borrowed value of the target type, destructuring // tuples as necessary. assert(accessor->getAccessorKind() == AccessorKind::Read); - destructureYieldsForReadAccessor(TC, origType, canValueType, yields); + destructureYieldsForReadAccessor(TC, expansion, origType, canValueType, + yields); } /// Create the appropriate SIL function type for the given formal type @@ -1270,7 +1293,7 @@ static void destructureYieldsForCoroutine(TypeConverter &TC, /// /// \param conventions - conventions as expressed for the original type static CanSILFunctionType getSILFunctionType( - TypeConverter &TC, AbstractionPattern origType, + TypeConverter &TC, TypeExpansionContext expansionContext, AbstractionPattern origType, CanAnyFunctionType substFnInterfaceType, AnyFunctionType::ExtInfo extInfo, const Conventions &conventions, const ForeignInfo &foreignInfo, Optional origConstant, Optional constant, @@ -1322,14 +1345,15 @@ static CanSILFunctionType getSILFunctionType( // Destructure the result tuple type. SmallVector results; { - DestructureResults destructurer(TC, conventions, results); + DestructureResults destructurer(expansionContext, TC, conventions, results); destructurer.destructure(origResultType, substFormalResultType); } // Destructure the input tuple type. SmallVector inputs; { - DestructureInputs destructurer(TC, conventions, foreignInfo, inputs); + DestructureInputs destructurer(expansionContext, TC, conventions, + foreignInfo, inputs); destructurer.destructure(origType, substFnInterfaceType.getParams(), extInfo); @@ -1338,16 +1362,16 @@ static CanSILFunctionType getSILFunctionType( // Destructure the coroutine yields. SILCoroutineKind coroutineKind = SILCoroutineKind::None; SmallVector yields; - destructureYieldsForCoroutine(TC, origConstant, constant, reqtSubs, - yields, coroutineKind); - + destructureYieldsForCoroutine(TC, expansionContext, origConstant, constant, + reqtSubs, yields, coroutineKind); + // Lower the capture context parameters, if any. if (constant && constant->getAnyFunctionRef()) { - auto expansion = ResilienceExpansion::Maximal; + auto expansion = TypeExpansionContext::maximal( + expansionContext.getContext(), expansionContext.isWholeModuleContext()); if (constant->isSerialized()) - expansion = ResilienceExpansion::Minimal; - lowerCaptureContextParameters(TC, *constant, genericSig, expansion, - inputs); + expansion = TypeExpansionContext::minimal(); + lowerCaptureContextParameters(TC, *constant, genericSig, expansion, inputs); } auto calleeConvention = ParameterConvention::Direct_Unowned; @@ -1742,7 +1766,7 @@ getSILFunctionTypeForAbstractCFunction(TypeConverter &TC, Optional constant); static CanSILFunctionType getNativeSILFunctionType( - TypeConverter &TC, AbstractionPattern origType, + TypeConverter &TC, TypeExpansionContext context, AbstractionPattern origType, CanAnyFunctionType substInterfaceType, AnyFunctionType::ExtInfo extInfo, Optional origConstant, Optional constant, Optional reqtSubs, @@ -1764,23 +1788,23 @@ static CanSILFunctionType getNativeSILFunctionType( switch (constant ? constant->kind : SILDeclRef::Kind::Func) { case SILDeclRef::Kind::Initializer: case SILDeclRef::Kind::EnumElement: - return getSILFunctionType(TC, origType, substInterfaceType, extInfo, - DefaultInitializerConventions(), ForeignInfo(), - origConstant, constant, reqtSubs, + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, DefaultInitializerConventions(), + ForeignInfo(), origConstant, constant, reqtSubs, witnessMethodConformance); case SILDeclRef::Kind::Allocator: - return getSILFunctionType(TC, origType, substInterfaceType, extInfo, - DefaultAllocatorConventions(), ForeignInfo(), - origConstant, constant, reqtSubs, + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, DefaultAllocatorConventions(), + ForeignInfo(), origConstant, constant, reqtSubs, witnessMethodConformance); case SILDeclRef::Kind::Func: // If we have a setter, use the special setter convention. This ensures // that we take normal parameters at +1. if (constant && constant->isSetter()) { - return getSILFunctionType(TC, origType, substInterfaceType, extInfo, - DefaultSetterConventions(), ForeignInfo(), - origConstant, constant, reqtSubs, - witnessMethodConformance); + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, DefaultSetterConventions(), + ForeignInfo(), origConstant, constant, + reqtSubs, witnessMethodConformance); } LLVM_FALLTHROUGH; case SILDeclRef::Kind::Destroyer: @@ -1791,14 +1815,14 @@ static CanSILFunctionType getNativeSILFunctionType( case SILDeclRef::Kind::IVarInitializer: case SILDeclRef::Kind::IVarDestroyer: { auto conv = DefaultConventions(NormalParameterConvention::Guaranteed); - return getSILFunctionType(TC, origType, substInterfaceType, extInfo, conv, - ForeignInfo(), origConstant, constant, reqtSubs, - witnessMethodConformance); + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, conv, ForeignInfo(), origConstant, + constant, reqtSubs, witnessMethodConformance); } case SILDeclRef::Kind::Deallocator: - return getSILFunctionType(TC, origType, substInterfaceType, extInfo, - DeallocatorConventions(), ForeignInfo(), - origConstant, constant, reqtSubs, + return getSILFunctionType(TC, context, origType, substInterfaceType, + extInfo, DeallocatorConventions(), + ForeignInfo(), origConstant, constant, reqtSubs, witnessMethodConformance); } } @@ -1808,9 +1832,10 @@ static CanSILFunctionType getNativeSILFunctionType( } CanSILFunctionType swift::getNativeSILFunctionType( - TypeConverter &TC, AbstractionPattern origType, - CanAnyFunctionType substType, Optional origConstant, - Optional substConstant, Optional reqtSubs, + TypeConverter &TC, TypeExpansionContext context, + AbstractionPattern origType, CanAnyFunctionType substType, + Optional origConstant, Optional substConstant, + Optional reqtSubs, ProtocolConformanceRef witnessMethodConformance) { AnyFunctionType::ExtInfo extInfo; @@ -1823,7 +1848,7 @@ CanSILFunctionType swift::getNativeSILFunctionType( extInfo = substType->getExtInfo(); } - return ::getNativeSILFunctionType(TC, origType, substType, extInfo, + return ::getNativeSILFunctionType(TC, context, origType, substType, extInfo, origConstant, substConstant, reqtSubs, witnessMethodConformance); } @@ -2170,7 +2195,8 @@ getSILFunctionTypeForClangDecl(TypeConverter &TC, const clang::Decl *clangDecl, if (auto method = dyn_cast(clangDecl)) { auto origPattern = AbstractionPattern::getObjCMethod(origType, method, foreignInfo.Error); - return getSILFunctionType(TC, origPattern, substInterfaceType, extInfo, + return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, + substInterfaceType, extInfo, ObjCMethodConventions(method), foreignInfo, constant, constant, None, ProtocolConformanceRef()); @@ -2180,9 +2206,10 @@ getSILFunctionTypeForClangDecl(TypeConverter &TC, const clang::Decl *clangDecl, AbstractionPattern origPattern = AbstractionPattern::getCXXMethod(origType, method); auto conventions = CXXMethodConventions(method); - return getSILFunctionType(TC, origPattern, substInterfaceType, extInfo, - conventions, foreignInfo, constant, constant, - None, ProtocolConformanceRef()); + return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, + substInterfaceType, extInfo, conventions, + foreignInfo, constant, constant, None, + ProtocolConformanceRef()); } if (auto func = dyn_cast(clangDecl)) { @@ -2192,7 +2219,8 @@ getSILFunctionTypeForClangDecl(TypeConverter &TC, const clang::Decl *clangDecl, ? AbstractionPattern::getCFunctionAsMethod(origType, clangType, foreignInfo.Self) : AbstractionPattern(origType, clangType); - return getSILFunctionType(TC, origPattern, substInterfaceType, extInfo, + return getSILFunctionType(TC, TypeExpansionContext::minimal(), origPattern, + substInterfaceType, extInfo, CFunctionConventions(func), foreignInfo, constant, constant, None, ProtocolConformanceRef()); } @@ -2222,15 +2250,17 @@ getSILFunctionTypeForAbstractCFunction(TypeConverter &TC, } if (fnType) { return getSILFunctionType( - TC, origType, substType, extInfo, CFunctionTypeConventions(fnType), - ForeignInfo(), constant, constant, None, ProtocolConformanceRef()); + TC, TypeExpansionContext::minimal(), origType, substType, extInfo, + CFunctionTypeConventions(fnType), ForeignInfo(), constant, constant, + None, ProtocolConformanceRef()); } } // TODO: Ought to support captures in block funcs. - return getSILFunctionType(TC, origType, substType, extInfo, - DefaultBlockConventions(), ForeignInfo(), constant, - constant, None, ProtocolConformanceRef()); + return getSILFunctionType(TC, TypeExpansionContext::minimal(), origType, + substType, extInfo, DefaultBlockConventions(), + ForeignInfo(), constant, constant, None, + ProtocolConformanceRef()); } /// Try to find a clang method declaration for the given function. @@ -2395,8 +2425,9 @@ getSILFunctionTypeForObjCSelectorFamily(TypeConverter &TC, ObjCSelectorFamily fa const ForeignInfo &foreignInfo, Optional constant) { return getSILFunctionType( - TC, AbstractionPattern(origType), substInterfaceType, extInfo, - ObjCSelectorFamilyConventions(family), foreignInfo, constant, constant, + TC, TypeExpansionContext::minimal(), AbstractionPattern(origType), + substInterfaceType, extInfo, ObjCSelectorFamilyConventions(family), + foreignInfo, constant, constant, /*requirement subs*/ None, ProtocolConformanceRef()); } @@ -2418,10 +2449,9 @@ static bool isImporterGeneratedAccessor(const clang::Decl *clangDecl, return true; } -static CanSILFunctionType -getUncachedSILFunctionTypeForConstant(TypeConverter &TC, - SILDeclRef constant, - CanAnyFunctionType origLoweredInterfaceType) { +static CanSILFunctionType getUncachedSILFunctionTypeForConstant( + TypeConverter &TC, TypeExpansionContext context, SILDeclRef constant, + CanAnyFunctionType origLoweredInterfaceType) { assert(origLoweredInterfaceType->getExtInfo().getSILRepresentation() != SILFunctionTypeRepresentation::Thick && origLoweredInterfaceType->getExtInfo().getSILRepresentation() @@ -2439,9 +2469,9 @@ getUncachedSILFunctionTypeForConstant(TypeConverter &TC, } return ::getNativeSILFunctionType( - TC, AbstractionPattern(origLoweredInterfaceType), - origLoweredInterfaceType, extInfo, - constant, constant, None, witnessMethodConformance); + TC, context, AbstractionPattern(origLoweredInterfaceType), + origLoweredInterfaceType, extInfo, constant, constant, None, + witnessMethodConformance); } ForeignInfo foreignInfo; @@ -2481,12 +2511,12 @@ getUncachedSILFunctionTypeForConstant(TypeConverter &TC, extInfo, foreignInfo, constant); } -CanSILFunctionType TypeConverter:: -getUncachedSILFunctionTypeForConstant(SILDeclRef constant, - CanAnyFunctionType origInterfaceType) { +CanSILFunctionType TypeConverter::getUncachedSILFunctionTypeForConstant( + TypeExpansionContext context, SILDeclRef constant, + CanAnyFunctionType origInterfaceType) { auto origLoweredInterfaceType = getLoweredFormalTypes(constant, origInterfaceType).Uncurried; - return ::getUncachedSILFunctionTypeForConstant(*this, constant, + return ::getUncachedSILFunctionTypeForConstant(*this, context, constant, origLoweredInterfaceType); } @@ -2566,9 +2596,11 @@ static llvm::cl::opt DisableConstantInfoCache("sil-disable-typelowering-constantinfo-cache", llvm::cl::init(false)); -const SILConstantInfo &TypeConverter::getConstantInfo(SILDeclRef constant) { +const SILConstantInfo & +TypeConverter::getConstantInfo(TypeExpansionContext expansion, + SILDeclRef constant) { if (!DisableConstantInfoCache) { - auto found = ConstantTypes.find(constant); + auto found = ConstantTypes.find(std::make_pair(expansion, constant)); if (found != ConstantTypes.end()) return *found->second; } @@ -2589,7 +2621,7 @@ const SILConstantInfo &TypeConverter::getConstantInfo(SILDeclRef constant) { // The SIL type encodes conventions according to the original type. CanSILFunctionType silFnType = - ::getUncachedSILFunctionTypeForConstant(*this, constant, + ::getUncachedSILFunctionTypeForConstant(*this, expansion, constant, loweredInterfaceType); // SWIFT_ENABLE_TENSORFLOW @@ -2605,8 +2637,8 @@ const SILConstantInfo &TypeConverter::getConstantInfo(SILDeclRef constant) { // // We hackily fix this problem by redoing the computation in the right order. if (auto *autoDiffFuncId = constant.autoDiffDerivativeFunctionIdentifier) { - auto origFnConstantInfo = - getConstantInfo(constant.asAutoDiffOriginalFunction()); + auto origFnConstantInfo = getConstantInfo( + TypeExpansionContext::minimal(), constant.asAutoDiffOriginalFunction()); auto loweredIndices = autodiff::getLoweredParameterIndices( autoDiffFuncId->getParameterIndices(), formalInterfaceType); silFnType = origFnConstantInfo.SILFnType->getAutoDiffDerivativeFunctionType( @@ -2634,7 +2666,8 @@ const SILConstantInfo &TypeConverter::getConstantInfo(SILDeclRef constant) { if (DisableConstantInfoCache) return *result; - auto inserted = ConstantTypes.insert({constant, result}); + auto inserted = + ConstantTypes.insert({std::make_pair(expansion, constant), result}); assert(inserted.second); (void)inserted; return *result; @@ -2642,8 +2675,10 @@ const SILConstantInfo &TypeConverter::getConstantInfo(SILDeclRef constant) { /// Returns the SILParameterInfo for the given declaration's `self` parameter. /// `constant` must refer to a method. -SILParameterInfo TypeConverter::getConstantSelfParameter(SILDeclRef constant) { - auto ty = getConstantFunctionType(constant); +SILParameterInfo +TypeConverter::getConstantSelfParameter(TypeExpansionContext context, + SILDeclRef constant) { + auto ty = getConstantFunctionType(context, constant); // In most cases the "self" parameter is lowered as the back parameter. // The exception is C functions imported as methods. @@ -2747,10 +2782,11 @@ static CanType copyOptionalityFromDerivedToBase(TypeConverter &tc, /// Returns the ConstantInfo corresponding to the VTable thunk for overriding. /// Will be the same as getConstantInfo if the declaration does not override. const SILConstantInfo & -TypeConverter::getConstantOverrideInfo(SILDeclRef derived, SILDeclRef base) { +TypeConverter::getConstantOverrideInfo(TypeExpansionContext context, + SILDeclRef derived, SILDeclRef base) { // Foreign overrides currently don't need reabstraction. if (derived.isForeign) - return getConstantInfo(derived); + return getConstantInfo(context, derived); auto found = ConstantOverrideTypes.find({derived, base}); if (found != ConstantOverrideTypes.end()) @@ -2758,8 +2794,8 @@ TypeConverter::getConstantOverrideInfo(SILDeclRef derived, SILDeclRef base) { assert(base.requiresNewVTableEntry() && "base must not be an override"); - auto baseInfo = getConstantInfo(base); - auto derivedInfo = getConstantInfo(derived); + auto baseInfo = getConstantInfo(context, base); + auto derivedInfo = getConstantInfo(context, derived); // If the derived method is ABI-compatible with the base method, give the // vtable thunk the same signature as the derived method. @@ -2806,7 +2842,7 @@ TypeConverter::getConstantOverrideInfo(SILDeclRef derived, SILDeclRef base) { // Build the SILFunctionType for the vtable thunk. CanSILFunctionType fnTy = getNativeSILFunctionType( - *this, basePattern, overrideLoweredInterfaceTy, base, derived, + *this, context, basePattern, overrideLoweredInterfaceTy, base, derived, /*reqt subs*/ None, ProtocolConformanceRef()); // Build the SILConstantInfo and cache it. @@ -2839,10 +2875,13 @@ class SILTypeSubstituter : // context signature. CanGenericSignature Sig; + TypeExpansionContext typeExpansionContext; + bool shouldSubstituteOpaqueArchetypes; public: SILTypeSubstituter(TypeConverter &TC, + TypeExpansionContext context, TypeSubstitutionFn Subst, LookupConformanceFn Conformances, CanGenericSignature Sig, @@ -2851,6 +2890,7 @@ class SILTypeSubstituter : Subst(Subst), Conformances(Conformances), Sig(Sig), + typeExpansionContext(context), shouldSubstituteOpaqueArchetypes(shouldSubstituteOpaqueArchetypes) {} @@ -2914,13 +2954,31 @@ class SILTypeSubstituter : } witnessMethodConformance = conformance.subst(selfType, Subst, Conformances); + + // Substitute the underlying conformance of opaque type archetypes if we + // should look through opaque archetypes. + if (typeExpansionContext.shouldLookThroughOpaqueTypeArchetypes()) { + SubstOptions substOptions(None); + auto substType = selfType.subst(Subst, Conformances, substOptions) + ->getCanonicalType(); + if (substType->hasOpaqueArchetype()) { + witnessMethodConformance = substOpaqueTypesWithUnderlyingTypes( + witnessMethodConformance, substType, typeExpansionContext); + } + } } // The substituted type is no longer generic, so it'd never be // pseudogeneric. - auto extInfo = origType->getExtInfo().withIsPseudogeneric(false); + auto extInfo = origType->getExtInfo(); + if (!shouldSubstituteOpaqueArchetypes) + extInfo = extInfo.withIsPseudogeneric(false); - return SILFunctionType::get(nullptr, extInfo, + auto genericSig = shouldSubstituteOpaqueArchetypes + ? origType->getSubstGenericSignature() + : nullptr; + + return SILFunctionType::get(genericSig, extInfo, origType->getCoroutineKind(), origType->getCalleeConvention(), substParams, substYields, substResults, substErrorResult, @@ -3001,7 +3059,14 @@ class SILTypeSubstituter : } AbstractionPattern abstraction(Sig, origType); - return TC.getLoweredRValueType(abstraction, substType); + // If we looked through an opaque archetype to a function type we need to + // use the function type's abstraction. + if (isa(origType) && + isa(substType)) + abstraction = AbstractionPattern(Sig, substType); + + return TC.getLoweredRValueType(typeExpansionContext, abstraction, + substType); } }; @@ -3018,8 +3083,9 @@ SILType SILType::subst(TypeConverter &tc, TypeSubstitutionFn subs, if (!genericSig) genericSig = tc.getCurGenericContext(); - SILTypeSubstituter STST(tc, subs, conformances, - genericSig, shouldSubstituteOpaqueArchetypes); + SILTypeSubstituter STST(tc, TypeExpansionContext::minimal(), subs, + conformances, genericSig, + shouldSubstituteOpaqueArchetypes); return STST.subst(*this); } @@ -3043,8 +3109,8 @@ SILType SILType::subst(SILModule &M, SubstitutionMap subs) const{ /// it has the form of the normal SILFunctionType for the substituted /// type, except using the original conventions. CanSILFunctionType -SILFunctionType::substGenericArgs(SILModule &silModule, - SubstitutionMap subs) { +SILFunctionType::substGenericArgs(SILModule &silModule, SubstitutionMap subs, + TypeExpansionContext context) { if (!isPolymorphic()) { return CanSILFunctionType(this); } @@ -3055,20 +3121,49 @@ SILFunctionType::substGenericArgs(SILModule &silModule, return substGenericArgs(silModule, QuerySubstitutionMap{subs}, - LookUpConformanceInSubstitutionMap(subs)); + LookUpConformanceInSubstitutionMap(subs), + context); } CanSILFunctionType SILFunctionType::substGenericArgs(SILModule &silModule, TypeSubstitutionFn subs, - LookupConformanceFn conformances) { + LookupConformanceFn conformances, + TypeExpansionContext context) { if (!isPolymorphic()) return CanSILFunctionType(this); - SILTypeSubstituter substituter(silModule.Types, subs, conformances, + SILTypeSubstituter substituter(silModule.Types, context, subs, conformances, getSubstGenericSignature(), /*shouldSubstituteOpaqueTypes*/ false); return substituter.substSILFunctionType(CanSILFunctionType(this)); } +CanSILFunctionType +SILFunctionType::substituteOpaqueArchetypes(TypeConverter &TC, + TypeExpansionContext context) { + if (!hasOpaqueArchetype() || + !context.shouldLookThroughOpaqueTypeArchetypes()) + return CanSILFunctionType(this); + + ReplaceOpaqueTypesWithUnderlyingTypes replacer( + context.getContext(), context.getResilienceExpansion(), + context.isWholeModuleContext()); + + assert(!(getSubstGenericSignature() && TC.getCurGenericContext())); + + auto genericSig = getSubstGenericSignature(); + GenericContextScope genericContext(TC, genericSig); + if (!genericSig) { + genericSig = TC.getCurGenericContext(); + } + + SILTypeSubstituter substituter(TC, context, replacer, replacer, genericSig, + /*shouldSubstituteOpaqueTypes*/ true); + auto resTy = + substituter.substSILFunctionType(CanSILFunctionType(this)); + + return resTy; +} + /// Fast path for bridging types in a function type without uncurrying. CanAnyFunctionType TypeConverter::getBridgedFunctionType(AbstractionPattern pattern, @@ -3340,7 +3435,8 @@ static bool areABICompatibleParamsOrReturns(SILType a, SILType b, if (!dc || !dc->isChildContextOf(currentModule)) dc = currentModule; ReplaceOpaqueTypesWithUnderlyingTypes replacer( - dc, inFunction->getResilienceExpansion()); + dc, inFunction->getResilienceExpansion(), + inFunction->getModule().isWholeModule()); if (aa.getASTType()->hasOpaqueArchetype()) opaqueTypesSubsituted = aa.subst(inFunction->getModule(), replacer, replacer, CanGenericSignature(), true); @@ -3536,3 +3632,26 @@ SILFunctionType::withSubstitutions(SubstitutionMap subs) const { subs, isGenericSignatureImplied(), const_cast(this)->getASTContext()); } + +static DeclContext *getDeclContextForExpansion(const SILFunction &f) { + auto *dc = f.getDeclContext(); + if (!dc) + dc = f.getModule().getSwiftModule(); + auto *currentModule = f.getModule().getSwiftModule(); + if (!dc || !dc->isChildContextOf(currentModule)) + dc = currentModule; + return dc; +} + +TypeExpansionContext::TypeExpansionContext(const SILFunction &f) + : expansion(f.getResilienceExpansion()), + inContext(getDeclContextForExpansion(f)), + isContextWholeModule(f.getModule().isWholeModule()) {} + +CanSILFunctionType SILFunction::getLoweredFunctionTypeInContext( + TypeExpansionContext context) const { + auto origFunTy = getLoweredFunctionType(); + auto &M = getModule(); + auto funTy = M.Types.getLoweredType(origFunTy , context); + return cast(funTy.getASTType()); +} diff --git a/lib/SIL/SILGlobalVariable.cpp b/lib/SIL/SILGlobalVariable.cpp index 48d66dd76e3de..733ad528dcd52 100644 --- a/lib/SIL/SILGlobalVariable.cpp +++ b/lib/SIL/SILGlobalVariable.cpp @@ -310,3 +310,14 @@ swift::getVariableOfStaticInitializer(SILFunction *InitFunc, return nullptr; return GVar; } + +SILType +SILGlobalVariable::getLoweredTypeInContext(TypeExpansionContext context) const { + auto ty = getLoweredType(); + if (!ty.getASTType()->hasOpaqueArchetype() || + !context.shouldLookThroughOpaqueTypeArchetypes()) + return ty; + auto resultTy = + getModule().Types.getTypeLowering(ty, context).getLoweredType(); + return resultTy.getCategoryType(ty.getCategory()); +} diff --git a/lib/SIL/SILInstruction.cpp b/lib/SIL/SILInstruction.cpp index 4d73281ce1309..b1e14d28d4521 100644 --- a/lib/SIL/SILInstruction.cpp +++ b/lib/SIL/SILInstruction.cpp @@ -1172,9 +1172,9 @@ SILInstruction *SILInstruction::clone(SILInstruction *InsertPt) { /// additional handling. It is important to know this information when /// you perform such optimizations like e.g. jump-threading. bool SILInstruction::isTriviallyDuplicatable() const { - if (isa(this) || isa(this)) { + if (isAllocatingStack()) return false; - } + if (auto *ARI = dyn_cast(this)) { if (ARI->canAllocOnStack()) return false; @@ -1213,9 +1213,6 @@ bool SILInstruction::isTriviallyDuplicatable() const { if (isa(this)) return false; - if (auto *PA = dyn_cast(this)) - return !PA->isOnStack(); - // If you add more cases here, you should also update SILLoop:canDuplicate. return true; diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp index 7ee43554d1e42..3441ee91cacc3 100644 --- a/lib/SIL/SILInstructions.cpp +++ b/lib/SIL/SILInstructions.cpp @@ -285,7 +285,9 @@ AllocBoxInst *AllocBoxInst::create(SILDebugLocation Loc, } SILType AllocBoxInst::getAddressType() const { - return getSILBoxFieldType(getBoxType(), getModule().Types, 0).getAddressType(); + return getSILBoxFieldType(TypeExpansionContext(*this->getFunction()), + getBoxType(), getModule().Types, 0) + .getAddressType(); } VarDecl *AllocBoxInst::getDecl() const { @@ -416,8 +418,8 @@ ApplyInst::create(SILDebugLocation Loc, SILValue Callee, SubstitutionMap Subs, Optional ModuleConventions, SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes, const GenericSpecializationInformation *SpecializationInfo) { - SILType SubstCalleeSILTy = - Callee->getType().substGenericArgs(F.getModule(), Subs); + SILType SubstCalleeSILTy = Callee->getType().substGenericArgs( + F.getModule(), Subs, F.getTypeExpansionContext()); auto SubstCalleeTy = SubstCalleeSILTy.getAs(); SILFunctionConventions Conv(SubstCalleeTy, ModuleConventions.hasValue() @@ -462,8 +464,8 @@ BeginApplyInst::create(SILDebugLocation loc, SILValue callee, SILFunction &F, SILOpenedArchetypesState &openedArchetypes, const GenericSpecializationInformation *specializationInfo) { - SILType substCalleeSILType = - callee->getType().substGenericArgs(F.getModule(), subs); + SILType substCalleeSILType = callee->getType().substGenericArgs( + F.getModule(), subs, F.getTypeExpansionContext()); auto substCalleeType = substCalleeSILType.castTo(); SILFunctionConventions conv(substCalleeType, @@ -553,10 +555,11 @@ PartialApplyInst *PartialApplyInst::create( SILOpenedArchetypesState &OpenedArchetypes, const GenericSpecializationInformation *SpecializationInfo, OnStackKind onStack) { - SILType SubstCalleeTy = - Callee->getType().substGenericArgs(F.getModule(), Subs); + SILType SubstCalleeTy = Callee->getType().substGenericArgs( + F.getModule(), Subs, F.getTypeExpansionContext()); SILType ClosureType = SILBuilder::getPartialApplyResultType( - SubstCalleeTy, Args.size(), F.getModule(), {}, CalleeConvention, onStack); + F.getTypeExpansionContext(), SubstCalleeTy, Args.size(), F.getModule(), {}, + CalleeConvention, onStack); SmallVector TypeDependentOperands; collectTypeDependentOperands(TypeDependentOperands, OpenedArchetypes, F, @@ -591,8 +594,8 @@ TryApplyInst *TryApplyInst::create( ArrayRef args, SILBasicBlock *normalBB, SILBasicBlock *errorBB, SILFunction &F, SILOpenedArchetypesState &openedArchetypes, const GenericSpecializationInformation *specializationInfo) { - SILType substCalleeTy = - callee->getType().substGenericArgs(F.getModule(), subs); + SILType substCalleeTy = callee->getType().substGenericArgs( + F.getModule(), subs, F.getTypeExpansionContext()); SmallVector typeDependentOperands; collectTypeDependentOperands(typeDependentOperands, openedArchetypes, F, @@ -800,8 +803,9 @@ DifferentiabilityWitnessFunctionInst::DifferentiabilityWitnessFunctionInst( FunctionRefBaseInst::FunctionRefBaseInst(SILInstructionKind Kind, SILDebugLocation DebugLoc, - SILFunction *F) - : LiteralInst(Kind, DebugLoc, F->getLoweredType()), f(F) { + SILFunction *F, + TypeExpansionContext context) + : LiteralInst(Kind, DebugLoc, F->getLoweredTypeInContext(context)), f(F) { F->incrementRefCount(); } @@ -816,21 +820,25 @@ FunctionRefBaseInst::~FunctionRefBaseInst() { getInitiallyReferencedFunction()->decrementRefCount(); } -FunctionRefInst::FunctionRefInst(SILDebugLocation Loc, SILFunction *F) - : FunctionRefBaseInst(SILInstructionKind::FunctionRefInst, Loc, F) { +FunctionRefInst::FunctionRefInst(SILDebugLocation Loc, SILFunction *F, + TypeExpansionContext context) + : FunctionRefBaseInst(SILInstructionKind::FunctionRefInst, Loc, F, + context) { assert(!F->isDynamicallyReplaceable()); } DynamicFunctionRefInst::DynamicFunctionRefInst(SILDebugLocation Loc, - SILFunction *F) - : FunctionRefBaseInst(SILInstructionKind::DynamicFunctionRefInst, Loc, F) { + SILFunction *F, + TypeExpansionContext context) + : FunctionRefBaseInst(SILInstructionKind::DynamicFunctionRefInst, Loc, F, + context) { assert(F->isDynamicallyReplaceable()); } PreviousDynamicFunctionRefInst::PreviousDynamicFunctionRefInst( - SILDebugLocation Loc, SILFunction *F) + SILDebugLocation Loc, SILFunction *F, TypeExpansionContext context) : FunctionRefBaseInst(SILInstructionKind::PreviousDynamicFunctionRefInst, - Loc, F) { + Loc, F, context) { assert(!F->isDynamicallyReplaceable()); } @@ -840,16 +848,19 @@ AllocGlobalInst::AllocGlobalInst(SILDebugLocation Loc, Global(Global) {} GlobalAddrInst::GlobalAddrInst(SILDebugLocation DebugLoc, - SILGlobalVariable *Global) - : InstructionBase(DebugLoc, Global->getLoweredType().getAddressType(), + SILGlobalVariable *Global, + TypeExpansionContext context) + : InstructionBase(DebugLoc, + Global->getLoweredTypeInContext(context).getAddressType(), Global) {} GlobalValueInst::GlobalValueInst(SILDebugLocation DebugLoc, - SILGlobalVariable *Global) - : InstructionBase(DebugLoc, Global->getLoweredType().getObjectType(), + SILGlobalVariable *Global, + TypeExpansionContext context) + : InstructionBase(DebugLoc, + Global->getLoweredTypeInContext(context).getObjectType(), Global) {} - const IntrinsicInfo &BuiltinInst::getIntrinsicInfo() const { return getModule().getIntrinsicInfo(getName()); } @@ -1279,7 +1290,8 @@ bool StructExtractInst::isTrivialFieldOfOneRCIDStruct() const { // Otherwise check if we have a non-trivial type. If we don't have one, // continue. - if (StructTy.getFieldType(D, F->getModule()).isTrivial(*F)) + if (StructTy.getFieldType(D, F->getModule(), TypeExpansionContext(*F)) + .isTrivial(*F)) continue; // Ok, this type is non-trivial. If we have not seen a non-trivial field @@ -1324,7 +1336,8 @@ bool StructExtractInst::isFieldOnlyNonTrivialField() const { // Ok, we have a field that is not equal to the field we are // extracting. If that field is trivial, we do not care about // it... continue. - if (StructTy.getFieldType(D, F->getModule()).isTrivial(*F)) + if (StructTy.getFieldType(D, F->getModule(), TypeExpansionContext(*F)) + .isTrivial(*F)) continue; // We have found a non trivial member that is not the member we are @@ -2642,11 +2655,12 @@ static void computeAggregateFirstLevelSubtypeInfo( // TODO: Create an iterator for accessing first level projections to eliminate // this SmallVector. llvm::SmallVector Projections; - Projection::getFirstLevelProjections(OpType, M, Projections); + Projection::getFirstLevelProjections(OpType, M, F.getTypeExpansionContext(), + Projections); auto OpOwnershipKind = Operand.getOwnershipKind(); for (auto &P : Projections) { - SILType ProjType = P.getType(OpType, M); + SILType ProjType = P.getType(OpType, M, F.getTypeExpansionContext()); Types.emplace_back(ProjType); OwnershipKinds.emplace_back( OpOwnershipKind.getProjectedOwnershipKind(F, ProjType)); diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp index 4da10fa36df5f..b1e624a6c58c5 100644 --- a/lib/SIL/SILType.cpp +++ b/lib/SIL/SILType.cpp @@ -86,7 +86,7 @@ bool SILType::isTrivial(const SILFunction &F) const { bool SILType::isReferenceCounted(SILModule &M) const { return M.Types.getTypeLowering(*this, - ResilienceExpansion::Minimal) + TypeExpansionContext::minimal()) .isReferenceCounted(); } @@ -133,8 +133,8 @@ bool SILType::canRefCast(SILType operTy, SILType resultTy, SILModule &M) { && toTy.isHeapObjectReferenceType(); } -SILType SILType::getFieldType(VarDecl *field, - TypeConverter &TC) const { +SILType SILType::getFieldType(VarDecl *field, TypeConverter &TC, + TypeExpansionContext context) const { AbstractionPattern origFieldTy = TC.getAbstractionPattern(field); CanType substFieldTy; if (field->hasClangNode()) { @@ -144,7 +144,8 @@ SILType SILType::getFieldType(VarDecl *field, getASTType()->getTypeOfMember(&TC.M, field, nullptr)->getCanonicalType(); } - auto loweredTy = TC.getLoweredRValueType(origFieldTy, substFieldTy); + auto loweredTy = + TC.getLoweredRValueType(context, origFieldTy, substFieldTy); if (isAddress() || getClassOrBoundGenericClass() != nullptr) { return SILType::getPrimitiveAddressType(loweredTy); } else { @@ -152,12 +153,13 @@ SILType SILType::getFieldType(VarDecl *field, } } -SILType SILType::getFieldType(VarDecl *field, SILModule &M) const { - return getFieldType(field, M.Types); +SILType SILType::getFieldType(VarDecl *field, SILModule &M, + TypeExpansionContext context) const { + return getFieldType(field, M.Types, context); } -SILType SILType::getEnumElementType(EnumElementDecl *elt, - TypeConverter &TC) const { +SILType SILType::getEnumElementType(EnumElementDecl *elt, TypeConverter &TC, + TypeExpansionContext context) const { assert(elt->getDeclContext() == getEnumOrBoundGenericEnum()); assert(elt->hasAssociatedValues()); @@ -168,7 +170,7 @@ SILType SILType::getEnumElementType(EnumElementDecl *elt, // If the case is indirect, then the payload is boxed. if (elt->isIndirect() || elt->getParentEnum()->isIndirect()) { - auto box = TC.getBoxTypeForEnumElement(*this, elt); + auto box = TC.getBoxTypeForEnumElement(context, *this, elt); return SILType(SILType::getPrimitiveObjectType(box).getASTType(), getCategory()); } @@ -176,15 +178,15 @@ SILType SILType::getEnumElementType(EnumElementDecl *elt, auto substEltTy = getASTType()->getTypeOfMember(&TC.M, elt, elt->getArgumentInterfaceType()); - auto loweredTy = - TC.getLoweredRValueType(TC.getAbstractionPattern(elt), - substEltTy); + auto loweredTy = TC.getLoweredRValueType( + context, TC.getAbstractionPattern(elt), substEltTy); return SILType(loweredTy, getCategory()); } -SILType SILType::getEnumElementType(EnumElementDecl *elt, SILModule &M) const { - return getEnumElementType(elt, M.Types); +SILType SILType::getEnumElementType(EnumElementDecl *elt, SILModule &M, + TypeExpansionContext context) const { + return getEnumElementType(elt, M.Types, context); } bool SILType::isLoadableOrOpaque(const SILFunction &F) const { @@ -196,10 +198,10 @@ bool SILType::isAddressOnly(const SILFunction &F) const { return F.getTypeLowering(*this).isAddressOnly(); } -SILType SILType::substGenericArgs(SILModule &M, - SubstitutionMap SubMap) const { +SILType SILType::substGenericArgs(SILModule &M, SubstitutionMap SubMap, + TypeExpansionContext context) const { auto fnTy = castTo(); - auto canFnTy = CanSILFunctionType(fnTy->substGenericArgs(M, SubMap)); + auto canFnTy = CanSILFunctionType(fnTy->substGenericArgs(M, SubMap, context)); return SILType::getPrimitiveObjectType(canFnTy); } @@ -217,7 +219,8 @@ bool SILType::isHeapObjectReferenceType() const { return false; } -bool SILType::aggregateContainsRecord(SILType Record, SILModule &Mod) const { +bool SILType::aggregateContainsRecord(SILType Record, SILModule &Mod, + TypeExpansionContext context) const { assert(!hasArchetype() && "Agg should be proven to not be generic " "before passed to this function."); assert(!Record.hasArchetype() && "Record should be proven to not be generic " @@ -246,14 +249,14 @@ bool SILType::aggregateContainsRecord(SILType Record, SILModule &Mod) const { if (EnumDecl *E = Ty.getEnumOrBoundGenericEnum()) { for (auto Elt : E->getAllElements()) if (Elt->hasAssociatedValues()) - Worklist.push_back(Ty.getEnumElementType(Elt, Mod)); + Worklist.push_back(Ty.getEnumElementType(Elt, Mod, context)); continue; } // Then if we have a struct address... if (StructDecl *S = Ty.getStructOrBoundGenericStruct()) for (VarDecl *Var : S->getStoredProperties()) - Worklist.push_back(Ty.getFieldType(Var, Mod)); + Worklist.push_back(Ty.getFieldType(Var, Mod, context)); // If we have a class address, it is a pointer so it cannot contain other // types. @@ -387,21 +390,22 @@ SILType SILType::mapTypeOutOfContext() const { getCategory()); } -CanType -swift::getSILBoxFieldLoweredType(SILBoxType *type, TypeConverter &TC, - unsigned index) { +CanType swift::getSILBoxFieldLoweredType(TypeExpansionContext context, + SILBoxType *type, TypeConverter &TC, + unsigned index) { auto fieldTy = type->getLayout()->getFields()[index].getLoweredType(); // Apply generic arguments if the layout is generic. if (auto subMap = type->getSubstitutions()) { auto sig = type->getLayout()->getGenericSignature(); - return SILType::getPrimitiveObjectType(fieldTy) + fieldTy = SILType::getPrimitiveObjectType(fieldTy) .subst(TC, QuerySubstitutionMap{subMap}, LookUpConformanceInSubstitutionMap(subMap), sig) .getASTType(); } + fieldTy = TC.getLoweredType(fieldTy, context).getASTType(); return fieldTy; } @@ -440,9 +444,8 @@ SILModuleConventions::SILModuleConventions(SILModule &M) bool SILModuleConventions::isReturnedIndirectlyInSIL(SILType type, SILModule &M) { if (SILModuleConventions(M).loweredAddresses) { - return M.Types.getTypeLowering(type, - ResilienceExpansion::Minimal) - .isAddressOnly(); + return M.Types.getTypeLowering(type, TypeExpansionContext::minimal()) + .isAddressOnly(); } return false; @@ -450,9 +453,8 @@ bool SILModuleConventions::isReturnedIndirectlyInSIL(SILType type, bool SILModuleConventions::isPassedIndirectlyInSIL(SILType type, SILModule &M) { if (SILModuleConventions(M).loweredAddresses) { - return M.Types.getTypeLowering(type, - ResilienceExpansion::Minimal) - .isAddressOnly(); + return M.Types.getTypeLowering(type, TypeExpansionContext::minimal()) + .isAddressOnly(); } return false; @@ -546,8 +548,14 @@ bool SILType::hasAbstractionDifference(SILFunctionTypeRepresentation rep, return (*this != type2); } -bool SILType::isLoweringOf(SILModule &Mod, CanType formalType) { +bool SILType::isLoweringOf(TypeExpansionContext context, SILModule &Mod, + CanType formalType) { SILType loweredType = *this; + if (formalType->hasOpaqueArchetype() && + context.shouldLookThroughOpaqueTypeArchetypes() && + loweredType.getASTType() == + Mod.Types.getLoweredRValueType(context, formalType)) + return true; // Optional lowers its contained type. SILType loweredObjectType = loweredType.getOptionalObjectType(); @@ -555,7 +563,7 @@ bool SILType::isLoweringOf(SILModule &Mod, CanType formalType) { if (loweredObjectType) { return formalObjectType && - loweredObjectType.isLoweringOf(Mod, formalObjectType); + loweredObjectType.isLoweringOf(context, Mod, formalObjectType); } // Metatypes preserve their instance type through lowering. @@ -586,7 +594,8 @@ bool SILType::isLoweringOf(SILModule &Mod, CanType formalType) { for (unsigned i = 0, e = loweredTT->getNumElements(); i < e; ++i) { auto loweredTTEltType = SILType::getPrimitiveAddressType(loweredTT.getElementType(i)); - if (!loweredTTEltType.isLoweringOf(Mod, formalTT.getElementType(i))) + if (!loweredTTEltType.isLoweringOf(context, Mod, + formalTT.getElementType(i))) return false; } return true; diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index 3ffe4caa281e0..ecfeb533ff6ce 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -141,14 +141,15 @@ void verifyKeyPathComponent(SILModule &M, bool forPropertyDescriptor, bool hasIndices) { auto &C = M.getASTContext(); - + auto typeExpansionContext = + TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(expansion); auto opaque = AbstractionPattern::getOpaque(); auto loweredBaseTy = - M.Types.getLoweredType(opaque, baseTy, expansion); + M.Types.getLoweredType(opaque, baseTy, typeExpansionContext); auto componentTy = component.getComponentType().subst(patternSubs) ->getCanonicalType(); auto loweredComponentTy = - M.Types.getLoweredType(opaque, componentTy, expansion); + M.Types.getLoweredType(opaque, componentTy, typeExpansionContext); auto checkIndexEqualsAndHash = [&]{ if (!component.getSubscriptIndices().empty()) { @@ -160,7 +161,7 @@ void verifyKeyPathComponent(SILModule &M, "operator"); auto substEqualsType = equals->getLoweredFunctionType() - ->substGenericArgs(M, patternSubs); + ->substGenericArgs(M, patternSubs, TypeExpansionContext::minimal()); require(substEqualsType->getParameters().size() == 2, "must have two arguments"); @@ -193,7 +194,7 @@ void verifyKeyPathComponent(SILModule &M, "operator"); auto substHashType = hash->getLoweredFunctionType() - ->substGenericArgs(M, patternSubs); + ->substGenericArgs(M, patternSubs, TypeExpansionContext::minimal()); require(substHashType->getParameters().size() == 1, "must have two arguments"); @@ -241,7 +242,8 @@ void verifyKeyPathComponent(SILModule &M, require(property->hasStorage(), "property must be stored"); require(!property->isResilient(M.getSwiftModule(), expansion), "cannot access storage of resilient property"); - auto propertyTy = loweredBaseTy.getFieldType(property, M); + auto propertyTy = + loweredBaseTy.getFieldType(property, M, typeExpansionContext); require(propertyTy.getObjectType() == loweredComponentTy.getObjectType(), "component type should match the maximal abstraction of the " @@ -276,8 +278,8 @@ void verifyKeyPathComponent(SILModule &M, "less visible getters"); } - auto substGetterType = getter->getLoweredFunctionType() - ->substGenericArgs(M, patternSubs); + auto substGetterType = getter->getLoweredFunctionType()->substGenericArgs( + M, patternSubs, TypeExpansionContext::minimal()); require(substGetterType->getRepresentation() == SILFunctionTypeRepresentation::Thin, "getter should be a thin function"); @@ -324,7 +326,7 @@ void verifyKeyPathComponent(SILModule &M, } auto substSetterType = setter->getLoweredFunctionType() - ->substGenericArgs(M, patternSubs); + ->substGenericArgs(M, patternSubs, TypeExpansionContext::minimal()); require(substSetterType->getRepresentation() == SILFunctionTypeRepresentation::Thin, @@ -373,8 +375,9 @@ void verifyKeyPathComponent(SILModule &M, require(contextType == operands[opIndex].get()->getType(), "operand must match type required by pattern"); SILType loweredType = index.LoweredType; - require(loweredType.isLoweringOf(M, index.FormalType), - "pattern index formal type doesn't match lowered type"); + require( + loweredType.isLoweringOf(typeExpansionContext, M, index.FormalType), + "pattern index formal type doesn't match lowered type"); } checkIndexEqualsAndHash(); @@ -1308,7 +1311,7 @@ class SILVerifier : public SILVerifierBase { } // Apply the substitutions. - return fnTy->substGenericArgs(F.getModule(), subs); + return fnTy->substGenericArgs(F.getModule(), subs, F.getTypeExpansionContext()); } /// Check that for each opened archetype or dynamic self type in substitutions @@ -1855,7 +1858,8 @@ class SILVerifier : public SILVerifierBase { void checkGlobalAccessInst(GlobalAccessInst *GAI) { SILGlobalVariable *RefG = GAI->getReferencedGlobal(); - require(GAI->getType().getObjectType() == RefG->getLoweredType(), + require(GAI->getType().getObjectType() == + RefG->getLoweredTypeInContext(F.getTypeExpansionContext()), "global_addr/value must be the type of the variable it references"); if (auto *VD = RefG->getDecl()) { require(!VD->isResilient(F.getModule().getSwiftModule(), @@ -2436,7 +2440,8 @@ class SILVerifier : public SILVerifierBase { "project_box operand should be a value"); auto boxTy = I->getOperand()->getType().getAs(); require(boxTy, "project_box operand should be a @box type"); - require(I->getType() == getSILBoxFieldType(boxTy, F.getModule().Types, + require(I->getType() == getSILBoxFieldType(F.getTypeExpansionContext(), boxTy, + F.getModule().Types, I->getFieldIndex()), "project_box result should be address of boxed type"); @@ -2505,7 +2510,8 @@ class SILVerifier : public SILVerifierBase { "number of struct operands does not match number of stored " "member variables of struct"); - SILType loweredType = structTy.getFieldType(field, F.getModule()); + SILType loweredType = + structTy.getFieldType(field, F.getModule(), F.getTypeExpansionContext()); if (SI->getModule().getStage() != SILStage::Lowered) { require((*opi)->getType() == loweredType, "struct operand type does not match field type"); @@ -2527,8 +2533,8 @@ class SILVerifier : public SILVerifierBase { if (UI->getElement()->hasAssociatedValues()) { require(UI->getOperand()->getType().isObject(), "EnumInst operand must be an object"); - SILType caseTy = UI->getType().getEnumElementType(UI->getElement(), - F.getModule()); + SILType caseTy = UI->getType().getEnumElementType( + UI->getElement(), F.getModule(), F.getTypeExpansionContext()); if (UI->getModule().getStage() != SILStage::Lowered) { require(caseTy == UI->getOperand()->getType(), "EnumInst operand type does not match type of case"); @@ -2548,9 +2554,8 @@ class SILVerifier : public SILVerifierBase { require(UI->getType().isAddress(), "InitEnumDataAddrInst must produce an address"); - SILType caseTy = - UI->getOperand()->getType().getEnumElementType(UI->getElement(), - F.getModule()); + SILType caseTy = UI->getOperand()->getType().getEnumElementType( + UI->getElement(), F.getModule(), F.getTypeExpansionContext()); if (UI->getModule().getStage() != SILStage::Lowered) { requireSameType( @@ -2571,9 +2576,8 @@ class SILVerifier : public SILVerifierBase { require(UI->getType().isObject(), "UncheckedEnumData must produce an address"); - SILType caseTy = - UI->getOperand()->getType().getEnumElementType(UI->getElement(), - F.getModule()); + SILType caseTy = UI->getOperand()->getType().getEnumElementType( + UI->getElement(), F.getModule(), F.getTypeExpansionContext()); if (UI->getModule().getStage() != SILStage::Lowered) { require(caseTy == UI->getType(), @@ -2593,9 +2597,8 @@ class SILVerifier : public SILVerifierBase { require(UI->getType().isAddress(), "UncheckedTakeEnumDataAddrInst must produce an address"); - SILType caseTy = - UI->getOperand()->getType().getEnumElementType(UI->getElement(), - F.getModule()); + SILType caseTy = UI->getOperand()->getType().getEnumElementType( + UI->getElement(), F.getModule(), F.getTypeExpansionContext()); if (UI->getModule().getStage() != SILStage::Lowered) { require(caseTy == UI->getType(), "UncheckedTakeEnumDataAddrInst result " @@ -2631,7 +2634,8 @@ class SILVerifier : public SILVerifierBase { // Is a SIL type a potential lowering of a formal type? bool isLoweringOf(SILType loweredType, CanType formalType) { - return loweredType.isLoweringOf(F.getModule(), formalType); + return loweredType.isLoweringOf(F.getTypeExpansionContext(), F.getModule(), + formalType); } void checkMetatypeInst(MetatypeInst *MI) { @@ -2721,9 +2725,9 @@ class SILVerifier : public SILVerifierBase { require(AI->getType().isObject(), "result of alloc_box must be an object"); for (unsigned field : indices(AI->getBoxType()->getLayout()->getFields())) { - verifyOpenedArchetype(AI, - getSILBoxFieldLoweredType(AI->getBoxType(), F.getModule().Types, - field)); + verifyOpenedArchetype(AI, getSILBoxFieldLoweredType( + F.getTypeExpansionContext(), AI->getBoxType(), + F.getModule().Types, field)); } // An alloc_box with a mark_uninitialized user can not have any other users. @@ -2817,8 +2821,8 @@ class SILVerifier : public SILVerifierBase { "struct_extract field is not a member of the struct"); if (EI->getModule().getStage() != SILStage::Lowered) { - SILType loweredFieldTy = - operandTy.getFieldType(EI->getField(), F.getModule()); + SILType loweredFieldTy = operandTy.getFieldType( + EI->getField(), F.getModule(), F.getTypeExpansionContext()); require(loweredFieldTy == EI->getType(), "result of struct_extract does not match type of field"); } @@ -2863,8 +2867,8 @@ class SILVerifier : public SILVerifierBase { "struct_element_addr field is not a member of the struct"); if (EI->getModule().getStage() != SILStage::Lowered) { - SILType loweredFieldTy = - operandTy.getFieldType(EI->getField(), F.getModule()); + SILType loweredFieldTy = operandTy.getFieldType( + EI->getField(), F.getModule(), F.getTypeExpansionContext()); require(loweredFieldTy == EI->getType(), "result of struct_element_addr does not match type of field"); } @@ -2889,8 +2893,8 @@ class SILVerifier : public SILVerifierBase { "ref_element_addr field must be a member of the class"); if (EI->getModule().getStage() != SILStage::Lowered) { - SILType loweredFieldTy = - operandTy.getFieldType(EI->getField(), F.getModule()); + SILType loweredFieldTy = operandTy.getFieldType( + EI->getField(), F.getModule(), F.getTypeExpansionContext()); require(loweredFieldTy == EI->getType(), "result of ref_element_addr does not match type of field"); } @@ -2988,7 +2992,8 @@ class SILVerifier : public SILVerifierBase { // The type of the dynamic method must match the usual type of the method, // but with the more opaque Self type. - auto constantInfo = F.getModule().Types.getConstantInfo(method); + auto constantInfo = + F.getModule().Types.getConstantInfo(F.getTypeExpansionContext(), method); auto methodTy = constantInfo.SILFnType; assert(!methodTy->isCoroutine()); @@ -2996,7 +3001,8 @@ class SILVerifier : public SILVerifierBase { // Map interface types to archetypes. if (auto *env = F.getModule().Types.getConstantGenericEnvironment(method)) { auto subs = env->getForwardingSubstitutionMap(); - methodTy = methodTy->substGenericArgs(F.getModule(), subs); + methodTy = methodTy->substGenericArgs(F.getModule(), subs, + F.getTypeExpansionContext()); } assert(!methodTy->isPolymorphic()); @@ -3066,7 +3072,8 @@ class SILVerifier : public SILVerifierBase { void checkClassMethodInst(ClassMethodInst *CMI) { auto member = CMI->getMember(); - auto overrideTy = TC.getConstantOverrideType(member); + auto overrideTy = + TC.getConstantOverrideType(F.getTypeExpansionContext(), member); if (CMI->getModule().getStage() != SILStage::Lowered) { requireSameType( CMI->getType(), SILType::getPrimitiveObjectType(overrideTy), @@ -3094,7 +3101,8 @@ class SILVerifier : public SILVerifierBase { void checkSuperMethodInst(SuperMethodInst *CMI) { auto member = CMI->getMember(); - auto overrideTy = TC.getConstantOverrideType(member); + auto overrideTy = + TC.getConstantOverrideType(F.getTypeExpansionContext(), member); if (CMI->getModule().getStage() != SILStage::Lowered) { requireSameType( CMI->getType(), SILType::getPrimitiveObjectType(overrideTy), @@ -3145,7 +3153,8 @@ class SILVerifier : public SILVerifierBase { operandInstanceType = metatypeType.getInstanceType(); if (operandInstanceType.getClassOrBoundGenericClass()) { - auto overrideTy = TC.getConstantOverrideType(member); + auto overrideTy = + TC.getConstantOverrideType(F.getTypeExpansionContext(), member); requireSameType( OMI->getType(), SILType::getPrimitiveObjectType(overrideTy), "result type of objc_method must match abstracted type of method"); @@ -3170,7 +3179,8 @@ class SILVerifier : public SILVerifierBase { void checkObjCSuperMethodInst(ObjCSuperMethodInst *OMI) { auto member = OMI->getMember(); - auto overrideTy = TC.getConstantOverrideType(member); + auto overrideTy = + TC.getConstantOverrideType(F.getTypeExpansionContext(), member); if (OMI->getModule().getStage() != SILStage::Lowered) { requireSameType( OMI->getType(), SILType::getPrimitiveObjectType(overrideTy), @@ -4013,7 +4023,9 @@ class SILVerifier : public SILVerifierBase { LLVM_DEBUG(RI->print(llvm::dbgs())); SILType functionResultType = - F.mapTypeIntoContext(fnConv.getSILResultType()); + F.getLoweredType( + F.mapTypeIntoContext(fnConv.getSILResultType()).getASTType()) + .getCategoryType(fnConv.getSILResultType().getCategory()); SILType instResultType = RI->getOperand()->getType(); LLVM_DEBUG(llvm::dbgs() << "function return type: "; functionResultType.dump(); @@ -4026,11 +4038,15 @@ class SILVerifier : public SILVerifierBase { void checkThrowInst(ThrowInst *TI) { LLVM_DEBUG(TI->print(llvm::dbgs())); - CanSILFunctionType fnType = F.getLoweredFunctionType(); + CanSILFunctionType fnType = + F.getLoweredFunctionTypeInContext(F.getTypeExpansionContext()); require(fnType->hasErrorResult(), "throw in function that doesn't have an error result"); - SILType functionResultType = F.mapTypeIntoContext(fnConv.getSILErrorType()); + SILType functionResultType = + F.getLoweredType( + F.mapTypeIntoContext(fnConv.getSILErrorType()).getASTType()) + .getCategoryType(fnConv.getSILErrorType().getCategory()); SILType instResultType = TI->getOperand()->getType(); LLVM_DEBUG(llvm::dbgs() << "function error result type: "; functionResultType.dump(); @@ -4046,7 +4062,8 @@ class SILVerifier : public SILVerifierBase { } void checkYieldInst(YieldInst *YI) { - CanSILFunctionType fnType = F.getLoweredFunctionType(); + CanSILFunctionType fnType = + F.getLoweredFunctionTypeInContext(F.getTypeExpansionContext()); require(fnType->isCoroutine(), "yield in non-coroutine function"); @@ -4246,7 +4263,8 @@ class SILVerifier : public SILVerifierBase { } if (dest->getArguments().size() == 1) { - SILType eltArgTy = uTy.getEnumElementType(elt, F.getModule()); + SILType eltArgTy = uTy.getEnumElementType(elt, F.getModule(), + F.getTypeExpansionContext()); SILType bbArgTy = dest->getArguments()[0]->getType(); if (F.getModule().getStage() != SILStage::Lowered) { // During the lowered stage, a function type might have different @@ -4652,7 +4670,9 @@ class SILVerifier : public SILVerifierBase { auto mappedTy = F.mapTypeIntoContext(ty); SILArgument *bbarg = *argI; ++argI; - if (bbarg->getType() != mappedTy) { + if (bbarg->getType() != mappedTy && + bbarg->getType() != F.getLoweredType(mappedTy.getASTType()) + .getCategoryType(mappedTy.getCategory())) { llvm::errs() << what << " type mismatch!\n"; llvm::errs() << " argument: "; bbarg->dump(); llvm::errs() << " expected: "; mappedTy.dump(); @@ -5257,7 +5277,8 @@ void SILVTable::verify(const SILModule &M) const { for (auto &entry : getEntries()) { // All vtable entries must be decls in a class context. assert(entry.Method.hasDecl() && "vtable entry is not a decl"); - auto baseInfo = M.Types.getConstantInfo(entry.Method); + auto baseInfo = + M.Types.getConstantInfo(TypeExpansionContext::minimal(), entry.Method); ValueDecl *decl = entry.Method.getDecl(); assert((!isa(decl) diff --git a/lib/SIL/TypeLowering.cpp b/lib/SIL/TypeLowering.cpp index 3ba5b5e8db965..2bc02260fa86d 100644 --- a/lib/SIL/TypeLowering.cpp +++ b/lib/SIL/TypeLowering.cpp @@ -92,7 +92,7 @@ static bool hasSingletonMetatype(CanType instanceType) { } CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture, - ResilienceExpansion expansion) { + TypeExpansionContext expansion) { auto decl = capture.getDecl(); auto *var = cast(decl); assert(var->hasStorage() && @@ -103,7 +103,11 @@ CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture, // by its address (like a var) instead. if (!var->supportsMutation() && (Context.LangOpts.EnableSILOpaqueValues || - !getTypeLowering(var->getType(), expansion).isAddressOnly())) + !getTypeLowering( + var->getType(), + TypeExpansionContext::noOpaqueTypeArchetypesSubstitution( + expansion.getResilienceExpansion())) + .isAddressOnly())) return CaptureKind::Constant; // In-out parameters are captured by address. @@ -132,7 +136,7 @@ using RecursiveProperties = TypeLowering::RecursiveProperties; static RecursiveProperties classifyType(CanType type, TypeConverter &TC, CanGenericSignature sig, - ResilienceExpansion expansion); + TypeExpansionContext expansion); namespace { /// A CRTP helper class for doing things that depends on type @@ -143,9 +147,9 @@ namespace { protected: TypeConverter &TC; CanGenericSignature Sig; - ResilienceExpansion Expansion; + TypeExpansionContext Expansion; TypeClassifierBase(TypeConverter &TC, CanGenericSignature Sig, - ResilienceExpansion Expansion) + TypeExpansionContext Expansion) : TC(TC), Sig(Sig), Expansion(Expansion) {} public: @@ -389,7 +393,7 @@ namespace { auto referentType = type->getReferentType(); \ auto concreteType = getConcreteReferenceStorageReferent(referentType); \ if (Name##StorageType::get(concreteType, TC.Context) \ - ->isLoadable(Expansion)) { \ + ->isLoadable(Expansion.getResilienceExpansion())) { \ return asImpl().visitLoadable##Name##StorageType(type); \ } else { \ return asImpl().visitAddressOnly##Name##StorageType(type); \ @@ -401,6 +405,13 @@ namespace { } #include "swift/AST/ReferenceStorage.def" + RetTy visitOpaqueTypeArchetypeType(CanOpaqueTypeArchetypeType ty) { + auto replacedTy = substOpaqueTypesWithUnderlyingTypes(ty, Expansion); + if (replacedTy == ty) + return visitArchetypeType(ty); + return this->visit(replacedTy); + } + RetTy visitArchetypeType(CanArchetypeType type) { if (type->requiresClass()) { return asImpl().handleReference(type); @@ -511,7 +522,7 @@ namespace { public TypeClassifierBase { public: TypeClassifier(TypeConverter &TC, CanGenericSignature Sig, - ResilienceExpansion Expansion) + TypeExpansionContext Expansion) : TypeClassifierBase(TC, Sig, Expansion) {} RecursiveProperties handle(CanType type, RecursiveProperties properties) { @@ -565,7 +576,7 @@ namespace { static RecursiveProperties classifyType(CanType type, TypeConverter &tc, CanGenericSignature sig, - ResilienceExpansion expansion) { + TypeExpansionContext expansion) { return TypeClassifier(tc, sig, expansion).visit(type); } @@ -574,7 +585,7 @@ static RecursiveProperties classifyType(CanType type, TypeConverter &tc, /// something of unknown size. bool SILType::isAddressOnly(CanType type, TypeConverter &tc, CanGenericSignature sig, - ResilienceExpansion expansion) { + TypeExpansionContext expansion) { return classifyType(type, tc, sig, expansion).isAddressOnly(); } @@ -586,7 +597,7 @@ namespace { protected: LoadableTypeLowering(SILType type, RecursiveProperties properties, IsReferenceCounted_t isRefCounted, - ResilienceExpansion forExpansion) + TypeExpansionContext forExpansion) : TypeLowering(type, properties, isRefCounted, forExpansion) {} public: @@ -613,7 +624,7 @@ namespace { class TrivialTypeLowering final : public LoadableTypeLowering { public: TrivialTypeLowering(SILType type, RecursiveProperties properties, - ResilienceExpansion forExpansion) + TypeExpansionContext forExpansion) : LoadableTypeLowering(type, properties, IsNotReferenceCounted, forExpansion) { assert(properties.isFixedABI()); @@ -683,7 +694,7 @@ namespace { NonTrivialLoadableTypeLowering(SILType type, RecursiveProperties properties, IsReferenceCounted_t isRefCounted, - ResilienceExpansion forExpansion) + TypeExpansionContext forExpansion) : LoadableTypeLowering(type, properties, isRefCounted, forExpansion) { assert(!properties.isTrivial()); } @@ -776,7 +787,7 @@ namespace { public: LoadableAggTypeLowering(CanType type, RecursiveProperties properties, - ResilienceExpansion forExpansion) + TypeExpansionContext forExpansion) : NonTrivialLoadableTypeLowering(SILType::getPrimitiveObjectType(type), properties, IsNotReferenceCounted, forExpansion) { @@ -924,7 +935,7 @@ namespace { auto paramIndices = fnTy->getDifferentiationParameterIndices(); children.push_back(Child{ NormalDifferentiableFunctionTypeComponent::Original, - TC.getTypeLowering(origFnTy, getResilienceExpansion()) + TC.getTypeLowering(origFnTy, getExpansionContext()) }); for (AutoDiffDerivativeFunctionKind kind : {AutoDiffDerivativeFunctionKind::JVP, @@ -940,7 +951,7 @@ namespace { // wrong extractee. assert(extractee.getAsDerivativeFunctionKind() == kind); children.push_back(Child{ - extractee, TC.getTypeLowering(silTy, getResilienceExpansion())}); + extractee, TC.getTypeLowering(silTy, getExpansionContext())}); } assert(children.size() == 3); } @@ -976,14 +987,14 @@ namespace { auto paramIndices = fnTy->getDifferentiationParameterIndices(); children.push_back(Child{ LinearDifferentiableFunctionTypeComponent::Original, - TC.getTypeLowering(origFnTy, getResilienceExpansion()) + TC.getTypeLowering(origFnTy, getExpansionContext()) }); auto transposeFnTy = origFnTy->getAutoDiffTransposeFunctionType( paramIndices, TC, LookUpConformanceInModule(&TC.M)); auto transposeSILFnTy = SILType::getPrimitiveObjectType(transposeFnTy); children.push_back(Child{ LinearDifferentiableFunctionTypeComponent::Transpose, - TC.getTypeLowering(transposeSILFnTy, getResilienceExpansion()) + TC.getTypeLowering(transposeSILFnTy, getExpansionContext()) }); assert(children.size() == 2); } @@ -994,7 +1005,7 @@ namespace { : public LoadableAggTypeLowering { public: LoadableTupleTypeLowering(CanType type, RecursiveProperties properties, - ResilienceExpansion forExpansion) + TypeExpansionContext forExpansion) : LoadableAggTypeLowering(type, properties, forExpansion) {} SILValue emitRValueProject(SILBuilder &B, SILLocation loc, @@ -1019,7 +1030,7 @@ namespace { unsigned index = 0; for (auto elt : tupleTy.getElementTypes()) { auto silElt = SILType::getPrimitiveType(elt, silTy.getCategory()); - auto &eltTL = TC.getTypeLowering(silElt, getResilienceExpansion()); + auto &eltTL = TC.getTypeLowering(silElt, getExpansionContext()); children.push_back(Child{index, eltTL}); ++index; } @@ -1031,7 +1042,7 @@ namespace { : public LoadableAggTypeLowering { public: LoadableStructTypeLowering(CanType type, RecursiveProperties properties, - ResilienceExpansion forExpansion) + TypeExpansionContext forExpansion) : LoadableAggTypeLowering(type, properties, forExpansion) {} SILValue emitRValueProject(SILBuilder &B, SILLocation loc, @@ -1054,8 +1065,8 @@ namespace { assert(structDecl); for (auto prop : structDecl->getStoredProperties()) { - SILType propTy = silTy.getFieldType(prop, TC); - auto &propTL = TC.getTypeLowering(propTy, getResilienceExpansion()); + SILType propTy = silTy.getFieldType(prop, TC, getExpansionContext()); + auto &propTL = TC.getTypeLowering(propTy, getExpansionContext()); children.push_back(Child{prop, propTL}); } } @@ -1065,7 +1076,7 @@ namespace { class LoadableEnumTypeLowering final : public NonTrivialLoadableTypeLowering { public: LoadableEnumTypeLowering(CanType type, RecursiveProperties properties, - ResilienceExpansion forExpansion) + TypeExpansionContext forExpansion) : NonTrivialLoadableTypeLowering(SILType::getPrimitiveObjectType(type), properties, IsNotReferenceCounted, @@ -1108,7 +1119,7 @@ namespace { public: LeafLoadableTypeLowering(SILType type, RecursiveProperties properties, IsReferenceCounted_t isRefCounted, - ResilienceExpansion forExpansion) + TypeExpansionContext forExpansion) : NonTrivialLoadableTypeLowering(type, properties, isRefCounted, forExpansion) {} @@ -1128,7 +1139,7 @@ namespace { /// loadable. class ReferenceTypeLowering : public LeafLoadableTypeLowering { public: - ReferenceTypeLowering(SILType type, ResilienceExpansion forExpansion) + ReferenceTypeLowering(SILType type, TypeExpansionContext forExpansion) : LeafLoadableTypeLowering(type, RecursiveProperties::forReference(), IsReferenceCounted, forExpansion) {} @@ -1160,7 +1171,7 @@ namespace { class Loadable##Name##TypeLowering final : public LeafLoadableTypeLowering { \ public: \ Loadable##Name##TypeLowering(SILType type, \ - ResilienceExpansion forExpansion) \ + TypeExpansionContext forExpansion) \ : LeafLoadableTypeLowering(type, RecursiveProperties::forReference(), \ IsReferenceCounted, \ forExpansion) {} \ @@ -1186,7 +1197,7 @@ namespace { class AddressOnlyTypeLowering : public TypeLowering { public: AddressOnlyTypeLowering(SILType type, RecursiveProperties properties, - ResilienceExpansion forExpansion) + TypeExpansionContext forExpansion) : TypeLowering(type, properties, IsNotReferenceCounted, forExpansion) { assert(properties.isAddressOnly()); @@ -1258,7 +1269,7 @@ namespace { class UnsafeValueBufferTypeLowering : public AddressOnlyTypeLowering { public: UnsafeValueBufferTypeLowering(SILType type, - ResilienceExpansion forExpansion) + TypeExpansionContext forExpansion) : AddressOnlyTypeLowering(type, {IsNotTrivial, IsFixedABI, IsAddressOnly, IsNotResilient}, @@ -1289,7 +1300,7 @@ namespace { class OpaqueValueTypeLowering : public LeafLoadableTypeLowering { public: OpaqueValueTypeLowering(SILType type, RecursiveProperties properties, - ResilienceExpansion forExpansion) + TypeExpansionContext forExpansion) : LeafLoadableTypeLowering(type, properties, IsNotReferenceCounted, forExpansion) {} @@ -1331,7 +1342,7 @@ namespace { IsDependent_t Dependent; public: LowerType(TypeConverter &TC, CanGenericSignature Sig, - ResilienceExpansion Expansion, IsDependent_t Dependent) + TypeExpansionContext Expansion, IsDependent_t Dependent) : TypeClassifierBase(TC, Sig, Expansion), Dependent(Dependent) {} TypeLowering *handleTrivial(CanType type) { @@ -1411,7 +1422,8 @@ namespace { // Note: if the type is in a different module, the lowering does // not depend on the resilience expansion, so we do not need to set // the isResilent() flag above. - if (!sameModule || Expansion == ResilienceExpansion::Minimal) { + if (!sameModule || Expansion.getResilienceExpansion() == + ResilienceExpansion::Minimal) { properties.addSubobject(RecursiveProperties::forOpaque()); return true; } @@ -1556,10 +1568,34 @@ const TypeLowering *TypeConverter::find(TypeKey k) { if (found == types->end()) return nullptr; - assert(found->second && "type recursion not caught in Sema"); + assert((found->second || k.expansionContext.isMinimal()) && + "type recursion not caught in Sema"); return found->second; } +#ifndef NDEBUG +void TypeConverter::removeNullEntry(TypeKey k) { + if (!k.isCacheable()) + return; + + auto ck = k.getCachingKey(); + + llvm::DenseMap *types; + if (k.isDependent()) { + auto &state = DependentTypes.back(); + types = &state.Map; + } else { + types = &IndependentTypes; + } + + auto found = types->find(ck); + if (found == types->end() || found->second != nullptr) + return; + + types->erase(ck); +} +#endif + void TypeConverter::insert(TypeKey k, const TypeLowering *tl) { if (!k.isCacheable()) return; @@ -1570,13 +1606,13 @@ void TypeConverter::insert(TypeKey k, const TypeLowering *tl) { } else { types = &IndependentTypes; } - (*types)[k.getCachingKey()] = tl; } /// Lower each of the elements of the substituted type according to /// the abstraction pattern of the given original type. static CanTupleType computeLoweredTupleType(TypeConverter &tc, + TypeExpansionContext context, AbstractionPattern origType, CanTupleType substType) { assert(origType.matchesTuple(substType)); @@ -1599,7 +1635,7 @@ static CanTupleType computeLoweredTupleType(TypeConverter &tc, assert(!Flags.isVariadic()); CanType loweredSubstEltType = - tc.getLoweredRValueType(origEltType, substEltType); + tc.getLoweredRValueType(context, origEltType, substEltType); changed = (changed || substEltType != loweredSubstEltType || !Flags.isNone()); @@ -1621,14 +1657,14 @@ static CanTupleType computeLoweredTupleType(TypeConverter &tc, } static CanType computeLoweredOptionalType(TypeConverter &tc, + TypeExpansionContext context, AbstractionPattern origType, CanType substType, CanType substObjectType) { assert(substType.getOptionalObjectType() == substObjectType); - CanType loweredObjectType = - tc.getLoweredRValueType(origType.getOptionalObjectType(), - substObjectType); + CanType loweredObjectType = tc.getLoweredRValueType( + context, origType.getOptionalObjectType(), substObjectType); // If the object type didn't change, we don't have to rebuild anything. if (loweredObjectType == substObjectType) { @@ -1641,11 +1677,12 @@ static CanType computeLoweredOptionalType(TypeConverter &tc, static CanType computeLoweredReferenceStorageType(TypeConverter &tc, + TypeExpansionContext context, AbstractionPattern origType, CanReferenceStorageType substType) { - CanType loweredReferentType = - tc.getLoweredRValueType(origType.getReferenceStorageReferentType(), - substType.getReferentType()); + CanType loweredReferentType = tc.getLoweredRValueType( + context, origType.getReferenceStorageReferentType(), + substType.getReferentType()); if (loweredReferentType == substType.getReferentType()) return substType; @@ -1655,36 +1692,53 @@ computeLoweredReferenceStorageType(TypeConverter &tc, } CanSILFunctionType -TypeConverter::getSILFunctionType(AbstractionPattern origType, +TypeConverter::getSILFunctionType(TypeExpansionContext context, + AbstractionPattern origType, CanFunctionType substType) { return cast( - getLoweredRValueType(origType, substType)); + getLoweredRValueType(context, origType, substType)); +} + +bool TypeConverter::hasOpaqueArchetypeOrPropertiesOrCases(CanType ty) { + if (ty->hasOpaqueArchetype()) + return true; + + auto it = opaqueArchetypeFields.find(ty); + if (it == opaqueArchetypeFields.end()) { + bool res = ty->hasOpaqueArchetypePropertiesOrCases(); + opaqueArchetypeFields[ty] = res; + return res; + } + return it->second; } const TypeLowering & TypeConverter::getTypeLowering(AbstractionPattern origType, Type origSubstType, - ResilienceExpansion forExpansion) { + TypeExpansionContext forExpansion) { CanType substType = origSubstType->getCanonicalType(); - auto key = getTypeKey(origType, substType); - + auto origHadOpaqueTypeArchetype = + hasOpaqueArchetypeOrPropertiesOrCases(origSubstType->getCanonicalType()); + auto key = getTypeKey(origType, substType, forExpansion); assert((!key.isDependent() || getCurGenericContext()) && "dependent type outside of generic context?!"); assert(!substType->is()); - auto *prev = find(key); - auto *lowering = getTypeLoweringForExpansion(key, forExpansion, prev); + auto *candidateLowering = find(key.getKeyForMinimalExpansion()); + auto *lowering = getTypeLoweringForExpansion( + key, forExpansion, candidateLowering, origHadOpaqueTypeArchetype); if (lowering != nullptr) return *lowering; #ifndef NDEBUG // Catch reentrancy bugs. - if (prev == nullptr) - insert(key, nullptr); + if (candidateLowering == nullptr) + insert(key.getKeyForMinimalExpansion(), nullptr); #endif // Lower the type. - auto loweredSubstType = computeLoweredRValueType(origType, substType); + auto loweredSubstType = + computeLoweredRValueType(forExpansion, origType, substType); // If that didn't change the type and the key is cachable, there's no // point in re-checking the table, so just construct a type lowering @@ -1701,24 +1755,29 @@ TypeConverter::getTypeLowering(AbstractionPattern origType, } else { AbstractionPattern origTypeForCaching = AbstractionPattern(getCurGenericContext(), loweredSubstType); - auto loweredKey = getTypeKey(origTypeForCaching, loweredSubstType); + auto loweredKey = + getTypeKey(origTypeForCaching, loweredSubstType, forExpansion); lowering = &getTypeLoweringForLoweredType(loweredKey, - forExpansion); + forExpansion, + origHadOpaqueTypeArchetype); } - if (prev == nullptr) - insert(key, lowering); + if (!lowering->isResilient() && !origHadOpaqueTypeArchetype) + insert(key.getKeyForMinimalExpansion(), lowering); else { - prev->NextExpansion = lowering; - assert(prev->isResilient() == lowering->isResilient()); + insert(key, lowering); +#ifndef NDEBUG + removeNullEntry(key.getKeyForMinimalExpansion()); +#endif } - return *lowering; } -CanType TypeConverter::computeLoweredRValueType(AbstractionPattern origType, - CanType substType) { +CanType +TypeConverter::computeLoweredRValueType(TypeExpansionContext forExpansion, + AbstractionPattern origType, + CanType substType) { // AST function types are turned into SIL function types: // - the type is uncurried as desired // - types are turned into their unbridged equivalents, depending @@ -1753,12 +1812,12 @@ CanType TypeConverter::computeLoweredRValueType(AbstractionPattern origType, } } - return getNativeSILFunctionType(*this, origType, substFnType); + return getNativeSILFunctionType(*this, forExpansion, origType, substFnType); } // Ignore dynamic self types. if (auto selfType = dyn_cast(substType)) { - return selfType.getSelfType(); + return getLoweredRValueType(forExpansion, selfType.getSelfType()); } // Static metatypes are unitary and can optimized to a "thin" empty @@ -1769,7 +1828,7 @@ CanType TypeConverter::computeLoweredRValueType(AbstractionPattern origType, // representation. if (substMeta->hasRepresentation()) { assert(substMeta->isLegalSILType()); - return substMeta; + return substOpaqueTypesWithUnderlyingTypes(substMeta, forExpansion); } MetatypeRepresentation repr; @@ -1788,8 +1847,9 @@ CanType TypeConverter::computeLoweredRValueType(AbstractionPattern origType, else repr = MetatypeRepresentation::Thick; } - - CanType instanceType = substMeta.getInstanceType(); + + CanType instanceType = substOpaqueTypesWithUnderlyingTypes( + substMeta.getInstanceType(), forExpansion); // Regardless of thinness, metatypes are always trivial. return CanMetatypeType::get(instanceType, repr); @@ -1808,61 +1868,100 @@ CanType TypeConverter::computeLoweredRValueType(AbstractionPattern origType, // Lower tuple element types. if (auto substTupleType = dyn_cast(substType)) { - return computeLoweredTupleType(*this, origType, substTupleType); + return computeLoweredTupleType(*this, forExpansion, origType, + substTupleType); } // Lower the referent type of reference storage types. if (auto substRefType = dyn_cast(substType)) { - return computeLoweredReferenceStorageType(*this, origType, substRefType); + return computeLoweredReferenceStorageType(*this, forExpansion, origType, + substRefType); } // Lower the object type of optional types. if (auto substObjectType = substType.getOptionalObjectType()) { - return computeLoweredOptionalType(*this, origType, + return computeLoweredOptionalType(*this, forExpansion, origType, substType, substObjectType); } + if (auto silFnTy = dyn_cast(substType)) { + if (!substType->hasOpaqueArchetype() || + !forExpansion.shouldLookThroughOpaqueTypeArchetypes()) + return substType; + return silFnTy->substituteOpaqueArchetypes(*this, forExpansion); + } + // The Swift type directly corresponds to the lowered type. - return substType; + auto underlyingTy = + substOpaqueTypesWithUnderlyingTypes(substType, forExpansion, + /*allowLoweredTypes*/ true); + if (underlyingTy != substType) { + if (auto underlyingFnTy = dyn_cast(underlyingTy)) { + underlyingTy = computeLoweredRValueType( + forExpansion, AbstractionPattern::getOpaque(), underlyingTy); + } else + underlyingTy = computeLoweredRValueType( + forExpansion, + AbstractionPattern(getCurGenericContext(), underlyingTy), + underlyingTy); + } + + return underlyingTy; } const TypeLowering & -TypeConverter::getTypeLowering(SILType type, ResilienceExpansion forExpansion) { +TypeConverter::getTypeLowering(SILType type, + TypeExpansionContext forExpansion) { auto loweredType = type.getASTType(); auto key = getTypeKey(AbstractionPattern(getCurGenericContext(), loweredType), - loweredType); + loweredType, forExpansion); + + auto origHadOpaqueTypeArchetype = + hasOpaqueArchetypeOrPropertiesOrCases(loweredType); - return getTypeLoweringForLoweredType(key, forExpansion); + return getTypeLoweringForLoweredType(key, forExpansion, + origHadOpaqueTypeArchetype); } const TypeLowering & TypeConverter::getTypeLoweringForLoweredType(TypeKey key, - ResilienceExpansion forExpansion) { + TypeExpansionContext forExpansion, + bool origHadOpaqueTypeArchetype) { auto type = key.SubstType; assert(type->isLegalSILType() && "type is not lowered!"); (void)type; - auto *prev = find(key); - auto *lowering = getTypeLoweringForExpansion(key, forExpansion, prev); + auto *candidateLowering = find(key.getKeyForMinimalExpansion()); + auto *lowering = getTypeLoweringForExpansion( + key, forExpansion, candidateLowering, origHadOpaqueTypeArchetype); if (lowering != nullptr) return *lowering; #ifndef NDEBUG // Catch reentrancy bugs. - if (prev == nullptr) - insert(key, nullptr); + if (candidateLowering == nullptr) + insert(key.getKeyForMinimalExpansion(), nullptr); #endif - lowering = LowerType(*this, - CanGenericSignature(), - forExpansion, - key.isDependent()).visit(key.SubstType); + if (forExpansion.shouldLookThroughOpaqueTypeArchetypes() && + type->hasOpaqueArchetype()) { + type = computeLoweredRValueType( + forExpansion, AbstractionPattern(getCurGenericContext(), type), type); + } + + lowering = + LowerType(*this, CanGenericSignature(), forExpansion, key.isDependent()) + .visit(type); - if (prev) { - prev->NextExpansion = lowering; - assert(prev->isResilient() == lowering->isResilient()); - } else + if (!lowering->isResilient() && !origHadOpaqueTypeArchetype) + insert(key.getKeyForMinimalExpansion(), lowering); + else { insert(key, lowering); +#ifndef NDEBUG + removeNullEntry(key.getKeyForMinimalExpansion()); +#endif + } + return *lowering; } @@ -1872,28 +1971,25 @@ TypeConverter::getTypeLoweringForLoweredType(TypeKey key, /// go ahead and lower the type with the correct expansion. const TypeLowering *TypeConverter:: getTypeLoweringForExpansion(TypeKey key, - ResilienceExpansion forExpansion, - const TypeLowering *lowering) { + TypeExpansionContext forExpansion, + const TypeLowering *lowering, + bool origHadOpaqueTypeArchetype) { if (lowering == nullptr) return nullptr; - if (!lowering->isResilient()) { + if (!lowering->isResilient() && !origHadOpaqueTypeArchetype) { // Don't try to refine the lowering for other resilience expansions if - // we don't expect to get a different lowering anyway. + // we don't expect to get a different lowering anyway. Similar if the + // original type did not have opaque type archetypes. // // See LowerType::handleResilience() for the gory details; we only // set this flag if the type is resilient *and* inside our module. return lowering; } - // Search for a matching lowering in the linked list of lowerings. - while (lowering) { - if (lowering->getResilienceExpansion() == forExpansion) - return lowering; - - // Continue searching. - lowering = lowering->NextExpansion; - } + auto *exactLowering = find(key); + if (exactLowering) + return exactLowering; // We have to create a new one. return nullptr; @@ -1955,7 +2051,7 @@ static CanAnyFunctionType getDefaultArgGeneratorInterfaceType( auto sig = vd->getInnermostDeclContext()->getGenericSignatureOfContext(); if (auto *afd = dyn_cast(vd)) { auto *param = getParameterAt(afd, c.defaultArgIndex); - if (param->getDefaultValue()) { + if (param->hasDefaultExpr()) { auto captureInfo = param->getDefaultArgumentCaptureInfo(); sig = getEffectiveGenericSignature(afd, captureInfo); } @@ -2207,7 +2303,8 @@ TypeConverter::getConstantGenericEnvironment(SILDeclRef c) { return nullptr; } -SILType TypeConverter::getSubstitutedStorageType(AbstractStorageDecl *value, +SILType TypeConverter::getSubstitutedStorageType(TypeExpansionContext context, + AbstractStorageDecl *value, Type lvalueType) { // The l-value type is the result of applying substitutions to // the type-of-reference. Essentially, we want to apply those @@ -2226,7 +2323,7 @@ SILType TypeConverter::getSubstitutedStorageType(AbstractStorageDecl *value, substType = substType.getReferenceStorageReferent(); } - CanType substLoweredType = getLoweredRValueType(origType, substType); + CanType substLoweredType = getLoweredRValueType(context, origType, substType); // Type substitution preserves structural type structure, and the // type-of-reference is only different in the outermost structural @@ -2472,7 +2569,7 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) { // captures for default arguments that are actually referenced. if (auto *AFD = curFn.getAbstractFunctionDecl()) { for (auto *P : *AFD->getParameters()) { - if (P->getDefaultValue()) + if (P->hasDefaultExpr()) collectCaptures(P->getDefaultArgumentCaptureInfo(), dc); } } @@ -2485,7 +2582,7 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) { if (auto *afd = dyn_cast(curFn.getDecl())) { auto *param = getParameterAt(afd, curFn.defaultArgIndex); - if (param->getDefaultValue()) { + if (param->hasDefaultExpr()) { auto dc = afd->getInnermostDeclContext(); collectCaptures(param->getDefaultArgumentCaptureInfo(), dc); } @@ -2792,10 +2889,11 @@ TypeConverter::getInterfaceBoxTypeForCapture(ValueDecl *captured, env->mapTypeIntoContext(contextBoxTy) ->getCanonicalType()); } - assert(contextBoxTy->getLayout()->getFields().size() == 1 - && getSILBoxFieldType(contextBoxTy, *this, 0).getASTType() - == loweredContextType - && "box field type doesn't match capture!"); + assert(contextBoxTy->getLayout()->getFields().size() == 1 && + getSILBoxFieldType(TypeExpansionContext::minimal(), contextBoxTy, + *this, 0) + .getASTType() == loweredContextType && + "box field type doesn't match capture!"); #endif return boxTy; } @@ -2825,8 +2923,8 @@ TypeConverter::getContextBoxTypeForCapture(ValueDecl *captured, return boxType; } -CanSILBoxType TypeConverter::getBoxTypeForEnumElement(SILType enumType, - EnumElementDecl *elt) { +CanSILBoxType TypeConverter::getBoxTypeForEnumElement( + TypeExpansionContext context, SILType enumType, EnumElementDecl *elt) { auto *enumDecl = enumType.getEnumOrBoundGenericEnum(); @@ -2839,8 +2937,7 @@ CanSILBoxType TypeConverter::getBoxTypeForEnumElement(SILType enumType, if (boxSignature == CanGenericSignature()) { auto eltIntfTy = elt->getArgumentInterfaceType(); - - auto boxVarTy = getLoweredRValueType(eltIntfTy); + auto boxVarTy = getLoweredRValueType(context, eltIntfTy); auto layout = SILLayout::get(C, nullptr, SILField(boxVarTy, true)); return SILBoxType::get(C, layout, {}); } @@ -2852,8 +2949,8 @@ CanSILBoxType TypeConverter::getBoxTypeForEnumElement(SILType enumType, auto eltIntfTy = elt->getArgumentInterfaceType(); GenericContextScope scope(*this, boxSignature); - auto boxVarTy = getLoweredRValueType(getAbstractionPattern(elt), - eltIntfTy); + auto boxVarTy = getLoweredRValueType(context, + getAbstractionPattern(elt), eltIntfTy); auto layout = SILLayout::get(C, boxSignature, SILField(boxVarTy, true)); // Instantiate the layout with enum's substitution list. @@ -2865,13 +2962,15 @@ CanSILBoxType TypeConverter::getBoxTypeForEnumElement(SILType enumType, } static void countNumberOfInnerFields(unsigned &fieldsCount, TypeConverter &TC, - SILType Ty, ResilienceExpansion expansion) { + SILType Ty, + TypeExpansionContext expansion) { if (auto *structDecl = Ty.getStructOrBoundGenericStruct()) { - assert(!structDecl->isResilient(&TC.M, expansion) && - " FSO should not be trying to explode resilient (ie address-only) " - "types at all"); + assert( + !structDecl->isResilient(&TC.M, expansion.getResilienceExpansion()) && + " FSO should not be trying to explode resilient (ie address-only) " + "types at all"); for (auto *prop : structDecl->getStoredProperties()) { - SILType propTy = Ty.getFieldType(prop, TC); + SILType propTy = Ty.getFieldType(prop, TC, expansion); unsigned fieldsCountBefore = fieldsCount; countNumberOfInnerFields(fieldsCount, TC, propTy, expansion); if (fieldsCount == fieldsCountBefore) { @@ -2893,7 +2992,7 @@ static void countNumberOfInnerFields(unsigned &fieldsCount, TypeConverter &TC, if (enumDecl->isIndirect()) { return; } - assert(!enumDecl->isResilient(&TC.M, expansion) && + assert(!enumDecl->isResilient(&TC.M, expansion.getResilienceExpansion()) && " FSO should not be trying to explode resilient (ie address-only) " "types at all"); unsigned fieldsCountBefore = fieldsCount; @@ -2910,7 +3009,7 @@ static void countNumberOfInnerFields(unsigned &fieldsCount, TypeConverter &TC, // (we shouldn't expand enums) // Number of fields > 1 as "future proof" for this heuristic: // In case it is used by a pass that tries to explode enums. - auto payloadTy = Ty.getEnumElementType(elt, TC); + auto payloadTy = Ty.getEnumElementType(elt, TC, expansion); fieldsCount = 0; countNumberOfInnerFields(fieldsCount, TC, payloadTy, expansion); if (fieldsCount > maxEnumCount) { @@ -2923,8 +3022,8 @@ static void countNumberOfInnerFields(unsigned &fieldsCount, TypeConverter &TC, } unsigned TypeConverter::countNumberOfFields(SILType Ty, - ResilienceExpansion expansion) { - auto key = std::make_pair(Ty, unsigned(expansion)); + TypeExpansionContext expansion) { + auto key = std::make_pair(Ty, unsigned(expansion.getResilienceExpansion())); auto Iter = TypeFields.find(key); if (Iter != TypeFields.end()) { return std::max(Iter->second, 1U); @@ -2942,7 +3041,7 @@ void TypeLowering::print(llvm::raw_ostream &os) const { return "false"; }; os << "Type Lowering for lowered type: " << LoweredType << ".\n" - << "Expansion: " << ResilienceExpansion(ForExpansion) << "\n" + << "Expansion: " << getResilienceExpansion() << "\n" << "isTrivial: " << BOOL(Properties.isTrivial()) << ".\n" << "isFixedABI: " << BOOL(Properties.isFixedABI()) << ".\n" << "isAddressOnly: " << BOOL(Properties.isAddressOnly()) << ".\n" diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 21f7bc76210a9..5fc26095eae27 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -110,11 +110,12 @@ getBridgingFn(Optional &cacheSlot, // Check that the function takes the expected arguments and returns the // expected result type. SILDeclRef c(fd); - auto funcTy = SGM.Types.getConstantFunctionType(c); + auto funcTy = + SGM.Types.getConstantFunctionType(TypeExpansionContext::minimal(), c); SILFunctionConventions fnConv(funcTy, SGM.M); auto toSILType = [&SGM](Type ty) { - return SGM.Types.getLoweredType(ty, ResilienceExpansion::Minimal); + return SGM.Types.getLoweredType(ty, TypeExpansionContext::minimal()); }; if (inputTypes) { @@ -415,12 +416,10 @@ SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess, : ParameterConvention::Indirect_In_Guaranteed }, }; - auto extInfo = - SILFunctionType::ExtInfo(SILFunctionTypeRepresentation::Thin, - /*pseudogeneric*/false, - // SWIFT_ENABLE_TENSORFLOW - /*non-escaping*/false, - DifferentiabilityKind::NonDifferentiable); + auto extInfo = SILFunctionType::ExtInfo( + SILFunctionTypeRepresentation::Thin, + /*pseudogeneric*/ false, + /*non-escaping*/ false, DifferentiabilityKind::NonDifferentiable); auto functionTy = SILFunctionType::get(sig, extInfo, SILCoroutineKind::YieldOnce, @@ -1032,7 +1031,6 @@ SILFunction *SILGenModule::emitClosure(AbstractClosureExpr *ce) { // initializer of the containing type. if (!f->isExternalDeclaration()) return f; - preEmitFunction(constant, ce, f, ce); PrettyStackTraceSILFunction X("silgen closureexpr", f); SILGenFunction(*this, *f, ce).emitClosure(ce); @@ -1063,8 +1061,8 @@ bool SILGenModule::hasNonTrivialIVars(ClassDecl *cd) { auto *vd = dyn_cast(member); if (!vd || !vd->hasStorage()) continue; - auto &ti = Types.getTypeLowering(vd->getType(), - ResilienceExpansion::Maximal); + auto &ti = Types.getTypeLowering( + vd->getType(), TypeExpansionContext::maximalResilienceExpansionOnly()); if (!ti.isTrivial()) return true; } @@ -1176,7 +1174,7 @@ void SILGenModule::emitDefaultArgGenerator(SILDeclRef constant, llvm_unreachable("No default argument here?"); case DefaultArgumentKind::Normal: { - auto arg = param->getDefaultValue(); + auto arg = param->getTypeCheckedDefaultExpr(); emitOrDelayFunction(*this, constant, [this,constant,arg,initDC](SILFunction *f) { preEmitFunction(constant, arg, f, arg); @@ -1286,7 +1284,7 @@ SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName, Type initType = FunctionType::get({}, TupleType::getEmpty(C), type->getExtInfo()); auto initSILType = cast( - Types.getLoweredRValueType(initType)); + Types.getLoweredRValueType(TypeExpansionContext::minimal(), initType)); SILGenFunctionBuilder builder(*this); auto *f = builder.createFunction( @@ -1470,11 +1468,12 @@ SILGenModule::canStorageUseStoredKeyPathComponent(AbstractStorageDecl *decl, if (auto genericEnv = decl->getInnermostDeclContext()->getGenericEnvironmentOfContext()) componentObjTy = genericEnv->mapTypeIntoContext(componentObjTy); - auto storageTy = M.Types.getSubstitutedStorageType(decl, componentObjTy); - auto opaqueTy = - M.Types.getLoweredRValueType(AbstractionPattern::getOpaque(), - componentObjTy); - + auto storageTy = M.Types.getSubstitutedStorageType( + TypeExpansionContext::minimal(), decl, componentObjTy); + auto opaqueTy = M.Types.getLoweredRValueType( + TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(expansion), + AbstractionPattern::getOpaque(), componentObjTy); + return storageTy.getASTType() == opaqueTy; } case AccessStrategy::DirectToAccessor: @@ -1804,7 +1803,7 @@ void SILGenModule::emitSourceFile(SourceFile *sf) { std::unique_ptr SILModule::constructSIL(ModuleDecl *mod, TypeConverter &tc, SILOptions &options, FileUnit *SF) { - SharedTimer timer("SILGen"); + FrontendStatsTracer tracer(mod->getASTContext().Stats, "SILGen"); const DeclContext *DC; if (SF) { DC = SF; diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 00be4b4e930fa..d2980f81c191c 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -90,7 +90,8 @@ getIndirectApplyAbstractionPattern(SILGenFunction &SGF, static CanFunctionType getPartialApplyOfDynamicMethodFormalType(SILGenModule &SGM, SILDeclRef member, ConcreteDeclRef memberRef) { - auto memberCI = SGM.Types.getConstantInfo(member); + auto memberCI = + SGM.Types.getConstantInfo(TypeExpansionContext::minimal(), member); // Construct a non-generic version of the formal type. // This works because we're only using foreign members, where presumably @@ -133,7 +134,8 @@ getDynamicMethodLoweredType(SILModule &M, auto objcFormalTy = substMemberTy.withExtInfo(substMemberTy->getExtInfo() .withSILRepresentation(SILFunctionTypeRepresentation::ObjCMethod)); return SILType::getPrimitiveObjectType( - M.Types.getUncachedSILFunctionTypeForConstant(constant, objcFormalTy)); + M.Types.getUncachedSILFunctionTypeForConstant( + TypeExpansionContext::minimal(), constant, objcFormalTy)); } /// Check if we can perform a dynamic dispatch on a super method call. @@ -382,34 +384,39 @@ class Callee { SubstitutionMap subs, SILLocation l, bool callPreviousDynamicReplaceableImpl = false) { - auto &ci = SGF.getConstantInfo(c); - return Callee(SGF, c, ci.FormalPattern, ci.FormalType, subs, l, - callPreviousDynamicReplaceableImpl); + auto &ci = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); + return Callee( + SGF, c, ci.FormalPattern, ci.FormalType, + subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), l, + callPreviousDynamicReplaceableImpl); } static Callee forEnumElement(SILGenFunction &SGF, SILDeclRef c, SubstitutionMap subs, SILLocation l) { assert(isa(c.getDecl())); - auto &ci = SGF.getConstantInfo(c); - return Callee(Kind::EnumElement, SGF, c, ci.FormalPattern, - ci.FormalType, subs, l); + auto &ci = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); + return Callee( + Kind::EnumElement, SGF, c, ci.FormalPattern, ci.FormalType, + subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), l); } static Callee forClassMethod(SILGenFunction &SGF, SILDeclRef c, SubstitutionMap subs, SILLocation l) { auto base = c.getOverriddenVTableEntry(); - auto &baseCI = SGF.getConstantInfo(base); - auto &derivedCI = SGF.getConstantInfo(c); - return Callee(Kind::ClassMethod, SGF, c, - baseCI.FormalPattern, derivedCI.FormalType, subs, l); + auto &baseCI = SGF.getConstantInfo(SGF.getTypeExpansionContext(), base); + auto &derivedCI = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); + return Callee( + Kind::ClassMethod, SGF, c, baseCI.FormalPattern, derivedCI.FormalType, + subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), l); } static Callee forSuperMethod(SILGenFunction &SGF, SILDeclRef c, SubstitutionMap subs, SILLocation l) { - auto &ci = SGF.getConstantInfo(c); - return Callee(Kind::SuperMethod, SGF, c, - ci.FormalPattern, ci.FormalType, subs, l); + auto &ci = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); + return Callee( + Kind::SuperMethod, SGF, c, ci.FormalPattern, ci.FormalType, + subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), l); } static Callee forWitnessMethod(SILGenFunction &SGF, CanType protocolSelfType, @@ -430,15 +437,16 @@ class Callee { subs); } - auto &ci = SGF.getConstantInfo(c); - return Callee(Kind::WitnessMethod, SGF, c, ci.FormalPattern, - ci.FormalType, subs, l); + auto &ci = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); + return Callee( + Kind::WitnessMethod, SGF, c, ci.FormalPattern, ci.FormalType, + subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), l); } static Callee forDynamic(SILGenFunction &SGF, SILDeclRef c, SubstitutionMap constantSubs, CanAnyFunctionType substFormalType, SubstitutionMap subs, SILLocation l) { - auto &ci = SGF.getConstantInfo(c); + auto &ci = SGF.getConstantInfo(SGF.getTypeExpansionContext(), c); AbstractionPattern origFormalType = ci.FormalPattern; // Replace the original self type with the partially-applied subst type. @@ -456,8 +464,9 @@ class Callee { } origFormalType.rewriteType(CanGenericSignature(), origFormalFnType); - return Callee(Kind::DynamicMethod, SGF, c, origFormalType, - substFormalType, subs, l); + return Callee( + Kind::DynamicMethod, SGF, c, origFormalType, substFormalType, + subs.mapIntoTypeExpansionContext(SGF.getTypeExpansionContext()), l); } Callee(Callee &&) = default; @@ -534,8 +543,8 @@ class Callee { CalleeTypeInfo result; result.substFnType = - formalFnType.castTo()->substGenericArgs(SGF.SGM.M, - Substitutions); + formalFnType.castTo()->substGenericArgs( + SGF.SGM.M, Substitutions, SGF.getTypeExpansionContext()); if (!constant || !constant->isForeign) return result; @@ -578,7 +587,8 @@ class Callee { // If the call is curried, emit a direct call to the curry thunk. if (constant->isCurried) { - auto constantInfo = SGF.getConstantInfo(*constant); + auto constantInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); SILValue ref = SGF.emitGlobalFunctionRef(Loc, *constant, constantInfo); return ManagedValue::forUnmanaged(ref); } @@ -590,18 +600,21 @@ class Callee { return IndirectValue; case Kind::EnumElement: case Kind::StandaloneFunction: { - auto constantInfo = SGF.getConstantInfo(*constant); + auto constantInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); SILValue ref = SGF.emitGlobalFunctionRef(Loc, *constant, constantInfo); return ManagedValue::forUnmanaged(ref); } case Kind::StandaloneFunctionDynamicallyReplaceableImpl: { - auto constantInfo = SGF.getConstantInfo(*constant); + auto constantInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); SILValue ref = SGF.emitGlobalFunctionRef(Loc, *constant, constantInfo, true); return ManagedValue::forUnmanaged(ref); } case Kind::ClassMethod: { - auto methodTy = SGF.SGM.Types.getConstantOverrideType(*constant); + auto methodTy = SGF.SGM.Types.getConstantOverrideType( + SGF.getTypeExpansionContext(), *constant); // Otherwise, do the dynamic dispatch inline. ArgumentScope S(SGF, Loc); @@ -626,8 +639,8 @@ class Callee { SGF, Loc, *borrowedSelf); auto base = constant->getOverriddenVTableEntry(); - auto constantInfo = - SGF.SGM.Types.getConstantOverrideInfo(*constant, base); + auto constantInfo = SGF.SGM.Types.getConstantOverrideInfo( + SGF.getTypeExpansionContext(), *constant, base); ManagedValue fn; if (!constant->isForeign) { @@ -641,8 +654,10 @@ class Callee { return fn; } case Kind::WitnessMethod: { - auto constantInfo = SGF.getConstantInfo(*constant); + auto constantInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); + // TODO: substOpaqueTypesWithUnderlyingTypes ... auto proto = cast(Constant.getDecl()->getDeclContext()); auto selfType = proto->getSelfInterfaceType()->getCanonicalType(); auto lookupType = selfType.subst(Substitutions)->getCanonicalType(); @@ -687,7 +702,8 @@ class Callee { // If the call is curried, emit a direct call to the curry thunk. if (constant->isCurried) { - auto constantInfo = SGF.getConstantInfo(*constant); + auto constantInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); } } @@ -699,26 +715,30 @@ class Callee { case Kind::StandaloneFunctionDynamicallyReplaceableImpl: case Kind::StandaloneFunction: { - auto constantInfo = SGF.getConstantInfo(*constant); + auto constantInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); } case Kind::EnumElement: { // Emit a direct call to the element constructor thunk. - auto constantInfo = SGF.getConstantInfo(*constant); + auto constantInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); } case Kind::ClassMethod: { - auto constantInfo = SGF.SGM.Types.getConstantOverrideInfo(*constant); + auto constantInfo = SGF.SGM.Types.getConstantOverrideInfo( + SGF.getTypeExpansionContext(), *constant); return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); } case Kind::SuperMethod: { auto base = constant->getOverriddenVTableEntry(); - auto constantInfo = - SGF.SGM.Types.getConstantOverrideInfo(*constant, base); + auto constantInfo = SGF.SGM.Types.getConstantOverrideInfo( + SGF.getTypeExpansionContext(), *constant, base); return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); } case Kind::WitnessMethod: { - auto constantInfo = SGF.getConstantInfo(*constant); + auto constantInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), *constant); return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType()); } case Kind::DynamicMethod: { @@ -3951,8 +3971,8 @@ CallEmission::applyPartiallyAppliedSuperMethod(SGFContext C) { // because that's what the partially applied super method expects; firstLevelResult.formalType = callee.getSubstFormalType(); auto origFormalType = AbstractionPattern(firstLevelResult.formalType); - auto substFnType = - SGF.getSILFunctionType(origFormalType, firstLevelResult.formalType); + auto substFnType = SGF.getSILFunctionType( + SGF.getTypeExpansionContext(), origFormalType, firstLevelResult.formalType); // Emit the arguments. SmallVector uncurriedArgs; @@ -3978,7 +3998,8 @@ CallEmission::applyPartiallyAppliedSuperMethod(SGFContext C) { // partial_apply. upcastedSelf = upcastedSelf.ensurePlusOne(SGF, loc); - auto constantInfo = SGF.getConstantInfo(callee.getMethodName()); + auto constantInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), callee.getMethodName()); auto functionTy = constantInfo.getSILType(); ManagedValue superMethod; { @@ -4019,8 +4040,8 @@ CallEmission::applySpecializedEmitter(SpecializedEmitter &specializedEmitter, // expect. firstLevelResult.formalType = callee.getSubstFormalType(); auto origFormalType = AbstractionPattern(firstLevelResult.formalType); - auto substFnType = - SGF.getSILFunctionType(origFormalType, firstLevelResult.formalType); + auto substFnType = SGF.getSILFunctionType( + SGF.getTypeExpansionContext(), origFormalType, firstLevelResult.formalType); // If we have an early emitter, just let it take over for the // uncurried call site. @@ -4352,7 +4373,8 @@ bool SILGenModule::isNonMutatingSelfIndirect(SILDeclRef methodRef) { if (method->isStatic()) return false; - auto fnType = M.Types.getConstantFunctionType(methodRef); + auto fnType = M.Types.getConstantFunctionType(TypeExpansionContext::minimal(), + methodRef); auto importAsMember = method->getImportAsMemberStatus(); SILParameterInfo self; @@ -4640,7 +4662,7 @@ void SILGenFunction::emitYield(SILLocation loc, SmallVector yieldArgs; SmallVector delayedArgs; - auto fnType = F.getLoweredFunctionType(); + auto fnType = F.getLoweredFunctionTypeInContext(getTypeExpansionContext()); SmallVector substYieldTys; for (auto origYield : fnType->getYields()) { substYieldTys.push_back({ @@ -4740,7 +4762,8 @@ ManagedValue SILGenFunction::emitInjectEnum(SILLocation loc, // careful to stage the cleanups so that if the expression // throws, we know to deallocate the uninitialized box. if (element->isIndirect() || element->getParentEnum()->isIndirect()) { - auto boxTy = SGM.M.Types.getBoxTypeForEnumElement(enumTy, element); + auto boxTy = SGM.M.Types.getBoxTypeForEnumElement(getTypeExpansionContext(), + enumTy, element); auto *box = B.createAllocBox(loc, boxTy); auto *addr = B.createProjectBox(loc, box, 0); @@ -4868,7 +4891,7 @@ RValue SILGenFunction::emitApplyAllocatingInitializer(SILLocation loc, // Form the reference to the allocating initializer. auto initRef = SILDeclRef(ctor, SILDeclRef::Kind::Allocator) .asForeign(requiresForeignEntryPoint(ctor)); - auto initConstant = getConstantInfo(initRef); + auto initConstant = getConstantInfo(getTypeExpansionContext(), initRef); auto subs = init.getSubstitutions(); // Scope any further writeback just within this operation. @@ -4879,8 +4902,8 @@ RValue SILGenFunction::emitApplyAllocatingInitializer(SILLocation loc, SILType selfMetaTy; { // Determine the self metatype type. - CanSILFunctionType substFnType = - initConstant.SILFnType->substGenericArgs(SGM.M, subs); + CanSILFunctionType substFnType = initConstant.SILFnType->substGenericArgs( + SGM.M, subs, getTypeExpansionContext()); SILType selfParamMetaTy = getSILType(substFnType->getSelfParameter(), substFnType); @@ -4972,7 +4995,7 @@ RValue SILGenFunction::emitApplyMethod(SILLocation loc, ConcreteDeclRef declRef, // Form the reference to the method. auto callRef = SILDeclRef(call, SILDeclRef::Kind::Func) .asForeign(requiresForeignEntryPoint(declRef.getDecl())); - auto declRefConstant = getConstantInfo(callRef); + auto declRefConstant = getConstantInfo(getTypeExpansionContext(), callRef); auto subs = declRef.getSubstitutions(); // Scope any further writeback just within this operation. @@ -4984,7 +5007,8 @@ RValue SILGenFunction::emitApplyMethod(SILLocation loc, ConcreteDeclRef declRef, { // Determine the self metatype type. CanSILFunctionType substFnType = - declRefConstant.SILFnType->substGenericArgs(SGM.M, subs); + declRefConstant.SILFnType->substGenericArgs(SGM.M, subs, + getTypeExpansionContext()); SILType selfParamMetaTy = getSILType(substFnType->getSelfParameter(), substFnType); selfMetaTy = selfParamMetaTy; @@ -5490,8 +5514,8 @@ AccessorBaseArgPreparer::AccessorBaseArgPreparer(SILGenFunction &SGF, CanType baseFormalType, SILDeclRef accessor) : SGF(SGF), loc(loc), base(base), baseFormalType(baseFormalType), - accessor(accessor), - selfParam(SGF.SGM.Types.getConstantSelfParameter(accessor)), + accessor(accessor), selfParam(SGF.SGM.Types.getConstantSelfParameter( + SGF.getTypeExpansionContext(), accessor)), baseLoweredType(base.getType()) { assert(!base.isInContext()); assert(!base.isLValue() || !base.hasCleanup()); @@ -6067,6 +6091,39 @@ RValue SILGenFunction::emitDynamicSubscriptExpr(DynamicSubscriptExpr *e, return RValue(*this, e, emitManagedRValueWithCleanup(optResult, optTL)); } +SmallVector SILGenFunction::emitKeyPathSubscriptOperands( + SubscriptDecl *subscript, SubstitutionMap subs, Expr *indexExpr) { + Type interfaceType = subscript->getInterfaceType(); + CanFunctionType substFnType = + subs ? cast(interfaceType->castTo() + ->substGenericArgs(subs) + ->getCanonicalType()) + : cast(interfaceType->getCanonicalType()); + AbstractionPattern origFnType(substFnType); + auto fnType = + getLoweredType(origFnType, substFnType).castTo(); + + SmallVector argValues; + SmallVector delayedArgs; + ArgEmitter emitter(*this, fnType->getRepresentation(), + /*yield*/ false, + /*isForCoroutine*/ false, + ClaimedParamsRef(fnType, fnType->getParameters()), + argValues, delayedArgs, + /*foreign error*/ None, ImportAsMemberStatus()); + + auto prepared = + prepareSubscriptIndices(subscript, subs, + // Strategy doesn't matter + AccessStrategy::getStorage(), indexExpr); + emitter.emitPreparedArgs(std::move(prepared), origFnType); + + if (!delayedArgs.empty()) + emitDelayedArguments(*this, delayedArgs, argValues); + + return argValues; +} + ManagedValue ArgumentScope::popPreservingValue(ManagedValue mv) { formalEvalScope.pop(); return normalScope.popPreservingValue(mv); diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index 5520e6f15536f..bd88f7a2ad42b 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -123,7 +123,8 @@ emitBridgeNativeToObjectiveC(SILGenFunction &SGF, SGF.SGM.SwiftModule, dc); // Substitute into the witness function type. - witnessFnTy = witnessFnTy.substGenericArgs(SGF.SGM.M, typeSubMap); + witnessFnTy = witnessFnTy.substGenericArgs(SGF.SGM.M, typeSubMap, + SGF.getTypeExpansionContext()); // We might have to re-abstract the 'self' value if it is an // Optional. @@ -204,7 +205,8 @@ emitBridgeObjectiveCToNative(SILGenFunction &SGF, SubstitutionMap typeSubMap = witness.getSubstitutions(); // Substitute into the witness function type. - witnessFnTy = witnessFnTy->substGenericArgs(SGF.SGM.M, typeSubMap); + witnessFnTy = witnessFnTy->substGenericArgs(SGF.SGM.M, typeSubMap, + SGF.getTypeExpansionContext()); // The witness takes an _ObjectiveCType?, so convert to that type. CanType desiredValueType = OptionalType::get(objcType)->getCanonicalType(); @@ -220,7 +222,8 @@ emitBridgeObjectiveCToNative(SILGenFunction &SGF, SGF.B.createMetatype(loc, metatypeParam.getSILStorageType(SGF.SGM.M, witnessFnTy)); - auto witnessCI = SGF.getConstantInfo(witnessConstant); + auto witnessCI = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), witnessConstant); CanType formalResultTy = witnessCI.LoweredType.getResult(); auto subs = witness.getSubstitutions(); @@ -954,7 +957,8 @@ SILGenFunction::emitBlockToFunc(SILLocation loc, if (thunkTy->getInvocationGenericSignature()) { substFnTy = thunkTy->substGenericArgs(F.getModule(), - interfaceSubs); + interfaceSubs, + getTypeExpansionContext()); } // Create it in the current function. @@ -1263,12 +1267,16 @@ static SILFunctionType *emitObjCThunkArguments(SILGenFunction &SGF, auto subs = SGF.F.getForwardingSubstitutionMap(); - auto objcInfo = SGF.SGM.Types.getConstantInfo(thunk); - auto objcFnTy = objcInfo.SILFnType->substGenericArgs(SGF.SGM.M, subs); + auto objcInfo = + SGF.SGM.Types.getConstantInfo(SGF.getTypeExpansionContext(), thunk); + auto objcFnTy = objcInfo.SILFnType->substGenericArgs( + SGF.SGM.M, subs, SGF.getTypeExpansionContext()); auto objcFormalFnTy = substGenericArgs(objcInfo.LoweredType, subs); - auto swiftInfo = SGF.SGM.Types.getConstantInfo(native); - auto swiftFnTy = swiftInfo.SILFnType->substGenericArgs(SGF.SGM.M, subs); + auto swiftInfo = + SGF.SGM.Types.getConstantInfo(SGF.getTypeExpansionContext(), native); + auto swiftFnTy = swiftInfo.SILFnType->substGenericArgs( + SGF.SGM.M, subs, SGF.getTypeExpansionContext()); auto swiftFormalFnTy = substGenericArgs(swiftInfo.LoweredType, subs); SILFunctionConventions swiftConv(swiftFnTy, SGF.SGM.M); @@ -1402,9 +1410,10 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { } } - auto nativeInfo = getConstantInfo(native); + auto nativeInfo = getConstantInfo(getTypeExpansionContext(), native); auto subs = F.getForwardingSubstitutionMap(); - auto substTy = nativeInfo.SILFnType->substGenericArgs(SGM.M, subs); + auto substTy = nativeInfo.SILFnType->substGenericArgs( + SGM.M, subs, getTypeExpansionContext()); SILFunctionConventions substConv(substTy, SGM.M); // Use the same generic environment as the native entry point. @@ -1605,7 +1614,7 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { // Wrap the function in its original form. auto fd = cast(thunk.getDecl()); - auto nativeCI = getConstantInfo(thunk); + auto nativeCI = getConstantInfo(getTypeExpansionContext(), thunk); auto nativeFnTy = F.getLoweredFunctionType(); assert(nativeFnTy == nativeCI.SILFnType); @@ -1613,7 +1622,8 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(thunk)); SILDeclRef foreignDeclRef = thunk.asForeign(true); - SILConstantInfo foreignCI = getConstantInfo(foreignDeclRef); + SILConstantInfo foreignCI = + getConstantInfo(getTypeExpansionContext(), foreignDeclRef); auto foreignFnTy = foreignCI.SILFnType; // Find the foreign error convention and 'self' parameter index. @@ -1780,7 +1790,7 @@ void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { foreignCI); auto fnType = fn->getType().castTo(); - fnType = fnType->substGenericArgs(SGM.M, subs); + fnType = fnType->substGenericArgs(SGM.M, subs, getTypeExpansionContext()); CanType nativeFormalResultType = fd->mapTypeIntoContext(nativeCI.LoweredType.getResult()) diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index f43baef1ba102..c46970ecf36e4 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -49,7 +49,8 @@ static SILValue emitConstructorMetatypeArg(SILGenFunction &SGF, VD->setInterfaceType(metatype); SGF.AllocatorMetatype = SGF.F.begin()->createFunctionArgument( - SGF.getLoweredType(DC->mapTypeIntoContext(metatype)), VD); + SGF.getLoweredTypeForFunctionArgument(DC->mapTypeIntoContext(metatype)), + VD); return SGF.AllocatorMetatype; } @@ -78,8 +79,7 @@ static RValue emitImplicitValueConstructorArg(SILGenFunction &SGF, VD->setSpecifier(ParamSpecifier::Default); VD->setInterfaceType(interfaceType); - auto argType = SGF.SGM.Types.getLoweredType(type, - ResilienceExpansion::Minimal); + auto argType = SGF.getLoweredTypeForFunctionArgument(type); auto *arg = SGF.F.begin()->createFunctionArgument(argType, VD); ManagedValue mvArg; if (arg->getArgumentConvention().isOwnedConvention()) { @@ -129,7 +129,7 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, auto *paramList = ctor->getParameters(); auto *selfDecl = ctor->getImplicitSelfDecl(); auto selfIfaceTy = selfDecl->getInterfaceType(); - SILType selfTy = SGF.getLoweredType(selfDecl->getType()); + SILType selfTy = SGF.getLoweredTypeForFunctionArgument(selfDecl->getType()); // Emit the indirect return argument, if any. SILValue resultSlot; @@ -142,7 +142,8 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, ctor); VD->setSpecifier(ParamSpecifier::InOut); VD->setInterfaceType(selfIfaceTy); - resultSlot = SGF.F.begin()->createFunctionArgument(selfTy.getAddressType(), VD); + resultSlot = + SGF.F.begin()->createFunctionArgument(selfTy.getAddressType(), VD); } // Emit the elementwise arguments. @@ -164,7 +165,8 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, if (resultSlot) { auto elti = elements.begin(), eltEnd = elements.end(); for (VarDecl *field : decl->getStoredProperties()) { - auto fieldTy = selfTy.getFieldType(field, SGF.SGM.M); + auto fieldTy = + selfTy.getFieldType(field, SGF.SGM.M, SGF.getTypeExpansionContext()); SILValue slot = SGF.B.createStructElementAddr(Loc, resultSlot, field, fieldTy.getAddressType()); @@ -201,7 +203,8 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF, auto elti = elements.begin(), eltEnd = elements.end(); for (VarDecl *field : decl->getStoredProperties()) { - auto fieldTy = selfTy.getFieldType(field, SGF.SGM.M); + auto fieldTy = + selfTy.getFieldType(field, SGF.SGM.M, SGF.getTypeExpansionContext()); SILValue v; // If it's memberwise initialized, do so now. @@ -416,8 +419,8 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) { void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) { Type enumIfaceTy = element->getParentEnum()->getDeclaredInterfaceType(); Type enumTy = F.mapTypeIntoContext(enumIfaceTy); - auto &enumTI = SGM.Types.getTypeLowering(enumTy, - ResilienceExpansion::Minimal); + auto &enumTI = + SGM.Types.getTypeLowering(enumTy, TypeExpansionContext::minimal()); RegularLocation Loc(element); CleanupLocation CleanupLoc(element); diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index 8ef1cf2c6af67..ace1e9e71c359 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -371,12 +371,13 @@ class LocalVariableInitialization : public SingleBufferInitialization { "can't emit a local var for a non-local var decl"); assert(decl->hasStorage() && "can't emit storage for a computed variable"); assert(!SGF.VarLocs.count(decl) && "Already have an entry for this decl?"); - - auto boxType = SGF.SGM.Types - .getContextBoxTypeForCapture(decl, - SGF.SGM.Types.getLoweredRValueType(decl->getType()), - SGF.F.getGenericEnvironment(), - /*mutable*/ true); + // The box type's context is lowered in the minimal resilience domain. + auto boxType = SGF.SGM.Types.getContextBoxTypeForCapture( + decl, + SGF.SGM.Types.getLoweredRValueType(TypeExpansionContext::minimal(), + decl->getType()), + SGF.F.getGenericEnvironment(), + /*mutable*/ true); // The variable may have its lifetime extended by a closure, heap-allocate // it using a box. @@ -850,7 +851,8 @@ void EnumElementPatternInitialization::emitEnumMatch( } // Otherwise, the bound value for the enum case is available. - SILType eltTy = value.getType().getEnumElementType(eltDecl, SGF.SGM.M); + SILType eltTy = value.getType().getEnumElementType( + eltDecl, SGF.SGM.M, SGF.getTypeExpansionContext()); auto &eltTL = SGF.getTypeLowering(eltTy); if (mv.getType().isAddress()) { @@ -1237,7 +1239,7 @@ SILValue SILGenFunction::emitOSVersionRangeCheck(SILLocation loc, auto silDeclRef = SILDeclRef(versionQueryDecl); SILValue availabilityGTEFn = emitGlobalFunctionRef( - loc, silDeclRef, getConstantInfo(silDeclRef)); + loc, silDeclRef, getConstantInfo(getTypeExpansionContext(), silDeclRef)); SILValue args[] = {majorValue, minorValue, subminorValue}; return B.createApply(loc, availabilityGTEFn, SubstitutionMap(), args); diff --git a/lib/SILGen/SILGenDestructor.cpp b/lib/SILGen/SILGenDestructor.cpp index 1c816b3314ce5..3041fb58404ee 100644 --- a/lib/SILGen/SILGenDestructor.cpp +++ b/lib/SILGen/SILGenDestructor.cpp @@ -232,7 +232,8 @@ void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) { auto superclassDtor = SILDeclRef(superclassDtorDecl, SILDeclRef::Kind::Deallocator) .asForeign(); - auto superclassDtorType = SGM.Types.getConstantType(superclassDtor); + auto superclassDtorType = + SGM.Types.getConstantType(getTypeExpansionContext(), superclassDtor); SILValue superclassDtorValue = B.createObjCSuperMethod( cleanupLoc, selfValue, superclassDtor, superclassDtorType); diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 49c4c31b7ba88..35870f3e68871 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -1457,10 +1457,13 @@ RValueEmitter::visitBridgeToObjCExpr(BridgeToObjCExpr *E, SGFContext C) { RValue RValueEmitter::visitArchetypeToSuperExpr(ArchetypeToSuperExpr *E, SGFContext C) { ManagedValue archetype = SGF.emitRValueAsSingleValue(E->getSubExpr()); + auto loweredTy = SGF.getLoweredLoadableType(E->getType()); + if (loweredTy == archetype.getType()) + return RValue(SGF, E, archetype); + // Replace the cleanup with a new one on the superclass value so we always use // concrete retain/release operations. - auto base = SGF.B.createUpcast(E, archetype, - SGF.getLoweredLoadableType(E->getType())); + auto base = SGF.B.createUpcast(E, archetype, loweredTy); return RValue(SGF, E, base); } @@ -1554,7 +1557,8 @@ ManagedValue emitCFunctionPointer(SILGenFunction &SGF, // Produce a reference to the C-compatible entry point for the function. SILDeclRef constant(loc, /*curried*/ false, /*foreign*/ true); - SILConstantInfo constantInfo = SGF.getConstantInfo(constant); + SILConstantInfo constantInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), constant); // C function pointers cannot capture anything from their context. auto captures = SGF.SGM.Types.getLoweredLocalCaptures(constant); @@ -1983,7 +1987,11 @@ RValue RValueEmitter::visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E, E->getSubExpr()->getType()); auto &underlyingSubstTL = SGF.getTypeLowering(E->getSubExpr()->getType()); - + + if (underlyingSubstTL.getLoweredType() == opaqueTL.getLoweredType()) { + return SGF.emitRValue(E->getSubExpr(), C); + } + // If the opaque type is address only, initialize in place. if (opaqueTL.getLoweredType().isAddress()) { auto opaqueAddr = SGF.getBufferForExprResult( @@ -2022,15 +2030,18 @@ RValue RValueEmitter::visitUnderlyingToOpaqueExpr(UnderlyingToOpaqueExpr *E, // If the opaque type is loadable, emit the subexpression and bitcast it. auto value = SGF.emitRValueAsSingleValue(E->getSubExpr()); - if (underlyingSubstTL.getLoweredType() == underlyingTL.getLoweredType()) { + if (underlyingSubstTL.getLoweredType() != underlyingTL.getLoweredType()) { value = SGF.emitSubstToOrigValue(E, value, AbstractionPattern::getOpaque(), E->getSubExpr()->getType()->getCanonicalType()); } - + + if (value.getType() == opaqueTL.getLoweredType()) + return RValue(SGF, E, value); + auto cast = SGF.B.createUncheckedBitCast(E, value.forward(SGF), - opaqueTL.getLoweredType()); + opaqueTL.getLoweredType()); value = SGF.emitManagedRValueWithCleanup(cast); - + return RValue(SGF, E, value); } @@ -2213,7 +2224,8 @@ SILGenFunction::emitApplyOfDefaultArgGenerator(SILLocation loc, if (fnType->isPolymorphic()) subs = defaultArgsOwner.getSubstitutions(); - auto substFnType = fnType->substGenericArgs(SGM.M, subs); + auto substFnType = + fnType->substGenericArgs(SGM.M, subs, getTypeExpansionContext()); CalleeTypeInfo calleeTypeInfo(substFnType, origResultType, resultType); ResultPlanPtr resultPtr = @@ -2240,7 +2252,8 @@ RValue SILGenFunction::emitApplyOfStoredPropertyInitializer( auto fnRef = ManagedValue::forUnmanaged(emitGlobalFunctionRef(loc, constant)); auto fnType = fnRef.getType().castTo(); - auto substFnType = fnType->substGenericArgs(SGM.M, subs); + auto substFnType = + fnType->substGenericArgs(SGM.M, subs, getTypeExpansionContext()); CalleeTypeInfo calleeTypeInfo(substFnType, origResultType, resultType); ResultPlanPtr resultPlan = @@ -2677,8 +2690,10 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM, GenericContextScope scope(SGM.Types, genericSig); AbstractionPattern opaque = AbstractionPattern::getOpaque(); - loweredBaseTy = SGM.Types.getLoweredRValueType(opaque, baseType); - loweredPropTy = SGM.Types.getLoweredRValueType(opaque, propertyType); + loweredBaseTy = SGM.Types.getLoweredRValueType( + TypeExpansionContext::minimal(), opaque, baseType); + loweredPropTy = SGM.Types.getLoweredRValueType( + TypeExpansionContext::minimal(), opaque, propertyType); } auto paramConvention = ParameterConvention::Indirect_In_Guaranteed; @@ -2696,7 +2711,6 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM, auto signature = SILFunctionType::get(genericSig, SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, - // SWIFT_ENABLE_TENSORFLOW /*noescape*/ false, DifferentiabilityKind::NonDifferentiable), SILCoroutineKind::None, @@ -2815,8 +2829,10 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM, GenericContextScope scope(SGM.Types, genericSig); AbstractionPattern opaque = AbstractionPattern::getOpaque(); - loweredBaseTy = SGM.Types.getLoweredRValueType(opaque, baseType); - loweredPropTy = SGM.Types.getLoweredRValueType(opaque, propertyType); + loweredBaseTy = SGM.Types.getLoweredRValueType( + TypeExpansionContext::minimal(), opaque, baseType); + loweredPropTy = SGM.Types.getLoweredRValueType( + TypeExpansionContext::minimal(), opaque, propertyType); } auto &C = SGM.getASTContext(); @@ -2840,7 +2856,6 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM, auto signature = SILFunctionType::get(genericSig, SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, - // SWIFT_ENABLE_TENSORFLOW /*noescape*/ false, DifferentiabilityKind::NonDifferentiable), SILCoroutineKind::None, @@ -2999,8 +3014,8 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, RValue indexValue(indexTupleTy); auto indexLoweredTy = - SILType::getPrimitiveAddressType( - SGM.Types.getLoweredRValueType(indexTupleTy)); + SILType::getPrimitiveAddressType(SGM.Types.getLoweredRValueType( + TypeExpansionContext::minimal(), indexTupleTy)); // Get or create the equals witness [unsafeRawPointerTy, boolTy, genericSig, &C, &indexTypes, &equals, loc, @@ -3018,7 +3033,6 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, auto signature = SILFunctionType::get(genericSig, SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, - // SWIFT_ENABLE_TENSORFLOW /*noescape*/ false, DifferentiabilityKind::NonDifferentiable), SILCoroutineKind::None, @@ -3064,8 +3078,9 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, auto equalsMethod = equatableProtocol->getSingleRequirement( C.Id_EqualsOperator); auto equalsRef = SILDeclRef(equalsMethod); - auto equalsTy = subSGF.SGM.Types.getConstantType(equalsRef); - + auto equalsTy = subSGF.SGM.Types.getConstantType( + TypeExpansionContext(subSGF.F), equalsRef); + auto isFalseBB = subSGF.createBasicBlock(); auto i1Ty = SILType::getBuiltinIntegerType(1, C); for (unsigned i : indices(indexes)) { @@ -3097,8 +3112,8 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, = SubstitutionMap::getProtocolSubstitutions(equatableProtocol, formalCanTy, equatable); - auto equalsSubstTy = equalsTy.castTo() - ->substGenericArgs(SGM.M, equatableSub); + auto equalsSubstTy = equalsTy.castTo()->substGenericArgs( + SGM.M, equatableSub, TypeExpansionContext(subSGF.F)); auto equalsInfo = CalleeTypeInfo(equalsSubstTy, AbstractionPattern(boolTy), boolTy, None, @@ -3195,7 +3210,6 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, auto signature = SILFunctionType::get(genericSig, SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, /*pseudogeneric*/ false, - // SWIFT_ENABLE_TENSORFLOW /*noescape*/ false, DifferentiabilityKind::NonDifferentiable), SILCoroutineKind::None, @@ -3345,8 +3359,8 @@ lowerKeyPathSubscriptIndexTypes( } auto indexLoweredTy = SGM.Types.getLoweredType( - AbstractionPattern::getOpaque(), - indexTy, expansion); + AbstractionPattern::getOpaque(), indexTy, + TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(expansion)); indexLoweredTy = indexLoweredTy.mapTypeOutOfContext(); indexPatterns.push_back({indexTy->mapTypeOutOfContext() ->getCanonicalType(), @@ -3588,27 +3602,6 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) { auto baseTy = rootTy; SmallVector operands; - - auto lowerSubscriptOperands = - [this, &operands, E](const KeyPathExpr::Component &component) { - if (!component.getIndexExpr()) - return; - - // Evaluate the index arguments. - SmallVector indexValues; - auto indexResult = visit(component.getIndexExpr(), SGFContext()); - if (isa(indexResult.getType())) { - std::move(indexResult).extractElements(indexValues); - } else { - indexValues.push_back(std::move(indexResult)); - } - - for (auto &rv : indexValues) { - operands.push_back( - std::move(rv).forwardAsSingleValue(SGF, E)); - } - }; - for (auto &component : E->getComponents()) { switch (auto kind = component.getKind()) { @@ -3628,11 +3621,18 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) { component.getSubscriptIndexHashableConformances(), baseTy, /*for descriptor*/ false)); - lowerSubscriptOperands(component); - - assert(numOperands == operands.size() - && "operand count out of sync"); baseTy = loweredComponents.back().getComponentType(); + if (kind == KeyPathExpr::Component::Kind::Property) + break; + + auto subscript = cast(decl); + auto loweredArgs = SGF.emitKeyPathSubscriptOperands( + subscript, component.getDeclRef().getSubstitutions(), + component.getIndexExpr()); + + for (auto &arg : loweredArgs) { + operands.push_back(arg.forward(SGF)); + } break; } diff --git a/lib/SILGen/SILGenForeignError.cpp b/lib/SILGen/SILGenForeignError.cpp index 41acb7b8646da..ad33042cd1cf5 100644 --- a/lib/SILGen/SILGenForeignError.cpp +++ b/lib/SILGen/SILGenForeignError.cpp @@ -113,7 +113,8 @@ static SILValue emitIntValue(SILGenFunction &SGF, SILLocation loc, if (auto structDecl = type.getStructOrBoundGenericStruct()) { auto properties = structDecl->getStoredProperties(); assert(properties.size() == 1); - SILType fieldType = type.getFieldType(properties[0], SGF.SGM.M); + SILType fieldType = type.getFieldType(properties[0], SGF.SGM.M, + SGF.getTypeExpansionContext()); SILValue fieldValue = emitIntValue(SGF, loc, fieldType, value); return SGF.B.createStruct(loc, type, fieldValue); } diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 9fca470e3feb4..307ef69050cf2 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -153,10 +153,12 @@ SILGenFunction::emitSiblingMethodRef(SILLocation loc, // dispatch (viz. objc_msgSend for now). if (methodConstant.hasDecl() && methodConstant.getDecl()->isObjCDynamic()) { - methodValue = emitDynamicMethodRef( - loc, methodConstant, - SGM.Types.getConstantInfo(methodConstant).SILFnType) - .getValue(); + methodValue = + emitDynamicMethodRef( + loc, methodConstant, + SGM.Types.getConstantInfo(getTypeExpansionContext(), methodConstant) + .SILFnType) + .getValue(); } else { methodValue = emitGlobalFunctionRef(loc, methodConstant); } @@ -164,7 +166,8 @@ SILGenFunction::emitSiblingMethodRef(SILLocation loc, SILType methodTy = methodValue->getType(); // Specialize the generic method. - methodTy = methodTy.substGenericArgs(SGM.M, subMap); + methodTy = + methodTy.substGenericArgs(SGM.M, subMap, getTypeExpansionContext()); return std::make_tuple(ManagedValue::forUnmanaged(methodValue), methodTy); @@ -190,8 +193,8 @@ void SILGenFunction::emitCaptures(SILLocation loc, canGuarantee = true; break; } - - auto expansion = F.getResilienceExpansion(); + + auto expansion = getTypeExpansionContext(); for (auto capture : captureInfo.getCaptures()) { if (capture.isDynamicSelfMetadata()) { @@ -262,10 +265,12 @@ void SILGenFunction::emitCaptures(SILLocation loc, capturedArgs.push_back(emitUndef(getLoweredType(type).getAddressType())); break; case CaptureKind::Box: { - auto boxTy = SGM.Types.getContextBoxTypeForCapture(vd, - getLoweredType(type).getASTType(), - FunctionDC->getGenericEnvironmentOfContext(), - /*mutable*/ true); + auto boxTy = SGM.Types.getContextBoxTypeForCapture( + vd, + SGM.Types.getLoweredRValueType(TypeExpansionContext::minimal(), + type), + FunctionDC->getGenericEnvironmentOfContext(), + /*mutable*/ true); capturedArgs.push_back(emitUndef(boxTy)); break; } @@ -273,8 +278,28 @@ void SILGenFunction::emitCaptures(SILLocation loc, continue; } - auto Entry = found->second; + // Get an address value for a SILValue if it is address only in an type + // expansion context without opaque archetype substitution. + auto getAddressValue = [&](SILValue entryValue) -> SILValue { + if (SGM.Types + .getTypeLowering( + valueType, + TypeExpansionContext::noOpaqueTypeArchetypesSubstitution( + expansion.getResilienceExpansion())) + .isAddressOnly() && + !entryValue->getType().isAddress()) { + + auto addr = emitTemporaryAllocation(vd, entryValue->getType()); + auto val = B.emitCopyValueOperation(vd, entryValue); + auto &lowering = getTypeLowering(entryValue->getType()); + lowering.emitStore(B, vd, val, addr, StoreOwnershipQualifier::Init); + entryValue = addr; + enterDestroyCleanup(addr); + } + return entryValue; + }; + auto Entry = found->second; switch (SGM.Types.getDeclCaptureKind(capture, expansion)) { case CaptureKind::Constant: { // let declarations. @@ -309,20 +334,25 @@ void SILGenFunction::emitCaptures(SILLocation loc, } case CaptureKind::StorageAddress: { + auto entryValue = getAddressValue(Entry.value); // No-escaping stored declarations are captured as the // address of the value. - assert(Entry.value->getType().isAddress() && "no address for captured var!"); - capturedArgs.push_back(ManagedValue::forLValue(Entry.value)); + assert(entryValue->getType().isAddress() && "no address for captured var!"); + capturedArgs.push_back(ManagedValue::forLValue(entryValue)); break; } case CaptureKind::Box: { + auto entryValue = getAddressValue(Entry.value); // LValues are captured as both the box owning the value and the // address of the value. - assert(Entry.value->getType().isAddress() && "no address for captured var!"); - + assert(entryValue->getType().isAddress() && "no address for captured var!"); + // Boxes of opaque return values stay opaque. + auto minimalLoweredType = SGM.Types.getLoweredRValueType( + TypeExpansionContext::minimal(), type->getCanonicalType()); // If this is a boxed variable, we can use it directly. - if (Entry.box) { + if (Entry.box && + entryValue->getType().getASTType() == minimalLoweredType) { // We can guarantee our own box to the callee. if (canGuarantee) { capturedArgs.push_back( @@ -330,7 +360,7 @@ void SILGenFunction::emitCaptures(SILLocation loc, } else { capturedArgs.push_back(emitManagedRetain(loc, Entry.box)); } - escapesToMark.push_back(Entry.value); + escapesToMark.push_back(entryValue); } else { // Address only 'let' values are passed by box. This isn't great, in // that a variable captured by multiple closures will be boxed for each @@ -343,14 +373,13 @@ void SILGenFunction::emitCaptures(SILLocation loc, // closure context and pass it down to the partially applied function // in-place. // TODO: Use immutable box for immutable captures. - auto boxTy = SGM.Types.getContextBoxTypeForCapture(vd, - Entry.value->getType().getASTType(), - FunctionDC->getGenericEnvironmentOfContext(), - /*mutable*/ true); - + auto boxTy = SGM.Types.getContextBoxTypeForCapture( + vd, minimalLoweredType, FunctionDC->getGenericEnvironmentOfContext(), + /*mutable*/ true); + AllocBoxInst *allocBox = B.createAllocBox(loc, boxTy); ProjectBoxInst *boxAddress = B.createProjectBox(loc, allocBox, 0); - B.createCopyAddr(loc, Entry.value, boxAddress, IsNotTake, + B.createCopyAddr(loc, entryValue, boxAddress, IsNotTake, IsInitialization); if (canGuarantee) capturedArgs.push_back( @@ -377,7 +406,7 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, SubstitutionMap subs) { auto loweredCaptureInfo = SGM.Types.getLoweredLocalCaptures(constant); - auto constantInfo = getConstantInfo(constant); + auto constantInfo = getConstantInfo(getTypeExpansionContext(), constant); SILValue functionRef = emitGlobalFunctionRef(loc, constant, constantInfo); SILType functionTy = functionRef->getType(); @@ -400,7 +429,8 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, bool wasSpecialized = false; if (!subs.empty()) { - auto specialized = pft->substGenericArgs(F.getModule(), subs); + auto specialized = + pft->substGenericArgs(F.getModule(), subs, getTypeExpansionContext()); functionTy = SILType::getPrimitiveObjectType(specialized); wasSpecialized = true; } diff --git a/lib/SILGen/SILGenFunction.h b/lib/SILGen/SILGenFunction.h index 0efa1810897a2..7e24ccc9826fd 100644 --- a/lib/SILGen/SILGenFunction.h +++ b/lib/SILGen/SILGenFunction.h @@ -494,22 +494,35 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction SILGenBuilder &getBuilder() { return B; } SILOptions &getOptions() { return getModule().getOptions(); } + // Returns the type expansion context for types in this function. + TypeExpansionContext getTypeExpansionContext() { + return TypeExpansionContext(getFunction()); + } + const TypeLowering &getTypeLowering(AbstractionPattern orig, Type subst) { return F.getTypeLowering(orig, subst); } const TypeLowering &getTypeLowering(Type t) { return F.getTypeLowering(t); } - CanSILFunctionType getSILFunctionType(AbstractionPattern orig, + CanSILFunctionType getSILFunctionType(TypeExpansionContext context, + AbstractionPattern orig, CanFunctionType substFnType) { - return SGM.Types.getSILFunctionType(orig, substFnType); + return SGM.Types.getSILFunctionType(context, orig, substFnType); } - SILType getLoweredType(AbstractionPattern orig, Type subst) { + SILType getLoweredType(AbstractionPattern orig, + Type subst) { return F.getLoweredType(orig, subst); } SILType getLoweredType(Type t) { return F.getLoweredType(t); } + SILType getLoweredTypeForFunctionArgument(Type t) { + auto typeForConv = + SGM.Types.getLoweredType(t, TypeExpansionContext::minimal()); + return getLoweredType(t).getCategoryType(typeForConv.getCategory()); + } + SILType getLoweredLoadableType(Type t) { return F.getLoweredLoadableType(t); } @@ -524,8 +537,19 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction return silConv.getSILType(result, fnTy); } - const SILConstantInfo &getConstantInfo(SILDeclRef constant) { - return SGM.Types.getConstantInfo(constant); + SILType getSILTypeInContext(SILResultInfo result, CanSILFunctionType fnTy) { + auto t = F.mapTypeIntoContext(getSILType(result, fnTy)); + return getTypeLowering(t).getLoweredType().getCategoryType(t.getCategory()); + } + + SILType getSILTypeInContext(SILParameterInfo param, CanSILFunctionType fnTy) { + auto t = F.mapTypeIntoContext(getSILType(param, fnTy)); + return getTypeLowering(t).getLoweredType().getCategoryType(t.getCategory()); + } + + const SILConstantInfo &getConstantInfo(TypeExpansionContext context, + SILDeclRef constant) { + return SGM.Types.getConstantInfo(context, constant); } Optional getStaticEnforcement(VarDecl *var = nullptr); @@ -664,7 +688,19 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction SubstitutionMap witnessSubs, IsFreeFunctionWitness_t isFree, bool isSelfConformance); - + + /// Generates subscript arguments for keypath. This function handles lowering + /// of all index expressions including default arguments. + /// + /// \returns Lowered index arguments. + /// \param subscript - The subscript decl who's arguments are being lowered. + /// \param subs - Used to get subscript function type and to substitute generic args. + /// \param indexExpr - An expression holding the indices of the + /// subscript (either a TupleExpr or a ParenExpr). + SmallVector + emitKeyPathSubscriptOperands(SubscriptDecl *subscript, SubstitutionMap subs, + Expr *indexExpr); + /// Convert a block to a native function with a thunk. ManagedValue emitBlockToFunc(SILLocation loc, ManagedValue block, @@ -1162,7 +1198,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction /// Returns a reference to a constant in global context. For local func decls /// this returns the function constant with unapplied closure context. SILValue emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant) { - return emitGlobalFunctionRef(loc, constant, getConstantInfo(constant)); + return emitGlobalFunctionRef( + loc, constant, getConstantInfo(getTypeExpansionContext(), constant)); } SILValue emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index caf7acfc56ffa..747c6a97d1922 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -201,35 +201,37 @@ static CanType getSubstFormalRValueType(Expr *expr) { return expr->getType()->getRValueType()->getCanonicalType(); } -static LValueTypeData getAbstractedTypeData(SILGenModule &SGM, +static LValueTypeData getAbstractedTypeData(TypeExpansionContext context, + SILGenModule &SGM, SGFAccessKind accessKind, AbstractionPattern origFormalType, CanType substFormalType) { return { - accessKind, - origFormalType, - substFormalType, - SGM.Types.getLoweredRValueType(origFormalType, substFormalType) - }; + accessKind, origFormalType, substFormalType, + SGM.Types.getLoweredRValueType(context, origFormalType, substFormalType)}; } -static LValueTypeData getLogicalStorageTypeData(SILGenModule &SGM, +static LValueTypeData getLogicalStorageTypeData(TypeExpansionContext context, + SILGenModule &SGM, SGFAccessKind accessKind, CanType substFormalType) { assert(!isa(substFormalType)); AbstractionPattern origFormalType( substFormalType.getReferenceStorageReferent()); - return getAbstractedTypeData(SGM, accessKind, origFormalType, substFormalType); + return getAbstractedTypeData(context, SGM, accessKind, origFormalType, + substFormalType); } -static LValueTypeData getPhysicalStorageTypeData(SILGenModule &SGM, +static LValueTypeData getPhysicalStorageTypeData(TypeExpansionContext context, + SILGenModule &SGM, SGFAccessKind accessKind, AbstractStorageDecl *storage, CanType substFormalType) { assert(!isa(substFormalType)); auto origFormalType = SGM.Types.getAbstractionPattern(storage) .getReferenceStorageReferentType(); - return getAbstractedTypeData(SGM, accessKind, origFormalType, substFormalType); + return getAbstractedTypeData(context, SGM, accessKind, origFormalType, + substFormalType); } static bool shouldUseUnsafeEnforcement(VarDecl *var) { @@ -1208,7 +1210,8 @@ namespace { bool doesAccessorMutateSelf(SILGenFunction &SGF, SILDeclRef accessor) const { - auto accessorSelf = SGF.SGM.Types.getConstantSelfParameter(accessor); + auto accessorSelf = SGF.SGM.Types.getConstantSelfParameter( + SGF.getTypeExpansionContext(), accessor); return accessorSelf.getInterfaceType() && accessorSelf.isIndirectMutating(); } @@ -1396,10 +1399,12 @@ namespace { CanType ValType = SGF.F.mapTypeIntoContext(backingVar->getInterfaceType()) ->getCanonicalType(); - SILType varStorageType = - SGF.SGM.Types.getSubstitutedStorageType(backingVar, ValType); + // TODO: revist minimal + SILType varStorageType = SGF.SGM.Types.getSubstitutedStorageType( + TypeExpansionContext::minimal(), backingVar, ValType); auto typeData = - getLogicalStorageTypeData(SGF.SGM, getTypeData().AccessKind, ValType); + getLogicalStorageTypeData(SGF.getTypeExpansionContext(), SGF.SGM, + getTypeData().AccessKind, ValType); // Get the address of the storage property. ManagedValue proj; @@ -1441,11 +1446,13 @@ namespace { ManagedValue initFn = SGF.emitManagedRValueWithCleanup(initPAI); // Create the allocating setter function. It captures the base address. - auto setterInfo = SGF.getConstantInfo(setter); + auto setterInfo = + SGF.getConstantInfo(SGF.getTypeExpansionContext(), setter); SILValue setterFRef; if (setter.hasDecl() && setter.getDecl()->isObjCDynamic()) { auto methodTy = SILType::getPrimitiveObjectType( - SGF.SGM.Types.getConstantFunctionType(setter)); + SGF.SGM.Types.getConstantFunctionType(SGF.getTypeExpansionContext(), + setter)); setterFRef = SGF.B.createObjCMethod( loc, base.getValue(), setter, methodTy); } else @@ -2016,7 +2023,8 @@ namespace { projectFnType->getInvocationGenericSignature(), keyPathTy->getGenericArgs(), {}); - auto substFnType = projectFnType->substGenericArgs(SGF.SGM.M, subs); + auto substFnType = projectFnType->substGenericArgs( + SGF.SGM.M, subs, SGF.getTypeExpansionContext()); // Perform the begin_apply. SmallVector yields; @@ -2484,8 +2492,9 @@ namespace { void emitUsingStrategy(AccessStrategy strategy) { switch (strategy.getKind()) { case AccessStrategy::Storage: { - auto typeData = getPhysicalStorageTypeData(SGF.SGM, AccessKind, Storage, - FormalRValueType); + auto typeData = + getPhysicalStorageTypeData(SGF.getTypeExpansionContext(), SGF.SGM, + AccessKind, Storage, FormalRValueType); return asImpl().emitUsingStorage(typeData); } @@ -2496,8 +2505,8 @@ namespace { return asImpl().emitUsingAccessor(strategy.getAccessor(), false); case AccessStrategy::MaterializeToTemporary: { - auto typeData = - getLogicalStorageTypeData(SGF.SGM, AccessKind, FormalRValueType); + auto typeData = getLogicalStorageTypeData( + SGF.getTypeExpansionContext(), SGF.SGM, AccessKind, FormalRValueType); return asImpl().emitUsingMaterialization(strategy.getReadStrategy(), strategy.getWriteStrategy(), typeData); @@ -2513,22 +2522,24 @@ namespace { switch (accessorKind) { case AccessorKind::Get: case AccessorKind::Set: { - auto typeData = - getLogicalStorageTypeData(SGF.SGM, AccessKind, FormalRValueType); + auto typeData = getLogicalStorageTypeData( + SGF.getTypeExpansionContext(), SGF.SGM, AccessKind, FormalRValueType); return asImpl().emitUsingGetterSetter(accessor, isDirect, typeData); } case AccessorKind::Address: case AccessorKind::MutableAddress: { - auto typeData = getPhysicalStorageTypeData(SGF.SGM, AccessKind, Storage, - FormalRValueType); + auto typeData = + getPhysicalStorageTypeData(SGF.getTypeExpansionContext(), SGF.SGM, + AccessKind, Storage, FormalRValueType); return asImpl().emitUsingAddressor(accessor, isDirect, typeData); } case AccessorKind::Read: case AccessorKind::Modify: { - auto typeData = getPhysicalStorageTypeData(SGF.SGM, AccessKind, Storage, - FormalRValueType); + auto typeData = + getPhysicalStorageTypeData(SGF.getTypeExpansionContext(), SGF.SGM, + AccessKind, Storage, FormalRValueType); return asImpl().emitUsingCoroutineAccessor(accessor, isDirect, typeData); } @@ -3052,8 +3063,8 @@ struct MemberStorageAccessEmitter : AccessEmitter { void emitUsingAddressor(SILDeclRef addressor, bool isDirect, LValueTypeData typeData) { - SILType varStorageType = - SGF.SGM.Types.getSubstitutedStorageType(Storage, FormalRValueType); + SILType varStorageType = SGF.SGM.Types.getSubstitutedStorageType( + SGF.getTypeExpansionContext(), Storage, FormalRValueType); LV.add(Storage, addressor, IsSuper, isDirect, Subs, BaseFormalType, typeData, varStorageType, @@ -3117,8 +3128,8 @@ void LValue::addMemberVarComponent(SILGenFunction &SGF, SILLocation loc, } // Otherwise, it's a physical member. - SILType varStorageType = - SGF.SGM.Types.getSubstitutedStorageType(Storage, FormalRValueType); + SILType varStorageType = SGF.SGM.Types.getSubstitutedStorageType( + SGF.getTypeExpansionContext(), Storage, FormalRValueType); if (BaseFormalType->mayHaveSuperclass()) { LV.add(Storage, Options, varStorageType, typeData); @@ -3254,8 +3265,8 @@ LValue SILGenLValue::visitKeyPathApplicationExpr(KeyPathApplicationExpr *e, }(); if (useLogical) { - auto typeData = getLogicalStorageTypeData(SGF.SGM, accessKind, - substFormalType); + auto typeData = getLogicalStorageTypeData( + SGF.getTypeExpansionContext(), SGF.SGM, accessKind, substFormalType); Type baseFormalType = e->getBase()->getType()->getRValueType(); lv.add(typeData, keyPathKind, keyPath, @@ -3265,9 +3276,9 @@ LValue SILGenLValue::visitKeyPathApplicationExpr(KeyPathApplicationExpr *e, // in the opaque AbstractionPattern and push an OrigToSubstComponent here // so it can be peepholed. } else { - auto typeData = getAbstractedTypeData(SGF.SGM, accessKind, - AbstractionPattern::getOpaque(), - substFormalType); + auto typeData = getAbstractedTypeData( + TypeExpansionContext::minimal(), SGF.SGM, accessKind, + AbstractionPattern::getOpaque(), substFormalType); lv.add(typeData, keyPathKind, keyPath); diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp index f54c4f90a4128..3b95cc66d571e 100644 --- a/lib/SILGen/SILGenPattern.cpp +++ b/lib/SILGen/SILGenPattern.cpp @@ -1878,7 +1878,8 @@ void PatternMatchEmission::emitEnumElementObjectDispatch( bool hasNonVoidAssocValue = false; bool hasAssocValue = elt->hasAssociatedValues(); if (hasAssocValue) { - eltTy = src.getType().getEnumElementType(elt, SGF.SGM.M); + eltTy = src.getType().getEnumElementType(elt, SGF.SGM.M, + SGF.getTypeExpansionContext()); hasNonVoidAssocValue = !eltTy.getASTType()->isVoid(); } @@ -2060,7 +2061,8 @@ void PatternMatchEmission::emitEnumElementDispatch( SILType eltTy; bool hasElt = false; if (elt->hasAssociatedValues()) { - eltTy = src.getType().getEnumElementType(elt, SGF.SGM.M); + eltTy = src.getType().getEnumElementType(elt, SGF.SGM.M, + SGF.getTypeExpansionContext()); hasElt = !eltTy.getASTType()->isVoid(); } diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 9fca7b069151d..0b142aba0e724 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -791,7 +791,11 @@ void SILGenFunction::collectThunkParams( // Add the indirect results. for (auto resultTy : F.getConventions().getIndirectSILResultTypes()) { auto paramTy = F.mapTypeIntoContext(resultTy); - SILArgument *arg = F.begin()->createFunctionArgument(paramTy); + // Lower result parameters in the context of the function: opaque result + // types will be lowered to their underlying type if allowed by resilience. + auto inContextParamTy = F.getLoweredType(paramTy.getASTType()) + .getCategoryType(paramTy.getCategory()); + SILArgument *arg = F.begin()->createFunctionArgument(inContextParamTy); if (indirectResults) indirectResults->push_back(arg); } @@ -800,7 +804,11 @@ void SILGenFunction::collectThunkParams( auto paramTypes = F.getLoweredFunctionType()->getParameters(); for (auto param : paramTypes) { auto paramTy = F.mapTypeIntoContext(F.getConventions().getSILType(param)); - params.push_back(B.createInputFunctionArgument(paramTy, loc)); + // Lower parameters in the context of the function: opaque result types will + // be lowered to their underlying type if allowed by resilience. + auto inContextParamTy = F.getLoweredType(paramTy.getASTType()) + .getCategoryType(paramTy.getCategory()); + params.push_back(B.createInputFunctionArgument(inContextParamTy, loc)); } } @@ -2693,8 +2701,8 @@ void ResultPlanner::execute(ArrayRef innerDirectResults, // A helper function to add an outer direct result. auto addOuterDirectResult = [&](ManagedValue resultValue, SILResultInfo result) { - assert(resultValue.getType() - == SGF.F.mapTypeIntoContext(SGF.getSILType(result, CanSILFunctionType()))); + assert(resultValue.getType() == + SGF.getSILTypeInContext(result, CanSILFunctionType())); outerDirectResults.push_back(resultValue.forward(SGF)); }; @@ -4106,16 +4114,19 @@ SILGenFunction::emitVTableThunk(SILDeclRef base, CanSILFunctionType derivedFTy; if (baseLessVisibleThanDerived) { - derivedFTy = SGM.Types.getConstantOverrideType(derived); + derivedFTy = + SGM.Types.getConstantOverrideType(getTypeExpansionContext(), derived); } else { - derivedFTy = SGM.Types.getConstantInfo(derived).SILFnType; + derivedFTy = + SGM.Types.getConstantInfo(getTypeExpansionContext(), derived).SILFnType; } SubstitutionMap subs; if (auto *genericEnv = fd->getGenericEnvironment()) { F.setGenericEnvironment(genericEnv); subs = getForwardingSubstitutionMap(); - derivedFTy = derivedFTy->substGenericArgs(SGM.M, subs); + derivedFTy = + derivedFTy->substGenericArgs(SGM.M, subs, getTypeExpansionContext()); inputSubstType = cast( cast(inputSubstType) @@ -4165,7 +4176,8 @@ SILGenFunction::emitVTableThunk(SILDeclRef base, if (baseLessVisibleThanDerived) { // See the comment in SILVTableVisitor.h under maybeAddMethod(). auto selfValue = thunkArgs.back().getValue(); - auto derivedTy = SGM.Types.getConstantOverrideType(derived); + auto derivedTy = + SGM.Types.getConstantOverrideType(getTypeExpansionContext(), derived); derivedRef = emitClassMethodRef(loc, selfValue, derived, derivedTy); } else { derivedRef = B.createFunctionRefFor(loc, implFn); @@ -4287,16 +4299,15 @@ static WitnessDispatchKind getWitnessDispatchKind(SILDeclRef witness, } static CanSILFunctionType -getWitnessFunctionType(SILGenModule &SGM, - SILDeclRef witness, - WitnessDispatchKind witnessKind) { +getWitnessFunctionType(TypeExpansionContext context, SILGenModule &SGM, + SILDeclRef witness, WitnessDispatchKind witnessKind) { switch (witnessKind) { case WitnessDispatchKind::Static: case WitnessDispatchKind::Dynamic: case WitnessDispatchKind::Witness: - return SGM.Types.getConstantInfo(witness).SILFnType; + return SGM.Types.getConstantInfo(context, witness).SILFnType; case WitnessDispatchKind::Class: - return SGM.Types.getConstantOverrideType(witness); + return SGM.Types.getConstantOverrideType(context, witness); } llvm_unreachable("Unhandled WitnessDispatchKind in switch."); @@ -4397,7 +4408,7 @@ void SILGenFunction::emitProtocolWitness(AbstractionPattern reqtOrigTy, collectThunkParams(loc, origParams); // Get the type of the witness. - auto witnessInfo = getConstantInfo(witness); + auto witnessInfo = getConstantInfo(getTypeExpansionContext(), witness); CanAnyFunctionType witnessSubstTy = witnessInfo.LoweredType; if (auto genericFnType = dyn_cast(witnessSubstTy)) { witnessSubstTy = cast(genericFnType @@ -4416,10 +4427,12 @@ void SILGenFunction::emitProtocolWitness(AbstractionPattern reqtOrigTy, } // Get the lowered type of the witness. - auto origWitnessFTy = getWitnessFunctionType(SGM, witness, witnessKind); + auto origWitnessFTy = getWitnessFunctionType(getTypeExpansionContext(), SGM, + witness, witnessKind); auto witnessFTy = origWitnessFTy; if (!witnessSubs.empty()) - witnessFTy = origWitnessFTy->substGenericArgs(SGM.M, witnessSubs); + witnessFTy = origWitnessFTy->substGenericArgs(SGM.M, witnessSubs, + getTypeExpansionContext()); auto reqtSubstParams = reqtSubstTy.getParams(); auto witnessSubstParams = witnessSubstTy.getParams(); diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index d3b9edb10248b..4c57bf2e96ee1 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -98,9 +98,14 @@ class EmitBBArguments : public CanTypeVisitor elements; - auto &tl = SGF.SGM.Types.getTypeLowering(t, ResilienceExpansion::Minimal); + auto &tl = SGF.SGM.Types.getTypeLowering(t, SGF.getTypeExpansionContext()); bool canBeGuaranteed = tl.isLoadable(); // Collect the exploded elements. @@ -226,9 +231,10 @@ struct ArgumentInitHelper { uint16_t ArgNo = 0; ArgumentInitHelper(SILGenFunction &SGF, SILFunction &f) - : SGF(SGF), f(f), initB(SGF.B), - parameters(f.getLoweredFunctionType()->getParameters()) { - } + : SGF(SGF), f(f), initB(SGF.B), + parameters( + f.getLoweredFunctionTypeInContext(SGF.B.getTypeExpansionContext()) + ->getParameters()) {} unsigned getNumArgs() const { return ArgNo; } @@ -320,8 +326,7 @@ static void makeArgument(Type ty, ParamDecl *decl, for (auto fieldType : tupleTy->getElementTypes()) makeArgument(fieldType, decl, args, SGF); } else { - auto loweredTy = SGF.SGM.Types.getLoweredType(ty, - ResilienceExpansion::Minimal); + auto loweredTy = SGF.getLoweredTypeForFunctionArgument(ty); if (decl->isInOut()) loweredTy = SILType::getPrimitiveAddressType(loweredTy.getASTType()); auto arg = SGF.F.begin()->createFunctionArgument(loweredTy, decl); @@ -358,7 +363,7 @@ static void emitCaptureArguments(SILGenFunction &SGF, return SGF.F.mapTypeIntoContext(interfaceType); }; - auto expansion = SGF.F.getResilienceExpansion(); + auto expansion = SGF.getTypeExpansionContext(); switch (SGF.SGM.Types.getDeclCaptureKind(capture, expansion)) { case CaptureKind::Constant: { auto type = getVarTypeInCaptureContext(); @@ -400,9 +405,13 @@ static void emitCaptureArguments(SILGenFunction &SGF, // LValues are captured as a retained @box that owns // the captured value. auto type = getVarTypeInCaptureContext(); - auto boxTy = SGF.SGM.Types.getContextBoxTypeForCapture(VD, - SGF.SGM.Types.getLoweredRValueType(type), - SGF.F.getGenericEnvironment(), /*mutable*/ true); + // Get the content for the box in the minimal resilience domain because we + // are declaring a type. + auto boxTy = SGF.SGM.Types.getContextBoxTypeForCapture( + VD, + SGF.SGM.Types.getLoweredRValueType(TypeExpansionContext::minimal(), + type), + SGF.F.getGenericEnvironment(), /*mutable*/ true); SILValue box = SGF.F.begin()->createFunctionArgument( SILType::getPrimitiveObjectType(boxTy), VD); SILValue addr = SGF.B.createProjectBox(VD, box, 0); @@ -499,9 +508,12 @@ static void emitIndirectResultParameters(SILGenFunction &SGF, Type resultType, // The calling convention always uses minimal resilience expansion. auto &resultTI = SGF.SGM.Types.getTypeLowering(DC->mapTypeIntoContext(resultType), - ResilienceExpansion::Minimal); + SGF.getTypeExpansionContext()); + auto &resultTIConv = SGF.SGM.Types.getTypeLowering( + DC->mapTypeIntoContext(resultType), TypeExpansionContext::minimal()); + if (!SILModuleConventions::isReturnedIndirectlyInSIL( - resultTI.getLoweredType(), SGF.SGM.M)) { + resultTIConv.getLoweredType(), SGF.SGM.M)) { return; } auto &ctx = SGF.getASTContext(); @@ -511,9 +523,8 @@ static void emitIndirectResultParameters(SILGenFunction &SGF, Type resultType, DC); var->setSpecifier(ParamSpecifier::InOut); var->setInterfaceType(resultType); - - auto *arg = - SGF.F.begin()->createFunctionArgument(resultTI.getLoweredType(), var); + auto *arg = SGF.F.begin()->createFunctionArgument( + resultTI.getLoweredType().getAddressType(), var); (void)arg; } diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index 4e569288acf78..99aee2906f78c 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -186,7 +186,8 @@ getNextUncurryLevelRef(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk, thunk.autoDiffDerivativeFunctionIdentifier); assert(!next.isCurried); - auto constantInfo = SGF.SGM.Types.getConstantInfo(next); + auto constantInfo = + SGF.SGM.Types.getConstantInfo(SGF.getTypeExpansionContext(), next); // If the function is natively foreign, reference its foreign entry point. if (requiresForeignToNativeThunk(vd)) @@ -207,7 +208,8 @@ getNextUncurryLevelRef(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk, next}; } - auto methodTy = SGF.SGM.Types.getConstantOverrideType(next); + auto methodTy = SGF.SGM.Types.getConstantOverrideType( + SGF.getTypeExpansionContext(), next); SILValue result = SGF.emitClassMethodRef(loc, selfArg.getValue(), next, methodTy); return {ManagedValue::forUnmanaged(result), @@ -247,7 +249,7 @@ void SILGenFunction::emitCurryThunk(SILDeclRef thunk) { SILLocation loc(vd); Scope S(*this, vd); - auto thunkInfo = SGM.Types.getConstantInfo(thunk); + auto thunkInfo = SGM.Types.getConstantInfo(getTypeExpansionContext(), thunk); auto thunkFnTy = thunkInfo.SILFnType; SILFunctionConventions fromConv(thunkFnTy, SGM.M); @@ -281,8 +283,9 @@ void SILGenFunction::emitCurryThunk(SILDeclRef thunk) { // just grab the pattern for the curried fn ref and "call" it. assert(!calleeRef.isCurried); calleeRef.isCurried = true; - auto appliedFnPattern = SGM.Types.getConstantInfo(calleeRef).FormalPattern - .getFunctionResultType(); + auto appliedFnPattern = + SGM.Types.getConstantInfo(getTypeExpansionContext(), calleeRef) + .FormalPattern.getFunctionResultType(); auto appliedThunkPattern = thunkInfo.FormalPattern.getFunctionResultType(); @@ -354,7 +357,7 @@ SILValue SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, SILConstantInfo constantInfo, bool callPreviousDynamicReplaceableImpl) { - assert(constantInfo == getConstantInfo(constant)); + assert(constantInfo == getConstantInfo(getTypeExpansionContext(), constant)); // Builtins must be fully applied at the point of reference. if (constant.hasDecl() && @@ -378,7 +381,8 @@ SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, } auto f = SGM.getFunction(constant, NotForDefinition); - assert(f->getLoweredFunctionType() == constantInfo.SILFnType); + assert(f->getLoweredFunctionTypeInContext(B.getTypeExpansionContext()) == + constantInfo.SILFnType); if (callPreviousDynamicReplaceableImpl) return B.createPreviousDynamicFunctionRef(loc, f); else diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 8ea61ac269f2d..1fe367ccc2705 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -87,14 +87,17 @@ SILGenModule::emitVTableMethod(ClassDecl *theClass, derived.kind != SILDeclRef::Kind::Allocator); if (usesObjCDynamicDispatch) { - implFn = getDynamicThunk(derived, Types.getConstantInfo(derived).SILFnType); + implFn = getDynamicThunk( + derived, Types.getConstantInfo(TypeExpansionContext::minimal(), derived) + .SILFnType); // SWIFT_ENABLE_TENSORFLOW } else if (auto *adafi = derived.autoDiffDerivativeFunctionIdentifier) { // For JVP/VJP methods, create a vtable entry thunk. The thunk contains an // `differentiable_function` instruction, which is later filled during the // differentiation transform. - implFn = getOrCreateAutoDiffClassMethodThunk( - derived, Types.getConstantInfo(derived).SILFnType); + auto derivedFnType = Types.getConstantInfo( + TypeExpansionContext::minimal(), derived).SILFnType; + implFn = getOrCreateAutoDiffClassMethodThunk(derived, derivedFnType); // SWIFT_ENABLE_TENSORFLOW END } else { implFn = getFunction(derived, NotForDefinition); @@ -114,11 +117,13 @@ SILGenModule::emitVTableMethod(ClassDecl *theClass, // Determine the derived thunk type by lowering the derived type against the // abstraction pattern of the base. - auto baseInfo = Types.getConstantInfo(base); - auto derivedInfo = Types.getConstantInfo(derived); + auto baseInfo = Types.getConstantInfo(TypeExpansionContext::minimal(), base); + auto derivedInfo = + Types.getConstantInfo(TypeExpansionContext::minimal(), derived); auto basePattern = AbstractionPattern(baseInfo.LoweredType); - - auto overrideInfo = M.Types.getConstantOverrideInfo(derived, base); + + auto overrideInfo = M.Types.getConstantOverrideInfo( + TypeExpansionContext::minimal(), derived, base); // If base method's generic requirements are not satisfied by the derived // method then we need a thunk. @@ -610,7 +615,8 @@ SILFunction *SILGenModule::emitProtocolWitness( ProtocolConformanceRef conformance, SILLinkage linkage, IsSerialized_t isSerialized, SILDeclRef requirement, SILDeclRef witnessRef, IsFreeFunctionWitness_t isFree, Witness witness) { - auto requirementInfo = Types.getConstantInfo(requirement); + auto requirementInfo = + Types.getConstantInfo(TypeExpansionContext::minimal(), requirement); // Work out the lowered function type of the SIL witness thunk. auto reqtOrigTy = cast(requirementInfo.LoweredType); @@ -674,8 +680,9 @@ SILFunction *SILGenModule::emitProtocolWitness( // Lower the witness thunk type with the requirement's abstraction level. auto witnessSILFnType = getNativeSILFunctionType( - M.Types, AbstractionPattern(reqtOrigTy), reqtSubstTy, - requirement, witnessRef, witnessSubsForTypeLowering, conformance); + M.Types, TypeExpansionContext::minimal(), AbstractionPattern(reqtOrigTy), + reqtSubstTy, requirement, witnessRef, witnessSubsForTypeLowering, + conformance); // Mangle the name of the witness thunk. Mangle::ASTMangler NewMangler; @@ -743,7 +750,8 @@ static SILFunction *emitSelfConformanceWitness(SILGenModule &SGM, SelfProtocolConformance *conformance, SILLinkage linkage, SILDeclRef requirement) { - auto requirementInfo = SGM.Types.getConstantInfo(requirement); + auto requirementInfo = + SGM.Types.getConstantInfo(TypeExpansionContext::minimal(), requirement); // Work out the lowered function type of the SIL witness thunk. auto reqtOrigTy = cast(requirementInfo.LoweredType); @@ -772,8 +780,8 @@ static SILFunction *emitSelfConformanceWitness(SILGenModule &SGM, cast(reqtOrigTy.subst(reqtSubs)->getCanonicalType()); // Substitute into the requirement type to get the type of the thunk. - auto witnessSILFnType = - requirementInfo.SILFnType->substGenericArgs(SGM.M, reqtSubs); + auto witnessSILFnType = requirementInfo.SILFnType->substGenericArgs( + SGM.M, reqtSubs, TypeExpansionContext::minimal()); // Mangle the name of the witness thunk. std::string name = [&] { diff --git a/lib/SILGen/SwitchEnumBuilder.cpp b/lib/SILGen/SwitchEnumBuilder.cpp index c230ec981a713..4704d95fae200 100644 --- a/lib/SILGen/SwitchEnumBuilder.cpp +++ b/lib/SILGen/SwitchEnumBuilder.cpp @@ -144,8 +144,8 @@ void SwitchEnumBuilder::emit() && { ManagedValue input; if (decl->hasAssociatedValues()) { // Pull the payload out if we have one. - SILType inputType = - optional.getType().getEnumElementType(decl, builder.getModule()); + SILType inputType = optional.getType().getEnumElementType( + decl, builder.getModule(), builder.getFunction()); input = optional; if (!isAddressOnly) { input = builder.createOwnedPhiArgument(inputType); diff --git a/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp b/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp index 928106140beb0..fbd23936c2238 100644 --- a/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/AccessSummaryAnalysis.cpp @@ -380,13 +380,13 @@ void AccessSummaryAnalysis::recompute(FunctionInfo *initial) { } while (needAnotherIteration); } -std::string -AccessSummaryAnalysis::SubAccessSummary::getDescription(SILType BaseType, - SILModule &M) const { +std::string AccessSummaryAnalysis::SubAccessSummary::getDescription( + SILType BaseType, SILModule &M, TypeExpansionContext context) const { std::string sbuf; llvm::raw_string_ostream os(sbuf); - os << AccessSummaryAnalysis::getSubPathDescription(BaseType, SubPath, M); + os << AccessSummaryAnalysis::getSubPathDescription(BaseType, SubPath, M, + context); if (!SubPath->isRoot()) os << " "; @@ -409,9 +409,8 @@ void AccessSummaryAnalysis::ArgumentSummary::getSortedSubAccesses( assert(storage.size() == SubAccesses.size()); } -std::string -AccessSummaryAnalysis::ArgumentSummary::getDescription(SILType BaseType, - SILModule &M) const { +std::string AccessSummaryAnalysis::ArgumentSummary::getDescription( + SILType BaseType, SILModule &M, TypeExpansionContext context) const { std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "["; @@ -425,7 +424,7 @@ AccessSummaryAnalysis::ArgumentSummary::getDescription(SILType BaseType, if (index > 0) { os << ", "; } - os << subAccess.getDescription(BaseType, M); + os << subAccess.getDescription(BaseType, M, context); ++index; } os << "]"; @@ -551,7 +550,8 @@ AccessSummaryAnalysis::findSubPathAccessed(BeginAccessInst *BAI) { /// that stored-property relaxation supports: struct stored properties /// and tuple elements. std::string AccessSummaryAnalysis::getSubPathDescription( - SILType baseType, const IndexTrieNode *subPath, SILModule &M) { + SILType baseType, const IndexTrieNode *subPath, SILModule &M, + TypeExpansionContext context) { // Walk the trie to the root to collect the sequence (in reverse order). llvm::SmallVector reversedIndices; const IndexTrieNode *I = subPath; @@ -570,7 +570,7 @@ std::string AccessSummaryAnalysis::getSubPathDescription( if (StructDecl *D = containingType.getStructOrBoundGenericStruct()) { VarDecl *var = D->getStoredProperties()[index]; os << var->getBaseName(); - containingType = containingType.getFieldType(var, M); + containingType = containingType.getFieldType(var, M, context); continue; } @@ -635,7 +635,8 @@ void AccessSummaryAnalysis::FunctionSummary::print(raw_ostream &os, } SILArgument *arg = fn->getArgument(i); SILModule &m = fn->getModule(); - os << getAccessForArgument(i).getDescription(arg->getType(), m); + os << getAccessForArgument(i).getDescription(arg->getType(), m, + TypeExpansionContext(*fn)); } os << ")"; diff --git a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp index e2db274668799..90e304d0a5084 100644 --- a/lib/SILOptimizer/Analysis/AliasAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/AliasAnalysis.cpp @@ -475,8 +475,8 @@ static bool typedAccessTBAAMayAlias(SILType LTy, SILType RTy, // If one type is an aggregate and it contains the other type then the record // reference may alias the aggregate reference. - if (LTy.aggregateContainsRecord(RTy, Mod) || - RTy.aggregateContainsRecord(LTy, Mod)) + if (LTy.aggregateContainsRecord(RTy, Mod, F.getTypeExpansionContext()) || + RTy.aggregateContainsRecord(LTy, Mod, F.getTypeExpansionContext())) return true; // FIXME: All the code following could be made significantly more aggressive diff --git a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp index ce6af396ff29d..168ccea435b3f 100644 --- a/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/EscapeAnalysis.cpp @@ -25,6 +25,11 @@ using namespace swift; using CGNode = EscapeAnalysis::CGNode; +static llvm::cl::opt EnableInternalVerify( + "escapes-internal-verify", + llvm::cl::desc("Enable internal verification of escape analysis"), + llvm::cl::init(false)); + // Returns true if \p Ty recursively contains a reference. If \p mustBeRef is // true, only return true if the type is guaranteed to hold a reference. If \p // mustBeRef is false, only return false if the type is guaranteed not to hold a @@ -70,7 +75,9 @@ static bool findRecursiveRefType(SILType Ty, const SILFunction &F, if (auto *Str = Ty.getStructOrBoundGenericStruct()) { for (auto *Field : Str->getStoredProperties()) { - if (findRecursiveRefType(Ty.getFieldType(Field, Mod), F, mustBeRef)) + if (findRecursiveRefType( + Ty.getFieldType(Field, Mod, F.getTypeExpansionContext()), F, + mustBeRef)) return true; } return false; @@ -84,9 +91,10 @@ static bool findRecursiveRefType(SILType Ty, const SILFunction &F, } if (auto En = Ty.getEnumOrBoundGenericEnum()) { for (auto *ElemDecl : En->getAllElements()) { - if (ElemDecl->hasAssociatedValues() - && findRecursiveRefType(Ty.getEnumElementType(ElemDecl, Mod), F, - mustBeRef)) + if (ElemDecl->hasAssociatedValues() && + findRecursiveRefType( + Ty.getEnumElementType(ElemDecl, Mod, F.getTypeExpansionContext()), + F, mustBeRef)) return true; } return false; @@ -109,10 +117,9 @@ static bool mayContainReference(SILType Ty, const SILFunction &F) { // Returns true if the type \p Ty must be a reference or must transitively // contain a reference. If \p Ty is itself an address, return false. -// Will be used in a subsequent commit. -// static bool mustContainReference(SILType Ty, const SILFunction &F) { -// return findRecursiveRefType(Ty, F, true); -//} +static bool mustContainReference(SILType Ty, const SILFunction &F) { + return findRecursiveRefType(Ty, F, true); +} bool EscapeAnalysis::isPointer(ValueBase *V) const { auto *F = V->getFunction(); @@ -185,6 +192,23 @@ SILValue EscapeAnalysis::getPointerBase(SILValue value) const { return SILValue(); return TEI->getOperand(); } + case ValueKind::StructInst: + case ValueKind::TupleInst: + case ValueKind::EnumInst: { + // Allow a single-operand aggregate to share its operand's node. + auto *SVI = cast(value); + SILValue pointerOperand; + for (SILValue opV : SVI->getOperandValues()) { + if (!isPointer(opV)) + continue; + + if (pointerOperand) + return SILValue(); + + pointerOperand = opV; + } + return pointerOperand; + } default: return SILValue(); } @@ -309,6 +333,15 @@ class EscapeAnalysis::CGNodeMap { void EscapeAnalysis::CGNode::mergeProperties(CGNode *fromNode) { if (!V) V = fromNode->V; + + // TODO: Optimistically merge hasRC. 'this' node can only be merged with + // `fromNode` if their pointer values are compatible. If `fromNode->hasRC` is + // true, then it is guaranteed to represent the head of a heap object. Thus, + // it can only be merged with 'this' when the pointer values that access + // 'this' are also references. + // + // For now, this is pessimistic until we understand performance implications. + hasRC &= fromNode->hasRC; } template @@ -383,43 +416,156 @@ EscapeAnalysis::ConnectionGraph::getNode(ValueBase *V, bool createIfNeeded) { return Node->getMergeTarget(); } -EscapeAnalysis::CGNode *EscapeAnalysis::ConnectionGraph::getContentNode( - CGNode *AddrNode) { - // Do we already have a content node (which is not necessarily an immediate - // successor of AddrNode)? - if (AddrNode->pointsTo) - return AddrNode->pointsTo; +CGNode *EscapeAnalysis::ConnectionGraph::defer(CGNode *From, CGNode *To, + bool &Changed) { + if (!From->canAddDeferred(To)) + return From; - CGNode *Node = allocNode(AddrNode->V, NodeType::Content); - updatePointsTo(AddrNode, Node); - assert(ToMerge.empty() && - "Initially setting pointsTo should not require any node merges"); - return Node; + CGNode *FromPointsTo = From->pointsTo; + CGNode *ToPointsTo = To->pointsTo; + // If necessary, merge nodes while the graph is still in a valid state. + if (FromPointsTo && ToPointsTo && FromPointsTo != ToPointsTo) { + // We are adding an edge between two pointers which point to different + // content nodes. This will require merging the content nodes (and maybe + // other content nodes as well), because of the graph invariance 4). + // + // Once the pointee's are merged, the defer edge can be added without + // creating an inconsistency. + scheduleToMerge(FromPointsTo, ToPointsTo); + mergeAllScheduledNodes(); + Changed = true; + } + // 'From' and 'To' may have been merged, so addDeferred may no longer succeed. + if (From->getMergeTarget()->addDeferred(To->getMergeTarget())) + Changed = true; + + // If pointsTo on either side of the defer was uninitialized, initialize that + // side of the defer web. Do this after adding the new edge to avoid creating + // useless pointsTo edges. + if (!FromPointsTo && ToPointsTo) + initializePointsTo(From, ToPointsTo); + else if (FromPointsTo && !ToPointsTo) + initializePointsTo(To, FromPointsTo); + + return From->getMergeTarget(); } -bool EscapeAnalysis::ConnectionGraph::addDeferEdge(CGNode *From, CGNode *To) { - if (!From->addDeferred(To)) - return false; +// Precondition: The pointsTo fields of all nodes in initializeNode's defer web +// are either uninitialized or already initialized to newPointsTo. +void EscapeAnalysis::ConnectionGraph::initializePointsTo(CGNode *initialNode, + CGNode *newPointsTo, + bool createEdge) { + // Track nodes that require pointsTo edges. + llvm::SmallVector pointsToEdgeNodes; + if (createEdge) + pointsToEdgeNodes.push_back(initialNode); + + // Step 1: Visit each node that reaches or is reachable via defer edges until + // reaching a node with the newPointsTo or with a proper pointsTo edge. + + // A worklist to gather updated nodes in the defer web. + CGNodeWorklist updatedNodes(this); + unsigned updateCount = 0; + + auto visitDeferTarget = [&](CGNode *node, bool /*isSuccessor*/) { + if (updatedNodes.contains(node)) + return true; - CGNode *FromPointsTo = From->pointsTo; - CGNode *ToPointsTo = To->pointsTo; - if (FromPointsTo != ToPointsTo) { - if (!ToPointsTo) { - updatePointsTo(To, FromPointsTo->getMergeTarget()); - assert(ToMerge.empty() && - "Initially setting pointsTo should not require any node merges"); - } else { - // We are adding an edge between two pointers which point to different - // content nodes. This will require to merge the content nodes (and maybe - // other content nodes as well), because of the graph invariance 4). - updatePointsTo(From, ToPointsTo->getMergeTarget()); + if (node->pointsTo) { + assert(node->pointsTo == newPointsTo); + // Since this node already had a pointsTo, it must reach a pointsTo + // edge. Stop traversing the defer-web here--this is complete becaused + // nodes are initialized one at a time, each time a new defer edge is + // created. If this were not complete, then the backward traversal below + // in Step 2 could reach uninitialized nodes not seen here in Step 1. + pointsToEdgeNodes.push_back(node); + return true; } - } - return true; + ++updateCount; + if (node->defersTo.empty()) { + // If this node is the end of a defer-edge path with no pointsTo + // edge. Create a "fake" pointsTo edge to maintain the graph invariant + // (this changes the structure of the graph but adding this edge has no + // effect on the process of merging nodes or creating new defer edges). + pointsToEdgeNodes.push_back(node); + } + updatedNodes.push(node); + return true; + }; + // Seed updatedNodes with initialNode. + visitDeferTarget(initialNode, true); + // updatedNodes may grow during this loop. + for (unsigned idx = 0; idx < updatedNodes.size(); ++idx) + updatedNodes[idx]->visitDefers(visitDeferTarget); + // Reset this worklist so others can be used, but updateNode.nodeVector still + // holds all the nodes found by step 1. + updatedNodes.reset(); + + // Step 2: Update pointsTo fields by propagating backward from nodes that + // already have a pointsTo edge. + do { + while (!pointsToEdgeNodes.empty()) { + CGNode *edgeNode = pointsToEdgeNodes.pop_back_val(); + if (!edgeNode->pointsTo) { + // This node is either (1) a leaf node in the defer web (identified in + // step 1) or (2) an arbitrary node in a defer-cycle (identified in a + // previous iteration of the outer loop). + edgeNode->setPointsToEdge(newPointsTo); + newPointsTo->mergeUsePoints(edgeNode); + assert(updateCount--); + } + // If edgeNode is already set to newPointsTo, it either was already + // up-to-date before calling initializePointsTo, or it was visited during + // a previous iteration of the backward traversal below. Rather than + // distinguish these cases, always retry backward traversal--it just won't + // revisit any edges in the later case. + backwardTraverse(edgeNode, [&](Predecessor pred) { + if (pred.getInt() != EdgeType::Defer) + return Traversal::Backtrack; + + CGNode *predNode = pred.getPointer(); + if (predNode->pointsTo) { + assert(predNode->pointsTo->getMergeTarget() == newPointsTo); + return Traversal::Backtrack; + } + predNode->pointsTo = newPointsTo; + newPointsTo->mergeUsePoints(predNode); + assert(updateCount--); + return Traversal::Follow; + }); + } + // For all nodes visited in step 1, pick a single node that was not + // backward-reachable from a pointsTo edge, create an edge for it and + // restart traversal. This only happens when step 1 fails to find leaves in + // the defer web because of defer edge cycles. + while (!updatedNodes.empty()) { + CGNode *node = updatedNodes.nodeVector.pop_back_val(); + if (!node->pointsTo) { + pointsToEdgeNodes.push_back(node); + break; + } + } + // This outer loop is exceedingly unlikely to execute more than twice. + } while (!pointsToEdgeNodes.empty()); + assert(updateCount == 0); } void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() { + // Each merge step is self contained and verifiable, with one exception. When + // merging a node that points to itself with a node points to another node, + // multiple merge steps are necessary to make the defer web consistent. + // Example: + // NodeA pointsTo-> From + // From defersTo-> NodeA (an indirect self-cycle) + // To pointsTo-> NodeB + // Merged: + // NodeA pointsTo-> To + // To defersTo-> NodeA (To *should* pointTo itself) + // To pointsTo-> NodeB (but still has a pointsTo edge to NodeB) while (!ToMerge.empty()) { + if (EnableInternalVerify) + verify(/*allowMerge=*/true); + CGNode *From = ToMerge.pop_back_val(); CGNode *To = From->getMergeTarget(); assert(To != From && "Node scheduled to merge but no merge target set"); @@ -427,204 +573,178 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() { assert(From->Type == NodeType::Content && "Can only merge content nodes"); assert(To->Type == NodeType::Content && "Can only merge content nodes"); - // Unlink the predecessors and redirect the incoming pointsTo edge. - // Note: we don't redirect the defer-edges because we don't want to trigger - // updatePointsTo (which is called by addDeferEdge) right now. + // Redirect the incoming pointsTo edge and unlink the defer predecessors. + // + // Don't redirect the defer-edges because it may trigger mergePointsTo() or + // initializePointsTo(). By ensuring that 'From' is unreachable first, the + // graph appears consistent during those operations. for (Predecessor Pred : From->Preds) { CGNode *PredNode = Pred.getPointer(); if (Pred.getInt() == EdgeType::PointsTo) { - assert(PredNode->getPointsToEdge() == From && - "Incoming pointsTo edge not set in predecessor"); + assert(PredNode->getPointsToEdge() == From + && "Incoming pointsTo edge not set in predecessor"); if (PredNode != From) PredNode->setPointsToEdge(To); } else { assert(PredNode != From); auto Iter = PredNode->findDeferred(From); - assert(Iter != PredNode->defersTo.end() && - "Incoming defer-edge not found in predecessor's defer list"); + assert(Iter != PredNode->defersTo.end() + && "Incoming defer-edge not found in predecessor's defer list"); PredNode->defersTo.erase(Iter); } } - // Unlink and redirect the outgoing pointsTo edge. - if (CGNode *PT = From->getPointsToEdge()) { - if (PT != From) { - PT->removeFromPreds(Predecessor(From, EdgeType::PointsTo)); - } else { - PT = To; - } - if (CGNode *ExistingPT = To->getPointsToEdge()) { - // The To node already has an outgoing pointsTo edge, so the only thing - // we can do is to merge both content nodes. - scheduleToMerge(ExistingPT, PT); - } else { - To->setPointsToEdge(PT); - } - } // Unlink the outgoing defer edges. for (CGNode *Defers : From->defersTo) { assert(Defers != From && "defer edge may not form a self-cycle"); Defers->removeFromPreds(Predecessor(From, EdgeType::Defer)); } - // Redirect the incoming defer edges. This may trigger other node merges. - // Note that the Pred iterator may be invalidated (because we may add - // edges in the loop). So we don't do: for (Pred : From->Preds) {...} - for (unsigned PredIdx = 0; PredIdx < From->Preds.size(); ++PredIdx) { - CGNode *PredNode = From->Preds[PredIdx].getPointer(); - if (From->Preds[PredIdx].getInt() == EdgeType::Defer) { - assert(PredNode != From && "defer edge may not form a self-cycle"); - addDeferEdge(PredNode, To); - } - } - // Redirect the outgoing defer edges, which may also trigger other node - // merges. - for (CGNode *Defers : From->defersTo) { - addDeferEdge(To, Defers); - } - // There is no point in updating the pointsTo if the To node will be - // merged to another node eventually. - if (!To->mergeTo) { - // Ensure that graph invariance 4) is kept. At this point there may be still - // some violations because of the new adjacent edges of the To node. - for (unsigned PredIdx = 0; PredIdx < To->Preds.size(); ++PredIdx) { - if (To->Preds[PredIdx].getInt() == EdgeType::PointsTo) { - CGNode *PredNode = To->Preds[PredIdx].getPointer(); - for (unsigned PPIdx = 0; PPIdx < PredNode->Preds.size(); ++PPIdx) { - if (PredNode->Preds[PPIdx].getInt() == EdgeType::Defer) - updatePointsTo(PredNode->Preds[PPIdx].getPointer(), To); - } - for (CGNode *Def : PredNode->defersTo) { - updatePointsTo(Def, To); - } - } - } - if (CGNode *ToPT = To->getPointsToEdge()) { - ToPT = ToPT->getMergeTarget(); - for (CGNode *ToDef : To->defersTo) { - updatePointsTo(ToDef, ToPT); - assert(!ToPT->mergeTo); - } - for (unsigned PredIdx = 0; PredIdx < To->Preds.size(); ++PredIdx) { - if (To->Preds[PredIdx].getInt() == EdgeType::Defer) - updatePointsTo(To->Preds[PredIdx].getPointer(), ToPT); + // Handle self-cycles on From by creating a self-cycle at To. + auto redirectPointsTo = [&](CGNode *pointsTo) { + return (pointsTo == From) ? To : pointsTo; + }; + // Redirect the outgoing From -> pointsTo edge. + if (From->pointsToIsEdge) { + From->pointsTo->removeFromPreds(Predecessor(From, EdgeType::PointsTo)); + if (To->pointsToIsEdge) { + // If 'To' had a pointsTo edge to 'From', then it was redirected above. + // Otherwise FromPT and ToPT will be merged below; nothing to do here. + assert(To->pointsTo != From); + } else { + // If 'To' has no pointsTo at all, initialize its defer web. + if (!To->pointsTo) { + initializePointsToEdge(To, redirectPointsTo(From->pointsTo)); + } else { + // Upgrade 'To's pointsTo to an edge to preserve the fact that 'From' + // had a pointsTo edge. + To->pointsToIsEdge = true; + To->pointsTo = redirectPointsTo(To->pointsTo); + To->pointsTo->Preds.push_back(Predecessor(To, EdgeType::PointsTo)); } } - To->mergeEscapeState(From->State); } + // Merge 'From->pointsTo' and 'To->pointsTo' if needed, regardless of + // whether either is a proper edge. Merging may be needed because other + // nodes may have points-to edges to From->PointsTo that won't be visited + // when updating 'From's defer web. + // + // If To doesn't already have a points-to, it will simply be initialized + // when updating the merged defer web below. + if (CGNode *toPT = To->pointsTo) { + // If 'To' already points to 'From', then it will already point to 'From's + // pointTo after merging. An additional merge would be too conservative. + if (From->pointsTo && toPT != From) + scheduleToMerge(redirectPointsTo(From->pointsTo), toPT); + } + // Redirect adjacent defer edges, and immediately update all points-to + // fields in the defer web. + // + // Calling initializePointsTo may create new pointsTo edges from nodes in + // the defer-web. It is unsafe to mutate or query the graph in its currently + // inconsistent state. However, this particular case is safe because: + // - The graph is only locally inconsistent w.r.t. nodes still connected to + // 'From' via defer edges. + // - 'From' itself is no longer reachable via graph edges (it may only be + // referenced in points-to fields which haven't all been updated). + // - Calling initializePointsTo on one from 'From's deferred nodes implies + // that all nodes in 'From's defer web had a null pointsTo. + // - 'To's defer web remains consistent each time a new defer edge is + // added below. Any of 'To's existing deferred nodes either still need to + // be initialized or have already been initialized to the same pointsTo. + // + // Start by updating 'To's own pointsTo field. + if (To->pointsTo == From) + mergePointsTo(To, To); + + auto mergeDeferPointsTo = [&](CGNode *deferred, bool isSuccessor) { + assert(From != deferred && "defer edge may not form a self-cycle"); + if (To == deferred) + return true; + + // In case 'deferred' points to 'From', update its pointsTo before + // exposing it to 'To's defer web. + if (deferred->pointsTo == From) + mergePointsTo(deferred, To); + + if (isSuccessor) + To->addDeferred(deferred); + else + deferred->addDeferred(To); + + if (deferred->pointsTo && To->pointsTo) + mergePointsTo(deferred, To->pointsTo); + else if (deferred->pointsTo) + initializePointsTo(To, deferred->pointsTo); + else if (To->pointsTo) + initializePointsTo(deferred, To->pointsTo); + + return true; + }; + // Redirect the adjacent defer edges. + From->visitDefers(mergeDeferPointsTo); + + // Update the web of nodes that originally pointed to 'From' via 'From's old + // pointsTo predecessors (which are now attached to 'To'). + for (unsigned PredIdx = 0; PredIdx < To->Preds.size(); ++PredIdx) { + auto predEdge = To->Preds[PredIdx]; + if (predEdge.getInt() != EdgeType::PointsTo) + continue; + predEdge.getPointer()->visitDefers( + [&](CGNode *deferred, bool /*isSucc*/) { + mergePointsTo(deferred, To); + return true; + }); + } + To->mergeEscapeState(From->State); + // Cleanup the merged node. From->isMerged = true; From->Preds.clear(); From->defersTo.clear(); From->pointsTo = nullptr; } + if (EnableInternalVerify) + verify(/*allowMerge=*/true); } -void EscapeAnalysis::ConnectionGraph:: -updatePointsTo(CGNode *InitialNode, CGNode *pointsTo) { - // Visit all nodes in the defer web, which don't have the right pointsTo set. - assert(!pointsTo->mergeTo); - llvm::SmallVector WorkList; - WorkList.push_back(InitialNode); - InitialNode->isInWorkList = true; - bool isInitialSet = false; - for (unsigned Idx = 0; Idx < WorkList.size(); ++Idx) { - auto *Node = WorkList[Idx]; - if (Node->pointsTo == pointsTo) - continue; - - if (Node->pointsTo) { - // Mismatching: we need to merge! - scheduleToMerge(Node->pointsTo, pointsTo); - } else { - isInitialSet = true; - } +// As a result of a merge, update the pointsTo field of initialNode and +// everything in its defer web to newPointsTo. +// +// This may modify the graph by redirecting a pointsTo edges. +void EscapeAnalysis::ConnectionGraph::mergePointsTo(CGNode *initialNode, + CGNode *newPointsTo) { + CGNode *oldPointsTo = initialNode->pointsTo; + assert(oldPointsTo && "merging content should not initialize any pointsTo"); + if (oldPointsTo == newPointsTo) + return; - // If the node already has a pointsTo _edge_ we don't change it (we don't - // want to change the structure of the graph at this point). - if (!Node->pointsToIsEdge) { - if (Node->defersTo.empty()) { - // This node is the end of a defer-edge path with no pointsTo connected. - // We create an edge to pointsTo (agreed, this changes the structure of - // the graph but adding this edge is harmless). - Node->setPointsToEdge(pointsTo); - } else { - Node->pointsTo = pointsTo; - } - // Update use-points if the use-point information is already calculated. - pointsTo->mergeUsePoints(Node); - } + CGNodeWorklist updateNodes(this); + auto updatePointsTo = [&](CGNode *node) { + if (node->pointsTo == newPointsTo) + return; + // If the original graph was: 'node->From->To->newPointsTo' or + // 'node->From->From', then node is already be updated to point to + // 'To' and 'To' must be merged with newPointsTo. We must still update + // pointsTo so that all nodes in the defer web have the same pointsTo. + assert(node->pointsTo == oldPointsTo + || node->pointsTo->getMergeTarget() == newPointsTo); + if (node->pointsToIsEdge) { + node->pointsTo->removeFromPreds(Predecessor(node, EdgeType::PointsTo)); + node->setPointsToEdge(newPointsTo); + } else + node->pointsTo = newPointsTo; + updateNodes.push(node); + }; + updatePointsTo(initialNode); - // Add all adjacent nodes to the WorkList. - for (auto *Deferred : Node->defersTo) { - if (!Deferred->isInWorkList) { - WorkList.push_back(Deferred); - Deferred->isInWorkList = true; - } - } - for (Predecessor Pred : Node->Preds) { - if (Pred.getInt() == EdgeType::Defer) { - CGNode *PredNode = Pred.getPointer(); - if (!PredNode->isInWorkList) { - WorkList.push_back(PredNode); - PredNode->isInWorkList = true; - } - } - } - } - if (isInitialSet) { - // Here we handle a special case: all defer-edge paths must eventually end - // in a points-to edge to pointsTo. We ensure this by setting the edge on - // nodes which have no defer-successors (see above). But this does not cover - // the case where there is a terminating cycle in the defer-edge path, - // e.g. A -> B -> C -> B - // We find all nodes which don't reach a points-to edge and add additional - // points-to edges to fix that. - llvm::SmallVector PotentiallyInCycles; - - // Keep all nodes with a points-to edge in the WorkList and remove all other - // nodes. - unsigned InsertionPoint = 0; - for (CGNode *Node : WorkList) { - if (Node->pointsToIsEdge) { - WorkList[InsertionPoint++] = Node; - } else { - Node->isInWorkList = false; - PotentiallyInCycles.push_back(Node); - } - } - WorkList.set_size(InsertionPoint); - unsigned Idx = 0; - while (!PotentiallyInCycles.empty()) { - - // Propagate the "reaches-a-points-to-edge" backwards in the defer-edge - // sub-graph by adding those nodes to the WorkList. - while (Idx < WorkList.size()) { - auto *Node = WorkList[Idx++]; - for (Predecessor Pred : Node->Preds) { - if (Pred.getInt() == EdgeType::Defer) { - CGNode *PredNode = Pred.getPointer(); - if (!PredNode->isInWorkList) { - WorkList.push_back(PredNode); - PredNode->isInWorkList = true; - } - } - } - } - // Check if we still have some nodes which don't reach a points-to edge, - // i.e. points not yet in the WorkList. - while (!PotentiallyInCycles.empty()) { - auto *Node = PotentiallyInCycles.pop_back_val(); - if (!Node->isInWorkList) { - // We create a points-to edge for the first node which doesn't reach - // a points-to edge yet. - Node->setPointsToEdge(pointsTo); - WorkList.push_back(Node); - Node->isInWorkList = true; - break; - } - } - } - } - clearWorkListFlags(WorkList); + // Visit each node that reaches or is reachable via defer edges until reaching + // a node with the newPointsTo. + auto visitDeferTarget = [&](CGNode *node, bool /*isSuccessor*/) { + if (!updateNodes.contains(node)) + updatePointsTo(node); + return true; + }; + for (unsigned Idx = 0; Idx < updateNodes.size(); ++Idx) + updateNodes[Idx]->visitDefers(visitDeferTarget); } void EscapeAnalysis::ConnectionGraph::propagateEscapeStates() { @@ -705,6 +825,41 @@ void EscapeAnalysis::ConnectionGraph::computeUsePoints() { } while (Changed); } +CGNode *EscapeAnalysis::ConnectionGraph::createContentNode(CGNode *addrNode, + SILValue addrVal, + bool hasRC) { + CGNode *newContent = allocNode(addrVal, NodeType::Content, hasRC); + initializePointsToEdge(addrNode, newContent); + assert(ToMerge.empty() + && "Initially setting pointsTo should not require any node merges"); + return newContent; +} + +// Create a content node for merging based on an address node in the destination +// graph and a content node in the source graph. +CGNode * +EscapeAnalysis::ConnectionGraph::createMergedContent(CGNode *destAddrNode, + CGNode *srcContent) { + // destAddrNode may itself be a content node, so its value may be null. Since + // we don't have the original pointer value, build a new content node based + // on the source content. + // + // TODO: node properties will come from `srcContent` here... + return createContentNode(destAddrNode, destAddrNode->V, srcContent->hasRC); +} + +// Get a node representing the field data within the given reference-counted +// node. The caller has already determined that rcNode represents the head of a +// heap object rather than field content or the address of a local variable or +// argument. +CGNode *EscapeAnalysis::ConnectionGraph::getFieldContent(CGNode *rcNode) { + assert(rcNode->isContent()); + if (rcNode->pointsTo) + return rcNode->pointsTo; + + return createContentNode(rcNode, rcNode->V, /*hasRC=*/false); +} + bool EscapeAnalysis::ConnectionGraph::mergeFrom(ConnectionGraph *SourceGraph, CGNodeMap &Mapping) { // The main point of the merging algorithm is to map each content node in the @@ -734,46 +889,43 @@ bool EscapeAnalysis::ConnectionGraph::mergeFrom(ConnectionGraph *SourceGraph, if (!SourcePT) continue; - CGNode *MappedDestPT = Mapping.get(SourcePT); - if (!DestNd->pointsTo) { - // The following getContentNode() will create a new content node. + CGNode *DestPT = DestNd->pointsTo; + if (!DestPT) { + DestPT = createMergedContent(DestNd, SourcePT); Changed = true; } - CGNode *DestPT = getContentNode(DestNd); - if (MappedDestPT) { - // We already found the destination node through another path. - if (DestPT != MappedDestPT) { - // There are two content nodes in this graph which map to the same - // content node in the source graph -> we have to merge them. - scheduleToMerge(DestPT, MappedDestPT); - mergeAllScheduledNodes(); - Changed = true; - NodesMerged = true; - } - assert(SourcePT->isInWorkList); - } else { - // It's the first time we see the destination node, so we add it to the - // mapping. + CGNode *MappedDestPT = Mapping.get(SourcePT); + if (!MappedDestPT) { + // This is the first time the dest node is seen; just add the mapping. Mapping.add(SourcePT, DestPT); + continue; } + // We already found the destination node through another path. + assert(Mapping.getMappedNodes().contains(SourcePT)); + if (DestPT == MappedDestPT) + continue; + + // There are two content nodes in this graph which map to the same + // content node in the source graph -> we have to merge them. + scheduleToMerge(DestPT, MappedDestPT); + mergeAllScheduledNodes(); + Changed = true; + NodesMerged = true; } } while (NodesMerged); - - Mapping.getMappedNodes().reset(); + Mapping.getMappedNodes().reset(); // Make way for a different worklist. // Second step: add the source graph's defer edges to this graph. - llvm::SmallVector WorkList; for (CGNode *SourceNd : Mapping.getMappedNodes().nodeVector) { - assert(WorkList.empty()); - WorkList.push_back(SourceNd); - SourceNd->isInWorkList = true; + CGNodeWorklist Worklist(SourceGraph); + Worklist.push(SourceNd); CGNode *DestFrom = Mapping.get(SourceNd); assert(DestFrom && "node should have been merged to the graph"); // Collect all nodes which are reachable from the SourceNd via a path // which only contains defer-edges. - for (unsigned Idx = 0; Idx < WorkList.size(); ++Idx) { - CGNode *SourceReachable = WorkList[Idx]; + for (unsigned Idx = 0; Idx < Worklist.size(); ++Idx) { + CGNode *SourceReachable = Worklist[Idx]; CGNode *DestReachable = Mapping.get(SourceReachable); // Create the edge in this graph. Note: this may trigger merging of // content nodes. @@ -785,16 +937,9 @@ bool EscapeAnalysis::ConnectionGraph::mergeFrom(ConnectionGraph *SourceGraph, // node of the defer-edge to escaping. Changed |= DestFrom->mergeEscapeState(EscapeState::Global); } - - for (auto *Deferred : SourceReachable->defersTo) { - if (!Deferred->isInWorkList) { - WorkList.push_back(Deferred); - Deferred->isInWorkList = true; - } - } + for (auto *Deferred : SourceReachable->defersTo) + Worklist.tryPush(Deferred); } - clearWorkListFlags(WorkList); - WorkList.clear(); } return Changed; } @@ -980,6 +1125,8 @@ std::string CGForDotView::getNodeLabel(const Node *Node) const { switch (Node->OrigNode->Type) { case swift::EscapeAnalysis::NodeType::Content: + if (Node->OrigNode->hasRefCount()) + O << "rc-"; O << "content"; break; case swift::EscapeAnalysis::NodeType::Return: @@ -1017,7 +1164,11 @@ std::string CGForDotView::getNodeAttributes(const Node *Node) const { std::string attr; switch (Orig->Type) { case swift::EscapeAnalysis::NodeType::Content: - attr = "style=\"rounded\""; + attr = "style=\"rounded"; + if (Orig->hasRefCount()) { + attr += ",filled"; + } + attr += "\""; break; case swift::EscapeAnalysis::NodeType::Argument: case swift::EscapeAnalysis::NodeType::Return: @@ -1136,6 +1287,9 @@ void EscapeAnalysis::ConnectionGraph::dumpCG() const { void EscapeAnalysis::CGNode::dump() const { llvm::errs() << getTypeStr(); + if (hasRefCount()) + llvm::errs() << " [rc]"; + if (V) llvm::errs() << ": " << *V; else @@ -1246,13 +1400,33 @@ void EscapeAnalysis::ConnectionGraph::print(llvm::raw_ostream &OS) const { OS << Separator << NodeStr(Def); Separator = ", "; } + if (Nd->hasRefCount()) + OS << " [rc]"; + OS << '\n'; } OS << "End\n"; #endif } -void EscapeAnalysis::ConnectionGraph::verify() const { +/// Checks an invariant of the connection graph: The points-to nodes of +/// the defer-successors must match with the points-to of this node. +bool CGNode::matchPointToOfDefers(bool allowMerge) const { + auto redirect = [allowMerge](CGNode *node) { + return (allowMerge && node) ? node->getMergeTarget() : node; + }; + for (CGNode *Def : defersTo) { + if (redirect(pointsTo) != redirect(Def->pointsTo)) + return false; + } + /// A defer-path in the graph must not end without the specified points-to + /// node. + if (pointsTo && !pointsToIsEdge && defersTo.empty()) + return false; + return true; +} + +void EscapeAnalysis::ConnectionGraph::verify(bool allowMerge) const { #ifndef NDEBUG verifyStructure(); @@ -1261,7 +1435,11 @@ void EscapeAnalysis::ConnectionGraph::verify() const { // ConnectionGraph invariant #4: For any node N, all paths starting at N // which consist of only defer-edges and a single trailing points-to edge // must lead to the same - assert(Nd->matchPointToOfDefers()); + assert(Nd->matchPointToOfDefers(allowMerge)); + if (Nd->isContent() && Nd->V) { + if (Nd->hasRefCount()) + assert(mayContainReference(Nd->V->getType(), *F)); + } } #endif } @@ -1326,6 +1504,47 @@ static bool linkBBArgs(SILBasicBlock *BB) { return true; } +EscapeAnalysis::CGNode * +EscapeAnalysis::getValueContent(ConnectionGraph *conGraph, SILValue addrVal) { + CGNode *addrNode = conGraph->getNode(addrVal); + if (!addrNode) + return nullptr; + + if (CGNode *content = addrNode->getPointsToEdge()) + return content; + + SILValue addrNodeValue = addrNode->getValueOrNull(); + SILValue baseAddr = getPointerRoot(addrVal); + if (addrNode->isContent()) { + // Try to maintain an invariant that a node with content is a pointer. + if (!isPointer(addrNodeValue) && isPointer(baseAddr)) + addrNode->updateValue(baseAddr); + } else { + assert(isPointer(addrNodeValue)); + assert(addrNodeValue == getPointerRoot(addrVal)); + } + auto *F = addrVal->getFunction(); + bool hasRC = mustContainReference(baseAddr->getType(), *F) + || mustContainReference(addrVal->getType(), *F); + + // Have we already merged a content node? + if (CGNode *content = addrNode->getContentNodeOrNull()) { + // hasRC might not match if one of the values pointing to this content was + // cast to an unknown type. If any of the types must contain a reference, + // then the content should contain a reference. + if (content->hasRefCount()) + assert(mayContainReference(baseAddr->getType(), *F)); + else if (hasRC) + content->setRefCount(); + + return content; + } + if (!isPointer(baseAddr)) + return nullptr; + + return conGraph->createContentNode(addrNode, baseAddr, hasRC); +} + void EscapeAnalysis::buildConnectionGraph(FunctionInfo *FInfo, FunctionOrder &BottomUpOrder, int RecursionDepth) { @@ -1485,56 +1704,59 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, // allocated array buffer. The call is like a struct(buffer) // instruction. if (CGNode *BufferNode = ConGraph->getNode(FAS.getArgument(0))) { - CGNode *ArrayNode = ConGraph->getNode(ASC.getCallResult()); - CGNode *ArrayContent = ConGraph->getContentNode(ArrayNode); + SILValue ArrayBase = ASC.getCallResult(); + CGNode *ArrayContent = getValueContent(ConGraph, ArrayBase); + assert(ArrayContent && "Array base must have a node"); ConGraph->defer(ArrayContent, BufferNode); } return; } break; case ArrayCallKind::kGetElement: - if (CGNode *AddrNode = ConGraph->getNode(ASC.getSelf())) { - CGNode *DestNode = nullptr; + if (CGNode *ArrayRefNode = getValueContent(ConGraph, ASC.getSelf())) { + CGNode *LoadedElement = nullptr; // This is like a load from a ref_element_addr. if (ASC.hasGetElementDirectResult()) { - DestNode = ConGraph->getNode(ASC.getCallResult()); + LoadedElement = ConGraph->getNode(ASC.getCallResult()); } else { - CGNode *DestAddrNode = ConGraph->getNode(FAS.getArgument(0)); - assert(DestAddrNode && "indirect result must have node"); // The content of the destination address. - DestNode = ConGraph->getContentNode(DestAddrNode); + LoadedElement = getValueContent(ConGraph, FAS.getArgument(0)); + assert(LoadedElement && "indirect result must have node"); } - if (DestNode) { - // One content node for going from the array buffer pointer to - // the element address (like ref_element_addr). - CGNode *RefElement = ConGraph->getContentNode(AddrNode); - // Another content node to actually load the element. - CGNode *ArrayContent = ConGraph->getContentNode(RefElement); - ConGraph->defer(DestNode, ArrayContent); + if (LoadedElement) { + CGNode *ArrayElementStorage = + ConGraph->getFieldContent(ArrayRefNode); + ConGraph->defer(LoadedElement, ArrayElementStorage); return; } } break; case ArrayCallKind::kGetElementAddress: // This is like a ref_element_addr. - if (CGNode *SelfNode = ConGraph->getNode(ASC.getSelf())) { - ConGraph->defer(ConGraph->getNode(ASC.getCallResult()), - ConGraph->getContentNode(SelfNode)); + if (CGNode *ArrayRefNode = getValueContent(ConGraph, ASC.getSelf())) { + ConGraph->defer(ConGraph->getNode(ASC.getCallResult()), ArrayRefNode); } return; case ArrayCallKind::kWithUnsafeMutableBufferPointer: // Model this like an escape of the elements of the array and a capture // of anything captured by the closure. // Self is passed inout. - if (CGNode *AddrArrayStruct = ConGraph->getNode(ASC.getSelf())) { - CGNode *ArrayStructValueNode = - ConGraph->getContentNode(AddrArrayStruct); + if (CGNode *ArrayStructValue = + getValueContent(ConGraph, ASC.getSelf())) { + // One content node for going from the array buffer pointer to // the element address (like ref_element_addr). - CGNode *RefElement = ConGraph->getContentNode(ArrayStructValueNode); - // Another content node to actually load the element. - CGNode *ArrayContent = ConGraph->getContentNode(RefElement); - ConGraph->setEscapesGlobal(ArrayContent); + CGNode *ArrayRefNode = ArrayStructValue->getContentNodeOrNull(); + if (!ArrayRefNode) { + ArrayRefNode = ConGraph->createContentNode( + ArrayStructValue, ArrayStructValue->getValueOrNull(), + /*hasRC=*/true); + } else + ArrayRefNode->setRefCount(); + + // Another content node for the element storage. + CGNode *ArrayElementStorage = ConGraph->getFieldContent(ArrayRefNode); + ArrayElementStorage->markEscaping(); // The first non indirect result is the closure. auto Args = FAS.getArgumentsWithoutIndirectResults(); setEscapesGlobal(ConGraph, Args[0]); @@ -1652,24 +1874,27 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, #include "swift/AST/ReferenceStorage.def" case SILInstructionKind::StrongReleaseInst: case SILInstructionKind::ReleaseValueInst: { + // A release instruction may deallocate the pointer operand. This may + // capture anything pointed to by the released object, but not the pointer + // to the object itself (because it will be a dangling pointer after + // deallocation). SILValue OpV = I->getOperand(0); - if (CGNode *AddrNode = ConGraph->getNode(OpV)) { - // A release instruction may deallocate the pointer operand. This may - // capture any content of the released object, but not the pointer to - // the object itself (because it will be a dangling pointer after - // deallocation). - CGNode *CapturedByDeinit = ConGraph->getContentNode(AddrNode); - // Get the content node for the object's properties. The object header - // itself cannot escape from the deinit. - CapturedByDeinit = ConGraph->getContentNode(CapturedByDeinit); - if (deinitIsKnownToNotCapture(OpV)) { - // Presumably this is necessary because, even though the deinit - // doesn't escape the immediate properties of this class, it may - // indirectly escape some other memory content(?) - CapturedByDeinit = ConGraph->getContentNode(CapturedByDeinit); - } - ConGraph->setEscapesGlobal(CapturedByDeinit); + CGNode *rcContent = getValueContent(ConGraph, OpV); + if (!rcContent) + return; + + // rcContent->hasRefCount() may or may not be true depending on whether + // the type could be analyzed. Either way, treat it structurally like a + // refcounted object. + CGNode *fieldContent = ConGraph->getFieldContent(rcContent); + if (!deinitIsKnownToNotCapture(OpV)) { + fieldContent->markEscaping(); + return; } + // This deinit is known to not directly capture it's own field content, + // however, indirect deinitializers could still capture anything pointed + // to by those fields. + ConGraph->escapeContentsOf(fieldContent); return; } @@ -1677,26 +1902,35 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, case SILInstructionKind::Load##Name##Inst: #include "swift/AST/ReferenceStorage.def" case SILInstructionKind::LoadInst: - // We treat ref_element_addr like a load (see NodeType::Content). + assert(!cast(I)->getType().isAddress()); + LLVM_FALLTHROUGH; case SILInstructionKind::RefElementAddrInst: case SILInstructionKind::RefTailAddrInst: case SILInstructionKind::ProjectBoxInst: case SILInstructionKind::InitExistentialAddrInst: case SILInstructionKind::OpenExistentialAddrInst: { + // Loads and projections into RC objects have a similar pattern: + // + // For RC object projections, get the non-address reference operand and + // return an RC content node that the reference directly points to. It is + // as-if the RC content node holds the pointer to the object fields. + // + // For loads, get the address-type operand and return the content node + // that the address directly points to. The load's address may itself come + // from a ref_element_addr, project_box or open_existential, in which + // case, the loaded content will be the field content, not the RC content. auto SVI = cast(I); - if (isPointer(SVI)) { - CGNode *AddrNode = ConGraph->getNode(SVI->getOperand(0)); - if (!AddrNode) { - // A load from an address we don't handle -> be conservative. - CGNode *ValueNode = ConGraph->getNode(SVI); - ConGraph->setEscapesGlobal(ValueNode); - return; - } - CGNode *PointsTo = ConGraph->getContentNode(AddrNode); - // No need for a separate node for the load instruction: - // just reuse the content node. + if (!isPointer(SVI)) + return; + + SILValue pointerVal = SVI->getOperand(0); + if (CGNode *PointsTo = getValueContent(ConGraph, pointerVal)) { ConGraph->setNode(SVI, PointsTo); + return; } + // A load or projection from an address we don't handle -> be + // conservative. + setEscapesGlobal(ConGraph, SVI); return; } case SILInstructionKind::CopyAddrInst: { @@ -1707,53 +1941,59 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, } // A copy_addr is like a 'store (load src) to dest'. - CGNode *SrcAddrNode = ConGraph->getNode(I->getOperand(CopyAddrInst::Src)); - if (!SrcAddrNode) { + SILValue srcAddr = I->getOperand(CopyAddrInst::Src); + CGNode *loadedContent = getValueContent(ConGraph, srcAddr); + if (!loadedContent) { setAllEscaping(I, ConGraph); break; } - - CGNode *LoadedValue = ConGraph->getContentNode(SrcAddrNode); - CGNode *DestAddrNode = - ConGraph->getNode(I->getOperand(CopyAddrInst::Dest)); - if (DestAddrNode) { - // Create a defer-edge from the loaded to the stored value. - CGNode *PointsTo = ConGraph->getContentNode(DestAddrNode); - ConGraph->defer(PointsTo, LoadedValue); - } else { - // A store to an address we don't handle -> be conservative. - ConGraph->setEscapesGlobal(LoadedValue); + SILValue destAddr = I->getOperand(CopyAddrInst::Dest); + // Create a defer-edge from the store location to the loaded content. + if (CGNode *destContent = getValueContent(ConGraph, destAddr)) { + ConGraph->defer(destContent, loadedContent); + return; } + // A store to an address we don't handle -> be conservative. + setEscapesGlobal(ConGraph, srcAddr); return; } #define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ case SILInstructionKind::Store##Name##Inst: #include "swift/AST/ReferenceStorage.def" - case SILInstructionKind::StoreInst: - if (CGNode *ValueNode = - ConGraph->getNode(I->getOperand(StoreInst::Src))) { - CGNode *AddrNode = ConGraph->getNode(I->getOperand(StoreInst::Dest)); - if (AddrNode) { - // Create a defer-edge from the content to the stored value. - CGNode *PointsTo = ConGraph->getContentNode(AddrNode); - ConGraph->defer(PointsTo, ValueNode); - } else { - // A store to an address we don't handle -> be conservative. - ConGraph->setEscapesGlobal(ValueNode); - } + case SILInstructionKind::StoreInst: { + SILValue srcVal = I->getOperand(StoreInst::Src); + CGNode *valueNode = ConGraph->getNode(srcVal); + // If the stored value isn't tracked, ignore the store. + if (!valueNode) + return; + + // The store destination content is always one pointsTo level away from + // its address. Either the address points to a variable or argument, and + // the pointee is removed by a level of pointer indirection, or the + // address corresponds is a projection within a reference counted object + // (via ref_element_addr, project_box, or open_existential_addr) where the + // stored field content is chained one level below the RC content. + SILValue destAddr = I->getOperand(StoreInst::Dest); + if (CGNode *pointsTo = getValueContent(ConGraph, destAddr)) { + // Create a defer-edge from the content to the stored value. + ConGraph->defer(pointsTo, valueNode); + return; } + // A store to an address we don't handle -> be conservative. + setEscapesGlobal(ConGraph, srcVal); return; + } case SILInstructionKind::PartialApplyInst: { // The result of a partial_apply is a thick function which stores the // boxed partial applied arguments. We create defer-edges from the // partial_apply values to the arguments. auto PAI = cast(I); - CGNode *ResultNode = ConGraph->getNode(PAI); - assert(ResultNode && "thick functions must have a CG node"); - for (const Operand &Op : PAI->getAllOperands()) { - if (CGNode *ArgNode = ConGraph->getNode(Op.get())) { - ResultNode = ConGraph->defer(ResultNode, ArgNode); + if (CGNode *ResultNode = ConGraph->getNode(PAI)) { + for (const Operand &Op : PAI->getAllOperands()) { + if (CGNode *ArgNode = ConGraph->getNode(Op.get())) { + ResultNode = ConGraph->defer(ResultNode, ArgNode); + } } } return; @@ -1770,20 +2010,11 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, case SILInstructionKind::EnumInst: { // Aggregate composition is like assigning the aggregate fields to the // resulting aggregate value. - auto SVI = cast(I); - CGNode *ResultNode = nullptr; - for (const Operand &Op : SVI->getAllOperands()) { - if (CGNode *FieldNode = ConGraph->getNode(Op.get())) { - if (!ResultNode) { - // A small optimization to reduce the graph size: we re-use the - // first field node as result node. - ConGraph->setNode(SVI, FieldNode); - ResultNode = FieldNode; - assert(isPointer(SVI)); - } else { - ResultNode = ConGraph->defer(ResultNode, FieldNode); - } - } + auto svi = cast(I); + CGNode *resultNode = ConGraph->getNode(svi); + for (const Operand &operand : svi->getAllOperands()) { + if (CGNode *subNode = ConGraph->getNode(operand.get())) + ConGraph->defer(resultNode, subNode); } return; } @@ -1797,9 +2028,8 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I, auto *TEI = cast(I); assert(isExtractOfArrayUninitializedPointer(TEI) && "tuple_extract should be handled as projection"); - CGNode *ArrayNode = ConGraph->getNode(TEI->getOperand()); - CGNode *ArrayElements = ConGraph->getContentNode(ArrayNode); - ConGraph->setNode(TEI, ArrayElements); + if (CGNode *ArrayElements = getValueContent(ConGraph, TEI->getOperand())) + ConGraph->setNode(TEI, ArrayElements); return; } case SILInstructionKind::UncheckedRefCastAddrInst: { @@ -2095,7 +2325,7 @@ bool EscapeAnalysis::canEscapeToUsePoint(SILValue V, SILNode *UsePoint, // In this case the apply is only a use-point for V1 and V1's content node. // As V1's content node is the same as V's content node, we also make the // check for the content node. - CGNode *ContentNode = ConGraph->getContentNode(Node); + CGNode *ContentNode = getValueContent(ConGraph, V); if (ContentNode->escapesInsideFunction(V)) return true; @@ -2187,8 +2417,8 @@ bool EscapeAnalysis::canPointToSameMemory(SILValue V1, SILValue V2) { return true; // Check if both nodes may point to the same content. - CGNode *Content1 = ConGraph->getContentNode(Node1); - CGNode *Content2 = ConGraph->getContentNode(Node2); + CGNode *Content1 = getValueContent(ConGraph, V1); + CGNode *Content2 = getValueContent(ConGraph, V2); SILType T1 = V1->getType(); SILType T2 = V2->getType(); @@ -2202,11 +2432,11 @@ bool EscapeAnalysis::canPointToSameMemory(SILValue V1, SILValue V2) { // have to go down one content level if just one of the values is a // ref-counted object. if (T1.isAddress() && hasReferenceSemantics(T2)) { - Content2 = ConGraph->getContentNode(Content2); + Content2 = ConGraph->getFieldContent(Content2); return Content1 == Content2; } if (T2.isAddress() && hasReferenceSemantics(T1)) { - Content1 = ConGraph->getContentNode(Content1); + Content1 = ConGraph->getFieldContent(Content1); return Content1 == Content2; } return true; diff --git a/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp b/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp index 203e7cca65921..43fa3d930e048 100644 --- a/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/TypeExpansionAnalysis.cpp @@ -24,10 +24,13 @@ using namespace swift; // memory usage of this cache. static const int TypeExpansionAnalysisMaxCacheSize = 4096; -const ProjectionPathList& -TypeExpansionAnalysis::getTypeExpansion(SILType B, SILModule *Mod) { +const ProjectionPathList & +TypeExpansionAnalysis::getTypeExpansion(SILType B, SILModule *Mod, + TypeExpansionContext context) { // Check whether we have the type expansion. - auto Iter = ExpansionCache.find(B); + auto key = std::make_pair(B, context); + auto Iter = ExpansionCache.find(key); + // if (Iter != ExpansionCache.end()) { return Iter->second; } @@ -36,8 +39,8 @@ TypeExpansionAnalysis::getTypeExpansion(SILType B, SILModule *Mod) { if (!shouldExpand(*Mod, B)) { // Push the empty projection path. ProjectionPath P(B); - ExpansionCache[B].push_back(P); - return ExpansionCache[B]; + ExpansionCache[key].push_back(P); + return ExpansionCache[key]; } // Flush the cache if the size of the cache is too large. @@ -46,8 +49,9 @@ TypeExpansionAnalysis::getTypeExpansion(SILType B, SILModule *Mod) { } // Build the type expansion for the leaf nodes. - ProjectionPath::expandTypeIntoLeafProjectionPaths(B, Mod, ExpansionCache[B]); - return ExpansionCache[B]; + ProjectionPath::expandTypeIntoLeafProjectionPaths(B, Mod, context, + ExpansionCache[key]); + return ExpansionCache[key]; } SILAnalysis *swift::createTypeExpansionAnalysis(SILModule *M) { diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp index b4d3be9dbda36..41671b27609de 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp @@ -517,7 +517,8 @@ void ExistentialTransform::populateThunkBody() { MakeAbstractConformanceForGenericType()); /// Perform the substitutions. - auto SubstCalleeType = GenCalleeType->substGenericArgs(M, SubMap); + auto SubstCalleeType = GenCalleeType->substGenericArgs( + M, SubMap, Builder.getTypeExpansionContext()); /// Obtain the Result Type. SILValue ReturnValue; diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp index 620d02b9c3be1..69089e5f54770 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp @@ -581,8 +581,8 @@ void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() { // Produce a substitutions list and a set of substituted SIL types // required for creating a new SIL function. Subs = F->getForwardingSubstitutionMap(); - auto SubstCalleeType = - GenCalleeType->substGenericArgs(M, Subs); + auto SubstCalleeType = GenCalleeType->substGenericArgs( + M, Subs, Builder.getTypeExpansionContext()); SubstCalleeSILType = SILType::getPrimitiveObjectType(SubstCalleeType); SILFunctionConventions Conv(SubstCalleeType, M); ResultType = Conv.getSILResultType(); diff --git a/lib/SILOptimizer/IPO/CapturePromotion.cpp b/lib/SILOptimizer/IPO/CapturePromotion.cpp index dff5e4489c9e0..db161542862f7 100644 --- a/lib/SILOptimizer/IPO/CapturePromotion.cpp +++ b/lib/SILOptimizer/IPO/CapturePromotion.cpp @@ -368,8 +368,11 @@ computeNewArgInterfaceTypes(SILFunction *F, IndicesSet &PromotableIndices, auto paramBoxTy = paramTy.castTo(); assert(paramBoxTy->getLayout()->getFields().size() == 1 && "promoting compound box not implemented yet"); - auto paramBoxedTy = getSILBoxFieldType(paramBoxTy, Types, 0); - auto ¶mTL = Types.getTypeLowering(paramBoxedTy, expansion); + auto paramBoxedTy = + getSILBoxFieldType(TypeExpansionContext(*F), paramBoxTy, Types, 0); + assert(expansion == F->getResilienceExpansion()); + auto ¶mTL = + Types.getTypeLowering(paramBoxedTy, TypeExpansionContext(*F)); ParameterConvention convention; if (paramTL.isAddressOnly()) { convention = ParameterConvention::Indirect_In; @@ -480,8 +483,9 @@ ClosureCloner::populateCloned() { auto BoxTy = (*I)->getType().castTo(); assert(BoxTy->getLayout()->getFields().size() == 1 && "promoting compound box not implemented"); - auto BoxedTy = getSILBoxFieldType(BoxTy, Cloned->getModule().Types, 0) - .getObjectType(); + auto BoxedTy = getSILBoxFieldType(TypeExpansionContext(*Cloned), BoxTy, + Cloned->getModule().Types, 0) + .getObjectType(); SILValue MappedValue = ClonedEntryBB->createFunctionArgument(BoxedTy, (*I)->getDecl()); @@ -999,7 +1003,8 @@ bool isPartialApplyNonEscapingUser(Operand *CurrentOp, PartialApplyInst *PAI, auto BoxTy = BoxArg->getType().castTo(); assert(BoxTy->getLayout()->getFields().size() == 1 && "promoting compound box not implemented yet"); - if (getSILBoxFieldType(BoxTy, M.Types, 0).isAddressOnly(*F)) { + if (getSILBoxFieldType(TypeExpansionContext(*Fn), BoxTy, M.Types, 0) + .isAddressOnly(*F)) { LLVM_DEBUG(llvm::dbgs() << " FAIL! Box is an address only " "argument!\n"); return false; @@ -1273,8 +1278,8 @@ processPartialApplyInst(SILOptFunctionBuilder &FuncBuilder, auto CalleeFunctionTy = PAI->getCallee()->getType().castTo(); auto SubstCalleeFunctionTy = CalleeFunctionTy; if (PAI->hasSubstitutions()) - SubstCalleeFunctionTy = - CalleeFunctionTy->substGenericArgs(M, PAI->getSubstitutionMap()); + SubstCalleeFunctionTy = CalleeFunctionTy->substGenericArgs( + M, PAI->getSubstitutionMap(), TypeExpansionContext(*F)); SILFunctionConventions calleeConv(SubstCalleeFunctionTy, M); auto CalleePInfo = SubstCalleeFunctionTy->getParameters(); SILFunctionConventions paConv(PAI->getType().castTo(), M); diff --git a/lib/SILOptimizer/IPO/CapturePropagation.cpp b/lib/SILOptimizer/IPO/CapturePropagation.cpp index b24c8d1fce234..4294f5e3f8d72 100644 --- a/lib/SILOptimizer/IPO/CapturePropagation.cpp +++ b/lib/SILOptimizer/IPO/CapturePropagation.cpp @@ -421,10 +421,11 @@ static SILFunction *getSpecializedWithDeadParams( return nullptr; // Perform a generic specialization of the Specialized function. - ReabstractionInfo ReInfo(ApplySite(), Specialized, - PAI->getSubstitutionMap(), - Specialized->isSerialized(), - /* ConvertIndirectToDirect */ false); + ReabstractionInfo ReInfo( + FuncBuilder.getModule().getSwiftModule(), + FuncBuilder.getModule().isWholeModule(), ApplySite(), Specialized, + PAI->getSubstitutionMap(), Specialized->isSerialized(), + /* ConvertIndirectToDirect */ false); GenericFuncSpecializer FuncSpecializer(FuncBuilder, Specialized, ReInfo.getClonerParamSubstitutionMap(), diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index 6395f744aa76b..d9395b29b8f92 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -800,8 +800,9 @@ void ClosureSpecCloner::populateCloned() { } // Otherwise, create a new argument which copies the original argument + auto typeInContext = Cloned->getLoweredType(Arg->getType()); SILValue MappedValue = - ClonedEntryBB->createFunctionArgument(Arg->getType(), Arg->getDecl()); + ClonedEntryBB->createFunctionArgument(typeInContext, Arg->getDecl()); entryArgs.push_back(MappedValue); } @@ -821,6 +822,8 @@ void ClosureSpecCloner::populateCloned() { unsigned idx = 0; for (auto &PInfo : ClosedOverFunConv.getParameters().slice(NumNotCaptured)) { auto paramTy = ClosedOverFunConv.getSILType(PInfo); + // Get the type in context of the new function. + paramTy = Cloned->getLoweredType(paramTy); SILValue MappedValue = ClonedEntryBB->createFunctionArgument(paramTy); NewPAIArgs.push_back(MappedValue); auto CapturedVal = diff --git a/lib/SILOptimizer/IPO/EagerSpecializer.cpp b/lib/SILOptimizer/IPO/EagerSpecializer.cpp index ca0df01328595..a56bd3c8bdacd 100644 --- a/lib/SILOptimizer/IPO/EagerSpecializer.cpp +++ b/lib/SILOptimizer/IPO/EagerSpecializer.cpp @@ -231,7 +231,8 @@ emitInvocation(SILBuilder &Builder, if (ReInfo.getSpecializedType()->isPolymorphic()) { Subs = ReInfo.getCallerParamSubstitutionMap(); CalleeSubstFnTy = CanSILFuncTy->substGenericArgs( - Builder.getModule(), ReInfo.getCallerParamSubstitutionMap()); + Builder.getModule(), ReInfo.getCallerParamSubstitutionMap(), + Builder.getTypeExpansionContext()); assert(!CalleeSubstFnTy->isPolymorphic() && "Substituted callee type should not be polymorphic"); assert(!CalleeSubstFnTy->hasTypeParameter() && @@ -628,7 +629,8 @@ emitArgumentConversion(SmallVectorImpl &CallArgs) { auto CalleeSubstFnTy = CanSILFuncTy; if (CanSILFuncTy->isPolymorphic()) { CalleeSubstFnTy = CanSILFuncTy->substGenericArgs( - Builder.getModule(), ReInfo.getCallerParamSubstitutionMap()); + Builder.getModule(), ReInfo.getCallerParamSubstitutionMap(), + Builder.getTypeExpansionContext()); assert(!CalleeSubstFnTy->isPolymorphic() && "Substituted callee type should not be polymorphic"); assert(!CalleeSubstFnTy->hasTypeParameter() && @@ -763,7 +765,9 @@ void EagerSpecializerTransform::run() { // TODO: Use a decision-tree to reduce the amount of dynamic checks being // performed. for (auto *SA : F.getSpecializeAttrs()) { - ReInfoVec.emplace_back(&F, SA->getSpecializedSignature()); + ReInfoVec.emplace_back(FuncBuilder.getModule().getSwiftModule(), + FuncBuilder.getModule().isWholeModule(), &F, + SA->getSpecializedSignature()); auto *NewFunc = eagerSpecialize(FuncBuilder, &F, *SA, ReInfoVec.back()); SpecializedFuncs.push_back(NewFunc); diff --git a/lib/SILOptimizer/IPO/GlobalOpt.cpp b/lib/SILOptimizer/IPO/GlobalOpt.cpp index 4581f7faa0cf8..e0cc724ab1a1b 100644 --- a/lib/SILOptimizer/IPO/GlobalOpt.cpp +++ b/lib/SILOptimizer/IPO/GlobalOpt.cpp @@ -264,7 +264,8 @@ static SILFunction *getGlobalGetterFunction(SILOptFunctionBuilder &FunctionBuild Serialized = IsSerialized; } - auto refType = M.Types.getLoweredRValueType(varDecl->getInterfaceType()); + auto refType = M.Types.getLoweredRValueType(TypeExpansionContext::minimal(), + varDecl->getInterfaceType()); // Function takes no arguments and returns refType SILResultInfo Results[] = { SILResultInfo(refType, @@ -747,7 +748,9 @@ void SILGlobalOpt::optimizeInitializer(SILFunction *AddrF, if (hasPublicVisibility(SILG->getLinkage())) expansion = ResilienceExpansion::Minimal; - auto &tl = Module->Types.getTypeLowering(SILG->getLoweredType(), expansion); + auto &tl = Module->Types.getTypeLowering( + SILG->getLoweredType(), + TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(expansion)); if (!tl.isLoadable()) return; diff --git a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp index 6fc43adc5fe52..5b1dab1e9ed3c 100644 --- a/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp +++ b/lib/SILOptimizer/IPO/LetPropertiesOpts.cpp @@ -376,7 +376,7 @@ bool LetPropertiesOpt::isConstantLetProperty(VarDecl *Property) { // FIXME: Expansion auto &TL = Module->Types.getTypeLowering(Property->getType(), - ResilienceExpansion::Minimal); + TypeExpansionContext::minimal()); if (!TL.isTrivial()) { LLVM_DEBUG(llvm::dbgs() << "Property '" << *Property << "' is not of trivial type\n"); diff --git a/lib/SILOptimizer/IPO/UsePrespecialized.cpp b/lib/SILOptimizer/IPO/UsePrespecialized.cpp index 2b1e8f58aa42b..b2f7bfde4e40f 100644 --- a/lib/SILOptimizer/IPO/UsePrespecialized.cpp +++ b/lib/SILOptimizer/IPO/UsePrespecialized.cpp @@ -90,7 +90,8 @@ bool UsePrespecialized::replaceByPrespecialized(SILFunction &F) { if (Subs.hasArchetypes()) continue; - ReabstractionInfo ReInfo(AI, ReferencedF, Subs, IsNotSerialized); + ReabstractionInfo ReInfo(M.getSwiftModule(), M.isWholeModule(), AI, + ReferencedF, Subs, IsNotSerialized); if (!ReInfo.canBeSpecialized()) continue; diff --git a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp index 315007020431c..4625eb2d2b5a1 100644 --- a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp +++ b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp @@ -70,6 +70,10 @@ canDuplicateOrMoveToPreheader(SILLoop *loop, SILBasicBlock *preheader, invariants.insert(inst); } else if (!inst->isTriviallyDuplicatable()) return false; + // It wouldn't make sense to rotate dealloc_stack without also rotating the + // alloc_stack, which is covered by isTriviallyDuplicatable. + else if (isa(inst)) + return false; else if (isa(inst)) { moves.push_back(inst); invariants.insert(inst); diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp index a8138c942ddc3..5188411efe102 100644 --- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp +++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp @@ -63,7 +63,8 @@ static void gatherDestroysOfContainer(const MarkUninitializedInst *MUI, // DIMemoryObjectInfo Implementation //===----------------------------------------------------------------------===// -static unsigned getElementCountRec(SILModule &Module, SILType T, +static unsigned getElementCountRec(TypeExpansionContext context, + SILModule &Module, SILType T, bool IsSelfOfNonDelegatingInitializer) { // If this is a tuple, it is always recursively flattened. if (CanTupleType TT = T.getAs()) { @@ -71,7 +72,7 @@ static unsigned getElementCountRec(SILModule &Module, SILType T, unsigned NumElements = 0; for (unsigned i = 0, e = TT->getNumElements(); i < e; i++) NumElements += - getElementCountRec(Module, T.getTupleElementType(i), false); + getElementCountRec(context, Module, T.getTupleElementType(i), false); return NumElements; } @@ -83,8 +84,8 @@ static unsigned getElementCountRec(SILModule &Module, SILType T, if (auto *NTD = T.getNominalOrBoundGenericNominal()) { unsigned NumElements = 0; for (auto *VD : NTD->getStoredProperties()) - NumElements += - getElementCountRec(Module, T.getFieldType(VD, Module), false); + NumElements += getElementCountRec( + context, Module, T.getFieldType(VD, Module, context), false); return NumElements; } } @@ -134,7 +135,8 @@ DIMemoryObjectInfo::DIMemoryObjectInfo(MarkUninitializedInst *MI) // Otherwise, we break down the initializer. NumElements = - getElementCountRec(Module, MemorySILType, isNonDelegatingInit()); + getElementCountRec(TypeExpansionContext(*MI->getFunction()), Module, + MemorySILType, isNonDelegatingInit()); // If this is a derived class init method, track an extra element to determine // whether super.init has been called at each program point. @@ -152,16 +154,18 @@ SILInstruction *DIMemoryObjectInfo::getFunctionEntryPoint() const { } /// Given a symbolic element number, return the type of the element. -static SILType getElementTypeRec(SILModule &Module, SILType T, unsigned EltNo, +static SILType getElementTypeRec(TypeExpansionContext context, + SILModule &Module, SILType T, unsigned EltNo, bool IsSelfOfNonDelegatingInitializer) { // If this is a tuple type, walk into it. if (CanTupleType TT = T.getAs()) { assert(!IsSelfOfNonDelegatingInitializer && "self never has tuple type"); for (unsigned i = 0, e = TT->getNumElements(); i < e; i++) { auto FieldType = T.getTupleElementType(i); - unsigned NumFieldElements = getElementCountRec(Module, FieldType, false); + unsigned NumFieldElements = + getElementCountRec(context, Module, FieldType, false); if (EltNo < NumFieldElements) - return getElementTypeRec(Module, FieldType, EltNo, false); + return getElementTypeRec(context, Module, FieldType, EltNo, false); EltNo -= NumFieldElements; } // This can only happen if we look at a symbolic element number of an empty @@ -177,11 +181,11 @@ static SILType getElementTypeRec(SILModule &Module, SILType T, unsigned EltNo, bool HasStoredProperties = false; for (auto *VD : NTD->getStoredProperties()) { HasStoredProperties = true; - auto FieldType = T.getFieldType(VD, Module); + auto FieldType = T.getFieldType(VD, Module, context); unsigned NumFieldElements = - getElementCountRec(Module, FieldType, false); + getElementCountRec(context, Module, FieldType, false); if (EltNo < NumFieldElements) - return getElementTypeRec(Module, FieldType, EltNo, false); + return getElementTypeRec(context, Module, FieldType, EltNo, false); EltNo -= NumFieldElements; } @@ -202,7 +206,8 @@ static SILType getElementTypeRec(SILModule &Module, SILType T, unsigned EltNo, /// getElementTypeRec - Return the swift type of the specified element. SILType DIMemoryObjectInfo::getElementType(unsigned EltNo) const { auto &Module = MemoryInst->getModule(); - return getElementTypeRec(Module, MemorySILType, EltNo, isNonDelegatingInit()); + return getElementTypeRec(TypeExpansionContext(*MemoryInst->getFunction()), + Module, MemorySILType, EltNo, isNonDelegatingInit()); } /// computeTupleElementAddress - Given a tuple element number (in the flattened @@ -225,7 +230,8 @@ SILValue DIMemoryObjectInfo::emitElementAddress( unsigned FieldNo = 0; for (unsigned i = 0, e = TT->getNumElements(); i < e; i++) { auto EltTy = PointeeType.getTupleElementType(i); - unsigned NumSubElt = getElementCountRec(Module, EltTy, false); + unsigned NumSubElt = getElementCountRec( + TypeExpansionContext(B.getFunction()), Module, EltTy, false); if (EltNo < NumSubElt) { Ptr = B.createTupleElementAddr(Loc, Ptr, FieldNo); PointeeType = EltTy; @@ -255,10 +261,11 @@ SILValue DIMemoryObjectInfo::emitElementAddress( EndBorrowList.emplace_back(Borrowed, Original); } } - - auto FieldType = PointeeType.getFieldType(VD, Module); + auto expansionContext = TypeExpansionContext(B.getFunction()); + auto FieldType = + PointeeType.getFieldType(VD, Module, expansionContext); unsigned NumFieldElements = - getElementCountRec(Module, FieldType, false); + getElementCountRec(expansionContext, Module, FieldType, false); if (EltNo < NumFieldElements) { if (isa(NTD)) { Ptr = B.createStructElementAddr(Loc, Ptr, VD); @@ -300,7 +307,8 @@ SILValue DIMemoryObjectInfo::emitElementAddress( /// Push the symbolic path name to the specified element number onto the /// specified std::string. -static void getPathStringToElementRec(SILModule &Module, SILType T, +static void getPathStringToElementRec(TypeExpansionContext context, + SILModule &Module, SILType T, unsigned EltNo, std::string &Result) { CanTupleType TT = T.getAs(); if (!TT) { @@ -313,7 +321,7 @@ static void getPathStringToElementRec(SILModule &Module, SILType T, for (unsigned i = 0, e = TT->getNumElements(); i < e; i++) { auto Field = TT->getElement(i); SILType FieldTy = T.getTupleElementType(i); - unsigned NumFieldElements = getElementCountRec(Module, FieldTy, false); + unsigned NumFieldElements = getElementCountRec(context, Module, FieldTy, false); if (EltNo < NumFieldElements) { Result += '.'; @@ -321,7 +329,7 @@ static void getPathStringToElementRec(SILModule &Module, SILType T, Result += Field.getName().str(); else Result += llvm::utostr(FieldNo); - return getPathStringToElementRec(Module, FieldTy, EltNo, Result); + return getPathStringToElementRec(context, Module, FieldTy, EltNo, Result); } EltNo -= NumFieldElements; @@ -346,14 +354,16 @@ DIMemoryObjectInfo::getPathStringToElement(unsigned Element, Result = ""; // If this is indexing into a field of 'self', look it up. + auto expansionContext = TypeExpansionContext(*MemoryInst->getFunction()); if (isNonDelegatingInit() && !isDerivedClassSelfOnly()) { if (auto *NTD = MemorySILType.getNominalOrBoundGenericNominal()) { bool HasStoredProperty = false; for (auto *VD : NTD->getStoredProperties()) { HasStoredProperty = true; - auto FieldType = MemorySILType.getFieldType(VD, Module); + auto FieldType = + MemorySILType.getFieldType(VD, Module, expansionContext); unsigned NumFieldElements = - getElementCountRec(Module, FieldType, false); + getElementCountRec(expansionContext, Module, FieldType, false); if (Element < NumFieldElements) { Result += '.'; auto originalProperty = VD->getOriginalWrappedProperty(); @@ -362,7 +372,8 @@ DIMemoryObjectInfo::getPathStringToElement(unsigned Element, } else { Result += VD->getName().str(); } - getPathStringToElementRec(Module, FieldType, Element, Result); + getPathStringToElementRec(expansionContext, Module, FieldType, + Element, Result); return VD; } Element -= NumFieldElements; @@ -375,7 +386,8 @@ DIMemoryObjectInfo::getPathStringToElement(unsigned Element, } // Get the path through a tuple, if relevant. - getPathStringToElementRec(Module, MemorySILType, Element, Result); + getPathStringToElementRec(expansionContext, Module, MemorySILType, Element, + Result); // If we are analyzing a variable, we can generally get the decl associated // with it. @@ -402,9 +414,11 @@ bool DIMemoryObjectInfo::isElementLetProperty(unsigned Element) const { return false; } + auto expansionContext = TypeExpansionContext(*MemoryInst->getFunction()); for (auto *VD : NTD->getStoredProperties()) { - auto FieldType = MemorySILType.getFieldType(VD, Module); - unsigned NumFieldElements = getElementCountRec(Module, FieldType, false); + auto FieldType = MemorySILType.getFieldType(VD, Module, expansionContext); + unsigned NumFieldElements = + getElementCountRec(expansionContext, Module, FieldType, false); if (Element < NumFieldElements) return VD->isLet(); Element -= NumFieldElements; @@ -591,7 +605,8 @@ void ElementUseCollector::addElementUses(unsigned BaseEltNo, SILType UseTy, unsigned NumElements = 1; if (TheMemory.NumElements != 1 && !InStructSubElement && !InEnumSubElement) NumElements = - getElementCountRec(Module, UseTy, IsSelfOfNonDelegatingInitializer); + getElementCountRec(TypeExpansionContext(*User->getFunction()), Module, + UseTy, IsSelfOfNonDelegatingInitializer); trackUse(DIMemoryUse(User, Kind, BaseEltNo, NumElements)); } @@ -617,7 +632,8 @@ void ElementUseCollector::collectTupleElementUses(TupleElementAddrInst *TEAI, if (T.is()) { for (unsigned i = 0; i != FieldNo; ++i) { SILType EltTy = T.getTupleElementType(i); - BaseEltNo += getElementCountRec(Module, EltTy, false); + BaseEltNo += getElementCountRec(TypeExpansionContext(*TEAI->getFunction()), + Module, EltTy, false); } } @@ -644,7 +660,8 @@ void ElementUseCollector::collectDestructureTupleResultUses( if (T.is()) { for (unsigned i = 0; i != FieldNo; ++i) { SILType EltTy = T.getTupleElementType(i); - BaseEltNo += getElementCountRec(Module, EltTy, false); + BaseEltNo += getElementCountRec(TypeExpansionContext(*DTR->getFunction()), + Module, EltTy, false); } } @@ -670,8 +687,9 @@ void ElementUseCollector::collectStructElementUses(StructElementAddrInst *SEAI, if (SEAI->getField() == VD) break; - auto FieldType = SEAI->getOperand()->getType().getFieldType(VD, Module); - BaseEltNo += getElementCountRec(Module, FieldType, false); + auto expansionContext = TypeExpansionContext(*SEAI->getFunction()); + auto FieldType = SEAI->getOperand()->getType().getFieldType(VD, Module, expansionContext); + BaseEltNo += getElementCountRec(expansionContext, Module, FieldType, false); } collectUses(SEAI, BaseEltNo); @@ -1119,8 +1137,11 @@ void ElementUseCollector::collectClassSelfUses() { unsigned NumElements = 0; for (auto *VD : NTD->getStoredProperties()) { EltNumbering[VD] = NumElements; - NumElements += - getElementCountRec(Module, T.getFieldType(VD, Module), false); + auto expansionContext = + TypeExpansionContext(*TheMemory.MemoryInst->getFunction()); + NumElements += getElementCountRec( + expansionContext, Module, + T.getFieldType(VD, Module, expansionContext), false); } } diff --git a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp index f4f6247e4aad5..0dec95dd11056 100644 --- a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp +++ b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp @@ -499,12 +499,14 @@ static void addSwapAtFixit(InFlightDiagnostic &Diag, CallExpr *&FoundCall, /// and tuple elements. static std::string getPathDescription(DeclName BaseName, SILType BaseType, const IndexTrieNode *SubPath, - SILModule &M) { + SILModule &M, + TypeExpansionContext context) { std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "'" << BaseName; - os << AccessSummaryAnalysis::getSubPathDescription(BaseType, SubPath, M); + os << AccessSummaryAnalysis::getSubPathDescription(BaseType, SubPath, M, + context); os << "'"; return os.str(); @@ -547,7 +549,8 @@ static void diagnoseExclusivityViolation(const ConflictingAccess &Violation, SILType BaseType = FirstAccess.getInstruction()->getType().getAddressType(); SILModule &M = FirstAccess.getInstruction()->getModule(); std::string PathDescription = getPathDescription( - VD->getBaseName(), BaseType, MainAccess.getSubPath(), M); + VD->getBaseName(), BaseType, MainAccess.getSubPath(), M, + TypeExpansionContext(*FirstAccess.getInstruction()->getFunction())); // Determine whether we can safely suggest replacing the violation with // a call to MutableCollection.swapAt(). diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index 68cad07a54f3a..2f61489ae4938 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -52,6 +52,7 @@ #include "swift/SILOptimizer/Analysis/LoopAnalysis.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/DerivativeLookup.h" #include "swift/SILOptimizer/Utils/Differentiation.h" #include "swift/SILOptimizer/Utils/LoopUtils.h" @@ -667,7 +668,7 @@ class LinearMapInfo { auto linMapStructType = linMapStruct->getDeclaredInterfaceType()->getCanonicalType(); return typeConverter.getLoweredType(linMapStructType, - ResilienceExpansion::Minimal); + TypeExpansionContext::minimal()); } /// Returns the branching trace enum associated with the given original block. @@ -682,7 +683,7 @@ class LinearMapInfo { auto traceDeclType = traceDecl->getDeclaredInterfaceType()->getCanonicalType(); return typeConverter.getLoweredType(traceDeclType, - ResilienceExpansion::Minimal); + TypeExpansionContext::minimal()); } /// Returns the enum element in the given successor block's branching trace @@ -2053,7 +2054,8 @@ static void emitZeroIntoBuffer( assert(zeroDecl->isProtocolRequirement()); auto *accessorDecl = zeroDecl->getAccessor(AccessorKind::Get); SILDeclRef accessorDeclRef(accessorDecl, SILDeclRef::Kind::Func); - auto silFnType = typeConverter.getConstantType(accessorDeclRef); + auto silFnType = typeConverter.getConstantType( + TypeExpansionContext::minimal(), accessorDeclRef); // %wm = witness_method ... auto *getter = builder.createWitnessMethod( loc, type, confRef, accessorDeclRef, silFnType); @@ -2339,8 +2341,12 @@ static SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, thunkType, fromInterfaceType, toInterfaceType, Type(), module.getSwiftModule()); + // FIXME(TF-989): Mark reabstraction thunks as transparent. This requires + // generating ossa reabstraction thunks so that they can be inlined during + // mandatory inlining when `-enable-strip-ownership-after-serialization` is + // true and ownership model eliminator is not run after differentiation. auto *thunk = fb.getOrCreateSharedFunction( - loc, name, thunkDeclType, IsBare, IsTransparent, IsSerialized, + loc, name, thunkDeclType, IsBare, IsNotTransparent, IsSerialized, ProfileCounter(), IsReabstractionThunk, IsNotDynamic); if (!thunk->empty()) return thunk; @@ -2521,19 +2527,6 @@ class VJPEmitter final /// predecessor enum argument). SmallPtrSet remappedBasicBlocks; - /// A pair of a trampoline block phi argument and its corresponding - /// destination block phi argument. - struct TrampolinedArgumentPair { - SILPhiArgument *trampolineArgument; - SILPhiArgument *destinationArgument; - }; - /// An array that keeps track of all `@guaranteed` phi arguments in any - /// trampoline blocks we've added. Each of these arguments needs to have a - /// lifetime-ending use past its destination argument's lifetime-ending use, - /// so we keep track of these pairs of arguments and emit `end_borrow`s when - /// function cloning is finished. - SmallVector trampolinedGuaranteedPhiArguments; - bool errorOccurred = false; /// Mapping from original blocks to pullback values. Used to build pullback @@ -2605,7 +2598,7 @@ class VJPEmitter final auto getTangentParameterInfoForOriginalResult = [&]( CanType tanType, ResultConvention origResConv) -> SILParameterInfo { auto &tl = context.getTypeConverter().getTypeLowering( - tanType, ResilienceExpansion::Minimal); + tanType, TypeExpansionContext::minimal()); ParameterConvention conv; switch (origResConv) { case ResultConvention::Owned: @@ -2629,7 +2622,7 @@ class VJPEmitter final auto getTangentResultInfoForOriginalParameter = [&]( CanType tanType, ParameterConvention origParamConv) -> SILResultInfo { auto &tl = context.getTypeConverter().getTypeLowering( - tanType, ResilienceExpansion::Minimal); + tanType, TypeExpansionContext::minimal()); ResultConvention conv; switch (origParamConv) { case ParameterConvention::Direct_Owned: @@ -2733,7 +2726,7 @@ class VJPEmitter final auto enumTy = getOpASTType(predEnum->getDeclaredInterfaceType() ->getCanonicalType()); auto enumLoweredTy = context.getTypeConverter().getLoweredType( - enumTy, ResilienceExpansion::Minimal); + enumTy, TypeExpansionContext::minimal()); vjpBB->createPhiArgument(enumLoweredTy, ValueOwnershipKind::Owned); remappedBasicBlocks.insert(bb); return vjpBB; @@ -2759,7 +2752,7 @@ class VJPEmitter final auto nomType = getOpASTType( nominal->getDeclaredInterfaceType()->getCanonicalType()); auto nomSILType = context.getTypeConverter().getLoweredType( - nomType, ResilienceExpansion::Minimal); + nomType, TypeExpansionContext::minimal()); return nomSILType; } @@ -2791,8 +2784,8 @@ class VJPEmitter final auto enumLoweredTy = getNominalDeclLoweredType(succEnum); auto *enumEltDecl = pullbackInfo.lookUpBranchingTraceEnumElement(predBB, succBB); - auto enumEltType = getOpType( - enumLoweredTy.getEnumElementType(enumEltDecl, getModule())); + auto enumEltType = getOpType(enumLoweredTy.getEnumElementType( + enumEltDecl, getModule(), TypeExpansionContext::minimal())); // If the enum element type does not have a box type (i.e. the enum case is // not indirect), then directly create an enum. auto boxType = dyn_cast(enumEltType.getASTType()); @@ -2915,18 +2908,9 @@ class VJPEmitter final auto *vjpSuccBB = getOpBasicBlock(origSuccBB); // Create the trampoline block. auto *trampolineBB = vjp->createBasicBlockBefore(vjpSuccBB); - for (auto *destArg : vjpSuccBB->getArguments().drop_back()) { - auto *trampolineArg = trampolineBB->createPhiArgument( + for (auto *destArg : vjpSuccBB->getArguments().drop_back()) + trampolineBB->createPhiArgument( destArg->getType(), destArg->getOwnershipKind()); - // Each `@guaranteed` trampoline argument needs to have a - // lifetime-ending use past its destination argument's lifetime-ending - // uses, so we keep track of these pairs of arguments in - // `trampolinedGuaranteedPhiArguments` and emit `end_borrow`s when - // function cloning is finished. - if (trampolineArg->getOwnershipKind() == ValueOwnershipKind::Guaranteed) - trampolinedGuaranteedPhiArguments.push_back( - {trampolineArg, cast(destArg)}); - } // Build predecessor enum value for successor block and branch to it. SILBuilder trampolineBuilder(trampolineBB); auto *succEnumVal = buildPredecessorEnumValue( @@ -3177,7 +3161,7 @@ class VJPEmitter final auto loweredPullbackType = getOpType(context.getTypeConverter().getLoweredType( pullbackDecl->getInterfaceType()->getCanonicalType(), - ResilienceExpansion::Minimal)) + TypeExpansionContext::minimal())) .castTo(); if (!loweredPullbackType->isEqual(actualPullbackType)) { // Set non-reabstracted original pullback type in nested apply info. @@ -3551,7 +3535,7 @@ class JVPEmitter final auto nomType = getOpASTType(nominal->getDeclaredInterfaceType()->getCanonicalType()); auto nomSILType = context.getTypeConverter().getLoweredType( - nomType, ResilienceExpansion::Minimal); + nomType, TypeExpansionContext::minimal()); return nomSILType; } @@ -3621,7 +3605,7 @@ class JVPEmitter final SILValue emitZeroDirect(CanType type, SILLocation loc) { auto diffBuilder = getDifferentialBuilder(); auto silType = getModule().Types.getLoweredLoadableType( - type, ResilienceExpansion::Minimal, getModule()); + type, TypeExpansionContext::minimal(), getModule()); auto *buffer = diffBuilder.createAllocStack(loc, silType); emitZeroIndirect(type, buffer, loc); auto loaded = diffBuilder.emitLoadValueOperation( @@ -4865,7 +4849,7 @@ class JVPEmitter final auto loweredDifferentialType = getOpType(context.getTypeConverter().getLoweredType( differentialDecl->getInterfaceType()->getCanonicalType(), - ResilienceExpansion::Minimal)) + TypeExpansionContext::minimal())) .castTo(); // If actual differential type does not match lowered differential type, // reabstract the differential using a thunk. @@ -5592,8 +5576,8 @@ class PullbackEmitter final : public SILInstructionVisitor { getPullbackInfo().getBranchingTraceEnumLoweredType(succBB); auto *enumEltDecl = getPullbackInfo().lookUpBranchingTraceEnumElement(origBB, succBB); - auto enumEltType = remapType( - enumLoweredTy.getEnumElementType(enumEltDecl, getModule())); + auto enumEltType = remapType(enumLoweredTy.getEnumElementType( + enumEltDecl, getModule(), TypeExpansionContext::minimal())); pullbackTrampolineBB->createPhiArgument(enumEltType, ValueOwnershipKind::Owned); } @@ -6271,7 +6255,7 @@ class PullbackEmitter final : public SILInstructionVisitor { auto tangentVectorTy = getTangentSpace(structTy)->getType()->getCanonicalType(); assert(!getModule().Types.getTypeLowering( - tangentVectorTy, ResilienceExpansion::Minimal) + tangentVectorTy, TypeExpansionContext::minimal()) .isAddressOnly()); auto *tangentVectorDecl = tangentVectorTy->getStructOrBoundGenericStruct(); @@ -6335,7 +6319,7 @@ class PullbackEmitter final : public SILInstructionVisitor { auto tangentVectorTy = getTangentSpace(structTy)->getType()->getCanonicalType(); assert(!getModule().Types.getTypeLowering( - tangentVectorTy, ResilienceExpansion::Minimal) + tangentVectorTy, TypeExpansionContext::minimal()) .isAddressOnly()); auto tangentVectorSILTy = SILType::getPrimitiveObjectType(tangentVectorTy); @@ -6381,7 +6365,7 @@ class PullbackEmitter final : public SILInstructionVisitor { auto fieldTy = field->getType().subst(substMap); auto fieldSILTy = getContext().getTypeConverter().getLoweredType( - fieldTy, ResilienceExpansion::Minimal); + fieldTy, TypeExpansionContext::minimal()); assert(fieldSILTy.isObject()); eltVals.push_back(makeZeroAdjointValue(fieldSILTy)); } @@ -6839,7 +6823,7 @@ void PullbackEmitter::emitZeroIndirect(CanType type, SILValue bufferAccess, SILValue PullbackEmitter::emitZeroDirect(CanType type, SILLocation loc) { auto silType = getModule().Types.getLoweredLoadableType( - type, ResilienceExpansion::Minimal, getModule()); + type, TypeExpansionContext::minimal(), getModule()); auto *buffer = builder.createAllocStack(loc, silType); emitZeroIndirect(type, buffer, loc); auto loaded = builder.emitLoadValueOperation( @@ -7008,7 +6992,8 @@ void PullbackEmitter::accumulateIndirect( proto); assert(!confRef.isInvalid() && "Missing conformance to `AdditiveArithmetic`"); SILDeclRef declRef(combinerFuncDecl, SILDeclRef::Kind::Func); - auto silFnTy = getContext().getTypeConverter().getConstantType(declRef); + auto silFnTy = getContext().getTypeConverter().getConstantType( + TypeExpansionContext::minimal(), declRef); // %0 = witness_method @+ auto witnessMethod = builder.createWitnessMethod(loc, adjointASTTy, confRef, declRef, @@ -7065,7 +7050,8 @@ void PullbackEmitter::accumulateIndirect(SILValue lhsDestAccess, auto confRef = swiftMod->lookupConformance(astType, proto); assert(!confRef.isInvalid() && "Missing conformance to `AdditiveArithmetic`"); SILDeclRef declRef(accumulatorFuncDecl, SILDeclRef::Kind::Func); - auto silFnTy = getContext().getTypeConverter().getConstantType(declRef); + auto silFnTy = getContext().getTypeConverter().getConstantType( + TypeExpansionContext::minimal(), declRef); // %0 = witness_method @+= auto witnessMethod = builder.createWitnessMethod(loc, astType, confRef, declRef, silFnTy); @@ -7118,21 +7104,12 @@ bool VJPEmitter::run() { if (errorOccurred) return true; - // Each `@guaranteed` trampoline argument needs to have a lifetime-ending use - // past its destination argument's lifetime-ending uses (aka. `end_borrow`). - // `trampolinedGuaranteedPhiArguments` tracks all `@guaranteed` trampoline - // arguments. We emit an `end_borrow` immediately past each destination - // argument's lifetime-ending uses. - for (auto &trampolinedArgPair : trampolinedGuaranteedPhiArguments) { - for (auto *destArgUse : trampolinedArgPair.destinationArgument->getUses()) { - if (auto *lifetimeEnd = dyn_cast(destArgUse->getUser())) { - getBuilder().setInsertionPoint(lifetimeEnd->getParentBlock(), - std::next(lifetimeEnd->getIterator())); - getBuilder().emitEndBorrowOperation( - lifetimeEnd->getLoc(), trampolinedArgPair.trampolineArgument); - } - } - } + // Merge VJP basic blocks. This is significant for control flow + // differentiation: trampoline destination bbs are merged into trampoline bbs. + // NOTE(TF-990): Merging basic blocks ensures that `@guaranteed` trampoline + // bb arguments have a lifetime-ending `end_borrow` use, and is robust when + // `-enable-strip-ownership-after-serialization` is true. + mergeBasicBlocks(vjp); // Generate pullback code. PullbackEmitter PullbackEmitter(*this); diff --git a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp index 091ab93943547..434f9b1665886 100644 --- a/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp +++ b/lib/SILOptimizer/Mandatory/OSLogOptimization.cpp @@ -89,6 +89,7 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILLocation.h" #include "swift/SIL/SILModule.h" +#include "swift/SIL/TypeLowering.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/CFGOptUtils.h" @@ -101,6 +102,7 @@ #include "llvm/ADT/MapVector.h" using namespace swift; +using namespace Lowering; template static void diagnose(ASTContext &Context, SourceLoc loc, Diag diag, @@ -239,6 +241,12 @@ static bool isStringType(SILType silType, ASTContext &astContext) { return nominalDecl && nominalDecl == astContext.getStringDecl(); } +/// Return true if and only if the given SIL type represents an Array type. +static bool isArrayType(SILType silType, ASTContext &astContext) { + NominalTypeDecl *nominalDecl = silType.getNominalOrBoundGenericNominal(); + return nominalDecl && nominalDecl == astContext.getArrayDecl(); +} + /// Decide if the given instruction (which could possibly be a call) should /// be constant evaluated. /// @@ -274,20 +282,52 @@ evaluateOrSkip(ConstExprStepEvaluator &stepEval, /// Return true iff the given value is a stdlib Int or Bool and it not a direct /// construction of Int or Bool. -static bool isFoldableIntOrBool(SILValue value, SILInstruction *definingInst, - ASTContext &astContext) { - assert(definingInst); - return !isa(definingInst) && - isIntegerOrBoolType(value->getType(), astContext); +static bool isFoldableIntOrBool(SILValue value, ASTContext &astContext) { + return isIntegerOrBoolType(value->getType(), astContext) && + !isa(value); } /// Return true iff the given value is a string and is not an initialization /// of an string from a string literal. -static bool isFoldableString(SILValue value, SILInstruction *definingInst, - ASTContext &astContext) { - assert(definingInst); +static bool isFoldableString(SILValue value, ASTContext &astContext) { return isStringType(value->getType(), astContext) && - !getStringMakeUTF8Init(definingInst); + (!isa(value) || + !getStringMakeUTF8Init(cast(value))); +} + +/// Return true iff the given value is an array and is not an initialization +/// of an array from an array literal. +static bool isFoldableArray(SILValue value, ASTContext &astContext) { + if (!isArrayType(value->getType(), astContext)) + return false; + // If value is an initialization of an array from a literal or an empty array + // initializer, it need not be folded. Arrays constructed from literals use a + // function with semantics: "array.uninitialized_intrinsic" that returns + // a pair, where the first element of the pair is the array. + SILInstruction *definingInst = value->getDefiningInstruction(); + if (!definingInst) + return true; + SILInstruction *constructorInst = definingInst; + if (isa(definingInst) || + isa(definingInst)) { + constructorInst = definingInst->getOperand(0)->getDefiningInstruction(); + } + if (!constructorInst || !isa(constructorInst)) + return true; + SILFunction *callee = cast(constructorInst)->getCalleeFunction(); + return !callee || + (!callee->hasSemanticsAttr("array.init.empty") && + !callee->hasSemanticsAttr("array.uninitialized_intrinsic")); +} + +/// Return true iff the given value is a closure but is not a creation of a +/// closure e.g., through partial_apply or thin_to_thick_function or +/// convert_function. +static bool isFoldableClosure(SILValue value) { + return value->getType().is() && + (!isa(value) && !isa(value) && + !isa(value) && + !isa(value)); } /// Check whether a SILValue is foldable. String, integer, array and @@ -307,8 +347,9 @@ static bool isSILValueFoldable(SILValue value) { !isa(definingInst) && !isa(definingInst) && !isa(definingInst) && - (isFoldableIntOrBool(value, definingInst, astContext) || - isFoldableString(value, definingInst, astContext))); + (isFoldableIntOrBool(value, astContext) || + isFoldableString(value, astContext) || + isFoldableArray(value, astContext) || isFoldableClosure(value))); } /// Diagnose failure during evaluation of a call to a constant-evaluable @@ -450,6 +491,143 @@ static Optional collectConstants(FoldState &foldState) { return None; // No error. } +/// Generate SIL code to create an array of constant size from the given +/// SILValues \p elements. This function creates the same sequence of SIL +/// instructions that would be generated for initializing an array from an array +/// literal of the form [element1, element2, ..., elementn]. +/// +/// \param elements SILValues that the array should contain +/// \param arrayType the type of the array that must be created. +/// \param builder SILBuilder that provides the context for emitting the code +/// for the array. +/// \param loc SILLocation to use in the emitted instructions. +/// \return the SILValue of the array that is created with the given \c +/// elements. +static SILValue emitCodeForConstantArray(ArrayRef elements, + CanType arrayType, SILBuilder &builder, + SILLocation loc) { + ASTContext &astContext = builder.getASTContext(); + assert(astContext.getArrayDecl() == + arrayType->getNominalOrBoundGenericNominal()); + SILModule &module = builder.getModule(); + SILFunction &fun = builder.getFunction(); + + // Create a SILValue for the number of elements. + unsigned numElements = elements.size(); + SILValue numElementsSIL = builder.createIntegerLiteral( + loc, SILType::getBuiltinWordType(astContext), numElements); + + // Find the SILFunction that corresponds to _allocateUninitializedArray. + FuncDecl *arrayAllocateDecl = astContext.getAllocateUninitializedArray(); + assert(arrayAllocateDecl); + std::string allocatorMangledName = + SILDeclRef(arrayAllocateDecl, SILDeclRef::Kind::Func).mangle(); + SILFunction *arrayAllocateFun = + module.findFunction(allocatorMangledName, SILLinkage::PublicExternal); + assert(arrayAllocateFun); + + // Call the _allocateUninitializedArray function with numElementsSIL. The + // call returns a two-element tuple, where the first element is the newly + // created array and the second element is a pointer to the internal storage + // of the array. + SubstitutionMap subMap = arrayType->getContextSubstitutionMap( + module.getSwiftModule(), astContext.getArrayDecl()); + FunctionRefInst *arrayAllocateRef = + builder.createFunctionRef(loc, arrayAllocateFun); + ApplyInst *applyInst = builder.createApply( + loc, arrayAllocateRef, subMap, ArrayRef(numElementsSIL), false); + + // Extract the elements of the tuple returned by the call to the allocator. + SILValue arraySIL; + SILValue storagePointerSIL; + if (fun.hasOwnership()) { + DestructureTupleInst *destructureInst = + builder.createDestructureTuple(loc, applyInst); + arraySIL = destructureInst->getResults()[0]; + storagePointerSIL = destructureInst->getResults()[1]; + } else { + SILType arraySILType = SILType::getPrimitiveObjectType(arrayType); + arraySIL = builder.createTupleExtract(loc, applyInst, 0, arraySILType); + storagePointerSIL = builder.createTupleExtract( + loc, applyInst, 1, SILType::getRawPointerType(astContext)); + } + + if (elements.empty()) { + // Nothing more to be done if we are creating an empty array. + return arraySIL; + } + + // Convert the pointer to the storage to an address. The elements will be + // stored into offsets from this address. + SILType elementSILType = elements[0]->getType(); + PointerToAddressInst *storageAddr = builder.createPointerToAddress( + loc, storagePointerSIL, elementSILType.getAddressType(), + /*isStrict*/ true, + /*isInvariant*/ false); + + // Iterate over the elements and store them into the storage address + // after offsetting it appropriately. + + // Create a TypeLowering for emitting stores. Note that TypeLowering + // provides a utility for emitting stores for storing trivial and + // non-trivial values, and also handles OSSA and non-OSSA. + const TypeLowering &elementTypeLowering = + builder.getTypeLowering(elementSILType); + + unsigned elementIndex = 0; + for (SILValue elementSIL : elements) { + // Compute the address where the element must be stored. + SILValue currentStorageAddr; + if (elementIndex != 0) { + SILValue indexSIL = builder.createIntegerLiteral( + loc, SILType::getBuiltinWordType(astContext), elementIndex); + currentStorageAddr = builder.createIndexAddr(loc, storageAddr, indexSIL); + } else { + currentStorageAddr = storageAddr; + } + // Store the generated element into the currentStorageAddr. This is an + // initializing store and therefore there is no need to free any existing + // element. + elementTypeLowering.emitStore(builder, loc, elementSIL, currentStorageAddr, + StoreOwnershipQualifier::Init); + elementIndex++; + } + return arraySIL; +} + +/// Given a SILValue \p value, return the instruction immediately following the +/// definition of the value. That is, if the value is defined by an +/// instruction, return the instruction following the definition. Otherwise, if +/// the value is a basic block parameter, return the first instruction of the +/// basic block. +SILInstruction *getInstructionFollowingValueDefinition(SILValue value) { + SILInstruction *definingInst = value->getDefiningInstruction(); + if (definingInst) { + return &*std::next(definingInst->getIterator()); + } + // Here value must be a basic block argument. + SILBasicBlock *bb = value->getParentBlock(); + return &*bb->begin(); +} + +/// Given a SILValue \p value, create a copy of the value using copy_value in +/// OSSA or retain in non-OSSA, if \p value is a non-trivial type. Otherwise, if +/// \p value is a trivial type, return the value itself. +SILValue makeOwnedCopyOfSILValue(SILValue value, SILFunction &fun) { + SILType type = value->getType(); + if (type.isTrivial(fun)) + return value; + assert(!type.isAddress() && "cannot make owned copy of addresses"); + + SILInstruction *instAfterValueDefinition = + getInstructionFollowingValueDefinition(value); + SILLocation copyLoc = instAfterValueDefinition->getLoc(); + SILBuilderWithScope builder(instAfterValueDefinition); + const TypeLowering &typeLowering = builder.getTypeLowering(type); + SILValue copy = typeLowering.emitCopyValue(builder, copyLoc, value); + return copy; +} + /// Generate SIL code that computes the constant given by the symbolic value /// `symVal`. Note that strings and struct-typed constant values will require /// multiple instructions to be emitted. @@ -532,6 +710,78 @@ static SILValue emitCodeForSymbolicValue(SymbolicValue symVal, loc, aggregateType, ArrayRef(newPropertySIL)); return newStructInst; } + case SymbolicValue::Array: { + assert(expectedType->isEqual(symVal.getArrayType())); + CanType elementType; + ArrayRef arrayElements = + symVal.getStorageOfArray().getStoredElements(elementType); + + // Emit code for the symbolic values corresponding to the array elements. + SmallVector elementSILValues; + for (SymbolicValue elementSymVal : arrayElements) { + SILValue elementSIL = emitCodeForSymbolicValue(elementSymVal, elementType, + builder, loc, stringInfo); + elementSILValues.push_back(elementSIL); + } + SILValue arraySIL = emitCodeForConstantArray( + elementSILValues, expectedType->getCanonicalType(), builder, loc); + return arraySIL; + } + case SymbolicValue::Closure: { + assert(expectedType->is() || + expectedType->is()); + + SymbolicClosure *closure = symVal.getClosure(); + SubstitutionMap callSubstMap = closure->getCallSubstitutionMap(); + SILModule &module = builder.getModule(); + ArrayRef captures = closure->getCaptures(); + + // Recursively emit code for all captured values that are mapped to a + // symbolic value. If there is a captured value that is not mapped + // to a symbolic value, use the captured value as such (after possibly + // copying non-trivial captures). + SmallVector capturedSILVals; + for (SymbolicClosureArgument capture : captures) { + SILValue captureOperand = capture.first; + Optional captureSymVal = capture.second; + if (!captureSymVal) { + SILFunction &fun = builder.getFunction(); + assert(captureOperand->getFunction() == &fun && + "non-constant captured arugment not defined in this function"); + // If the captureOperand is a non-trivial value, it should be copied + // as it now used in a new folded closure. + SILValue captureCopy = makeOwnedCopyOfSILValue(captureOperand, fun); + capturedSILVals.push_back(captureCopy); + continue; + } + // Here, we have a symbolic value for the capture. Therefore, use it to + // create a new constant at this point. Note that the captured operand + // type may have generic parameters which has to be substituted with the + // substitution map that was inferred by the constant evaluator at the + // partial-apply site. + SILType operandType = captureOperand->getType(); + SILType captureType = operandType.subst(module, callSubstMap); + SILValue captureSILVal = emitCodeForSymbolicValue( + captureSymVal.getValue(), captureType.getASTType(), builder, loc, + stringInfo); + capturedSILVals.push_back(captureSILVal); + } + + FunctionRefInst *functionRef = + builder.createFunctionRef(loc, closure->getTarget()); + SILType closureType = closure->getClosureType(); + ParameterConvention convention = + closureType.getAs()->getCalleeConvention(); + PartialApplyInst *papply = builder.createPartialApply( + loc, functionRef, callSubstMap, capturedSILVals, convention); + // The type of the created closure must be a lowering of the expected type. + SILType resultType = papply->getType(); + CanType expectedCanType = expectedType->getCanonicalType(); + assert(expectedType->is() + ? resultType.getASTType() == expectedCanType + : resultType.is()); + return papply; + } default: { llvm_unreachable("Symbolic value kind is not supported"); } @@ -631,12 +881,10 @@ static void replaceAllUsesAndFixLifetimes(SILValue foldedVal, "cannot constant fold a terminator instruction"); assert(foldedInst && "constant value does not have a defining instruction"); - // First, replace all uses of originalVal by foldedVal, and then adjust their - // lifetimes if necessary. - originalVal->replaceAllUsesWith(foldedVal); - if (originalVal->getType().isTrivial(*fun)) { assert(foldedVal->getType().isTrivial(*fun)); + // Just replace originalVal by foldedVal. + originalVal->replaceAllUsesWith(foldedVal); return; } assert(!foldedVal->getType().isTrivial(*fun)); @@ -644,12 +892,34 @@ static void replaceAllUsesAndFixLifetimes(SILValue foldedVal, if (!fun->hasOwnership()) { // In non-ownership SIL, handle only folding of struct_extract instruction, // which is the only important instruction that should be folded by this - // pass. Note that folding an arbitrary instruction in non-ownership SIL - // makes updating reference counts of the original value much harder and - // error prone. + // pass. The logic used here is not correct in general and overfits a + // specific form of SIL. This code should be removed once OSSA is enabled + // for this pass. // TODO: this code can be safely removed once ownership SIL becomes the // default SIL this pass works on. - assert(isa(originalInst)); + assert(isa(originalInst) && + !originalVal->getType().isAddress()); + + // First, replace all uses of originalVal by foldedVal, and then adjust + // their lifetimes if necessary. + originalVal->replaceAllUsesWith(foldedVal); + + unsigned retainCount = 0; + unsigned consumeCount = 0; + for (Operand *use : foldedVal->getUses()) { + SILInstruction *user = use->getUser(); + if (isa(user) || isa(user)) + consumeCount++; + if (isa(user)) + retainCount++; + // Note that there could other consuming operations but they are not + // handled here as this code should be phased out soon. + } + if (consumeCount > retainCount) { + // The original value was at +1 and therefore consumed at the end. Since + // the foldedVal is also at +1 there is nothing to be done. + return; + } cleanupAtEndOfLifetime(foldedInst, [&](SILInstruction *lifetimeEndInst) { SILBuilderWithScope builder(lifetimeEndInst); builder.emitReleaseValue(lifetimeEndInst->getLoc(), foldedVal); @@ -661,6 +931,7 @@ static void replaceAllUsesAndFixLifetimes(SILValue foldedVal, "constant value must have owned ownership kind"); if (originalVal.getOwnershipKind() == ValueOwnershipKind::Owned) { + originalVal->replaceAllUsesWith(foldedVal); // Destroy originalVal, which is now unused, immediately after its // definition. Note that originalVal's destorys are now transferred to // foldedVal. @@ -671,10 +942,20 @@ static void replaceAllUsesAndFixLifetimes(SILValue foldedVal, return; } - // Here, originalVal is not owned. Hence, destroy foldedVal at the end of its + // Here, originalVal is not owned. Hence, borrow form foldedVal and use the + // borrow in place of originalVal. Also, destroy foldedVal at the end of its // lifetime. - cleanupAtEndOfLifetime(foldedInst, [&](SILInstruction *lifetimeEndInst) { + assert(originalVal.getOwnershipKind() == ValueOwnershipKind::Guaranteed); + + SILBuilderWithScope builder(&*std::next(foldedInst->getIterator())); + BeginBorrowInst *borrow = + builder.createBeginBorrow(foldedInst->getLoc(), foldedVal); + + originalVal->replaceAllUsesWith(borrow); + + cleanupAtEndOfLifetime(borrow, [&](SILInstruction *lifetimeEndInst) { SILBuilderWithScope builder(lifetimeEndInst); + builder.createEndBorrow(lifetimeEndInst->getLoc(), borrow); builder.emitDestroyValueOperation(lifetimeEndInst->getLoc(), foldedVal); }); return; @@ -753,9 +1034,11 @@ static bool checkOSLogMessageIsConstant(SingleValueInstruction *osLogMessage, StructDecl *structDecl = osLogMessageType.getStructOrBoundGenericStruct(); assert(structDecl); + auto typeExpansionContext = + TypeExpansionContext(*osLogMessage->getFunction()); VarDecl *interpolationPropDecl = structDecl->getStoredProperties().front(); - SILType osLogInterpolationType = - osLogMessageType.getFieldType(interpolationPropDecl, module); + SILType osLogInterpolationType = osLogMessageType.getFieldType( + interpolationPropDecl, module, typeExpansionContext); StructDecl *interpolationStruct = osLogInterpolationType.getStructOrBoundGenericStruct(); assert(interpolationStruct); @@ -780,7 +1063,7 @@ static bool checkOSLogMessageIsConstant(SingleValueInstruction *osLogMessage, /// Constant evaluate instructions starting from 'start' and fold the uses /// of the value 'oslogMessage'. Stop when oslogMessageValue is released. -static void constantFold(SILInstruction *start, +static bool constantFold(SILInstruction *start, SingleValueInstruction *oslogMessage, unsigned assertConfig) { SILFunction *fun = start->getFunction(); @@ -794,7 +1077,7 @@ static void constantFold(SILInstruction *start, auto errorInfo = collectConstants(state); if (errorInfo) // Evaluation failed with diagnostics. - return; + return false; // At this point, the `OSLogMessage` instance should be mapped to a constant // value in the interpreter state. If this is not the case, it means the @@ -802,9 +1085,10 @@ static void constantFold(SILInstruction *start, // incorrect. Detect and diagnose this scenario. bool errorDetected = checkOSLogMessageIsConstant(oslogMessage, state); if (errorDetected) - return; + return false; substituteConstants(state); + return true; } /// Given a call to the initializer of OSLogMessage, which conforms to @@ -812,8 +1096,9 @@ static void constantFold(SILInstruction *start, /// marks the begining of the string interpolation that is used to create an /// OSLogMessage instance. This function traverses the backward data-dependence /// chain of the given OSLogMessage initializer: \p oslogInit. As a special case -/// it avoid chasing the data-dependenceies through a partial-apply as they are -/// considered as constants. +/// it avoids chasing the data-dependencies from the captured values of +/// partial-apply instructions, as a partial apply instruction is considered as +/// a constant regardless of the constantness of its captures. static SILInstruction *beginOfInterpolation(ApplyInst *oslogInit) { auto oslogInitCallSite = FullApplySite(oslogInit); SILFunction *callee = oslogInitCallSite.getCalleeFunction(); @@ -838,7 +1123,14 @@ static SILInstruction *beginOfInterpolation(ApplyInst *oslogInit) { // Partial applies are used to capture the dynamic arguments passed to // the string interpolation. Their arguments are not required to be // known at compile time and they need not be constant evaluated. - // Therefore, do not follow this dependency chain. + // Therefore, follow only the dependency chain along function ref operand. + SILInstruction *definingInstruction = + inst->getOperand(0)->getDefiningInstruction(); + assert(definingInstruction && "no function-ref operand in partial-apply"); + if (seenInstructions.insert(definingInstruction).second) { + worklist.push_back(definingInstruction); + candidateStartInstructions.insert(definingInstruction); + } continue; } @@ -992,13 +1284,20 @@ class OSLogOptimization : public SILFunctionTransform { } } + bool madeChange = false; + // Constant fold the uses of properties of OSLogMessage instance. Note that // the function body will change due to constant folding, after each // iteration. for (auto *oslogInit : oslogMessageInits) { SILInstruction *interpolationStart = beginOfInterpolation(oslogInit); assert(interpolationStart); - constantFold(interpolationStart, oslogInit, assertConfig); + madeChange |= constantFold(interpolationStart, oslogInit, assertConfig); + } + + // TODO: Can we be more conservative here with our invalidation? + if (madeChange) { + invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody); } } }; diff --git a/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp index 402d40edf5c77..40c47fd45f47d 100644 --- a/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp +++ b/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp @@ -258,7 +258,8 @@ static void splitDestructure(SILBuilder &B, SILInstruction *I, SILValue Op) { SILType OpType = Op->getType(); llvm::SmallVector Projections; - Projection::getFirstLevelProjections(OpType, M, Projections); + Projection::getFirstLevelProjections(OpType, M, B.getTypeExpansionContext(), + Projections); assert(Projections.size() == I->getNumResults()); auto Results = I->getResults(); diff --git a/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp index a333d41114343..5aa0d49fa6034 100644 --- a/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp +++ b/lib/SILOptimizer/Mandatory/PMOMemoryUseCollector.cpp @@ -34,7 +34,9 @@ PMOMemoryObjectInfo::PMOMemoryObjectInfo(AllocationInst *allocation) if (auto *abi = dyn_cast(MemoryInst)) { assert(abi->getBoxType()->getLayout()->getFields().size() == 1 && "analyzing multi-field boxes not implemented"); - MemorySILType = getSILBoxFieldType(abi->getBoxType(), module.Types, 0); + MemorySILType = + getSILBoxFieldType(TypeExpansionContext(*abi->getFunction()), + abi->getBoxType(), module.Types, 0); } else { MemorySILType = cast(MemoryInst)->getElementType(); } diff --git a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp index 586938773f638..4ad37b981c35a 100644 --- a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp +++ b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp @@ -13,14 +13,18 @@ #define DEBUG_TYPE "predictable-memopt" #include "PMOMemoryUseCollector.h" +#include "swift/Basic/BlotSetVector.h" +#include "swift/Basic/STLExtras.h" #include "swift/SIL/BasicBlockUtils.h" #include "swift/SIL/BranchPropagatedUser.h" #include "swift/SIL/OwnershipUtils.h" #include "swift/SIL/SILBuilder.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/CFGOptUtils.h" #include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/SILSSAUpdater.h" +#include "swift/SILOptimizer/Utils/ValueLifetime.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Compiler.h" @@ -47,19 +51,22 @@ getFullyReferenceableStruct(SILType Ty) { return SD; } -static unsigned getNumSubElements(SILType T, SILModule &M) { +static unsigned getNumSubElements(SILType T, SILModule &M, + TypeExpansionContext context) { if (auto TT = T.getAs()) { unsigned NumElements = 0; for (auto index : indices(TT.getElementTypes())) - NumElements += getNumSubElements(T.getTupleElementType(index), M); + NumElements += + getNumSubElements(T.getTupleElementType(index), M, context); return NumElements; } if (auto *SD = getFullyReferenceableStruct(T)) { unsigned NumElements = 0; for (auto *D : SD->getStoredProperties()) - NumElements += getNumSubElements(T.getFieldType(D, M), M); + NumElements += + getNumSubElements(T.getFieldType(D, M, context), M, context); return NumElements; } @@ -127,7 +134,9 @@ static unsigned computeSubelement(SILValue Pointer, // Keep track of what subelement is being referenced. for (unsigned i = 0, e = TEAI->getFieldNo(); i != e; ++i) { - SubElementNumber += getNumSubElements(TT.getTupleElementType(i), M); + SubElementNumber += + getNumSubElements(TT.getTupleElementType(i), M, + TypeExpansionContext(*RootInst->getFunction())); } Pointer = TEAI->getOperand(); continue; @@ -140,7 +149,9 @@ static unsigned computeSubelement(SILValue Pointer, StructDecl *SD = SEAI->getStructDecl(); for (auto *D : SD->getStoredProperties()) { if (D == SEAI->getField()) break; - SubElementNumber += getNumSubElements(ST.getFieldType(D, M), M); + auto context = TypeExpansionContext(*RootInst->getFunction()); + SubElementNumber += + getNumSubElements(ST.getFieldType(D, M, context), M, context); } Pointer = SEAI->getOperand(); @@ -316,7 +327,8 @@ static SILValue nonDestructivelyExtractSubElement(const AvailableValue &Val, for (unsigned EltNo : indices(TT.getElementTypes())) { // Keep track of what subelement is being referenced. SILType EltTy = ValTy.getTupleElementType(EltNo); - unsigned NumSubElt = getNumSubElements(EltTy, B.getModule()); + unsigned NumSubElt = getNumSubElements( + EltTy, B.getModule(), TypeExpansionContext(B.getFunction())); if (SubElementNumber < NumSubElt) { auto BorrowedVal = Val.emitBeginBorrow(B, Loc); auto NewVal = @@ -338,9 +350,11 @@ static SILValue nonDestructivelyExtractSubElement(const AvailableValue &Val, // Extract struct elements. if (auto *SD = getFullyReferenceableStruct(ValTy)) { for (auto *D : SD->getStoredProperties()) { - auto fieldType = ValTy.getFieldType(D, B.getModule()); - unsigned NumSubElt = getNumSubElements(fieldType, B.getModule()); - + auto fieldType = ValTy.getFieldType( + D, B.getModule(), TypeExpansionContext(B.getFunction())); + unsigned NumSubElt = getNumSubElements( + fieldType, B.getModule(), TypeExpansionContext(B.getFunction())); + if (SubElementNumber < NumSubElt) { auto BorrowedVal = Val.emitBeginBorrow(B, Loc); auto NewVal = @@ -387,6 +401,12 @@ static bool anyMissing(unsigned StartSubElt, unsigned NumSubElts, namespace { +enum class AvailableValueExpectedOwnership { + Take, + Borrow, + Copy, +}; + /// A class that aggregates available values, loading them if they are not /// available. class AvailableValueAggregator { @@ -396,7 +416,7 @@ class AvailableValueAggregator { MutableArrayRef AvailableValueList; SmallVectorImpl &Uses; DeadEndBlocks &deadEndBlocks; - bool isTake; + AvailableValueExpectedOwnership expectedOwnership; /// Keep track of all instructions that we have added. Once we are done /// promoting a value, we need to make sure that if we need to balance any @@ -404,14 +424,23 @@ class AvailableValueAggregator { /// take. SmallVector insertedInsts; + /// The list of phi nodes inserted by the SSA updater. + SmallVector insertedPhiNodes; + + /// A set of copy_values whose lifetime we balanced while inserting phi + /// nodes. This means that these copy_value must be skipped in + /// addMissingDestroysForCopiedValues. + SmallPtrSet copyValueProcessedWithPhiNodes; + public: AvailableValueAggregator(SILInstruction *Inst, MutableArrayRef AvailableValueList, SmallVectorImpl &Uses, - DeadEndBlocks &deadEndBlocks, bool isTake) + DeadEndBlocks &deadEndBlocks, + AvailableValueExpectedOwnership expectedOwnership) : M(Inst->getModule()), B(Inst), Loc(Inst->getLoc()), AvailableValueList(AvailableValueList), Uses(Uses), - deadEndBlocks(deadEndBlocks), isTake(isTake) {} + deadEndBlocks(deadEndBlocks), expectedOwnership(expectedOwnership) {} // This is intended to be passed by reference only once constructed. AvailableValueAggregator(const AvailableValueAggregator &) = delete; @@ -424,17 +453,32 @@ class AvailableValueAggregator { bool isTopLevel = true); bool canTake(SILType loadTy, unsigned firstElt) const; - /// If as a result of us copying values, we may have unconsumed destroys, find - /// the appropriate location and place the values there. Only used when - /// ownership is enabled. - SingleValueInstruction *addMissingDestroysForCopiedValues(LoadBorrowInst *li, - SILValue newVal); - - SingleValueInstruction *addMissingDestroysForCopiedValues(LoadInst *li, - SILValue newVal); - void print(llvm::raw_ostream &os) const; void dump() const LLVM_ATTRIBUTE_USED; + + bool isTake() const { + return expectedOwnership == AvailableValueExpectedOwnership::Take; + } + + bool isBorrow() const { + return expectedOwnership == AvailableValueExpectedOwnership::Borrow; + } + + bool isCopy() const { + return expectedOwnership == AvailableValueExpectedOwnership::Copy; + } + + /// Given a load_borrow that we have aggregated a new value for, fixup the + /// reference counts of the intermediate copies and phis to ensure that all + /// forwarding operations in the CFG are strongly control equivalent (i.e. run + /// the same number of times). + void fixupOwnership(SILInstruction *load, SILValue newVal) { + assert(isa(load) || isa(load)); + + addHandOffCopyDestroysForPhis(load, newVal); + addMissingDestroysForCopiedValues(load, newVal); + } + private: SILValue aggregateFullyAvailableValue(SILType loadTy, unsigned firstElt); SILValue aggregateTupleSubElts(TupleType *tt, SILType loadTy, @@ -444,6 +488,18 @@ class AvailableValueAggregator { SILValue handlePrimitiveValue(SILType loadTy, SILValue address, unsigned firstElt); bool isFullyAvailable(SILType loadTy, unsigned firstElt) const; + + + /// If as a result of us copying values, we may have unconsumed destroys, find + /// the appropriate location and place the values there. Only used when + /// ownership is enabled. + void addMissingDestroysForCopiedValues(SILInstruction *load, SILValue newVal); + + /// As a result of us using the SSA updater, insert hand off copy/destroys at + /// each phi and make sure that intermediate phis do not leak by inserting + /// destroys along paths that go through the intermediate phi that do not also + /// go through the + void addHandOffCopyDestroysForPhis(SILInstruction *load, SILValue newVal); }; } // end anonymous namespace @@ -470,7 +526,8 @@ bool AvailableValueAggregator::isFullyAvailable(SILType loadTy, if (!firstVal || firstVal.getType() != loadTy) return false; - return llvm::all_of(range(getNumSubElements(loadTy, M)), + return llvm::all_of(range(getNumSubElements( + loadTy, M, TypeExpansionContext(B.getFunction()))), [&](unsigned index) -> bool { auto &val = AvailableValueList[firstElt + index]; return val.getValue() == firstVal.getValue() && @@ -496,7 +553,8 @@ bool AvailableValueAggregator::canTake(SILType loadTy, if (TupleType *tt = loadTy.getAs()) { return llvm::all_of(indices(tt->getElements()), [&](unsigned eltNo) { SILType eltTy = loadTy.getTupleElementType(eltNo); - unsigned numSubElt = getNumSubElements(eltTy, M); + unsigned numSubElt = + getNumSubElements(eltTy, M, TypeExpansionContext(B.getFunction())); bool success = canTake(eltTy, firstElt); firstElt += numSubElt; return success; @@ -505,8 +563,9 @@ bool AvailableValueAggregator::canTake(SILType loadTy, if (auto *sd = getFullyReferenceableStruct(loadTy)) { return llvm::all_of(sd->getStoredProperties(), [&](VarDecl *decl) -> bool { - SILType eltTy = loadTy.getFieldType(decl, M); - unsigned numSubElt = getNumSubElements(eltTy, M); + auto context = TypeExpansionContext(B.getFunction()); + SILType eltTy = loadTy.getFieldType(decl, M, context); + unsigned numSubElt = getNumSubElements(eltTy, M, context); bool success = canTake(eltTy, firstElt); firstElt += numSubElt; return success; @@ -526,27 +585,66 @@ SILValue AvailableValueAggregator::aggregateValues(SILType LoadTy, bool isTopLevel) { // If we are performing a take, make sure that we have available values for // /all/ of our values. Otherwise, bail. - if (isTopLevel && isTake && !canTake(LoadTy, FirstElt)) { + if (isTopLevel && isTake() && !canTake(LoadTy, FirstElt)) { return SILValue(); } // Check to see if the requested value is fully available, as an aggregate. // This is a super-common case for single-element structs, but is also a // general answer for arbitrary structs and tuples as well. - if (SILValue Result = aggregateFullyAvailableValue(LoadTy, FirstElt)) + if (SILValue Result = aggregateFullyAvailableValue(LoadTy, FirstElt)) { return Result; + } // If we have a tuple type, then aggregate the tuple's elements into a full // tuple value. - if (TupleType *TT = LoadTy.getAs()) - return aggregateTupleSubElts(TT, LoadTy, Address, FirstElt); + if (TupleType *tupleType = LoadTy.getAs()) { + SILValue result = + aggregateTupleSubElts(tupleType, LoadTy, Address, FirstElt); + if (isTopLevel && + result.getOwnershipKind() == ValueOwnershipKind::Guaranteed) { + SILValue borrowedResult = result; + SILBuilderWithScope builder(&*B.getInsertionPoint(), &insertedInsts); + result = builder.emitCopyValueOperation(Loc, borrowedResult); + SmallVector introducers; + bool foundIntroducers = + getUnderlyingBorrowIntroducingValues(borrowedResult, introducers); + (void)foundIntroducers; + assert(foundIntroducers); + for (auto value : introducers) { + builder.emitEndBorrowOperation(Loc, value.value); + } + } + return result; + } // If we have a struct type, then aggregate the struct's elements into a full // struct value. - if (auto *SD = getFullyReferenceableStruct(LoadTy)) - return aggregateStructSubElts(SD, LoadTy, Address, FirstElt); + if (auto *structDecl = getFullyReferenceableStruct(LoadTy)) { + SILValue result = + aggregateStructSubElts(structDecl, LoadTy, Address, FirstElt); + if (isTopLevel && + result.getOwnershipKind() == ValueOwnershipKind::Guaranteed) { + SILValue borrowedResult = result; + SILBuilderWithScope builder(&*B.getInsertionPoint(), &insertedInsts); + result = builder.emitCopyValueOperation(Loc, borrowedResult); + SmallVector introducers; + bool foundIntroducers = + getUnderlyingBorrowIntroducingValues(borrowedResult, introducers); + (void)foundIntroducers; + assert(foundIntroducers); + for (auto value : introducers) { + builder.emitEndBorrowOperation(Loc, value.value); + } + } + return result; + } // Otherwise, we have a non-aggregate primitive. Load or extract the value. + // + // NOTE: We should never call this when taking since when taking we know that + // our underlying value is always fully available. + assert(!isTake()); return handlePrimitiveValue(LoadTy, Address, FirstElt); } @@ -576,7 +674,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy, SILBuilderWithScope builder(insertPts[0], &insertedInsts); SILLocation loc = insertPts[0]->getLoc(); // If we have a take, just return the value. - if (isTake) + if (isTake()) return firstVal.getValue(); // Otherwise, return a copy of the value. return builder.emitCopyValueOperation(loc, firstVal.getValue()); @@ -586,7 +684,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy, // SSA updater to get a value. The reason why this is safe is that we can only // have multiple insertion points if we are storing exactly the same value // implying that we can just copy firstVal at each insertion point. - SILSSAUpdater updater; + SILSSAUpdater updater(&insertedPhiNodes); updater.Initialize(loadTy); Optional singularValue; @@ -597,7 +695,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy, SILValue eltVal = firstVal.getValue(); // If we are not taking, copy the element value. - if (!isTake) { + if (!isTake()) { eltVal = builder.emitCopyValueOperation(loc, eltVal); } @@ -613,13 +711,31 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy, // If we only are tracking a singular value, we do not need to construct // SSA. Just return that value. - if (auto val = singularValue.getValueOr(SILValue())) + if (auto val = singularValue.getValueOr(SILValue())) { + // This assert documents that we are expecting that if we are in ossa, have + // a non-trivial value, and are not taking, we should never go down this + // code path. If we did, we would need to insert a copy here. The reason why + // we know we will never go down this code path is since we have been + // inserting copy_values implying that our potential singular value would be + // of the copy_values which are guaranteed to all be different. + assert((!B.hasOwnership() || isTake() || + val->getType().isTrivial(*B.getInsertionBB()->getParent())) && + "Should never reach this code path if we are in ossa and have a " + "non-trivial value"); return val; + } // Finally, grab the value from the SSA updater. SILValue result = updater.GetValueInMiddleOfBlock(B.getInsertionBB()); assert(result.getOwnershipKind().isCompatibleWith(ValueOwnershipKind::Owned)); - return result; + if (isTake() || !B.hasOwnership()) { + return result; + } + + // Be careful with this value and insert a copy in our load block to prevent + // any weird control equivalence issues. + SILBuilderWithScope builder(&*B.getInsertionPoint(), &insertedInsts); + return builder.emitCopyValueOperation(Loc, result); } SILValue AvailableValueAggregator::aggregateTupleSubElts(TupleType *TT, @@ -630,13 +746,14 @@ SILValue AvailableValueAggregator::aggregateTupleSubElts(TupleType *TT, for (unsigned EltNo : indices(TT->getElements())) { SILType EltTy = LoadTy.getTupleElementType(EltNo); - unsigned NumSubElt = getNumSubElements(EltTy, M); + unsigned NumSubElt = + getNumSubElements(EltTy, M, TypeExpansionContext(B.getFunction())); // If we are missing any of the available values in this struct element, // compute an address to load from. SILValue EltAddr; if (anyMissing(FirstElt, NumSubElt, AvailableValueList)) { - assert(!isTake && "When taking, values should never be missing?!"); + assert(!isTake() && "When taking, values should never be missing?!"); EltAddr = B.createTupleElementAddr(Loc, Address, EltNo, EltTy.getAddressType()); } @@ -646,6 +763,15 @@ SILValue AvailableValueAggregator::aggregateTupleSubElts(TupleType *TT, FirstElt += NumSubElt; } + // If we are going to use this to promote a borrowed value, insert borrow + // operations. Eventually I am going to do this for everything, but this + // should make it easier to bring up. + if (!isTake()) { + for (unsigned i : indices(ResultElts)) { + ResultElts[i] = B.emitBeginBorrowOperation(Loc, ResultElts[i]); + } + } + return B.createTuple(Loc, LoadTy, ResultElts); } @@ -656,14 +782,15 @@ SILValue AvailableValueAggregator::aggregateStructSubElts(StructDecl *sd, SmallVector resultElts; for (auto *decl : sd->getStoredProperties()) { - SILType eltTy = loadTy.getFieldType(decl, M); - unsigned numSubElt = getNumSubElements(eltTy, M); + auto context = TypeExpansionContext(B.getFunction()); + SILType eltTy = loadTy.getFieldType(decl, M, context); + unsigned numSubElt = getNumSubElements(eltTy, M, context); // If we are missing any of the available values in this struct element, // compute an address to load from. SILValue eltAddr; if (anyMissing(firstElt, numSubElt, AvailableValueList)) { - assert(!isTake && "When taking, values should never be missing?!"); + assert(!isTake() && "When taking, values should never be missing?!"); eltAddr = B.createStructElementAddr(Loc, address, decl, eltTy.getAddressType()); } @@ -673,24 +800,32 @@ SILValue AvailableValueAggregator::aggregateStructSubElts(StructDecl *sd, firstElt += numSubElt; } + if (!isTake()) { + for (unsigned i : indices(resultElts)) { + resultElts[i] = B.emitBeginBorrowOperation(Loc, resultElts[i]); + } + } + return B.createStruct(Loc, loadTy, resultElts); } -// We have looked through all of the aggregate values and finally found a -// "primitive value". If the value is available, use it (extracting if we need -// to), otherwise emit a load of the value with the appropriate qualifier. +// We have looked through all of the aggregate values and finally found a value +// that is not available without transforming, i.e. a "primitive value". If the +// value is available, use it (extracting if we need to), otherwise emit a load +// of the value with the appropriate qualifier. SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy, SILValue address, unsigned firstElt) { - auto &val = AvailableValueList[firstElt]; + assert(!isTake() && "Should only take fully available values?!"); // If the value is not available, load the value and update our use list. + auto &val = AvailableValueList[firstElt]; if (!val) { - assert(!isTake && "Should only take fully available values?!"); LoadInst *load = ([&]() { if (B.hasOwnership()) { - return B.createTrivialLoadOr(Loc, address, - LoadOwnershipQualifier::Copy); + SILBuilderWithScope builder(&*B.getInsertionPoint(), &insertedInsts); + return builder.createTrivialLoadOr(Loc, address, + LoadOwnershipQualifier::Copy); } return B.createLoad(Loc, address, LoadOwnershipQualifier::Unqualified); }()); @@ -712,12 +847,21 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy, !builder.hasOwnership() || eltVal.getOwnershipKind().isCompatibleWith(ValueOwnershipKind::Owned)); assert(eltVal->getType() == loadTy && "Subelement types mismatch"); - return eltVal; + + if (!builder.hasOwnership()) { + return eltVal; + } + + SILBuilderWithScope builder2(&*B.getInsertionPoint(), &insertedInsts); + return builder2.emitCopyValueOperation(Loc, eltVal); } // If we have an available value, then we want to extract the subelement from - // the borrowed aggregate before each insertion point. - SILSSAUpdater updater; + // the borrowed aggregate before each insertion point. Note that since we have + // inserted copies at each of these insertion points, we know that we will + // never have the same value along all paths unless we have a trivial value + // meaning the SSA updater given a non-trivial value must /always/ be used. + SILSSAUpdater updater(&insertedPhiNodes); updater.Initialize(loadTy); Optional singularValue; @@ -739,37 +883,335 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy, updater.AddAvailableValue(i->getParent(), eltVal); } - // If we only are tracking a singular value, we do not need to construct - // SSA. Just return that value. - if (auto val = singularValue.getValueOr(SILValue())) + SILBasicBlock *insertBlock = B.getInsertionBB(); + + // If we are not in ossa and have a singular value or if we are in ossa and + // have a trivial singular value, just return that value. + // + // This can never happen for non-trivial values in ossa since we never should + // visit this code path if we have a take implying that non-trivial values + // /will/ have a copy and thus are guaranteed (since each copy yields a + // different value) to not be singular values. + if (auto val = singularValue.getValueOr(SILValue())) { + assert((!B.hasOwnership() || + val->getType().isTrivial(*insertBlock->getParent())) && + "Should have inserted copies for each insertion point, so shouldn't " + "have a singular value if non-trivial?!"); return val; + } // Finally, grab the value from the SSA updater. - SILValue eltVal = updater.GetValueInMiddleOfBlock(B.getInsertionBB()); + SILValue eltVal = updater.GetValueInMiddleOfBlock(insertBlock); assert(!B.hasOwnership() || eltVal.getOwnershipKind().isCompatibleWith(ValueOwnershipKind::Owned)); assert(eltVal->getType() == loadTy && "Subelement types mismatch"); - return eltVal; + if (!B.hasOwnership()) + return eltVal; + SILBuilderWithScope builder(&*B.getInsertionPoint(), &insertedInsts); + return builder.emitCopyValueOperation(Loc, eltVal); } -SingleValueInstruction * -AvailableValueAggregator::addMissingDestroysForCopiedValues(LoadInst *li, - SILValue newVal) { - assert(B.hasOwnership() && - "We assume this is only called if we have ownership"); +static SILInstruction *getNonPhiBlockIncomingValueDef(SILValue incomingValue, + CopyValueInst *phiCopy) { + auto *phiBlock = phiCopy->getParent(); + if (phiBlock == incomingValue->getParentBlock()) { + return nullptr; + } + + if (auto *cvi = dyn_cast(incomingValue)) { + return cvi; + } + + assert(isa(incomingValue)); + + // Otherwise, our copy_value may not be post-dominated by our phi. To + // work around that, we need to insert destroys along the other + // paths. So set base to the first instruction in our argument's block, + // so we can insert destroys for our base. + return &*incomingValue->getParentBlock()->begin(); +} + +static bool +terminatorHasAnyKnownPhis(TermInst *ti, + ArrayRef insertedPhiNodesSorted) { + for (auto succArgList : ti->getSuccessorBlockArguments()) { + if (llvm::any_of(succArgList, [&](SILPhiArgument *arg) { + return binary_search(insertedPhiNodesSorted, arg); + })) { + return true; + } + } + + return false; +} + +namespace { + +class PhiNodeCopyCleanupInserter { + llvm::SmallMapVector incomingValues; + + /// Map from index -> (incomingValueIndex, copy). + /// + /// We are going to stable_sort this array using the indices of + /// incomingValueIndex. This will ensure that we always visit in + /// insertion order our incoming values (since the indices we are + /// sorting by are the count of incoming values we have seen so far + /// when we see the incoming value) and maintain the internal + /// insertion sort within our range as well. This ensures that we + /// visit our incoming values in visitation order and that within + /// their own values, also visit them in visitation order with + /// respect to each other. + SmallVector, 16> copiesToCleanup; + + /// The lifetime frontier that we use to compute lifetime endpoints + /// when emitting cleanups. + ValueLifetimeAnalysis::Frontier lifetimeFrontier; + +public: + PhiNodeCopyCleanupInserter() = default; + + void trackNewCleanup(SILValue incomingValue, CopyValueInst *copy) { + auto entry = std::make_pair(incomingValue, incomingValues.size()); + auto iter = incomingValues.insert(entry); + // If we did not succeed, then iter.first.second is the index of + // incoming value. Otherwise, it will be nextIndex. + copiesToCleanup.emplace_back(iter.first->second, copy); + } + + void emit(DeadEndBlocks &deadEndBlocks) &&; +}; + +} // end anonymous namespace + +void PhiNodeCopyCleanupInserter::emit(DeadEndBlocks &deadEndBlocks) && { + // READ THIS: We are being very careful here to avoid allowing for + // non-determinism to enter here. + // + // 1. First we create a list of indices of our phi node data. Then we use a + // stable sort those indices into the order in which our phi node cleanups + // would be in if we compared just using incomingValues. We use a stable + // sort here to ensure that within the same "cohort" of values, our order + // is insertion order. + // + // 2. We go through the list of phiNodeCleanupStates in insertion order. We + // also maintain a set of already visited base values. When we visit the + // first phiNodeCleanupState for a specific phi, we process the phi + // then. This ensures that we always process the phis in insertion order as + // well. + SmallVector copiesToCleanupIndicesSorted; + llvm::copy(indices(copiesToCleanup), + std::back_inserter(copiesToCleanupIndicesSorted)); + + stable_sort(copiesToCleanupIndicesSorted, + [&](unsigned lhsIndex, unsigned rhsIndex) { + unsigned lhs = copiesToCleanup[lhsIndex].first; + unsigned rhs = copiesToCleanup[rhsIndex].first; + return lhs < rhs; + }); + + for (auto ii = copiesToCleanupIndicesSorted.begin(), + ie = copiesToCleanupIndicesSorted.end(); + ii != ie;) { + unsigned incomingValueIndex = copiesToCleanup[*ii].first; + + // First find the end of the values for which ii does not equal baseValue. + auto rangeEnd = std::find_if_not(std::next(ii), ie, [&](unsigned index) { + return incomingValueIndex == copiesToCleanup[index].first; + }); + + SWIFT_DEFER { + // Once we have finished processing, set ii to rangeEnd. This ensures that + // the code below does not need to worry about updating the iterator. + ii = rangeEnd; + }; + + SILValue incomingValue = + std::next(incomingValues.begin(), incomingValueIndex)->first; + CopyValueInst *phiCopy = copiesToCleanup[*ii].second; + auto *insertPt = getNonPhiBlockIncomingValueDef(incomingValue, phiCopy); + auto loc = RegularLocation::getAutoGeneratedLocation(); + + // Before we do anything, see if we have a single cleanup state. In such a + // case, we could have that we have a phi node as an incoming value and a + // copy_value in that same block. In such a case, we want to just insert the + // copy and continue. This means that + // cleanupState.getNonPhiBlockIncomingValueDef() should always return a + // non-null value in the code below. + if (std::next(ii) == rangeEnd && isa(incomingValue) && + !insertPt) { + SILBasicBlock *phiBlock = phiCopy->getParent(); + SILBuilderWithScope builder(phiBlock->getTerminator()); + builder.createDestroyValue(loc, incomingValue); + continue; + } + + // Otherwise, we know that we have for this incomingValue, multiple + // potential insert pts that we need to handle at the same time with our + // lifetime query. Gather up those uses. + SmallVector users; + transform(llvm::make_range(ii, rangeEnd), std::back_inserter(users), + [&](unsigned index) { return copiesToCleanup[index].second; }); + + // Then lifetime extend our base over the copy_value. + assert(lifetimeFrontier.empty()); + auto *def = getNonPhiBlockIncomingValueDef(incomingValue, phiCopy); + assert(def && "Should never have a nullptr here since we handled all of " + "the single block cases earlier"); + ValueLifetimeAnalysis analysis(def, users); + bool foundCriticalEdges = !analysis.computeFrontier( + lifetimeFrontier, ValueLifetimeAnalysis::DontModifyCFG, &deadEndBlocks); + (void)foundCriticalEdges; + assert(!foundCriticalEdges); + + while (!lifetimeFrontier.empty()) { + auto *insertPoint = lifetimeFrontier.pop_back_val(); + SILBuilderWithScope builder(insertPoint); + builder.createDestroyValue(loc, incomingValue); + } + } +} + +void AvailableValueAggregator::addHandOffCopyDestroysForPhis( + SILInstruction *load, SILValue newVal) { + assert(isa(load) || isa(load)); SmallPtrSet visitedBlocks; SmallVector leakingBlocks; - bool foundLoop = false; + SmallVector, 8> incomingValues; auto loc = RegularLocation::getAutoGeneratedLocation(); - while (!insertedInsts.empty()) { - auto *cvi = dyn_cast(insertedInsts.pop_back_val()); - if (!cvi) + +#ifndef NDEBUG + LLVM_DEBUG(llvm::dbgs() << "Inserted Phis!\n"); + for (auto *phi : insertedPhiNodes) { + LLVM_DEBUG(llvm::dbgs() << "Phi: " << *phi); + } +#endif + + // Before we begin, identify the offset for all phis that are intermediate + // phis inserted by the SSA updater. We are taking advantage of the fact that + // the SSA updater just constructs the web without knowledge of ownership. So + // if a phi node is only used by another phi node that we inserted, then we + // have an intermediate phi node. + // + // TODO: There should be a better way of doing this than doing a copy + sort. + SmallVector insertedPhiNodesSorted; + llvm::copy(insertedPhiNodes, std::back_inserter(insertedPhiNodesSorted)); + llvm::sort(insertedPhiNodesSorted); + + SmallBitVector intermediatePhiOffsets(insertedPhiNodes.size()); + for (unsigned i : indices(insertedPhiNodes)) { + if (TermInst *termInst = + insertedPhiNodes[i]->getSingleUserOfType()) { + // Only set the value if we find termInst has a successor with a phi node + // in our insertedPhiNodes. + if (terminatorHasAnyKnownPhis(termInst, insertedPhiNodesSorted)) { + intermediatePhiOffsets.set(i); + } + } + } + + // First go through all of our phi nodes doing the following: + // + // 1. If any of the phi node have a copy_value as an operand, we know that the + // copy_value does not dominate our final definition since otherwise the + // SSA updater would not have inserted a phi node here. In such a case + // since we may not have that the copy_value is post-dominated by the phi, + // we need to insert a copy_value at the phi to allow for post-domination + // and then use the ValueLifetimeChecker to determine the rest of the + // frontier for the base value. + // + // 2. If our phi node is used by another phi node, we run into a similar + // problem where we could have that our original phi node does not dominate + // our final definition (since the SSA updater would not have inserted the + // phi) and may not be strongly control dependent on our phi. To work + // around this problem, we insert at the phi a copy_value to allow for the + // phi to post_dominate its copy and then extend the lifetime of the phied + // value over that copy. + // + // As an extra complication to this, when we insert compensating releases for + // any copy_values from (1), we need to insert the destroy_value on "base + // values" (either a copy_value or the first instruction of a phi argument's + // block) /after/ we have found all of the base_values to ensure that if the + // same base value is used by multiple phis, we do not insert too many destroy + // value. + // + // NOTE: At first glance one may think that such a problem could not occur + // with phi nodes as well. Sadly if we allow for double backedge loops, it is + // possible (there may be more cases). + PhiNodeCopyCleanupInserter cleanupInserter; + + for (unsigned i : indices(insertedPhiNodes)) { + auto *phi = insertedPhiNodes[i]; + + // If our phi is not owned, continue. No fixes are needed. + if (phi->getOwnershipKind() != ValueOwnershipKind::Owned) continue; - // Clear our state. + LLVM_DEBUG(llvm::dbgs() << "Visiting inserted phi: " << *phi); + // Otherwise, we have a copy_value that may not be strongly control + // equivalent with our phi node. In such a case, we need to use + // ValueLifetimeAnalysis to lifetime extend the copy such that we can + // produce a new copy_value at the phi. We insert destroys along the + // frontier. visitedBlocks.clear(); leakingBlocks.clear(); + incomingValues.clear(); + + phi->getIncomingPhiValues(incomingValues); + unsigned phiIndex = phi->getIndex(); + for (auto pair : incomingValues) { + SILValue value = pair.second; + + // If we had a non-trivial type with non-owned ownership, we will not see + // a copy_value, so skip them here. + if (value.getOwnershipKind() != ValueOwnershipKind::Owned) + continue; + + // Otherwise, value should be from a copy_value or a phi node. + assert(isa(value) || isa(value)); + + // If we have a copy_value, remove it from the inserted insts set so we + // skip it when we start processing insertedInstrs. + if (auto *cvi = dyn_cast(value)) { + copyValueProcessedWithPhiNodes.insert(cvi); + + // Then check if our termInst is in the same block as our copy_value. In + // such a case, we can just use the copy_value as our phi's value + // without needing to worry about any issues around control equivalence. + if (pair.first == cvi->getParent()) + continue; + } else { + assert(isa(value)); + } + + // Otherwise, insert a copy_value instruction right before the phi. We use + // that for our actual phi. + auto *termInst = pair.first->getTerminator(); + SILBuilderWithScope builder(termInst); + CopyValueInst *phiCopy = builder.createCopyValue(loc, value); + termInst->setOperand(phiIndex, phiCopy); + + // Now that we know our base, phi, phiCopy for this specific incoming + // value, append it to the phiNodeClenaupState so we can insert + // destroy_values late after we visit all insertedPhiNodes. + cleanupInserter.trackNewCleanup(value, phiCopy); + } + + // Then see if our phi is an intermediate phi. If it is an intermediate phi, + // we know that this is not the phi node that is post-dominated by the + // load_borrow and that we will lifetime extend it via the child + // phi. Instead, we need to just ensure that our phi arg does not leak onto + // its set of post-dominating paths, subtracting from that set the path + // through our terminator use. + if (intermediatePhiOffsets[i]) { + continue; + } + + // If we reach this point, then we know that we are a phi node that actually + // dominates our user so we need to lifetime extend it over the + // load_borrow. Thus insert copy_value along the incoming edges and then + // lifetime extend the phi node over the load_borrow. + // // The linear lifetime checker doesn't care if the passed in load is // actually a user of our copy_value. What we care about is that the load is // guaranteed to be in the block where we have reformed the tuple in a @@ -781,63 +1223,87 @@ AvailableValueAggregator::addMissingDestroysForCopiedValues(LoadInst *li, auto errorKind = ownership::ErrorBehaviorKind::ReturnFalse; LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); auto error = checker.checkValue( - cvi, {BranchPropagatedUser(&li->getAllOperands()[0])}, {}, errorKind, + phi, {BranchPropagatedUser(&load->getAllOperands()[0])}, {}, errorKind, &leakingBlocks); - if (!error.getFoundError()) + + if (!error.getFoundError()) { + // If we did not find an error, then our copy_value must be strongly + // control equivalent as our load_borrow. So just insert a destroy_value + // for the copy_value. + auto next = std::next(load->getIterator()); + SILBuilderWithScope builder(next); + builder.emitDestroyValueOperation(next->getLoc(), phi); continue; + } - // Ok, we found some leaking blocks. Since we are using the linear lifetime - // checker with memory, we do not have any guarantees that the store is out - // side of a loop and a load is in a loop. In such a case, we want to - // replace the load with a copy_value. - foundLoop |= error.getFoundOverConsume(); + // Ok, we found some leaking blocks and potentially a loop. If we do not + // find a loop, insert the destroy_value after the load_borrow. We do not do + // this if we found a loop since our leaking blocks will lifetime extend the + // value over the loop. + if (!error.getFoundOverConsume()) { + auto next = std::next(load->getIterator()); + SILBuilderWithScope builder(next); + builder.emitDestroyValueOperation(next->getLoc(), phi); + } - // Ok, we found some leaking blocks. Insert destroys at the - // beginning of these blocks for our copy_value. + // Ok, we found some leaking blocks. Insert destroys at the beginning of + // these blocks for our copy_value. for (auto *bb : leakingBlocks) { SILBuilderWithScope b(bb->begin()); - b.emitDestroyValueOperation(loc, cvi); + b.emitDestroyValueOperation(loc, phi); } } - // If we didn't find a loop, we are done, just return svi to get RAUWed. - if (!foundLoop) { - return li; - } - - // If we found a loop, then we know that our leaking blocks are the exiting - // blocks of the loop and the value has been lifetime extended over the loop. + // Alright! In summary, we just lifetime extended all of our phis, + // lifetime extended them to the load block, and inserted phi copies + // at all of our intermediate phi nodes. Now we need to cleanup and + // insert all of the compensating destroy_value that we need. + std::move(cleanupInserter).emit(deadEndBlocks); - // If we have a load, we need to put in a copy so that the destroys within - // the loop are properly balanced. - newVal = SILBuilderWithScope(li).emitCopyValueOperation(loc, newVal); - - li->replaceAllUsesWith(newVal); - SILValue addr = li->getOperand(); - li->eraseFromParent(); - if (auto *addrI = addr->getDefiningInstruction()) - recursivelyDeleteTriviallyDeadInstructions(addrI); - return nullptr; + // Clear the phi node array now that we are done. + insertedPhiNodes.clear(); } -SingleValueInstruction * -AvailableValueAggregator::addMissingDestroysForCopiedValues(LoadBorrowInst *lbi, - SILValue newVal) { +void AvailableValueAggregator::addMissingDestroysForCopiedValues( + SILInstruction *load, SILValue newVal) { assert(B.hasOwnership() && "We assume this is only called if we have ownership"); SmallPtrSet visitedBlocks; SmallVector leakingBlocks; - bool foundLoop = false; auto loc = RegularLocation::getAutoGeneratedLocation(); - while (!insertedInsts.empty()) { - auto *cvi = dyn_cast(insertedInsts.pop_back_val()); + + for (auto *inst : insertedInsts) { + // Otherwise, see if this is a load [copy]. It if it a load [copy], then we + // know that the load [copy] must be in the load block meaing we can just + // put a destroy_value /after/ the load_borrow to ensure that the value + // lives long enough for us to copy_value it or a derived value for the + // begin_borrow. + if (auto *li = dyn_cast(inst)) { + if (li->getOwnershipQualifier() == LoadOwnershipQualifier::Copy) { + assert(li->getParent() == load->getParent()); + auto next = std::next(load->getIterator()); + SILBuilderWithScope builder(next); + builder.emitDestroyValueOperation(next->getLoc(), li); + continue; + } + } + + // Our copy_value may have been unset above if it was used by a phi + // (implying it does not dominate our final user). + auto *cvi = dyn_cast(inst); if (!cvi) continue; + // If we already handled this copy_value above when handling phi nodes, just + // continue. + if (copyValueProcessedWithPhiNodes.count(cvi)) + continue; + // Clear our state. visitedBlocks.clear(); leakingBlocks.clear(); + // The linear lifetime checker doesn't care if the passed in load is // actually a user of our copy_value. What we care about is that the load is // guaranteed to be in the block where we have reformed the tuple in a @@ -849,53 +1315,36 @@ AvailableValueAggregator::addMissingDestroysForCopiedValues(LoadBorrowInst *lbi, auto errorKind = ownership::ErrorBehaviorKind::ReturnFalse; LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks); auto error = checker.checkValue( - cvi, {BranchPropagatedUser(&lbi->getAllOperands()[0])}, {}, errorKind, + cvi, {BranchPropagatedUser(&load->getAllOperands()[0])}, {}, errorKind, &leakingBlocks); - if (!error.getFoundError()) + + if (!error.getFoundError()) { + // If we did not find an error, then our copy_value must be strongly + // control equivalent as our load_borrow. So just insert a destroy_value + // for the copy_value. + auto next = std::next(load->getIterator()); + SILBuilderWithScope builder(next); + builder.emitDestroyValueOperation(next->getLoc(), cvi); continue; + } - // Ok, we found some leaking blocks. Since we are using the linear lifetime - // checker with memory, we do not have any guarantees that the store is out - // side of a loop and a load is in a loop. In such a case, we want to - // replace the load with a copy_value. - foundLoop |= error.getFoundOverConsume(); + // Ok, we found some leaking blocks and potentially a loop. If we do not + // find a loop, insert the destroy_value after the load_borrow. We do not do + // this if we found a loop since our leaking blocks will lifetime extend the + // value over the loop. + if (!error.getFoundOverConsume()) { + auto next = std::next(load->getIterator()); + SILBuilderWithScope builder(next); + builder.emitDestroyValueOperation(next->getLoc(), cvi); + } - // Ok, we found some leaking blocks. Insert destroys at the - // beginning of these blocks for our copy_value. + // Ok, we found some leaking blocks. Insert destroys at the beginning of + // these blocks for our copy_value. for (auto *bb : leakingBlocks) { SILBuilderWithScope b(bb->begin()); b.emitDestroyValueOperation(loc, cvi); } } - - // If we didn't find a loop, we are done, just return svi to get RAUWed. - if (!foundLoop) { - // If we had a load_borrow, we have created an extra copy that we are going - // to borrow at the load point. This means we need to handle the destroying - // of the value along paths reachable from the load_borrow. Luckily that - // will exactly be after the end_borrows of the load_borrow. - for (auto *use : lbi->getUses()) { - if (auto *ebi = dyn_cast(use->getUser())) { - auto next = std::next(ebi->getIterator()); - SILBuilderWithScope(next).emitDestroyValueOperation(ebi->getLoc(), - newVal); - } - } - return lbi; - } - - // If we found a loop, then we know that our leaking blocks are the exiting - // blocks of the loop and the value has been lifetime extended over the loop. - // If we have a load_borrow, we create a begin_borrow for the end_borrows in - // the loop. - newVal = SILBuilderWithScope(lbi).createBeginBorrow(lbi->getLoc(), newVal); - - lbi->replaceAllUsesWith(newVal); - SILValue addr = lbi->getOperand(); - lbi->eraseFromParent(); - if (auto *addrI = addr->getDefiningInstruction()) - recursivelyDeleteTriviallyDeadInstructions(addrI); - return nullptr; } //===----------------------------------------------------------------------===// @@ -1074,8 +1523,9 @@ static inline void updateAvailableValuesHelper( // TODO: Is this needed now? assert(startSubElt != ~0U && "Store within enum projection not handled"); - for (unsigned i : - range(getNumSubElements(address->getType().getObjectType(), mod))) { + for (unsigned i : range(getNumSubElements( + address->getType().getObjectType(), mod, + TypeExpansionContext(*theMemory->getFunction())))) { // If this element is not required, don't fill it in. if (!requiredElts[startSubElt + i]) continue; @@ -1201,12 +1651,13 @@ void AvailableValueDataflowContext::updateAvailableValues( SILType ValTy = CAI->getDest()->getType(); bool AnyRequired = false; - for (unsigned i : range(getNumSubElements(ValTy, getModule()))) { + for (unsigned i : range(getNumSubElements( + ValTy, getModule(), TypeExpansionContext(*CAI->getFunction())))) { // If this element is not required, don't fill it in. AnyRequired = RequiredElts[StartSubElt+i]; if (AnyRequired) break; } - + // If this is a copy addr that doesn't intersect the loaded subelements, // just continue with an unmodified load mask. if (!AnyRequired) @@ -1493,7 +1944,8 @@ static SILType getMemoryType(AllocationInst *memory) { if (auto *abi = dyn_cast(memory)) { assert(abi->getBoxType()->getLayout()->getFields().size() == 1 && "optimizing multi-field boxes not implemented"); - return getSILBoxFieldType(abi->getBoxType(), abi->getModule().Types, 0); + return getSILBoxFieldType(TypeExpansionContext(*abi->getFunction()), + abi->getBoxType(), abi->getModule().Types, 0); } assert(isa(memory)); @@ -1532,8 +1984,9 @@ class AllocOptimize { DeadEndBlocks &deadEndBlocks) : Module(memory->getModule()), TheMemory(memory), MemoryType(getMemoryType(memory)), - NumMemorySubElements(getNumSubElements(MemoryType, Module)), Uses(uses), - Releases(releases), deadEndBlocks(deadEndBlocks), + NumMemorySubElements(getNumSubElements( + MemoryType, Module, TypeExpansionContext(*memory->getFunction()))), + Uses(uses), Releases(releases), deadEndBlocks(deadEndBlocks), DataflowContext(TheMemory, NumMemorySubElements, uses) {} bool optimizeMemoryAccesses(); @@ -1578,7 +2031,8 @@ Optional> AllocOptimize::computeAvailableValues( if (FirstElt == ~0U) return None; - unsigned NumLoadSubElements = getNumSubElements(LoadTy, Module); + unsigned NumLoadSubElements = getNumSubElements( + LoadTy, Module, TypeExpansionContext(*TheMemory->getFunction())); // Set up the bitvector of elements being demanded by the load. SmallBitVector RequiredElts(NumMemorySubElements); @@ -1650,11 +2104,11 @@ bool AllocOptimize::promoteLoadCopy(LoadInst *li) { // not available. We are "propagating" a +1 available value from the store // points. AvailableValueAggregator agg(li, availableValues, Uses, deadEndBlocks, - false /*isTake*/); + AvailableValueExpectedOwnership::Copy); SILValue newVal = agg.aggregateValues(loadTy, li->getOperand(), firstElt); - LLVM_DEBUG(llvm::dbgs() << " *** Promoting load: " << *li << "\n"); - LLVM_DEBUG(llvm::dbgs() << " To value: " << *newVal << "\n"); + LLVM_DEBUG(llvm::dbgs() << " *** Promoting load: " << *li); + LLVM_DEBUG(llvm::dbgs() << " To value: " << *newVal); ++NumLoadPromoted; // If we did not have ownership, we did not insert extra copies at our stores, @@ -1675,16 +2129,15 @@ bool AllocOptimize::promoteLoadCopy(LoadInst *li) { // blocks that we may have can be found by performing a linear lifetime check // over all copies that we found using the load as the "consuming uses" (just // for the purposes of identifying the consuming block). - auto *oldLoad = agg.addMissingDestroysForCopiedValues(li, newVal); + agg.fixupOwnership(li, newVal); - // If we are returned the load, eliminate it. Otherwise, it was already - // handled for us... so return true. - if (!oldLoad) - return true; + // Now that we have fixed up all of our missing destroys, insert the copy + // value for our actual load and RAUW. + newVal = SILBuilderWithScope(li).emitCopyValueOperation(li->getLoc(), newVal); - oldLoad->replaceAllUsesWith(newVal); - SILValue addr = oldLoad->getOperand(0); - oldLoad->eraseFromParent(); + li->replaceAllUsesWith(newVal); + SILValue addr = li->getOperand(); + li->eraseFromParent(); if (auto *addrI = addr->getDefiningInstruction()) recursivelyDeleteTriviallyDeadInstructions(addrI); return true; @@ -1742,6 +2195,8 @@ bool AllocOptimize::promoteLoadBorrow(LoadBorrowInst *lbi) { if (!result.hasValue()) return false; + ++NumLoadPromoted; + SILType loadTy = result->first; unsigned firstElt = result->second; @@ -1750,36 +2205,42 @@ bool AllocOptimize::promoteLoadBorrow(LoadBorrowInst *lbi) { // not available. We are "propagating" a +1 available value from the store // points. AvailableValueAggregator agg(lbi, availableValues, Uses, deadEndBlocks, - false /*isTake*/); + AvailableValueExpectedOwnership::Borrow); SILValue newVal = agg.aggregateValues(loadTy, lbi->getOperand(), firstElt); - LLVM_DEBUG(llvm::dbgs() << " *** Promoting load: " << *lbi << "\n"); - LLVM_DEBUG(llvm::dbgs() << " To value: " << *newVal << "\n"); - - // If we inserted any copies, we created the copies at our stores. We know - // that in our load block, we will reform the aggregate as appropriate at the - // load implying that the value /must/ be fully consumed. If we promoted a +0 - // value, we created dominating destroys along those paths. Thus any leaking - // blocks that we may have can be found by performing a linear lifetime check - // over all copies that we found using the load as the "consuming uses" (just - // for the purposes of identifying the consuming block). - auto *oldLoad = agg.addMissingDestroysForCopiedValues(lbi, newVal); + LLVM_DEBUG(llvm::dbgs() << " *** Promoting load: " << *lbi); + LLVM_DEBUG(llvm::dbgs() << " To value: " << *newVal); - ++NumLoadPromoted; + // If we inserted any copies, we created the copies at our + // stores. We know that in our load block, we will reform the + // aggregate as appropriate, will borrow the value there and give us + // a whole pristine new value. Now in this routine, we go through + // all of the copies and phis that we inserted and ensure that: + // + // 1. Phis are always strongly control equivalent to the copies that + // produced their incoming values. + // + // 2. All intermediate copies are properly lifetime extended to the + // load block and all leaking blocks are filled in as appropriate + // with destroy_values. + agg.fixupOwnership(lbi, newVal); - // If we are returned the load, eliminate it. Otherwise, it was already - // handled for us... so return true. - if (!oldLoad) - return true; + // Now that we have fixed up the lifetimes of all of our incoming copies so + // that they are alive over the load point, copy, borrow newVal and insert + // destroy_value after the end_borrow and then RAUW. + SILBuilderWithScope builder(lbi); + SILValue copiedVal = builder.emitCopyValueOperation(lbi->getLoc(), newVal); + newVal = builder.createBeginBorrow(lbi->getLoc(), copiedVal); - // If our load was a +0 value, borrow the value and the RAUW. We reuse the - // end_borrows of our load_borrow. - newVal = - SILBuilderWithScope(oldLoad).createBeginBorrow(oldLoad->getLoc(), newVal); + for (auto *ebi : lbi->getUsersOfType()) { + auto next = std::next(ebi->getIterator()); + SILBuilderWithScope(next).emitDestroyValueOperation(ebi->getLoc(), + copiedVal); + } - oldLoad->replaceAllUsesWith(newVal); - SILValue addr = oldLoad->getOperand(0); - oldLoad->eraseFromParent(); + lbi->replaceAllUsesWith(newVal); + SILValue addr = lbi->getOperand(); + lbi->eraseFromParent(); if (auto *addrI = addr->getDefiningInstruction()) recursivelyDeleteTriviallyDeadInstructions(addrI); return true; @@ -1805,7 +2266,9 @@ bool AllocOptimize::canPromoteTake( // def/use behavior. unsigned firstElt = computeSubelement(address, TheMemory); assert(firstElt != ~0U && "destroy within enum projection is not valid"); - unsigned numLoadSubElements = getNumSubElements(loadTy, Module); + auto expansionContext = TypeExpansionContext(*inst->getFunction()); + unsigned numLoadSubElements = + getNumSubElements(loadTy, Module, expansionContext); // Find out if we have any available values. If no bits are demanded, we // trivially succeed. This can happen when there is a load of an empty struct. @@ -1829,7 +2292,7 @@ bool AllocOptimize::canPromoteTake( // available, we would need to split stores to promote this destroy_addr. We // do not support that yet. AvailableValueAggregator agg(inst, tmpList, Uses, deadEndBlocks, - true /*isTake*/); + AvailableValueExpectedOwnership::Take); if (!agg.canTake(loadTy, firstElt)) return false; @@ -1861,13 +2324,13 @@ void AllocOptimize::promoteDestroyAddr( // type as the load did, and emit smaller) loads for any subelements that were // not available. AvailableValueAggregator agg(dai, availableValues, Uses, deadEndBlocks, - true /*isTake*/); + AvailableValueExpectedOwnership::Take); SILValue newVal = agg.aggregateValues(loadTy, address, firstElt); ++NumDestroyAddrPromoted; - LLVM_DEBUG(llvm::dbgs() << " *** Promoting destroy_addr: " << *dai << "\n"); - LLVM_DEBUG(llvm::dbgs() << " To value: " << *newVal << "\n"); + LLVM_DEBUG(llvm::dbgs() << " *** Promoting destroy_addr: " << *dai); + LLVM_DEBUG(llvm::dbgs() << " To value: " << *newVal); SILBuilderWithScope(dai).emitDestroyValueOperation(dai->getLoc(), newVal); dai->eraseFromParent(); @@ -1889,13 +2352,13 @@ void AllocOptimize::promoteLoadTake( // type as the load did, and emit smaller) loads for any subelements that were // not available. AvailableValueAggregator agg(li, availableValues, Uses, deadEndBlocks, - true /*isTake*/); + AvailableValueExpectedOwnership::Take); SILValue newVal = agg.aggregateValues(loadTy, address, firstElt); ++NumLoadTakePromoted; - LLVM_DEBUG(llvm::dbgs() << " *** Promoting load_take: " << *li << "\n"); - LLVM_DEBUG(llvm::dbgs() << " To value: " << *newVal << "\n"); + LLVM_DEBUG(llvm::dbgs() << " *** Promoting load_take: " << *li); + LLVM_DEBUG(llvm::dbgs() << " To value: " << *newVal); // Then perform the RAUW. li->replaceAllUsesWith(newVal); @@ -2172,8 +2635,8 @@ static bool optimizeMemoryAccesses(SILFunction &fn) { continue; } - LLVM_DEBUG(llvm::dbgs() << "*** PMO Optimize Memory Accesses looking at: " - << *alloc << "\n"); + LLVM_DEBUG(llvm::dbgs() + << "*** PMO Optimize Memory Accesses looking at: " << *alloc); PMOMemoryObjectInfo memInfo(alloc); // Set up the datastructure used to collect the uses of the allocation. @@ -2215,8 +2678,8 @@ static bool eliminateDeadAllocations(SILFunction &fn) { } LLVM_DEBUG(llvm::dbgs() - << "*** PMO Dead Allocation Elimination looking at: " << *alloc - << "\n"); + << "*** PMO Dead Allocation Elimination looking at: " + << *alloc); PMOMemoryObjectInfo memInfo(alloc); // Set up the datastructure used to collect the uses of the allocation. diff --git a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp index 72fa8368a7fba..175bb0efc6709 100644 --- a/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp @@ -406,24 +406,38 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst // dead end blocks that use the value in a non-consuming way. // // TODO: There may be some way of sinking this into the loop below. - if (destroys.empty() && - llvm::any_of(borrowScopeIntroducers, - [](BorrowScopeIntroducingValue borrowScope) { - return borrowScope.isLocalScope(); - })) { + bool haveAnyLocalScopes = llvm::any_of( + borrowScopeIntroducers, [](BorrowScopeIntroducingValue borrowScope) { + return borrowScope.isLocalScope(); + }); + + if (destroys.empty() && haveAnyLocalScopes) { return false; } // If we reached this point, then we know that all of our users can accept a - // guaranteed value and our owned value is destroyed only by - // destroy_value. Check if all of our destroys are joint post-dominated by the - // our end borrow scope set. If they do not, then the copy_value is lifetime - // extending the guaranteed value, we can not eliminate it. + // guaranteed value and our owned value is destroyed only by a set of + // destroy_values. Check if: + // + // 1. All of our destroys are joint post-dominated by our end borrow scope + // set. If they do not, then the copy_value is lifetime extending the + // guaranteed value, we can not eliminate it. + // + // 2. If all of our destroy_values are dead end. In such a case, the linear + // lifetime checker will not perform any checks since it assumes that dead + // end destroys can be ignored. Since we are going to end the program + // anyways, we want to be conservative here and optimize only if we do not + // need to insert an end_borrow since all of our borrow introducers are + // non-local scopes. { SmallVector destroysForLinearLifetimeCheck; + bool foundNonDeadEnd = false; for (auto *dvi : destroys) { + foundNonDeadEnd |= !getDeadEndBlocks().isDeadEnd(dvi->getParent()); destroysForLinearLifetimeCheck.push_back(&dvi->getAllOperands()[0]); } + if (!foundNonDeadEnd && haveAnyLocalScopes) + return false; SmallVector scratchSpace; SmallPtrSet visitedBlocks; if (llvm::any_of(borrowScopeIntroducers, @@ -772,6 +786,10 @@ struct SemanticARCOpts : SILFunctionTransform { void run() override { SILFunction &f = *getFunction(); + // Return early if we are not performing OSSA optimizations. + if (!f.getModule().getOptions().EnableOSSAOptimizations) + return; + // Make sure we are running with ownership verification enabled. assert(f.getModule().getOptions().VerifySILOwnership && "Can not perform semantic arc optimization unless ownership " diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index 903f175158751..71fbacd6f1f50 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -295,10 +295,6 @@ void addSSAPasses(SILPassPipelinePlan &P, OptimizationLevelKind OpLevel) { // Mainly for Array.append(contentsOf) optimization. P.addArrayElementPropagation(); - // Specialize opaque archetypes. - // This can expose oportunities for the generic specializer. - P.addOpaqueArchetypeSpecializer(); - // Run the devirtualizer, specializer, and inliner. If any of these // makes a change we'll end up restarting the function passes on the // current function (after optimizing any new callees). @@ -696,6 +692,20 @@ SILPassPipelinePlan::getOnonePassPipeline(const SILOptions &Options) { return P; } +//===----------------------------------------------------------------------===// +// Serialize SIL Pass Pipeline +//===----------------------------------------------------------------------===// + +// Add to P a new pipeline that just serializes SIL. Meant to be used in +// situations where perf optzns are disabled, but we may need to serialize. +SILPassPipelinePlan +SILPassPipelinePlan::getSerializeSILPassPipeline(const SILOptions &Options) { + SILPassPipelinePlan P(Options); + P.startPipeline("Serialize SIL"); + P.addSerializeSILPass(); + return P; +} + //===----------------------------------------------------------------------===// // Inst Count Pass Pipeline //===----------------------------------------------------------------------===// diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index 42752a6acda1e..6d6abbaba6d5a 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -328,7 +328,7 @@ findUnexpectedBoxUse(SILValue Box, bool examinePartialApply, (!inAppliedFunction && isa(User))) continue; - // If our user instruction is a copy_value or a marked_uninitialized, visit + // If our user instruction is a copy_value or a mark_uninitialized, visit // the users recursively. if (isa(User) || isa(User)) { llvm::copy(cast(User)->getUses(), @@ -436,7 +436,8 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) { && "rewriting multi-field box not implemented"); auto *ASI = Builder.createAllocStack( ABI->getLoc(), - getSILBoxFieldType(ABI->getBoxType(), ABI->getModule().Types, 0), + getSILBoxFieldType(TypeExpansionContext(*ABI->getFunction()), + ABI->getBoxType(), ABI->getModule().Types, 0), ABI->getVarInfo(), ABI->hasDynamicLifetime()); // Transfer a mark_uninitialized if we have one. @@ -452,9 +453,9 @@ static bool rewriteAllocBoxAsAllocStack(AllocBoxInst *ABI) { assert(ABI->getBoxType()->getLayout()->getFields().size() == 1 && "promoting multi-field box not implemented"); - auto &Lowering = ABI->getFunction() - ->getTypeLowering( - getSILBoxFieldType(ABI->getBoxType(), ABI->getModule().Types, 0)); + auto &Lowering = ABI->getFunction()->getTypeLowering( + getSILBoxFieldType(TypeExpansionContext(*ABI->getFunction()), + ABI->getBoxType(), ABI->getModule().Types, 0)); auto Loc = CleanupLocation::get(ABI->getLoc()); for (auto LastRelease : FinalReleases) { @@ -585,7 +586,7 @@ SILFunction *PromotedParamCloner::initCloned(SILOptFunctionBuilder &FuncBuilder, auto &TC = Orig->getModule().Types; Lowering::GenericContextScope scope(TC, OrigFTI->getSubstGenericSignature()); - paramTy = getSILBoxFieldType(boxTy, TC, 0); + paramTy = getSILBoxFieldType(TypeExpansionContext(*Orig), boxTy, TC, 0); } auto promotedParam = SILParameterInfo(paramTy.getASTType(), ParameterConvention::Indirect_InoutAliasable); @@ -650,7 +651,8 @@ PromotedParamCloner::populateCloned() { auto boxTy = (*I)->getType().castTo(); assert(boxTy->getLayout()->getFields().size() == 1 && "promoting multi-field boxes not implemented yet"); - auto promotedTy = getSILBoxFieldType(boxTy, Cloned->getModule().Types, 0); + auto promotedTy = getSILBoxFieldType(TypeExpansionContext(*Cloned), boxTy, + Cloned->getModule().Types, 0); auto *promotedArg = ClonedEntryBB->createFunctionArgument(promotedTy, (*I)->getDecl()); OrigPromotedParameters.insert(*I); diff --git a/lib/SILOptimizer/Transforms/CMakeLists.txt b/lib/SILOptimizer/Transforms/CMakeLists.txt index f48201ab43c7a..336f2a78db0b3 100644 --- a/lib/SILOptimizer/Transforms/CMakeLists.txt +++ b/lib/SILOptimizer/Transforms/CMakeLists.txt @@ -34,7 +34,6 @@ silopt_register_sources( SILSROA.cpp SimplifyCFG.cpp Sink.cpp - SpecializeOpaqueArchetypes.cpp SpeculativeDevirtualizer.cpp StackPromotion.cpp UnsafeGuaranteedPeephole.cpp diff --git a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp index 182d6d642e094..266859152516a 100644 --- a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp @@ -855,7 +855,8 @@ void DSEContext::processRead(SILInstruction *I, SILValue Mem, DSEKind Kind) { // Expand the given Mem into individual fields and process them as separate // reads. LSLocationList Locs; - LSLocation::expand(L, &I->getModule(), Locs, TE); + LSLocation::expand(L, &I->getModule(), + TypeExpansionContext(*I->getFunction()), Locs, TE); // Are we building the genset and killset. if (isBuildingGenKillSet(Kind)) { @@ -940,7 +941,7 @@ void DSEContext::processWrite(SILInstruction *I, SILValue Val, SILValue Mem, // writes. bool Dead = true; LSLocationList Locs; - LSLocation::expand(L, Mod, Locs, TE); + LSLocation::expand(L, Mod, TypeExpansionContext(*I->getFunction()), Locs, TE); SmallBitVector V(Locs.size()); // Are we computing max store set. @@ -997,7 +998,7 @@ void DSEContext::processWrite(SILInstruction *I, SILValue Val, SILValue Mem, } // Try to create as few aggregated stores as possible out of the locations. - LSLocation::reduce(L, Mod, Alives); + LSLocation::reduce(L, Mod, TypeExpansionContext(*I->getFunction()), Alives); // Oops, we have too many smaller stores generated, bail out. if (Alives.size() > MaxPartialStoreCount) diff --git a/lib/SILOptimizer/Transforms/DestroyHoisting.cpp b/lib/SILOptimizer/Transforms/DestroyHoisting.cpp index 3498f716a7110..0a42f6160a685 100644 --- a/lib/SILOptimizer/Transforms/DestroyHoisting.cpp +++ b/lib/SILOptimizer/Transforms/DestroyHoisting.cpp @@ -716,6 +716,10 @@ class DestroyHoistingPass : public SILFunctionTransform { if (!F->hasOwnership()) return; + // If we are not supposed to perform ossa optimizations, bail. + if (!F->getModule().getOptions().EnableOSSAOptimizations) + return; + LLVM_DEBUG(llvm::dbgs() << "*** DestroyHoisting on function: " << F->getName() << " ***\n"); diff --git a/lib/SILOptimizer/Transforms/ObjectOutliner.cpp b/lib/SILOptimizer/Transforms/ObjectOutliner.cpp index 08f3bc0c54483..dd35ec91fbe74 100644 --- a/lib/SILOptimizer/Transforms/ObjectOutliner.cpp +++ b/lib/SILOptimizer/Transforms/ObjectOutliner.cpp @@ -488,7 +488,8 @@ bool ObjectOutliner::optimizeObjectAllocation(AllocRefInst *ARI) { void ObjectOutliner::replaceFindStringCall(ApplyInst *FindStringCall) { // Find the replacement function in the swift stdlib. SmallVector results; - SILModule *Module = &FindStringCall->getFunction()->getModule(); + auto &F = *FindStringCall->getFunction(); + SILModule *Module = &F.getModule(); Module->getASTContext().lookupInSwiftModule("_findStringSwitchCaseWithCache", results); if (results.size() != 1) @@ -517,8 +518,9 @@ void ObjectOutliner::replaceFindStringCall(ApplyInst *FindStringCall) { assert(!cacheDecl->isResilient(Module->getSwiftModule(), ResilienceExpansion::Minimal)); - SILType wordTy = cacheType.getFieldType( - cacheDecl->getStoredProperties().front(), *Module); + SILType wordTy = + cacheType.getFieldType(cacheDecl->getStoredProperties().front(), *Module, + F.getTypeExpansionContext()); GlobalVariableMangler Mangler; std::string GlobName = diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp index c78b1f5dba07a..d350a63081a55 100644 --- a/lib/SILOptimizer/Transforms/Outliner.cpp +++ b/lib/SILOptimizer/Transforms/Outliner.cpp @@ -288,7 +288,6 @@ CanSILFunctionType BridgedProperty::getOutlinedFunctionType(SILModule &M) { ResultConvention::Owned)); auto ExtInfo = SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, - // SWIFT_ENABLE_TENSORFLOW /*pseudogeneric*/ false, /*noescape*/ false, DifferentiabilityKind::NonDifferentiable); auto FunctionType = SILFunctionType::get( @@ -1110,12 +1109,10 @@ CanSILFunctionType ObjCMethodCall::getOutlinedFunctionType(SILModule &M) { OrigSigIdx++; } - auto ExtInfo = - SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, - /*pseudogeneric*/ false, - // SWIFT_ENABLE_TENSORFLOW - /*noescape*/ false, - DifferentiabilityKind::NonDifferentiable); + auto ExtInfo = SILFunctionType::ExtInfo( + SILFunctionType::Representation::Thin, + /*pseudogeneric*/ false, + /*noescape*/ false, DifferentiabilityKind::NonDifferentiable); SmallVector Results; // If we don't have a bridged return we changed from @autoreleased to @owned diff --git a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp index 0f610308babfa..d34370660a95b 100644 --- a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp +++ b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp @@ -677,7 +677,8 @@ SILValue BlockState::reduceValuesAtEndOfBlock(RLEContext &Ctx, LSLocation &L) { LSLocationValueMap Values; LSLocationList Locs; - LSLocation::expand(L, &BB->getModule(), Locs, Ctx.getTE()); + LSLocation::expand(L, &BB->getModule(), + TypeExpansionContext(*BB->getParent()), Locs, Ctx.getTE()); // Find the values that this basic block defines and the locations which // we do not have a concrete value in the current basic block. @@ -689,8 +690,8 @@ SILValue BlockState::reduceValuesAtEndOfBlock(RLEContext &Ctx, LSLocation &L) { // Second, reduce the available values into a single SILValue we can use to // forward. SILValue TheForwardingValue; - TheForwardingValue = LSValue::reduce(L, &BB->getModule(), Values, - BB->getTerminator()); + TheForwardingValue = + LSValue::reduce(L, &BB->getModule(), Values, BB->getTerminator()); /// Return the forwarding value. return TheForwardingValue; } @@ -856,7 +857,9 @@ void BlockState::processWrite(RLEContext &Ctx, SILInstruction *I, SILValue Mem, // Expand the given location and val into individual fields and process // them as separate writes. LSLocationList Locs; - LSLocation::expand(L, &I->getModule(), Locs, Ctx.getTE()); + LSLocation::expand(L, &I->getModule(), + TypeExpansionContext(*I->getFunction()), Locs, + Ctx.getTE()); if (isComputeAvailSetMax(Kind)) { for (unsigned i = 0; i < Locs.size(); ++i) { @@ -875,7 +878,8 @@ void BlockState::processWrite(RLEContext &Ctx, SILInstruction *I, SILValue Mem, // Are we computing available value or performing RLE? LSValueList Vals; - LSValue::expand(Val, &I->getModule(), Vals, Ctx.getTE()); + LSValue::expand(Val, &I->getModule(), TypeExpansionContext(*I->getFunction()), + Vals, Ctx.getTE()); if (isComputeAvailValue(Kind) || isPerformingRLE(Kind)) { for (unsigned i = 0; i < Locs.size(); ++i) { updateForwardSetAndValForWrite(Ctx, Ctx.getLocationBit(Locs[i]), @@ -907,7 +911,9 @@ void BlockState::processRead(RLEContext &Ctx, SILInstruction *I, SILValue Mem, // Expand the given LSLocation and Val into individual fields and process // them as separate reads. LSLocationList Locs; - LSLocation::expand(L, &I->getModule(), Locs, Ctx.getTE()); + LSLocation::expand(L, &I->getModule(), + TypeExpansionContext(*I->getFunction()), Locs, + Ctx.getTE()); if (isComputeAvailSetMax(Kind)) { for (unsigned i = 0; i < Locs.size(); ++i) { @@ -927,7 +933,8 @@ void BlockState::processRead(RLEContext &Ctx, SILInstruction *I, SILValue Mem, // Are we computing available values ?. bool CanForward = true; LSValueList Vals; - LSValue::expand(Val, &I->getModule(), Vals, Ctx.getTE()); + LSValue::expand(Val, &I->getModule(), TypeExpansionContext(*I->getFunction()), + Vals, Ctx.getTE()); if (isComputeAvailValue(Kind) || isPerformingRLE(Kind)) { for (unsigned i = 0; i < Locs.size(); ++i) { if (isTrackingLocation(ForwardSetIn, Ctx.getLocationBit(Locs[i]))) @@ -1245,7 +1252,8 @@ BlockState::ValueState BlockState::getValueStateAtEndOfBlock(RLEContext &Ctx, // expanded from the given location. unsigned CSCount = 0, CTCount = 0; LSLocationList Locs; - LSLocation::expand(L, &BB->getModule(), Locs, Ctx.getTE()); + LSLocation::expand(L, &BB->getModule(), + TypeExpansionContext(*BB->getParent()), Locs, Ctx.getTE()); ValueTableMap &OTM = getForwardValOut(); for (auto &X : Locs) { @@ -1319,12 +1327,15 @@ SILValue RLEContext::computePredecessorLocationValue(SILBasicBlock *BB, // Reduce the available values into a single SILValue we can use to forward SILInstruction *IPt = CurBB->getTerminator(); - Values.push_back({CurBB, LSValue::reduce(L, &BB->getModule(), LSValues, IPt)}); + Values.push_back( + {CurBB, LSValue::reduce(L, &BB->getModule(), LSValues, IPt)}); } // Finally, collect all the values for the SILArgument, materialize it using // the SSAUpdater. - Updater.Initialize(L.getType(&BB->getModule()).getObjectType()); + Updater.Initialize( + L.getType(&BB->getModule(), TypeExpansionContext(*BB->getParent())) + .getObjectType()); for (auto V : Values) { Updater.AddAvailableValue(V.first, V.second); } @@ -1337,7 +1348,8 @@ bool RLEContext::collectLocationValues(SILBasicBlock *BB, LSLocation &L, ValueTableMap &VM) { LSLocationList CSLocs; LSLocationList Locs; - LSLocation::expand(L, &BB->getModule(), Locs, TE); + LSLocation::expand(L, &BB->getModule(), + TypeExpansionContext(*BB->getParent()), Locs, TE); auto *Mod = &BB->getModule(); // Find the locations that this basic block defines and the locations which @@ -1352,7 +1364,7 @@ bool RLEContext::collectLocationValues(SILBasicBlock *BB, LSLocation &L, // For locations which we do not have concrete values for in this basic // block, try to reduce it to the minimum # of locations possible, this // will help us to generate as few SILArguments as possible. - LSLocation::reduce(L, Mod, CSLocs); + LSLocation::reduce(L, Mod, TypeExpansionContext(*BB->getParent()), CSLocs); // To handle covering value, we need to go to the predecessors and // materialize them there. @@ -1365,8 +1377,9 @@ bool RLEContext::collectLocationValues(SILBasicBlock *BB, LSLocation &L, // collect the newly created forwardable values. LSLocationList Locs; LSValueList Vals; - LSLocation::expand(X, Mod, Locs, TE); - LSValue::expand(V, Mod, Vals, TE); + auto expansionContext = TypeExpansionContext(*BB->getParent()); + LSLocation::expand(X, Mod, expansionContext, Locs, TE); + LSValue::expand(V, Mod, expansionContext, Vals, TE); for (unsigned i = 0; i < Locs.size(); ++i) { Values[Locs[i]] = Vals[i]; @@ -1570,7 +1583,8 @@ bool RLEContext::run() { LLVM_DEBUG(for (unsigned i = 0; i < LocationVault.size(); ++i) { llvm::dbgs() << "LSLocation #" << i; - getLocation(i).print(llvm::dbgs(), &Fn->getModule()); + getLocation(i).print(llvm::dbgs(), &Fn->getModule(), + TypeExpansionContext(*Fn)); }); if (Optimistic) diff --git a/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp b/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp index e52ce639db7d0..3642e337053fc 100644 --- a/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp +++ b/lib/SILOptimizer/Transforms/ReleaseDevirtualizer.cpp @@ -142,13 +142,14 @@ bool ReleaseDevirtualizer::createDeallocCall(SILType AllocType, SILFunction *Dealloc = M.lookUpFunction(DeallocRef); if (!Dealloc) return false; - - CanSILFunctionType DeallocType = Dealloc->getLoweredFunctionType(); + TypeExpansionContext context(*ReleaseInst->getFunction()); + CanSILFunctionType DeallocType = + Dealloc->getLoweredFunctionTypeInContext(context); auto *NTD = AllocType.getASTType()->getAnyNominal(); auto AllocSubMap = AllocType.getASTType() ->getContextSubstitutionMap(M.getSwiftModule(), NTD); - DeallocType = DeallocType->substGenericArgs(M, AllocSubMap); + DeallocType = DeallocType->substGenericArgs(M, AllocSubMap, context); SILBuilder B(ReleaseInst); if (object->getType() != AllocType) diff --git a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp index 61d1efa68b7c6..d7bae9dd2a835 100644 --- a/lib/SILOptimizer/Transforms/SILCodeMotion.cpp +++ b/lib/SILOptimizer/Transforms/SILCodeMotion.cpp @@ -60,7 +60,8 @@ static void createRefCountOpForPayload(SILBuilder &Builder, SILInstruction *I, // argument to the refcount instruction. SILValue EnumVal = DefOfEnum ? DefOfEnum : I->getOperand(0); - SILType ArgType = EnumVal->getType().getEnumElementType(EnumDecl, Mod); + SILType ArgType = EnumVal->getType().getEnumElementType( + EnumDecl, Mod, TypeExpansionContext(Builder.getFunction())); auto *UEDI = Builder.createUncheckedEnumData(I->getLoc(), EnumVal, EnumDecl, ArgType); diff --git a/lib/SILOptimizer/Transforms/SILSROA.cpp b/lib/SILOptimizer/Transforms/SILSROA.cpp index eafc9d41b120f..dcfb8d6803e78 100644 --- a/lib/SILOptimizer/Transforms/SILSROA.cpp +++ b/lib/SILOptimizer/Transforms/SILSROA.cpp @@ -228,8 +228,9 @@ createAllocas(llvm::SmallVector &NewAllocations) { "this point."); SILModule &M = AI->getModule(); for (auto *D : SD->getStoredProperties()) - NewAllocations.push_back( - B.createAllocStack(Loc, Type.getFieldType(D, M), {})); + NewAllocations.push_back(B.createAllocStack( + Loc, Type.getFieldType(D, M, TypeExpansionContext(B.getFunction())), + {})); } } diff --git a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp index 4a4530142072a..9fba73ceb7c3b 100644 --- a/lib/SILOptimizer/Transforms/SimplifyCFG.cpp +++ b/lib/SILOptimizer/Transforms/SimplifyCFG.cpp @@ -274,12 +274,15 @@ class ThreadInfo { ThreadInfo() = default; - void threadEdge() { + bool threadEdge() { LLVM_DEBUG(llvm::dbgs() << "thread edge from bb" << Src->getDebugID() << " to bb" << Dest->getDebugID() << '\n'); auto *SrcTerm = cast(Src->getTerminator()); BasicBlockCloner Cloner(SrcTerm->getDestBB()); + if (!Cloner.canCloneBlock()) + return false; + Cloner.cloneBranchTarget(SrcTerm); // We have copied the threaded block into the edge. @@ -313,7 +316,8 @@ class ThreadInfo { auto EnumVal = SEI->getOperand(); auto EnumTy = EnumVal->getType(); auto Loc = SEI->getLoc(); - auto Ty = EnumTy.getEnumElementType(EnumCase, SEI->getModule()); + auto Ty = EnumTy.getEnumElementType(EnumCase, SEI->getModule(), + Builder.getTypeExpansionContext()); SILValue UED( Builder.createUncheckedEnumData(Loc, EnumVal, EnumCase, Ty)); assert(UED->getType() == @@ -328,7 +332,8 @@ class ThreadInfo { // After rewriting the cloned branch, split the critical edge. // This does not currently update DominanceInfo. Cloner.splitCriticalEdges(nullptr, nullptr); - updateSSAAfterCloning(Cloner, Src, Dest); + Cloner.updateSSAAfterCloning(); + return true; } }; @@ -358,7 +363,8 @@ static SILValue createEnumElement(SILBuilder &Builder, // Do we have a payload. auto EnumTy = EnumVal->getType(); if (EnumElement->hasAssociatedValues()) { - auto Ty = EnumTy.getEnumElementType(EnumElement, SEI->getModule()); + auto Ty = EnumTy.getEnumElementType(EnumElement, SEI->getModule(), + Builder.getTypeExpansionContext()); SILValue UED(Builder.createUncheckedEnumData(SEI->getLoc(), EnumVal, EnumElement, Ty)); return Builder.createEnum(SEI->getLoc(), UED, EnumElement, EnumTy); @@ -549,8 +555,8 @@ bool SimplifyCFG::dominatorBasedSimplifications(SILFunction &Fn, return Changed; for (auto &ThreadInfo : JumpThreadableEdges) { - ThreadInfo.threadEdge(); - Changed = true; + if (ThreadInfo.threadEdge()) + Changed = true; } return Changed; @@ -781,7 +787,7 @@ static NullablePtr getEnumCase(SILValue Val, } static int getThreadingCost(SILInstruction *I) { - if (!isa(I) && !I->isTriviallyDuplicatable()) + if (!I->isTriviallyDuplicatable()) return 1000; // Don't jumpthread function calls. @@ -920,16 +926,6 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) { if (DestBB->getTerminator()->isFunctionExiting()) return false; - // We need to update SSA if a value duplicated is used outside of the - // duplicated block. - bool NeedToUpdateSSA = false; - - // Are the arguments to this block used outside of the block. - for (auto Arg : DestBB->getArguments()) - if ((NeedToUpdateSSA |= isUsedOutsideOfBlock(Arg))) { - break; - } - // We don't have a great cost model at the SIL level, so we don't want to // blissly duplicate tons of code with a goal of improved performance (we'll // leave that to LLVM). However, doing limited code duplication can lead to @@ -976,57 +972,39 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) { if (ThreadingBudget <= 0) return false; + // Don't jump thread through a potential header - this can produce irreducible + // control flow. Still, we make an exception for switch_enum. + bool DestIsLoopHeader = (LoopHeaders.count(DestBB) != 0); + if (DestIsLoopHeader) { + if (!isa(DestBB->getTerminator())) + return false; + } + // If it looks potentially interesting, decide whether we *can* do the // operation and whether the block is small enough to be worth duplicating. int copyCosts = 0; - SinkAddressProjections sinkProj; - for (auto ii = DestBB->begin(), ie = DestBB->end(); ii != ie;) { - copyCosts += getThreadingCost(&*ii); + BasicBlockCloner Cloner(DestBB); + for (auto &inst : *DestBB) { + copyCosts += getThreadingCost(&inst); if (ThreadingBudget <= copyCosts) return false; // If this is an address projection with outside uses, sink it before // checking for SSA update. - if (!sinkProj.analyzeAddressProjections(&*ii)) - return false; - - sinkProj.cloneProjections(); - // After cloning check if any of the non-address defs in the cloned block - // (including the current instruction) now have uses outside the - // block. Do this even if nothing was cloned. - if (!sinkProj.getInBlockDefs().empty()) - NeedToUpdateSSA = true; - - auto nextII = std::next(ii); - recursivelyDeleteTriviallyDeadInstructions( - &*ii, false, [&nextII](SILInstruction *deadInst) { - if (deadInst->getIterator() == nextII) - ++nextII; - }); - ii = nextII; - } - - // Don't jump thread through a potential header - this can produce irreducible - // control flow. Still, we make an exception for switch_enum. - bool DestIsLoopHeader = (LoopHeaders.count(DestBB) != 0); - if (DestIsLoopHeader) { - if (!isa(DestBB->getTerminator())) + if (!Cloner.canCloneInstruction(&inst)) return false; } - LLVM_DEBUG(llvm::dbgs() << "jump thread from bb" << SrcBB->getDebugID() << " to bb" << DestBB->getDebugID() << '\n'); JumpThreadingCost[DestBB] += copyCosts; - // Okay, it looks like we want to do this and we can. Duplicate the - // destination block into this one, rewriting uses of the BBArgs to use the - // branch arguments as we go. - BasicBlockCloner Cloner(DestBB); + // Duplicate the destination block into this one, rewriting uses of the BBArgs + // to use the branch arguments as we go. Cloner.cloneBranchTarget(BI); - // Does not currently update DominanceInfo. Cloner.splitCriticalEdges(nullptr, nullptr); + Cloner.updateSSAAfterCloning(); // Once all the instructions are copied, we can nuke BI itself. We also add // the threaded and edge block to the worklist now that they (likely) can be @@ -1034,9 +1012,6 @@ bool SimplifyCFG::tryJumpThreading(BranchInst *BI) { addToWorklist(SrcBB); addToWorklist(Cloner.getNewBB()); - if (NeedToUpdateSSA) - updateSSAAfterCloning(Cloner, Cloner.getNewBB(), DestBB); - // We may be able to simplify DestBB now that it has one fewer predecessor. simplifyAfterDroppingPredecessor(DestBB); @@ -1702,7 +1677,8 @@ bool SimplifyCFG::simplifySwitchEnumUnreachableBlocks(SwitchEnumInst *SEI) { auto &Mod = SEI->getModule(); auto OpndTy = SEI->getOperand()->getType(); - auto Ty = OpndTy.getEnumElementType(Element, Mod); + auto Ty = OpndTy.getEnumElementType( + Element, Mod, TypeExpansionContext(*SEI->getFunction())); auto *UED = SILBuilderWithScope(SEI) .createUncheckedEnumData(SEI->getLoc(), SEI->getOperand(), Element, Ty); @@ -2388,15 +2364,17 @@ bool SimplifyCFG::simplifyTryApplyBlock(TryApplyInst *TAI) { auto TargetFnTy = CalleeFnTy; if (TargetFnTy->isPolymorphic()) { - TargetFnTy = TargetFnTy->substGenericArgs(TAI->getModule(), - TAI->getSubstitutionMap()); + TargetFnTy = TargetFnTy->substGenericArgs( + TAI->getModule(), TAI->getSubstitutionMap(), + Builder.getTypeExpansionContext()); } SILFunctionConventions targetConv(TargetFnTy, TAI->getModule()); auto OrigFnTy = TAI->getCallee()->getType().getAs(); if (OrigFnTy->isPolymorphic()) { OrigFnTy = OrigFnTy->substGenericArgs(TAI->getModule(), - TAI->getSubstitutionMap()); + TAI->getSubstitutionMap(), + Builder.getTypeExpansionContext()); } SILFunctionConventions origConv(OrigFnTy, TAI->getModule()); @@ -2737,21 +2715,23 @@ bool SimplifyCFG::tailDuplicateObjCMethodCallSuccessorBlocks() { for (auto *BB : ObjCBlocks) { auto *Branch = cast(BB->getTerminator()); auto *DestBB = Branch->getDestBB(); - Changed = true; // Okay, it looks like we want to do this and we can. Duplicate the // destination block into this one, rewriting uses of the BBArgs to use the // branch arguments as we go. BasicBlockCloner Cloner(DestBB); + if (!Cloner.canCloneBlock()) + continue; + Cloner.cloneBranchTarget(Branch); // Does not currently update DominanceInfo. Cloner.splitCriticalEdges(nullptr, nullptr); + Cloner.updateSSAAfterCloning(); - updateSSAAfterCloning(Cloner, Cloner.getNewBB(), DestBB); + Changed = true; addToWorklist(Cloner.getNewBB()); } - return Changed; } @@ -2857,7 +2837,8 @@ bool ArgumentSplitter::createNewArguments() { return false; // Get the first level projection for the struct or tuple type. - Projection::getFirstLevelProjections(Arg->getType(), Mod, Projections); + Projection::getFirstLevelProjections(Arg->getType(), Mod, + TypeExpansionContext(*F), Projections); // We do not want to split arguments with less than 2 projections. if (Projections.size() < 2) @@ -2866,7 +2847,7 @@ bool ArgumentSplitter::createNewArguments() { // We do not want to split arguments that have less than 2 non-trivial // projections. if (count_if(Projections, [&](const Projection &P) { - return !P.getType(Ty, Mod).isTrivial(*F); + return !P.getType(Ty, Mod, TypeExpansionContext(*F)).isTrivial(*F); }) < 2) return false; @@ -2878,8 +2859,9 @@ bool ArgumentSplitter::createNewArguments() { // old one. llvm::SmallVector NewArgumentValues; for (auto &P : Projections) { - auto *NewArg = ParentBB->createPhiArgument(P.getType(Ty, Mod), - ValueOwnershipKind::Owned); + auto *NewArg = ParentBB->createPhiArgument( + P.getType(Ty, Mod, TypeExpansionContext(*F)), + ValueOwnershipKind::Owned); // This is unfortunate, but it feels wrong to put in an API into SILBuilder // that only takes in arguments. // diff --git a/lib/SILOptimizer/Transforms/SpecializeOpaqueArchetypes.cpp b/lib/SILOptimizer/Transforms/SpecializeOpaqueArchetypes.cpp deleted file mode 100644 index 11f66eb2666bf..0000000000000 --- a/lib/SILOptimizer/Transforms/SpecializeOpaqueArchetypes.cpp +++ /dev/null @@ -1,558 +0,0 @@ -//===--- SpecializeOpaqueArchetypes.cpp - Specialize opaque archetypes ---===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2019 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 pass to specialize opaque archetypes -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "opaque-archetype-specializer" - -#include "swift/AST/Types.h" -#include "swift/SIL/SILFunction.h" -#include "swift/SIL/SILInstruction.h" -#include "swift/SIL/TypeSubstCloner.h" -#include "swift/SILOptimizer/PassManager/Transforms.h" -#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" - -#include "llvm/Support/CommandLine.h" - -llvm::cl::opt - EnableOpaqueArchetypeSpecializer("enable-opaque-archetype-specializer", - llvm::cl::init(true)); - -using namespace swift; - -static const DeclContext * -getDeclContextIfInCurrentModule(const SILFunction &fn) { - auto *dc = fn.getDeclContext(); - auto *currentModule = fn.getModule().getSwiftModule(); - if (dc && dc->isChildContextOf(currentModule)) - return dc; - return currentModule; -} - -static Type substOpaqueTypesWithUnderlyingTypes( - Type ty, SILFunction *context) { - auto *dc = getDeclContextIfInCurrentModule(*context); - ReplaceOpaqueTypesWithUnderlyingTypes replacer( - dc, context->getResilienceExpansion()); - return ty.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes); -} - -static SubstitutionMap -substOpaqueTypesWithUnderlyingTypes(SubstitutionMap map, SILFunction *context) { - auto *dc = getDeclContextIfInCurrentModule(*context); - ReplaceOpaqueTypesWithUnderlyingTypes replacer( - dc, context->getResilienceExpansion()); - return map.subst(replacer, replacer, SubstFlags::SubstituteOpaqueArchetypes); -} - -namespace { -class OpaqueSpecializerCloner - : public SILCloner { - - using SuperTy = SILCloner; - - SILBasicBlock *entryBlock; - SILBasicBlock *cloneFromBlock; - - /// Cache for substituted types. - llvm::DenseMap TypeCache; - - SILFunction &Original; - -public: - friend class SILCloner; - friend class SILCloner; - friend class SILInstructionVisitor; - - OpaqueSpecializerCloner(SILFunction &fun) : SuperTy(fun), Original(fun) { - entryBlock = fun.getEntryBlock(); - cloneFromBlock = entryBlock->split(entryBlock->begin()); - } - - void clone(); - -protected: - void insertOpaqueToConcreteAddressCasts(SILInstruction *orig, - SILInstruction *cloned); - - void postProcess(SILInstruction *orig, SILInstruction *cloned) { - SILCloner::postProcess(orig, cloned); - insertOpaqueToConcreteAddressCasts(orig, cloned); - } - - void visitTerminator(SILBasicBlock *BB) { - visit(BB->getTerminator()); - } - - void visitReturnInst(ReturnInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - auto origResult = Inst->getOperand(); - auto clonedResult = getOpValue(Inst->getOperand()); - if (clonedResult->getType().getASTType() != - origResult->getType().getASTType()) { - clonedResult = createCast(RegularLocation::getAutoGeneratedLocation(), - clonedResult, origResult->getType()); - } - recordClonedInstruction( - Inst, - getBuilder().createReturn(getOpLocation(Inst->getLoc()), clonedResult)); - } - - void visitStructInst(StructInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - auto elements = getOpValueArray<8>(Inst->getElements()); - auto structTy = getOpType(Inst->getType()); - auto *structDecl = structTy.getStructOrBoundGenericStruct(); - unsigned idx = 0; - // Adjust field types if neccessary. - for (VarDecl *field : structDecl->getStoredProperties()) { - SILType loweredType = structTy.getFieldType( - field, getBuilder().getFunction().getModule()); - if (elements[idx]->getType() != loweredType) { - elements[idx] = createCast(getOpLocation(Inst->getLoc()), elements[idx], - loweredType); - } - idx++; - } - recordClonedInstruction( - Inst, getBuilder().createStruct(getOpLocation(Inst->getLoc()), - getOpType(Inst->getType()), elements)); - } - - void visitTupleInst(TupleInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - auto elements = getOpValueArray<8>(Inst->getElements()); - auto tupleTy = getOpType(Inst->getType()); - for (size_t i = 0, size = Inst->getElements().size(); i < size; ++i) { - auto elementTy = tupleTy.getTupleElementType(i); - if (Inst->getElement(i)->getType() != elementTy) { - elements[i] = - createCast(getOpLocation(Inst->getLoc()), elements[i], elementTy); - } - } - recordClonedInstruction( - Inst, getBuilder().createTuple(getOpLocation(Inst->getLoc()), - getOpType(Inst->getType()), elements)); - } - - void visitEnumInst(EnumInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - SILValue opd = SILValue(); - auto newTy = getOpType(Inst->getType()); - if (Inst->hasOperand()) { - opd = getOpValue(Inst->getOperand()); - SILType newCaseTy = newTy.getEnumElementType( - Inst->getElement(), getBuilder().getFunction().getModule()); - if (opd->getType() != newCaseTy) - opd = createCast(getOpLocation(Inst->getLoc()), opd, newCaseTy); - } - recordClonedInstruction( - Inst, getBuilder().createEnum(getOpLocation(Inst->getLoc()), opd, - Inst->getElement(), newTy)); - } - - void visitInitEnumDataAddrInst(InitEnumDataAddrInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - auto opd = getOpValue(Inst->getOperand()); - auto caseTy = opd->getType().getEnumElementType( - Inst->getElement(), getBuilder().getFunction().getModule()); - auto expectedTy = getOpType(Inst->getType()); - if (expectedTy != caseTy) - expectedTy = caseTy; - recordClonedInstruction(Inst, getBuilder().createInitEnumDataAddr( - getOpLocation(Inst->getLoc()), opd, - Inst->getElement(), expectedTy)); - } - - /// Projections should not change the type if the type is not specialized. - void visitStructElementAddrInst(StructElementAddrInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - auto opd = getOpValue(Inst->getOperand()); - recordClonedInstruction( - Inst, getBuilder().createStructElementAddr( - getOpLocation(Inst->getLoc()), opd, Inst->getField())); - } - - /// Projections should not change the type if the type is not specialized. - void visitStructExtractInst(StructExtractInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - auto opd = getOpValue(Inst->getOperand()); - recordClonedInstruction( - Inst, getBuilder().createStructExtract(getOpLocation(Inst->getLoc()), - opd, Inst->getField())); - } - /// Projections should not change the type if the type is not specialized. - void visitTupleElementAddrInst(TupleElementAddrInst *Inst) { - auto opd = getOpValue(Inst->getOperand()); - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - recordClonedInstruction(Inst, getBuilder().createTupleElementAddr( - getOpLocation(Inst->getLoc()), opd, - Inst->getFieldNo())); - } - /// Projections should not change the type if the type is not specialized. - void visitTupleExtractInst(TupleExtractInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - recordClonedInstruction( - Inst, getBuilder().createTupleExtract(getOpLocation(Inst->getLoc()), - getOpValue(Inst->getOperand()), - Inst->getFieldNo())); - } - /// Projections should not change the type if the type is not specialized. - void visitRefElementAddrInst(RefElementAddrInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - recordClonedInstruction( - Inst, getBuilder().createRefElementAddr( - getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand()), - Inst->getField())); - } - - /// Projections should not change the type if the type is not specialized. - void visitRefTailAddrInst(RefTailAddrInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - recordClonedInstruction( - Inst, getBuilder().createRefTailAddr(getOpLocation(Inst->getLoc()), - getOpValue(Inst->getOperand()), - Inst->getType())); - } - - void visitYieldInst(YieldInst *Inst) { - auto OrigValues = Inst->getYieldedValues(); - auto Values = getOpValueArray<8>(Inst->getYieldedValues()); - auto ResumeBB = getOpBasicBlock(Inst->getResumeBB()); - auto UnwindBB = getOpBasicBlock(Inst->getUnwindBB()); - for (auto idx : indices(Values)) { - if (OrigValues[idx]->getType().getASTType() != - Values[idx]->getType().getASTType()) { - Values[idx] = createCast(RegularLocation::getAutoGeneratedLocation(), - Values[idx], OrigValues[idx]->getType()); - } - } - - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - recordClonedInstruction( - Inst, getBuilder().createYield(getOpLocation(Inst->getLoc()), Values, - ResumeBB, UnwindBB)); - } - - void visitCopyAddrInst(CopyAddrInst *Inst) { - auto src = getOpValue(Inst->getSrc()); - auto dst = getOpValue(Inst->getDest()); - auto srcType = src->getType(); - auto destType = dst->getType(); - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - // If the types mismatch cast the operands to the non opaque archetype. - if (destType.getASTType() != srcType.getASTType()) { - if (srcType.getASTType()->hasOpaqueArchetype()) { - src = getBuilder().createUncheckedAddrCast( - getOpLocation(Inst->getLoc()), src, destType); - } else if (destType.getASTType()->hasOpaqueArchetype()) { - dst = getBuilder().createUncheckedAddrCast( - getOpLocation(Inst->getLoc()), dst, srcType); - } - } - recordClonedInstruction( - Inst, getBuilder().createCopyAddr(getOpLocation(Inst->getLoc()), src, - dst, Inst->isTakeOfSrc(), - Inst->isInitializationOfDest())); - } - - SILValue remapResultType(SILLocation loc, SILValue val) { - auto specializedTy = remapType(val->getType()); - if (val->getType() == specializedTy) - return val; - return createCast(loc, val, specializedTy); - } - - void visitThinToThickFunctionInst(ThinToThickFunctionInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - auto loc = getOpLocation(Inst->getLoc()); - auto opd = remapResultType(loc, getOpValue(Inst->getOperand())); - recordClonedInstruction(Inst, getBuilder().createThinToThickFunction( - loc, opd, getOpType(Inst->getType()))); - } - - void visitStoreInst(StoreInst *Inst) { - auto src = getOpValue(Inst->getSrc()); - auto dst = getOpValue(Inst->getDest()); - auto srcType = src->getType(); - auto destType = dst->getType(); - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - // If the types mismatch cast the operands to the non opaque archetype. - if (destType.getASTType() != srcType.getASTType()) { - if (srcType.getASTType()->hasOpaqueArchetype()) { - assert(!srcType.isAddress()); - src = createCast(getOpLocation(Inst->getLoc()), src, - destType.getObjectType()); - } else if (destType.getASTType()->hasOpaqueArchetype()) { - dst = getBuilder().createUncheckedAddrCast( - getOpLocation(Inst->getLoc()), dst, srcType.getAddressType()); - } - } - - if (!getBuilder().hasOwnership()) { - switch (Inst->getOwnershipQualifier()) { - case StoreOwnershipQualifier::Assign: { - auto *li = getBuilder().createLoad(getOpLocation(Inst->getLoc()), dst, - LoadOwnershipQualifier::Unqualified); - auto *si = getBuilder().createStore( - getOpLocation(Inst->getLoc()), src, getOpValue(Inst->getDest()), - StoreOwnershipQualifier::Unqualified); - getBuilder().emitDestroyValueOperation(getOpLocation(Inst->getLoc()), - li); - return recordClonedInstruction(Inst, si); - } - case StoreOwnershipQualifier::Init: - case StoreOwnershipQualifier::Trivial: - case StoreOwnershipQualifier::Unqualified: - break; - } - - return recordClonedInstruction( - Inst, - getBuilder().createStore(getOpLocation(Inst->getLoc()), src, dst, - StoreOwnershipQualifier::Unqualified)); - } - - recordClonedInstruction( - Inst, getBuilder().createStore(getOpLocation(Inst->getLoc()), src, dst, - Inst->getOwnershipQualifier())); - } - -protected: - - SILType remapType(SILType Ty) { - SILType &Sty = TypeCache[Ty]; - if (Sty) - return Sty; - auto *dc = getDeclContextIfInCurrentModule(Original); - - // Apply the opaque types substitution. - ReplaceOpaqueTypesWithUnderlyingTypes replacer( - dc, Original.getResilienceExpansion()); - Sty = Ty.subst(Original.getModule(), replacer, replacer, - CanGenericSignature(), true); - return Sty; - } - - CanType remapASTType(CanType ty) { - // Apply the opaque types substitution. - return substOpaqueTypesWithUnderlyingTypes(ty, &Original) - ->getCanonicalType(); - } - - ProtocolConformanceRef remapConformance(Type type, - ProtocolConformanceRef conf) { - auto *dc = getDeclContextIfInCurrentModule(Original); - // Apply the opaque types substitution. - ReplaceOpaqueTypesWithUnderlyingTypes replacer( - dc, Original.getResilienceExpansion()); - return conf.subst(type, replacer, replacer, - SubstFlags::SubstituteOpaqueArchetypes); - } - - SubstitutionMap remapSubstitutionMap(SubstitutionMap Subs) { - // Apply the opaque types substitution. - return substOpaqueTypesWithUnderlyingTypes(Subs, &Original); - } - - SILValue createCast(SILLocation loc, SILValue opd, SILType type) { - auto &CurFn = getBuilder().getFunction(); - if (opd->getType().isAddress()) { - return getBuilder().createUncheckedAddrCast(loc, opd, type); - } else if (opd->getType().is()) { - return getBuilder().createConvertFunction( - loc, opd, type, /*withoutActuallyEscaping*/ false); - } else if (opd->getType().isTrivial(CurFn)) { - return getBuilder().createUncheckedTrivialBitCast(loc, opd, type); - } else if (opd->getType().canRefCast(opd->getType(), type, - CurFn.getModule())) { - return getBuilder().createUncheckedRefCast(loc, opd, type); - } else { - // This could be improved upon by recursively recomposing the type. - auto *stackLoc = getBuilder().createAllocStack(loc, type); - auto *addr = getBuilder().createUncheckedAddrCast( - loc, stackLoc, opd->getType().getAddressType()); - getBuilder().createTrivialStoreOr(loc, opd, addr, - StoreOwnershipQualifier::Init, true); - SILValue res = getBuilder().createTrivialLoadOr( - loc, stackLoc, LoadOwnershipQualifier::Take, true); - getBuilder().createDeallocStack(loc, stackLoc); - return res; - } - } - - void replaceBlockArgumentType(SILLocation loc, SILBasicBlock *destBlock, - SILType withType) { - assert(destBlock->getArguments().size() == 1); - - auto origType = (*destBlock->args_begin())->getType(); - auto origPhi = destBlock->getPhiArguments()[0]; - SILValue undef = SILUndef::get(origType, getBuilder().getFunction()); - SmallVector useList(origPhi->use_begin(), origPhi->use_end()); - for (auto *use : useList) { - use->set(undef); - } - - auto *newPhi = - destBlock->replacePhiArgument(0, withType, origPhi->getOwnershipKind()); - - getBuilder().setInsertionPoint(destBlock->begin()); - auto cast = createCast(loc, newPhi, origType); - for (auto *use : useList) { - use->set(cast); - } - } - - void fixUp(SILFunction *) { - auto &clonedFunction = getBuilder().getFunction(); - for (auto &BB : clonedFunction) { - for (auto &cloned : BB) { - // Fix up the type of try_apply successor block arguments. - if (auto *tryApply = dyn_cast(&cloned)) { - auto normalBB = tryApply->getNormalBB(); - SILFunctionConventions calleeConv( - tryApply->getSubstCalleeType(), - tryApply->getFunction()->getModule()); - auto normalBBType = (*normalBB->args_begin())->getType(); - auto applyResultType = calleeConv.getSILResultType(); - if (normalBBType != calleeConv.getSILResultType()) { - replaceBlockArgumentType(tryApply->getLoc(), normalBB, applyResultType); - } - } - // Fix up the type of switch_enum successor block arguments. - if (auto *switchEnum = dyn_cast(&cloned)) { - SILType enumTy = switchEnum->getOperand()->getType(); - for (unsigned i = 0, e = switchEnum->getNumCases(); i < e; ++i) { - EnumElementDecl *elt; - SILBasicBlock *dest; - std::tie(elt, dest) = switchEnum->getCase(i); - - if (elt->hasAssociatedValues() && - dest->getArguments().size() == 1) { - SILType eltArgTy = - enumTy.getEnumElementType(elt, clonedFunction.getModule()); - SILType bbArgTy = dest->getArguments()[0]->getType(); - if (eltArgTy != bbArgTy) - replaceBlockArgumentType(switchEnum->getLoc(), dest, eltArgTy); - - } - } - } - } - } - } -}; -} // namespace - -void OpaqueSpecializerCloner::clone() { - for (auto arg: entryBlock->getArguments()) - recordFoldedValue(arg, arg); - cloneReachableBlocks(cloneFromBlock, {}, entryBlock, - true /*havePrepopulatedFunctionArgs*/); - getBuilder().setInsertionPoint(entryBlock); - getBuilder().createBranch(RegularLocation::getAutoGeneratedLocation(), - getOpBasicBlock(cloneFromBlock)); -} - -/// Update address uses of the opaque type archetype with the concrete type. -/// This is neccessary for apply instructions. -void OpaqueSpecializerCloner::insertOpaqueToConcreteAddressCasts( - SILInstruction *orig, SILInstruction *cloned) { - - // Replace apply operands. - if (auto apply = ApplySite::isa(cloned)) { - SavedInsertionPointRAII restore(getBuilder()); - getBuilder().setInsertionPoint(apply.getInstruction()); - auto substConv = apply.getSubstCalleeConv(); - unsigned idx = 0; - for (auto &opd : apply.getArgumentOperands()) { - auto argIdx = apply.getCalleeArgIndex(opd); - auto argType = substConv.getSILArgumentType(argIdx); - if (argType.getASTType() != opd.get()->getType().getASTType()) { - opd.set(createCast(apply.getLoc(), opd.get(), argType)); - } - ++idx; - } - } -} - -namespace { -class OpaqueArchetypeSpecializer : public SILFunctionTransform { - void run() override { - if (!EnableOpaqueArchetypeSpecializer) - return; - - auto *context = getFunction(); - - if (!context->shouldOptimize()) - return; - - auto opaqueArchetypeWouldChange = [=](CanType ty) -> bool { - if (!ty->hasOpaqueArchetype()) - return false; - - return ty.findIf([=](Type type) -> bool { - if (auto opaqueTy = type->getAs()) { - auto opaque = opaqueTy->getDecl(); - OpaqueSubstitutionKind subKind = - ReplaceOpaqueTypesWithUnderlyingTypes:: - shouldPerformSubstitution(opaque, - context->getModule().getSwiftModule(), - context->getResilienceExpansion()); - return subKind != OpaqueSubstitutionKind::DontSubstitute; - } - return false; - }); - }; - - // Look for opaque type archetypes. - bool foundOpaqueArchetype = false; - for (auto &BB : *getFunction()) { - for (auto &inst : BB) { - auto hasOpaqueOperand = [&] (SILInstruction &inst) -> bool { - // Check the operands for opaque types. - for (auto &opd : inst.getAllOperands()) - if (opaqueArchetypeWouldChange(opd.get()->getType().getASTType())) - return true; - return false; - }; - if ((foundOpaqueArchetype = hasOpaqueOperand(inst))) - break; - auto hasOpaqueResult = [&](SILInstruction &inst) -> bool { - // Check the results for opaque types. - for (const auto &res : inst.getResults()) - if (opaqueArchetypeWouldChange(res->getType().getASTType())) - return true; - return false; - }; - if ((foundOpaqueArchetype = hasOpaqueResult(inst))) - break; - } - if (foundOpaqueArchetype) - break; - } - - if (foundOpaqueArchetype) { - OpaqueSpecializerCloner s(*getFunction()); - s.clone(); - removeUnreachableBlocks(*getFunction()); - invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody); - } - } -}; -} // end anonymous namespace - -SILTransform *swift::createOpaqueArchetypeSpecializer() { - return new OpaqueArchetypeSpecializer(); -} diff --git a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp index 2b3c7e070f3e7..5ac534a26e9fa 100644 --- a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp +++ b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp @@ -83,16 +83,13 @@ class BugReducerTester : public SILFunctionTransform { ResultInfoArray.push_back( SILResultInfo(EmptyTupleCanType, ResultConvention::Unowned)); auto FuncType = SILFunctionType::get( - nullptr, SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, - false /*isPseudoGeneric*/, - // SWIFT_ENABLE_TENSORFLOW - false /*noescape*/, - DifferentiabilityKind - ::NonDifferentiable), + nullptr, + SILFunctionType::ExtInfo(SILFunctionType::Representation::Thin, + false /*isPseudoGeneric*/, false /*noescape*/, + DifferentiabilityKind::NonDifferentiable), SILCoroutineKind::None, ParameterConvention::Direct_Unowned, - ArrayRef(), ArrayRef(), - ResultInfoArray, None, - SubstitutionMap(), false, + ArrayRef(), ArrayRef(), ResultInfoArray, + None, SubstitutionMap(), false, getFunction()->getModule().getASTContext()); SILOptFunctionBuilder FunctionBuilder(*this); diff --git a/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp b/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp index 9c5ac3a6e8e42..e30cbc9cce79f 100644 --- a/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp +++ b/lib/SILOptimizer/UtilityPasses/LSLocationPrinter.cpp @@ -78,12 +78,14 @@ class LSLocationPrinter : public SILModuleTransform { SILValue V = LI->getOperand(); // This is an address type, take it object type. SILType Ty = V->getType().getObjectType(); - ProjectionPath::expandTypeIntoLeafProjectionPaths(Ty, M, PPList); + ProjectionPath::expandTypeIntoLeafProjectionPaths( + Ty, M, TypeExpansionContext(Fn), PPList); } else if (auto *SI = dyn_cast(&II)) { SILValue V = SI->getDest(); // This is an address type, take it object type. SILType Ty = V->getType().getObjectType(); - ProjectionPath::expandTypeIntoLeafProjectionPaths(Ty, M, PPList); + ProjectionPath::expandTypeIntoLeafProjectionPaths( + Ty, M, TypeExpansionContext(Fn), PPList); } else { // Not interested in these instructions yet. continue; @@ -91,7 +93,7 @@ class LSLocationPrinter : public SILModuleTransform { llvm::outs() << "#" << Counter++ << II; for (auto &T : PPList) { - T.getValue().print(llvm::outs(), *M); + T.getValue().print(llvm::outs(), *M, TypeExpansionContext(Fn)); } PPList.clear(); } @@ -111,12 +113,14 @@ class LSLocationPrinter : public SILModuleTransform { V = LI->getOperand(); // This is an address type, take it object type. Ty = V->getType().getObjectType(); - ProjectionPath::expandTypeIntoLeafProjectionPaths(Ty, M, PPList); + ProjectionPath::expandTypeIntoLeafProjectionPaths( + Ty, M, TypeExpansionContext(Fn), PPList); } else if (auto *SI = dyn_cast(&II)) { V = SI->getDest(); // This is an address type, take it object type. Ty = V->getType().getObjectType(); - ProjectionPath::expandTypeIntoLeafProjectionPaths(Ty, M, PPList); + ProjectionPath::expandTypeIntoLeafProjectionPaths( + Ty, M, TypeExpansionContext(Fn), PPList); } else { // Not interested in these instructions yet. continue; @@ -124,7 +128,7 @@ class LSLocationPrinter : public SILModuleTransform { llvm::outs() << "#" << Counter++ << II; for (auto &T : PPList) { - T.getValue().print(llvm::outs(), *M); + T.getValue().print(llvm::outs(), *M, TypeExpansionContext(Fn)); } PPList.clear(); } @@ -150,14 +154,16 @@ class LSLocationPrinter : public SILModuleTransform { L.init(UO, ProjectionPath::getProjectionPath(UO, Mem)); if (!L.isValid()) continue; - LSLocation::expand(L, &Fn.getModule(), Locs, TE); + LSLocation::expand(L, &Fn.getModule(), TypeExpansionContext(Fn), Locs, + TE); } else if (auto *SI = dyn_cast(&II)) { SILValue Mem = SI->getDest(); SILValue UO = getUnderlyingObject(Mem); L.init(UO, ProjectionPath::getProjectionPath(UO, Mem)); if (!L.isValid()) continue; - LSLocation::expand(L, &Fn.getModule(), Locs, TE); + LSLocation::expand(L, &Fn.getModule(), TypeExpansionContext(Fn), Locs, + TE); } else { // Not interested in these instructions yet. continue; @@ -165,7 +171,7 @@ class LSLocationPrinter : public SILModuleTransform { llvm::outs() << "#" << Counter++ << II; for (auto &Loc : Locs) { - Loc.print(llvm::outs(), &Fn.getModule()); + Loc.print(llvm::outs(), &Fn.getModule(), TypeExpansionContext(Fn)); } Locs.clear(); } @@ -194,14 +200,16 @@ class LSLocationPrinter : public SILModuleTransform { L.init(UO, ProjectionPath::getProjectionPath(UO, Mem)); if (!L.isValid()) continue; - LSLocation::expand(L, &Fn.getModule(), Locs, TE); + LSLocation::expand(L, &Fn.getModule(), TypeExpansionContext(Fn), Locs, + TE); } else if (auto *SI = dyn_cast(&II)) { SILValue Mem = SI->getDest(); SILValue UO = getUnderlyingObject(Mem); L.init(UO, ProjectionPath::getProjectionPath(UO, Mem)); if (!L.isValid()) continue; - LSLocation::expand(L, &Fn.getModule(), Locs, TE); + LSLocation::expand(L, &Fn.getModule(), TypeExpansionContext(Fn), Locs, + TE); } else { // Not interested in these instructions yet. continue; @@ -216,10 +224,10 @@ class LSLocationPrinter : public SILModuleTransform { } // This should get the original (unexpanded) location back. - LSLocation::reduce(L, &Fn.getModule(), SLocs); + LSLocation::reduce(L, &Fn.getModule(), TypeExpansionContext(Fn), SLocs); llvm::outs() << "#" << Counter++ << II; for (auto &Loc : SLocs) { - Loc.print(llvm::outs(), &Fn.getModule()); + Loc.print(llvm::outs(), &Fn.getModule(), TypeExpansionContext(Fn)); } L.reset(); Locs.clear(); diff --git a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp index 31703885545fa..cd192bcc9f9ef 100644 --- a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp +++ b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp @@ -12,11 +12,389 @@ #define DEBUG_TYPE "serialize-sil" #include "swift/Strings.h" +#include "swift/SIL/ApplySite.h" +#include "swift/SIL/SILCloner.h" +#include "swift/SIL/SILFunction.h" #include "swift/SILOptimizer/PassManager/Passes.h" #include "swift/SILOptimizer/PassManager/Transforms.h" +#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h" using namespace swift; +namespace { +/// In place map opaque archetypes to their underlying type in a function. +/// This needs to happen when a function changes from serializable to not +/// serializable. +class MapOpaqueArchetypes : public SILCloner { + using SuperTy = SILCloner; + + SILBasicBlock *origEntryBlock; + SILBasicBlock *clonedEntryBlock; +public: + friend class SILCloner; + friend class SILCloner; + friend class SILInstructionVisitor; + + MapOpaqueArchetypes(SILFunction &fun) : SuperTy(fun) { + origEntryBlock = fun.getEntryBlock(); + clonedEntryBlock = fun.createBasicBlock(); + } + + SILType remapType(SILType Ty) { + if (!Ty.getASTType()->hasOpaqueArchetype() || + !getBuilder() + .getTypeExpansionContext() + .shouldLookThroughOpaqueTypeArchetypes()) + return Ty; + + return getBuilder().getTypeLowering(Ty).getLoweredType().getCategoryType( + Ty.getCategory()); + } + + CanType remapASTType(CanType ty) { + if (!ty->hasOpaqueArchetype() || + !getBuilder() + .getTypeExpansionContext() + .shouldLookThroughOpaqueTypeArchetypes()) + return ty; + // Remap types containing opaque result types in the current context. + return getBuilder() + .getTypeLowering(SILType::getPrimitiveObjectType(ty)) + .getLoweredType() + .getASTType(); + } + + ProtocolConformanceRef remapConformance(Type ty, + ProtocolConformanceRef conf) { + auto context = getBuilder().getTypeExpansionContext(); + auto conformance = conf; + if (ty->hasOpaqueArchetype() && + context.shouldLookThroughOpaqueTypeArchetypes()) { + conformance = + substOpaqueTypesWithUnderlyingTypes(conformance, ty, context); + } + return conformance; + } + + void replace(); +}; +} // namespace + +void MapOpaqueArchetypes::replace() { + // Map the function arguments. + SmallVector entryArgs; + entryArgs.reserve(origEntryBlock->getArguments().size()); + for (auto &origArg : origEntryBlock->getArguments()) { + SILType mappedType = remapType(origArg->getType()); + auto *NewArg = clonedEntryBlock->createFunctionArgument( + mappedType, origArg->getDecl(), true); + entryArgs.push_back(NewArg); + } + + getBuilder().setInsertionPoint(clonedEntryBlock); + auto &fn = getBuilder().getFunction(); + cloneFunctionBody(&fn, clonedEntryBlock, entryArgs, + true /*replaceOriginalFunctionInPlace*/); + // Insert the new entry block at the beginning. + fn.getBlocks().splice(fn.getBlocks().begin(), fn.getBlocks(), + clonedEntryBlock); + removeUnreachableBlocks(fn); +} + +static bool opaqueArchetypeWouldChange(TypeExpansionContext context, + CanType ty) { + if (!ty->hasOpaqueArchetype()) + return false; + + return ty.findIf([=](Type type) -> bool { + if (auto opaqueTy = type->getAs()) { + auto opaque = opaqueTy->getDecl(); + auto module = context.getContext()->getParentModule(); + OpaqueSubstitutionKind subKind = + ReplaceOpaqueTypesWithUnderlyingTypes::shouldPerformSubstitution( + opaque, module, context.getResilienceExpansion()); + return subKind != OpaqueSubstitutionKind::DontSubstitute; + } + return false; + }); +} + +static bool hasOpaqueArchetypeOperand(TypeExpansionContext context, + SILInstruction &inst) { + // Check the operands for opaque types. + for (auto &opd : inst.getAllOperands()) + if (opaqueArchetypeWouldChange(context, opd.get()->getType().getASTType())) + return true; + return false; +} + +static bool hasOpaqueArchetypeResult(TypeExpansionContext context, + SILInstruction &inst) { + // Check the results for opaque types. + for (const auto &res : inst.getResults()) + if (opaqueArchetypeWouldChange(context, res->getType().getASTType())) + return true; + return false; +} + +static bool hasOpaqueArchetype(TypeExpansionContext context, + SILInstruction &inst) { + // Check operands and results. + if (hasOpaqueArchetypeOperand(context, inst)) + return true; + if (hasOpaqueArchetypeResult(context, inst)) + return true; + + // Check substitution maps. + switch (inst.getKind()) { + case SILInstructionKind::AllocStackInst: + case SILInstructionKind::AllocRefInst: + case SILInstructionKind::AllocRefDynamicInst: + case SILInstructionKind::AllocValueBufferInst: + case SILInstructionKind::AllocBoxInst: + case SILInstructionKind::AllocExistentialBoxInst: + case SILInstructionKind::IndexAddrInst: + case SILInstructionKind::TailAddrInst: + case SILInstructionKind::IndexRawPointerInst: + case SILInstructionKind::FunctionRefInst: + case SILInstructionKind::DynamicFunctionRefInst: + case SILInstructionKind::PreviousDynamicFunctionRefInst: + case SILInstructionKind::GlobalAddrInst: + case SILInstructionKind::GlobalValueInst: + case SILInstructionKind::IntegerLiteralInst: + case SILInstructionKind::FloatLiteralInst: + case SILInstructionKind::StringLiteralInst: + case SILInstructionKind::ClassMethodInst: + case SILInstructionKind::SuperMethodInst: + case SILInstructionKind::ObjCMethodInst: + case SILInstructionKind::ObjCSuperMethodInst: + case SILInstructionKind::WitnessMethodInst: + case SILInstructionKind::UpcastInst: + case SILInstructionKind::AddressToPointerInst: + case SILInstructionKind::PointerToAddressInst: + case SILInstructionKind::UncheckedRefCastInst: + case SILInstructionKind::UncheckedAddrCastInst: + case SILInstructionKind::UncheckedTrivialBitCastInst: + case SILInstructionKind::UncheckedBitwiseCastInst: + case SILInstructionKind::RefToRawPointerInst: + case SILInstructionKind::RawPointerToRefInst: +#define LOADABLE_REF_STORAGE(Name, ...) \ + case SILInstructionKind::RefTo##Name##Inst: \ + case SILInstructionKind::Name##ToRefInst: +#include "swift/AST/ReferenceStorage.def" +#undef LOADABLE_REF_STORAGE_HELPER + case SILInstructionKind::ConvertFunctionInst: + case SILInstructionKind::ConvertEscapeToNoEscapeInst: + case SILInstructionKind::ThinFunctionToPointerInst: + case SILInstructionKind::PointerToThinFunctionInst: + case SILInstructionKind::RefToBridgeObjectInst: + case SILInstructionKind::BridgeObjectToRefInst: + case SILInstructionKind::BridgeObjectToWordInst: + case SILInstructionKind::ThinToThickFunctionInst: + case SILInstructionKind::ThickToObjCMetatypeInst: + case SILInstructionKind::ObjCToThickMetatypeInst: + case SILInstructionKind::ObjCMetatypeToObjectInst: + case SILInstructionKind::ObjCExistentialMetatypeToObjectInst: + case SILInstructionKind::UnconditionalCheckedCastValueInst: + case SILInstructionKind::UnconditionalCheckedCastInst: + case SILInstructionKind::ClassifyBridgeObjectInst: + case SILInstructionKind::ValueToBridgeObjectInst: + case SILInstructionKind::MarkDependenceInst: + case SILInstructionKind::CopyBlockInst: + case SILInstructionKind::CopyBlockWithoutEscapingInst: + case SILInstructionKind::CopyValueInst: +#define UNCHECKED_REF_STORAGE(Name, ...) \ + case SILInstructionKind::StrongCopy##Name##ValueInst: +#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case SILInstructionKind::StrongCopy##Name##ValueInst: +#include "swift/AST/ReferenceStorage.def" +#undef UNCHECKED_REF_STORAGE +#undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE + case SILInstructionKind::UncheckedOwnershipConversionInst: + case SILInstructionKind::IsUniqueInst: + case SILInstructionKind::IsEscapingClosureInst: + case SILInstructionKind::LoadInst: + case SILInstructionKind::LoadBorrowInst: + case SILInstructionKind::BeginBorrowInst: + case SILInstructionKind::StoreBorrowInst: + case SILInstructionKind::BeginAccessInst: +#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \ + case SILInstructionKind::Load##Name##Inst: +#include "swift/AST/ReferenceStorage.def" +#undef NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE + case SILInstructionKind::MarkUninitializedInst: + case SILInstructionKind::ProjectValueBufferInst: + case SILInstructionKind::ProjectBoxInst: + case SILInstructionKind::ProjectExistentialBoxInst: + case SILInstructionKind::BuiltinInst: + case SILInstructionKind::MetatypeInst: + case SILInstructionKind::ValueMetatypeInst: + case SILInstructionKind::ExistentialMetatypeInst: + case SILInstructionKind::ObjCProtocolInst: + case SILInstructionKind::ObjectInst: + case SILInstructionKind::TupleInst: + case SILInstructionKind::TupleExtractInst: + case SILInstructionKind::TupleElementAddrInst: + case SILInstructionKind::StructInst: + case SILInstructionKind::StructExtractInst: + case SILInstructionKind::StructElementAddrInst: + case SILInstructionKind::RefElementAddrInst: + case SILInstructionKind::RefTailAddrInst: + case SILInstructionKind::EnumInst: + case SILInstructionKind::UncheckedEnumDataInst: + case SILInstructionKind::InitEnumDataAddrInst: + case SILInstructionKind::UncheckedTakeEnumDataAddrInst: + case SILInstructionKind::SelectEnumInst: + case SILInstructionKind::SelectEnumAddrInst: + case SILInstructionKind::SelectValueInst: + case SILInstructionKind::InitExistentialAddrInst: + case SILInstructionKind::InitExistentialValueInst: + case SILInstructionKind::OpenExistentialAddrInst: + case SILInstructionKind::InitExistentialRefInst: + case SILInstructionKind::OpenExistentialRefInst: + case SILInstructionKind::InitExistentialMetatypeInst: + case SILInstructionKind::OpenExistentialMetatypeInst: + case SILInstructionKind::OpenExistentialBoxInst: + case SILInstructionKind::OpenExistentialValueInst: + case SILInstructionKind::OpenExistentialBoxValueInst: + case SILInstructionKind::ProjectBlockStorageInst: + case SILInstructionKind::InitBlockStorageHeaderInst: + case SILInstructionKind::KeyPathInst: + case SILInstructionKind::UnreachableInst: + case SILInstructionKind::ReturnInst: + case SILInstructionKind::ThrowInst: + case SILInstructionKind::YieldInst: + case SILInstructionKind::UnwindInst: + case SILInstructionKind::BranchInst: + case SILInstructionKind::CondBranchInst: + case SILInstructionKind::SwitchValueInst: + case SILInstructionKind::SwitchEnumInst: + case SILInstructionKind::SwitchEnumAddrInst: + case SILInstructionKind::DynamicMethodBranchInst: + case SILInstructionKind::CheckedCastBranchInst: + case SILInstructionKind::CheckedCastAddrBranchInst: + case SILInstructionKind::CheckedCastValueBranchInst: + case SILInstructionKind::DeallocStackInst: + case SILInstructionKind::DeallocRefInst: + case SILInstructionKind::DeallocPartialRefInst: + case SILInstructionKind::DeallocValueBufferInst: + case SILInstructionKind::DeallocBoxInst: + case SILInstructionKind::DeallocExistentialBoxInst: + case SILInstructionKind::StrongRetainInst: + case SILInstructionKind::StrongReleaseInst: + case SILInstructionKind::UnmanagedRetainValueInst: + case SILInstructionKind::UnmanagedReleaseValueInst: + case SILInstructionKind::UnmanagedAutoreleaseValueInst: +#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case SILInstructionKind::StrongRetain##Name##Inst: \ + case SILInstructionKind::Name##RetainInst: \ + case SILInstructionKind::Name##ReleaseInst: +#include "swift/AST/ReferenceStorage.def" +#undef ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE + case SILInstructionKind::RetainValueInst: + case SILInstructionKind::RetainValueAddrInst: + case SILInstructionKind::ReleaseValueInst: + case SILInstructionKind::ReleaseValueAddrInst: + case SILInstructionKind::SetDeallocatingInst: + case SILInstructionKind::AutoreleaseValueInst: + case SILInstructionKind::BindMemoryInst: + case SILInstructionKind::FixLifetimeInst: + case SILInstructionKind::DestroyValueInst: + case SILInstructionKind::EndBorrowInst: + case SILInstructionKind::EndAccessInst: + case SILInstructionKind::BeginUnpairedAccessInst: + case SILInstructionKind::EndUnpairedAccessInst: + case SILInstructionKind::StoreInst: + case SILInstructionKind::AssignInst: + case SILInstructionKind::AssignByWrapperInst: + case SILInstructionKind::MarkFunctionEscapeInst: + case SILInstructionKind::DebugValueInst: + case SILInstructionKind::DebugValueAddrInst: +#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case SILInstructionKind::Store##Name##Inst: +#include "swift/AST/ReferenceStorage.def" + case SILInstructionKind::CopyAddrInst: + case SILInstructionKind::DestroyAddrInst: + case SILInstructionKind::EndLifetimeInst: + case SILInstructionKind::InjectEnumAddrInst: + case SILInstructionKind::DeinitExistentialAddrInst: + case SILInstructionKind::DeinitExistentialValueInst: + case SILInstructionKind::UnconditionalCheckedCastAddrInst: + case SILInstructionKind::UncheckedRefCastAddrInst: + case SILInstructionKind::AllocGlobalInst: + case SILInstructionKind::EndApplyInst: + case SILInstructionKind::AbortApplyInst: + case SILInstructionKind::CondFailInst: + case SILInstructionKind::DestructureStructInst: + case SILInstructionKind::DestructureTupleInst: + // SWIFT_ENABLE_TENSORFLOW + case SILInstructionKind::DifferentiableFunctionInst: + case SILInstructionKind::DifferentiableFunctionExtractInst: + case SILInstructionKind::LinearFunctionInst: + case SILInstructionKind::LinearFunctionExtractInst: + case SILInstructionKind::DifferentiabilityWitnessFunctionInst: + // SWIFT_ENABLE_TENSORFLOW END + // Handle by operand and result check. + break; + + case SILInstructionKind::ApplyInst: + case SILInstructionKind::PartialApplyInst: + case SILInstructionKind::TryApplyInst: + case SILInstructionKind::BeginApplyInst: + // Check substitution map. + auto apply = ApplySite(&inst); + auto subs = apply.getSubstitutionMap(); + for (auto ty: subs.getReplacementTypes()) { + if (opaqueArchetypeWouldChange(context, ty->getCanonicalType())) + return true; + } + break; + } + + return false; +} + +static bool hasOpaqueArchetypeArgument(TypeExpansionContext context, SILBasicBlock &BB) { + for (auto *arg : BB.getArguments()) { + if (opaqueArchetypeWouldChange(context, arg->getType().getASTType())) + return true; + } + return false; +} + +static bool hasAnyOpaqueArchetype(SILFunction &F) { + bool foundOpaqueArchetype = false; + auto context = F.getTypeExpansionContext(); + for (auto &BB : F) { + // Check basic block argument types. + if (hasOpaqueArchetypeArgument(context, BB)) { + foundOpaqueArchetype = true; + break; + } + + // Check instruction results and operands. + for (auto &inst : BB) { + if (hasOpaqueArchetype(context, inst)) { + foundOpaqueArchetype = true; + break; + } + } + + if (foundOpaqueArchetype) + break; + } + + return foundOpaqueArchetype; +} + +void updateOpaqueArchetypes(SILFunction &F) { + // Only map if there are opaque archetypes that could change. + if (!hasAnyOpaqueArchetype(F)) + return; + + MapOpaqueArchetypes(F).replace(); +} + /// A utility pass to serialize a SILModule at any place inside the optimization /// pipeline. class SerializeSILPass : public SILModuleTransform { @@ -24,7 +402,16 @@ class SerializeSILPass : public SILModuleTransform { /// optimizations and for a better dead function elimination. void removeSerializedFlagFromAllFunctions(SILModule &M) { for (auto &F : M) { + bool wasSerialized = F.isSerialized() != IsNotSerialized; F.setSerialized(IsNotSerialized); + + // We are removing [serialized] from the function. This will change how + // opaque archetypes are lowered in SIL - they might lower to their + // underlying type. Update the function's opaque archetypes. + if (wasSerialized && F.isDefinition()) { + updateOpaqueArchetypes(F); + invalidateAnalysis(&F, SILAnalysis::InvalidationKind::Everything); + } } for (auto &WT : M.getWitnessTables()) { diff --git a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp index 88f11083c49ee..526e2e6f07870 100644 --- a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp +++ b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp @@ -68,11 +68,19 @@ bool swift::removeUnreachableBlocks(SILFunction &f) { return changed; } -/// Helper function to perform SSA updates in case of jump threading. -void swift::updateSSAAfterCloning(BasicBlockCloner &cloner, - SILBasicBlock *srcBB, SILBasicBlock *destBB) { +void BasicBlockCloner::updateSSAAfterCloning() { + // All instructions should have been checked by canCloneInstruction. But we + // still need to check the arguments. + for (auto arg : origBB->getArguments()) { + if ((needsSSAUpdate |= isUsedOutsideOfBlock(arg))) { + break; + } + } + if (!needsSSAUpdate) + return; + SILSSAUpdater ssaUpdater; - for (auto availValPair : cloner.AvailVals) { + for (auto availValPair : availVals) { ValueBase *inst = availValPair.first; if (inst->use_empty()) continue; @@ -85,20 +93,20 @@ void swift::updateSSAAfterCloning(BasicBlockCloner &cloner, useList.push_back(UseWrapper(use)); ssaUpdater.Initialize(inst->getType()); - ssaUpdater.AddAvailableValue(destBB, inst); - ssaUpdater.AddAvailableValue(srcBB, newResult); + ssaUpdater.AddAvailableValue(origBB, inst); + ssaUpdater.AddAvailableValue(getNewBB(), newResult); if (useList.empty()) continue; // Update all the uses. for (auto useWrapper : useList) { - Operand *use = useWrapper; + Operand *use = useWrapper; // unwrap SILInstruction *user = use->getUser(); assert(user && "Missing user"); // Ignore uses in the same basic block. - if (user->getParent() == destBB) + if (user->getParent() == origBB) continue; ssaUpdater.RewriteUse(*use); @@ -128,6 +136,29 @@ bool BasicBlockCloner::splitCriticalEdges(DominanceInfo *domInfo, return changed; } +void BasicBlockCloner::sinkAddressProjections() { + // Because the address projections chains will be disjoint (an instruction + // in one chain cannot use the result of an instruction in another chain), + // the order they are sunk does not matter. + for (auto ii = origBB->begin(), ie = origBB->end(); ii != ie;) { + bool canSink = sinkProj.analyzeAddressProjections(&*ii); + (void)canSink; + assert(canSink && "canCloneInstruction should catch this."); + + sinkProj.cloneProjections(); + assert((sinkProj.getInBlockDefs().empty() || needsSSAUpdate) + && "canCloneInstruction should catch this."); + + auto nextII = std::next(ii); + recursivelyDeleteTriviallyDeadInstructions( + &*ii, false, [&nextII](SILInstruction *deadInst) { + if (deadInst->getIterator() == nextII) + ++nextII; + }); + ii = nextII; + } +} + // Populate 'projections' with the chain of address projections leading // to and including 'inst'. // @@ -149,7 +180,7 @@ bool SinkAddressProjections::analyzeAddressProjections(SILInstruction *inst) { return true; } if (auto *addressProj = dyn_cast(def)) { - if (addressProj->isTriviallyDuplicatable()) { + if (addressProj->isPure()) { projections.push_back(addressProj); return true; } @@ -183,19 +214,40 @@ bool SinkAddressProjections::cloneProjections() { return false; SILBasicBlock *bb = projections.front()->getParent(); - SmallVector usesToReplace; // Clone projections in last-to-first order. for (unsigned idx = 0; idx < projections.size(); ++idx) { auto *oldProj = projections[idx]; assert(oldProj->getParent() == bb); + // Reset transient per-projection sets. usesToReplace.clear(); + firstBlockUse.clear(); + // Gather uses. for (Operand *use : oldProj->getUses()) { - if (use->getUser()->getParent() != bb) + auto *useBB = use->getUser()->getParent(); + if (useBB != bb) { + firstBlockUse.try_emplace(useBB, use); usesToReplace.push_back(use); + } } + // Replace uses. Uses must be handled in the same order they were discovered + // above. + // + // Avoid cloning a projection multiple times per block. This avoids extra + // projections, but also prevents the removal of DebugValue. If a + // projection's only remaining is DebugValue, then it is deleted along with + // the DebugValue. for (Operand *use : usesToReplace) { - auto *newProj = oldProj->clone(use->getUser()); - use->set(cast(newProj)); + auto *useBB = use->getUser()->getParent(); + auto *firstUse = firstBlockUse.lookup(useBB); + SingleValueInstruction *newProj; + if (use == firstUse) + newProj = cast(oldProj->clone(use->getUser())); + else { + newProj = cast(firstUse->get()); + assert(newProj->getParent() == useBB); + newProj->moveFront(useBB); + } + use->set(newProj); } } return true; diff --git a/lib/SILOptimizer/Utils/CastOptimizer.cpp b/lib/SILOptimizer/Utils/CastOptimizer.cpp index 1ff70ac1ea143..69c5705346d6f 100644 --- a/lib/SILOptimizer/Utils/CastOptimizer.cpp +++ b/lib/SILOptimizer/Utils/CastOptimizer.cpp @@ -628,7 +628,8 @@ CastOptimizer::optimizeBridgedSwiftToObjCCast(SILDynamicCastInst dynamicCast) { std::tie(bridgedFunc, subMap) = result.getValue(); } - SILType SubstFnTy = bridgedFunc->getLoweredType().substGenericArgs(M, subMap); + SILType SubstFnTy = bridgedFunc->getLoweredType().substGenericArgs( + M, subMap, TypeExpansionContext(*F)); SILFunctionConventions substConv(SubstFnTy.castTo(), M); // Check that this is a case that the authors of this code thought it could @@ -806,7 +807,7 @@ CastOptimizer::optimizeBridgedCasts(SILDynamicCastInst dynamicCast) { if ((CanBridgedSourceTy && CanBridgedSourceTy->getAnyNominal() == M.getASTContext().getNSErrorDecl()) || - (CanBridgedTargetTy && CanBridgedSourceTy->getAnyNominal() == + (CanBridgedTargetTy && CanBridgedTargetTy->getAnyNominal() == M.getASTContext().getNSErrorDecl())) { // FIXME: Can't optimize bridging with NSError. return nullptr; diff --git a/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp b/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp index 390e6e826a6be..e74d950a4b671 100644 --- a/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp +++ b/lib/SILOptimizer/Utils/CheckedCastBrJumpThreading.cpp @@ -87,8 +87,8 @@ class CheckedCastBrJumpThreading { hasUnknownPreds(hasUnknownPreds) { } void modifyCFGForUnknownPreds(); - void modifyCFGForFailurePreds(Optional &Cloner); - void modifyCFGForSuccessPreds(Optional &Cloner); + void modifyCFGForFailurePreds(BasicBlockCloner &Cloner); + void modifyCFGForSuccessPreds(BasicBlockCloner &Cloner); }; // Contains an entry for each checked_cast_br to be optimized. @@ -243,15 +243,14 @@ void CheckedCastBrJumpThreading::Edit::modifyCFGForUnknownPreds() { /// Create a copy of the BB as a landing BB /// for all FailurePreds. -void CheckedCastBrJumpThreading::Edit:: -modifyCFGForFailurePreds(Optional &Cloner) { +void CheckedCastBrJumpThreading::Edit::modifyCFGForFailurePreds( + BasicBlockCloner &Cloner) { if (FailurePreds.empty()) return; - assert(!Cloner.hasValue()); - Cloner.emplace(CCBBlock); - Cloner->cloneBlock(); - SILBasicBlock *TargetFailureBB = Cloner->getNewBB(); + assert(!Cloner.wasCloned()); + Cloner.cloneBlock(); + SILBasicBlock *TargetFailureBB = Cloner.getNewBB(); auto *TI = TargetFailureBB->getTerminator(); SILBuilderWithScope Builder(TI); // This BB copy branches to a FailureBB. @@ -271,8 +270,8 @@ modifyCFGForFailurePreds(Optional &Cloner) { /// Create a copy of the BB or reuse BB as /// a landing basic block for all FailurePreds. -void CheckedCastBrJumpThreading::Edit:: -modifyCFGForSuccessPreds(Optional &Cloner) { +void CheckedCastBrJumpThreading::Edit::modifyCFGForSuccessPreds( + BasicBlockCloner &Cloner) { auto *CCBI = cast(CCBBlock->getTerminator()); if (InvertSuccess) { @@ -285,10 +284,9 @@ modifyCFGForSuccessPreds(Optional &Cloner) { if (!SuccessPreds.empty()) { // Create a copy of the BB as a landing BB. // for all SuccessPreds. - assert(!Cloner.hasValue()); - Cloner.emplace(CCBBlock); - Cloner->cloneBlock(); - SILBasicBlock *TargetSuccessBB = Cloner->getNewBB(); + assert(!Cloner.wasCloned()); + Cloner.cloneBlock(); + SILBasicBlock *TargetSuccessBB = Cloner.getNewBB(); auto *TI = TargetSuccessBB->getTerminator(); SILBuilderWithScope Builder(TI); // This BB copy branches to SuccessBB. @@ -343,6 +341,11 @@ bool CheckedCastBrJumpThreading::handleArgBBIsEntryBlock(SILBasicBlock *ArgBB, // Returns false if cloning required by jump threading cannot // be performed, because some of the constraints are violated. +// +// This does not check the constraint on address projections with out-of-block +// uses. Those are rare enough that they don't need to be checked first for +// efficiency, but they need to be gathered later, just before cloning, anyway +// in order to sink the projections. bool CheckedCastBrJumpThreading::checkCloningConstraints() { // Check some cloning related constraints. @@ -673,7 +676,9 @@ void CheckedCastBrJumpThreading::optimizeFunction() { Fn->verifyCriticalEdges(); for (Edit *edit : Edits) { - Optional Cloner; + BasicBlockCloner Cloner(edit->CCBBlock); + if (!Cloner.canCloneBlock()) + continue; // Create a copy of the BB as a landing BB // for all FailurePreds. @@ -684,12 +689,11 @@ void CheckedCastBrJumpThreading::optimizeFunction() { // Handle unknown preds. edit->modifyCFGForUnknownPreds(); - if (Cloner.hasValue()) { - updateSSAAfterCloning(*Cloner.getPointer(), Cloner->getNewBB(), - edit->CCBBlock); + if (Cloner.wasCloned()) { + Cloner.updateSSAAfterCloning(); - if (!Cloner->getNewBB()->pred_empty()) - BlocksForWorklist.push_back(Cloner->getNewBB()); + if (!Cloner.getNewBB()->pred_empty()) + BlocksForWorklist.push_back(Cloner.getNewBB()); } if (!edit->CCBBlock->pred_empty()) BlocksForWorklist.push_back(edit->CCBBlock); diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp index ff881c8fb690c..e7d6e9e0f2714 100644 --- a/lib/SILOptimizer/Utils/Devirtualize.cpp +++ b/lib/SILOptimizer/Utils/Devirtualize.cpp @@ -743,14 +743,16 @@ FullApplySite swift::devirtualizeClassMethod(FullApplySite applySite, auto *f = getTargetClassMethod(module, cd, mi); - CanSILFunctionType genCalleeType = f->getLoweredFunctionType(); + CanSILFunctionType genCalleeType = f->getLoweredFunctionTypeInContext( + TypeExpansionContext(*applySite.getFunction())); SubstitutionMap subs = getSubstitutionsForCallee( module, genCalleeType, classOrMetatype->getType().getASTType(), applySite); CanSILFunctionType substCalleeType = genCalleeType; if (genCalleeType->isPolymorphic()) - substCalleeType = genCalleeType->substGenericArgs(module, subs); + substCalleeType = genCalleeType->substGenericArgs( + module, subs, TypeExpansionContext(*applySite.getFunction())); SILFunctionConventions substConv(substCalleeType, module); SILBuilderWithScope builder(applySite.getInstruction()); @@ -937,7 +939,8 @@ SubstitutionMap swift::getWitnessMethodSubstitutions(SILModule &module, ApplySite applySite, SILFunction *f, ProtocolConformanceRef cRef) { - auto witnessFnTy = f->getLoweredFunctionType(); + auto witnessFnTy = f->getLoweredFunctionTypeInContext( + TypeExpansionContext(*applySite.getFunction())); assert(witnessFnTy->getRepresentation() == SILFunctionTypeRepresentation::WitnessMethod); @@ -975,8 +978,10 @@ static ApplySite devirtualizeWitnessMethod(ApplySite applySite, SILFunction *f, // Figure out the exact bound type of the function to be called by // applying all substitutions. - auto calleeCanType = f->getLoweredFunctionType(); - auto substCalleeCanType = calleeCanType->substGenericArgs(module, subMap); + auto calleeCanType = f->getLoweredFunctionTypeInContext( + TypeExpansionContext(*applySite.getFunction())); + auto substCalleeCanType = calleeCanType->substGenericArgs( + module, subMap, TypeExpansionContext(*applySite.getFunction())); // Collect arguments from the apply instruction. SmallVector arguments; diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index 01c7e96050c92..1cae4cdb0b5be 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -547,12 +547,12 @@ bool ReabstractionInfo::canBeSpecialized(ApplySite Apply, SILFunction *Callee, return ReInfo.prepareAndCheck(Apply, Callee, ParamSubs); } -ReabstractionInfo::ReabstractionInfo(ApplySite Apply, SILFunction *Callee, - SubstitutionMap ParamSubs, - IsSerialized_t Serialized, - bool ConvertIndirectToDirect, - OptRemark::Emitter *ORE) +ReabstractionInfo::ReabstractionInfo( + ModuleDecl *targetModule, bool isWholeModule, ApplySite Apply, + SILFunction *Callee, SubstitutionMap ParamSubs, IsSerialized_t Serialized, + bool ConvertIndirectToDirect, OptRemark::Emitter *ORE) : ConvertIndirectToDirect(ConvertIndirectToDirect), + TargetModule(targetModule), isWholeModule(isWholeModule), Serialized(Serialized) { if (!prepareAndCheck(Apply, Callee, ParamSubs, ORE)) return; @@ -586,14 +586,16 @@ ReabstractionInfo::ReabstractionInfo(ApplySite Apply, SILFunction *Callee, auto CalleeFnTy = Callee->getLoweredFunctionType(); assert(CalleeFnTy->isPolymorphic()); auto CalleeSubstFnTy = CalleeFnTy->substGenericArgs( - Callee->getModule(), getCalleeParamSubstitutionMap()); + Callee->getModule(), getCalleeParamSubstitutionMap(), + getResilienceExpansion()); assert(!CalleeSubstFnTy->isPolymorphic() && "Substituted callee type should not be polymorphic"); assert(!CalleeSubstFnTy->hasTypeParameter() && "Substituted callee type should not have type parameters"); SpecializedSubstFnTy = SpecializedFnTy->substGenericArgs( - Callee->getModule(), getCallerParamSubstitutionMap()); + Callee->getModule(), getCallerParamSubstitutionMap(), + getResilienceExpansion()); assert(!SpecializedSubstFnTy->isPolymorphic() && "Substituted callee type should not be polymorphic"); @@ -766,7 +768,8 @@ ReabstractionInfo::createSubstitutedType(SILFunction *OrigF, { Lowering::GenericContextScope GenericScope(M.Types, CanSpecializedGenericSig); - FnTy = OrigF->getLoweredFunctionType()->substGenericArgs(M, SubstMap); + FnTy = OrigF->getLoweredFunctionType()->substGenericArgs( + M, SubstMap, getResilienceExpansion()); // FIXME: Some of the added new requirements may not have been taken into // account by the substGenericArgs. So, canonicalize in the context of the // specialized signature. @@ -896,7 +899,7 @@ void ReabstractionInfo::performFullSpecializationPreparation( ClonerParamSubMap = ParamSubs; SubstitutedType = Callee->getLoweredFunctionType()->substGenericArgs( - M, ClonerParamSubMap); + M, ClonerParamSubMap, getResilienceExpansion()); CallerParamSubMap = {}; createSubstitutedAndSpecializedTypes(); } @@ -1765,8 +1768,10 @@ void ReabstractionInfo::finishPartialSpecializationPreparation( } /// This constructor is used when processing @_specialize. -ReabstractionInfo::ReabstractionInfo(SILFunction *Callee, - GenericSignature SpecializedSig) { +ReabstractionInfo::ReabstractionInfo(ModuleDecl *targetModule, + bool isWholeModule, SILFunction *Callee, + GenericSignature SpecializedSig) + : TargetModule(targetModule), isWholeModule(isWholeModule) { Serialized = Callee->isSerialized(); if (shouldNotSpecialize(Callee, nullptr)) @@ -1942,10 +1947,11 @@ static void prepareCallArguments(ApplySite AI, SILBuilder &Builder, /// Return a substituted callee function type. static CanSILFunctionType -getCalleeSubstFunctionType(SILValue Callee, SubstitutionMap Subs) { +getCalleeSubstFunctionType(SILValue Callee, SubstitutionMap Subs, + TypeExpansionContext context) { // Create a substituted callee type. auto CanFnTy = Callee->getType().castTo(); - return CanFnTy->substGenericArgs(*Callee->getModule(), Subs); + return CanFnTy->substGenericArgs(*Callee->getModule(), Subs, context); } /// Create a new apply based on an old one, but with a different @@ -1966,7 +1972,8 @@ static ApplySite replaceWithSpecializedCallee(ApplySite AI, Subs = ReInfo.getCallerParamSubstitutionMap(); } - auto CalleeSubstFnTy = getCalleeSubstFunctionType(Callee, Subs); + auto CalleeSubstFnTy = + getCalleeSubstFunctionType(Callee, Subs, ReInfo.getResilienceExpansion()); auto CalleeSILSubstFnTy = SILType::getPrimitiveObjectType(CalleeSubstFnTy); SILFunctionConventions substConv(CalleeSubstFnTy, Builder.getModule()); @@ -2271,9 +2278,10 @@ static bool createPrespecialized(StringRef UnspecializedName, if (!UnspecFunc || !UnspecFunc->isDefinition()) return false; - ReabstractionInfo ReInfo(ApplySite(), UnspecFunc, Apply.getSubstitutionMap(), - IsNotSerialized, /*ConvertIndirectToDirect=*/true, - nullptr); + ReabstractionInfo ReInfo(M.getSwiftModule(), M.isWholeModule(), ApplySite(), + UnspecFunc, Apply.getSubstitutionMap(), + IsNotSerialized, + /*ConvertIndirectToDirect=*/true, nullptr); if (!ReInfo.canBeSpecialized()) return false; @@ -2372,9 +2380,10 @@ void swift::trySpecializeApplyOfGeneric( Serialized = IsNotSerialized; } - ReabstractionInfo ReInfo(Apply, RefF, Apply.getSubstitutionMap(), - Serialized, /*ConvertIndirectToDirect=*/true, - &ORE); + ReabstractionInfo ReInfo(FuncBuilder.getModule().getSwiftModule(), + FuncBuilder.getModule().isWholeModule(), Apply, RefF, + Apply.getSubstitutionMap(), Serialized, + /*ConvertIndirectToDirect=*/true, &ORE); if (!ReInfo.canBeSpecialized()) return; diff --git a/lib/SILOptimizer/Utils/InstOptUtils.cpp b/lib/SILOptimizer/Utils/InstOptUtils.cpp index e952b85f57dbc..fa87ac8eb62cd 100644 --- a/lib/SILOptimizer/Utils/InstOptUtils.cpp +++ b/lib/SILOptimizer/Utils/InstOptUtils.cpp @@ -1224,7 +1224,7 @@ bool swift::simplifyUsers(SingleValueInstruction *inst) { /// True if a type can be expanded without a significant increase to code size. bool swift::shouldExpand(SILModule &module, SILType ty) { // FIXME: Expansion - auto expansion = ResilienceExpansion::Minimal; + auto expansion = TypeExpansionContext::minimal(); if (module.Types.getTypeLowering(ty, expansion).isAddressOnly()) { return false; diff --git a/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp b/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp index 93dcad0c477b6..80992cb15ad58 100644 --- a/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp +++ b/lib/SILOptimizer/Utils/LoadStoreOptUtils.cpp @@ -31,10 +31,9 @@ removeLSLocations(LSLocationValueMap &Values, LSLocationList &NextLevel) { //===----------------------------------------------------------------------===// // LSValue //===----------------------------------------------------------------------===// -void -LSValue::expand(SILValue Base, SILModule *M, LSValueList &Vals, - TypeExpansionAnalysis *TE) { - for (const auto &P : TE->getTypeExpansion((*Base).getType(), M)) { +void LSValue::expand(SILValue Base, SILModule *M, TypeExpansionContext context, + LSValueList &Vals, TypeExpansionAnalysis *TE) { + for (const auto &P : TE->getTypeExpansion((*Base).getType(), M, context)) { Vals.push_back(LSValue(Base, P.getValue())); } } @@ -42,18 +41,20 @@ LSValue::expand(SILValue Base, SILModule *M, LSValueList &Vals, void LSValue::reduceInner(LSLocation &Base, SILModule *M, LSLocationValueMap &Values, SILInstruction *InsertPt) { + TypeExpansionContext context(*InsertPt->getFunction()); + // If this is a class reference type, we have reached end of the type tree. - if (Base.getType(M).getClassOrBoundGenericClass()) + if (Base.getType(M, context).getClassOrBoundGenericClass()) return; // This a don't expand node. - if (!shouldExpand(*M, Base.getType(M))) { + if (!shouldExpand(*M, Base.getType(M, context))) { return; } // This is a leaf node, we must have a value for it. LSLocationList NextLevel; - Base.getNextLevelLSLocations(NextLevel, M); + Base.getNextLevelLSLocations(NextLevel, M, context); if (NextLevel.empty()) return; @@ -117,11 +118,10 @@ LSValue::reduceInner(LSLocation &Base, SILModule *M, LSLocationValueMap &Values, NullablePtr AI = Projection::createAggFromFirstLevelProjections( Builder, RegularLocation::getAutoGeneratedLocation(), - Base.getType(M).getObjectType(), - Vals); + Base.getType(M, context).getObjectType(), Vals); // This is the Value for the current base. - ProjectionPath P(Base.getType(M)); + ProjectionPath P(Base.getType(M, context)); Values[Base] = LSValue(SILValue(AI.get()), P); removeLSLocations(Values, NextLevel); } @@ -163,11 +163,11 @@ LSLocation::isMayAliasLSLocation(const LSLocation &RHS, AliasAnalysis *AA) { return true; } -void -LSLocation::getNextLevelLSLocations(LSLocationList &Locs, SILModule *Mod) { - SILType Ty = getType(Mod); +void LSLocation::getNextLevelLSLocations(LSLocationList &Locs, SILModule *Mod, + TypeExpansionContext context) { + SILType Ty = getType(Mod, context); llvm::SmallVector Out; - Projection::getFirstLevelProjections(Ty, *Mod, Out); + Projection::getFirstLevelProjections(Ty, *Mod, context, Out); for (auto &X : Out) { ProjectionPath P((*Base).getType()); P.append(Path.getValue()); @@ -176,22 +176,23 @@ LSLocation::getNextLevelLSLocations(LSLocationList &Locs, SILModule *Mod) { } } -void -LSLocation::expand(LSLocation Base, SILModule *M, LSLocationList &Locs, - TypeExpansionAnalysis *TE) { +void LSLocation::expand(LSLocation Base, SILModule *M, + TypeExpansionContext context, LSLocationList &Locs, + TypeExpansionAnalysis *TE) { const ProjectionPath &BasePath = Base.getPath().getValue(); - for (const auto &P : TE->getTypeExpansion(Base.getType(M), M)) { + for (const auto &P : + TE->getTypeExpansion(Base.getType(M, context), M, context)) { Locs.push_back(LSLocation(Base.getBase(), BasePath, P.getValue())); } } /// Gets the sub-locations of \p Base in \p SubLocations. /// Returns false if this is not possible or too complex. -static bool -getSubLocations(LSLocationList &SubLocations, LSLocation Base, SILModule *M, - const LSLocationList &Locs) { +static bool getSubLocations(LSLocationList &SubLocations, LSLocation Base, + SILModule *M, TypeExpansionContext context, + const LSLocationList &Locs) { // If this is a class reference type, we have reached end of the type tree. - if (Base.getType(M).getClassOrBoundGenericClass()) + if (Base.getType(M, context).getClassOrBoundGenericClass()) return false; // Don't expand if it would be too complex. As Locs is a list (and not a set) @@ -199,27 +200,28 @@ getSubLocations(LSLocationList &SubLocations, LSLocation Base, SILModule *M, // Usually Locs is small anyway, because we limit expansion to 6 members. // But with deeply nested types we could run in a corner case where Locs is // large. - if (!shouldExpand(*M, Base.getType(M)) || Locs.size() >= 8) { + if (!shouldExpand(*M, Base.getType(M, context)) || Locs.size() >= 8) { return false; } // This is a leaf node. - Base.getNextLevelLSLocations(SubLocations, M); + Base.getNextLevelLSLocations(SubLocations, M, context); return !SubLocations.empty(); } /// Replaces \p SubLocations with \p Base in \p Locs if all sub-locations are /// alive, i.e. present in \p Locs. -static bool -replaceSubLocations(LSLocation Base, SILModule *M, LSLocationList &Locs, - const LSLocationList &SubLocations) { +static bool replaceSubLocations(LSLocation Base, SILModule *M, + TypeExpansionContext context, + LSLocationList &Locs, + const LSLocationList &SubLocations) { // Find whether all its children of Base are alive. bool Alive = true; for (auto &X : SubLocations) { // Recurse into the next level. LSLocationList NextInnerLevel; - if (getSubLocations(NextInnerLevel, X, M, Locs)) { - Alive &= replaceSubLocations(X, M, Locs, NextInnerLevel); + if (getSubLocations(NextInnerLevel, X, M, context, Locs)) { + Alive &= replaceSubLocations(X, M, context, Locs, NextInnerLevel); } else { Alive &= is_contained(Locs, X); } @@ -237,18 +239,19 @@ replaceSubLocations(LSLocation Base, SILModule *M, LSLocationList &Locs, return true; } -void LSLocation::reduce(LSLocation Base, SILModule *M, LSLocationList &Locs) { +void LSLocation::reduce(LSLocation Base, SILModule *M, + TypeExpansionContext context, LSLocationList &Locs) { LSLocationList SubLocations; - if (getSubLocations(SubLocations, Base, M, Locs)) - replaceSubLocations(Base, M, Locs, SubLocations); + if (getSubLocations(SubLocations, Base, M, context, Locs)) + replaceSubLocations(Base, M, context, Locs, SubLocations); } -void -LSLocation::enumerateLSLocation(SILModule *M, SILValue Mem, - std::vector &Locations, - LSLocationIndexMap &IndexMap, - LSLocationBaseMap &BaseMap, - TypeExpansionAnalysis *TypeCache) { +void LSLocation::enumerateLSLocation(TypeExpansionContext context, SILModule *M, + SILValue Mem, + std::vector &Locations, + LSLocationIndexMap &IndexMap, + LSLocationBaseMap &BaseMap, + TypeExpansionAnalysis *TypeCache) { // We have processed this SILValue before. if (BaseMap.find(Mem) != BaseMap.end()) return; @@ -272,7 +275,7 @@ LSLocation::enumerateLSLocation(SILModule *M, SILValue Mem, // Expand the given Mem into individual fields and add them to the // locationvault. LSLocationList Locs; - LSLocation::expand(L, M, Locs, TypeCache); + LSLocation::expand(L, M, context, Locs, TypeCache); for (auto &Loc : Locs) { if (IndexMap.find(Loc) != IndexMap.end()) continue; @@ -292,14 +295,16 @@ LSLocation::enumerateLSLocations(SILFunction &F, for (auto &B : F) { for (auto &I : B) { if (auto *LI = dyn_cast(&I)) { - enumerateLSLocation(&I.getModule(), LI->getOperand(), Locations, - IndexMap, BaseMap, TypeCache); + enumerateLSLocation(F.getTypeExpansionContext(), &I.getModule(), + LI->getOperand(), Locations, IndexMap, BaseMap, + TypeCache); ++LSCount.first; continue; } if (auto *SI = dyn_cast(&I)) { - enumerateLSLocation(&I.getModule(), SI->getDest(), Locations, - IndexMap, BaseMap, TypeCache); + enumerateLSLocation(F.getTypeExpansionContext(), &I.getModule(), + SI->getDest(), Locations, IndexMap, BaseMap, + TypeCache); ++LSCount.second; continue; } diff --git a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp index 9625114d8fa24..3936838c88e21 100644 --- a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp +++ b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp @@ -438,7 +438,7 @@ UseWrapper::UseWrapper(Operand *Use) { } /// Return the operand we wrap. Reconstructing branch operands. -UseWrapper::operator Operand *() { +Operand *UseWrapper::getOperand() { switch (Type) { case kRegularUse: return U; diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 549fb240b19bd..fea91c70d6627 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -20,6 +20,7 @@ #include "CodeSynthesis.h" #include "CSDiagnostics.h" #include "MiscDiagnostics.h" +#include "SolutionResult.h" #include "TypeCheckProtocol.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTWalker.h" @@ -3218,7 +3219,7 @@ namespace { castKind == CheckedCastKind::SetDowncast) { auto toOptType = OptionalType::get(toType); ConditionalCheckedCastExpr *cast = new (ctx) ConditionalCheckedCastExpr( - sub, expr->getLoc(), SourceLoc(), TypeLoc::withoutLoc(toType)); + sub, expr->getLoc(), SourceLoc(), expr->getCastTypeLoc()); cs.setType(cast, toOptType); cs.setType(cast->getCastTypeLoc(), toType); if (expr->isImplicit()) @@ -4629,9 +4630,6 @@ namespace { /*applyExpr*/ nullptr, labels, /*hasTrailingClosure*/ false, locator); - auto component = KeyPathExpr::Component::forSubscriptWithPrebuiltIndexExpr( - ref, newIndexExpr, labels, resolvedTy, componentLoc, {}); - // We need to be able to hash the captured index values in order for // KeyPath itself to be hashable, so check that all of the subscript // index components are hashable and collect their conformances here. @@ -4641,7 +4639,10 @@ namespace { cs.getASTContext().getProtocol(KnownProtocolKind::Hashable); auto fnType = overload.openedType->castTo(); - for (const auto ¶m : fnType->getParams()) { + SmallVector newLabels; + for (auto ¶m : fnType->getParams()) { + newLabels.push_back(param.getLabel()); + auto indexType = simplifyType(param.getPlainType()); // Index type conformance to Hashable protocol has been // verified by the solver, we just need to get it again @@ -4654,8 +4655,10 @@ namespace { conformances.push_back(hashableConformance); } - component.setSubscriptIndexHashableConformances(conformances); - return component; + return KeyPathExpr::Component::forSubscriptWithPrebuiltIndexExpr( + ref, newIndexExpr, cs.getASTContext().AllocateCopy(newLabels), + resolvedTy, componentLoc, + cs.getASTContext().AllocateCopy(conformances)); } Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) { @@ -7480,93 +7483,81 @@ Expr *ConstraintSystem::coerceToRValue(Expr *expr) { [&](Expr *expr, Type type) { setType(expr, type); }); } -/// Emit the fixes computed as part of the solution, returning true if we were -/// able to emit an error message, or false if none of the fixits worked out. -bool ConstraintSystem::applySolutionFixes(Expr *E, const Solution &solution) { - // First transfer all of the deduced information back - // to the constraint system. - applySolution(solution); - - class DiagnosticWalker : public ASTWalker { - Expr *root; - const Solution &solution; - llvm::SmallDenseMap> fixesPerExpr; - - /// Determines whether any error have been diagnosed while - /// trying to apply fixes associated with a given solution. - bool DiagnosedAnyErrors = false; +namespace { + /// Function object to compare source locations, putting invalid + /// locations at the end. + class CompareExprSourceLocs { + SourceManager &sourceMgr; public: - DiagnosticWalker(Expr *expr, const Solution &solution) - : root(expr), solution(solution) { - for (auto *fix : solution.Fixes) - fixesPerExpr[fix->getAnchor()].push_back(fix); - } - - std::pair walkToExprPre(Expr *E) override { - // Diagnose root expression last. - if (E == root) - return {true, E}; - - if (auto *closure = dyn_cast(E)) { - auto result = solution.builderTransformedClosures.find(closure); - if (result != solution.builderTransformedClosures.end()) { - auto *transformedExpr = result->second.singleExpr; - // Since this closure has been transformed into something - // else let's look inside transformed expression instead. - transformedExpr->walk(*this); - return {false, E}; - } + explicit CompareExprSourceLocs(SourceManager &sourceMgr) + : sourceMgr(sourceMgr) { } + + bool operator()(Expr *lhs, Expr *rhs) const { + if (static_cast(lhs) != static_cast(rhs)) { + return static_cast(lhs); } - diagnose(E); - return {true, E}; - } + auto lhsLoc = lhs->getLoc(); + auto rhsLoc = rhs->getLoc(); + if (lhsLoc.isValid() != rhsLoc.isValid()) + return lhsLoc.isValid(); - Expr *walkToExprPost(Expr *E) override { - if (E == root) - diagnose(E); - return E; + return sourceMgr.isBeforeInBuffer(lhsLoc, rhsLoc); } + }; - std::pair walkToStmtPre(Stmt *S) override { - return {true, S}; - } +} - bool hadErrors() const { return DiagnosedAnyErrors; } +/// Emit the fixes computed as part of the solution, returning true if we were +/// able to emit an error message, or false if none of the fixits worked out. +bool ConstraintSystem::applySolutionFixes(const Solution &solution) { + /// Collect the fixes on a per-expression basis. + llvm::SmallDenseMap> fixesPerExpr; + for (auto *fix : solution.Fixes) { + fixesPerExpr[fix->getAnchor()].push_back(fix); + } - private: - void diagnose(Expr *E) { - auto fixes = fixesPerExpr.find(E); - if (fixes == fixesPerExpr.end()) - return; + // Collect all of the expressions that have fixes, and sort them by + // source ordering. + SmallVector exprsWithFixes; + for (const auto &fix : fixesPerExpr) { + exprsWithFixes.push_back(fix.getFirst()); + } + std::sort(exprsWithFixes.begin(), exprsWithFixes.end(), + CompareExprSourceLocs(Context.SourceMgr)); + + // Walk over each of the expressions, diagnosing fixes. + bool diagnosedAnyErrors = false; - // Coalesce fixes with the same locator to avoid duplicating notes. - llvm::SmallMapVector, 4> aggregatedFixes; - for (auto *fix : fixes->second) - aggregatedFixes[fix->getLocator()].push_back(fix); + for (auto expr : exprsWithFixes) { + // Coalesce fixes with the same locator to avoid duplicating notes. + auto fixes = fixesPerExpr[expr]; - for (auto fixesPerLocator : aggregatedFixes) { - auto fixes = fixesPerLocator.second; + using ConstraintFixVector = llvm::SmallVector; + llvm::SmallMapVector, 4> aggregatedFixes; + for (auto *fix : fixes) + aggregatedFixes[fix->getLocator()][fix->getKind()].push_back(fix); + + for (auto fixesPerLocator : aggregatedFixes) { + for (auto fixesPerKind : fixesPerLocator.second) { + auto fixes = fixesPerKind.second; auto *primaryFix = fixes[0]; ArrayRef secondaryFixes{fixes.begin() + 1, fixes.end()}; - auto *coalescedFix = primaryFix->coalescedWith(secondaryFixes); - auto diagnosed = coalescedFix->diagnose(); - if (coalescedFix->isWarning()) { + auto diagnosed = primaryFix->coalesceAndDiagnose(secondaryFixes); + if (primaryFix->isWarning()) { assert(diagnosed && "warnings should always be diagnosed"); (void)diagnosed; } else { - DiagnosedAnyErrors |= diagnosed; + diagnosedAnyErrors |= diagnosed; } } } - }; + } - DiagnosticWalker diagnostics(E, solution); - E->walk(diagnostics); - return diagnostics.hadErrors(); + return diagnosedAnyErrors; } /// Apply a given solution to the expression, producing a fully @@ -7575,18 +7566,13 @@ Expr *ConstraintSystem::applySolution(Solution &solution, Expr *expr, Type convertType, bool discardedExpr, bool skipClosures) { - // Add the node types back. - for (auto &nodeType : solution.addedNodeTypes) { - setType(nodeType.first, nodeType.second); - } - // If any fixes needed to be applied to arrive at this solution, resolve // them to specific expressions. if (!solution.Fixes.empty()) { if (shouldSuppressDiagnostics()) return nullptr; - bool diagnosedErrorsViaFixes = applySolutionFixes(expr, solution); + bool diagnosedErrorsViaFixes = applySolutionFixes(solution); // If all of the available fixes would result in a warning, // we can go ahead and apply this solution to AST. if (!llvm::all_of(solution.Fixes, [](const ConstraintFix *fix) { @@ -7747,3 +7733,50 @@ void Solution::setExprTypes(Expr *expr) const { SetExprTypes SET(*this); expr->walk(SET); } + +/// MARK: SolutionResult implementation. + +SolutionResult SolutionResult::forSolved(Solution &&solution) { + SolutionResult result(Kind::Success); + result.solutions = new Solution(std::move(solution)); + result.numSolutions = 1; + return result; +} + +SolutionResult SolutionResult::forAmbiguous( + MutableArrayRef solutions) { + assert(solutions.size() > 1 && "Not actually ambiguous"); + SolutionResult result(Kind::Ambiguous); + result.solutions = + (Solution *)malloc(sizeof(Solution) * solutions.size()); + result.numSolutions = solutions.size(); + std::uninitialized_copy(std::make_move_iterator(solutions.begin()), + std::make_move_iterator(solutions.end()), + result.solutions); + return result; +} + +SolutionResult::~SolutionResult() { + assert((!requiresDiagnostic() || emittedDiagnostic) && + "SolutionResult was destroyed without emitting a diagnostic"); + + for (unsigned i : range(numSolutions)) { + solutions[i].~Solution(); + } + free(solutions); +} + +const Solution &SolutionResult::getSolution() const { + assert(numSolutions == 1 && "Wrong number of solutions"); + return solutions[0]; +} + +Solution &&SolutionResult::takeSolution() && { + assert(numSolutions == 1 && "Wrong number of solutions"); + return std::move(solutions[0]); +} + +ArrayRef SolutionResult::getAmbiguousSolutions() const { + assert(getKind() == Ambiguous); + return makeArrayRef(solutions, numSolutions); +} diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index aaac4e4370d38..5e2381fe8a10a 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -85,7 +85,7 @@ ConstraintSystem::determineBestBindings() { } } - if (getASTContext().LangOpts.DebugConstraintSolver) { + if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); bindings.dump(typeVar, log, solverState->depth * 2); } @@ -734,10 +734,9 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) const { constraint->getLocator()}); } - // If we don't have any potential bindings, allow generic - // parameters and potential holes to default to `Unresolved`. + // If there are no bindings, typeVar may be a hole. if (shouldAttemptFixes() && result.Bindings.empty() && - (isPotentialHole(typeVar) || result.isGenericParameter())) { + typeVar->getImpl().canBindToHole()) { result.IsHole = true; result.addPotentialBinding({getASTContext().TheUnresolvedType, AllowedBindingKind::Exact, ConstraintKind::Defaultable, nullptr, @@ -991,11 +990,11 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const { cs.DefaultedConstraints.push_back(Binding.DefaultableBinding); if (locator->isForGenericParameter() && type->isHole()) { - // Drop `generic parameter '...'` part of the locator to group all of the - // missing generic parameters related to the same path together. + // Drop `generic parameter` locator element so that all missing + // generic parameters related to the same path can be coalesced later. auto path = locator->getPath(); auto genericParam = locator->getGenericParameter(); - auto *fix = ExplicitlySpecifyGenericArguments::create(cs, {genericParam}, + auto *fix = DefaultGenericArgument::create(cs, genericParam, cs.getConstraintLocator(locator->getAnchor(), path.drop_back())); if (cs.recordFix(fix)) return true; diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index 36ac377836cf1..1a75edf5a0fbe 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -3246,35 +3246,6 @@ bool FailureDiagnosis::diagnoseClosureExpr( return true; } - // If the body of the closure looked ok, then look for a contextual type - // error. This is necessary because FailureDiagnosis::diagnoseExprFailure - // doesn't do this for closures. - if (contextualType) { - auto fnType = contextualType->getAs(); - if (!fnType || fnType->isEqual(CS.getType(CE))) - return false; - - auto contextualResultType = fnType->getResult(); - // If the result type was unknown, it doesn't really make - // sense to diagnose from expected to unknown here. - if (isInvalidClosureResultType(contextualResultType)) - return false; - - // If the closure had an explicitly written return type incompatible with - // the contextual type, diagnose that. - if (CE->hasExplicitResultType() && - CE->getExplicitResultTypeLoc().getTypeRepr()) { - auto explicitResultTy = CE->getExplicitResultTypeLoc().getType(); - if (fnType && !explicitResultTy->isEqual(contextualResultType)) { - auto repr = CE->getExplicitResultTypeLoc().getTypeRepr(); - diagnose(repr->getStartLoc(), diag::incorrect_explicit_closure_result, - explicitResultTy, fnType->getResult()) - .fixItReplace(repr->getSourceRange(),fnType->getResult().getString()); - return true; - } - } - } - // Otherwise, we can't produce a specific diagnostic. return false; } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 6d1c1f598cd33..1ccb4ec24e194 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -682,7 +682,7 @@ bool MissingConformanceFailure::diagnoseAsAmbiguousOperatorRef() { // about missing conformance just in case. auto operatorID = name.getIdentifier(); - auto *applyExpr = cast_or_null(findParentExpr(anchor)); + auto *applyExpr = cast(findParentExpr(anchor)); if (auto *binaryOp = dyn_cast(applyExpr)) { auto lhsType = getType(binaryOp->getArg()->getElement(0)); auto rhsType = getType(binaryOp->getArg()->getElement(1)); @@ -1557,9 +1557,9 @@ bool AssignmentFailure::diagnoseAsError() { // Walk through the destination expression, resolving what the problem is. If // we find a node in the lvalue path that is problematic, this returns it. - auto immInfo = resolveImmutableBase(DestExpr); - - Optional choice = immInfo.second; + Expr *immutableExpr; + Optional choice; + std::tie(immutableExpr, choice) = resolveImmutableBase(DestExpr); // Attempt diagnostics based on the overload choice. if (choice.hasValue()) { @@ -1573,9 +1573,9 @@ bool AssignmentFailure::diagnoseAsError() { if (!choice->isDecl()) { if (choice->getKind() == OverloadChoiceKind::KeyPathApplication && - !isa(immInfo.first)) { + !isa(immutableExpr)) { std::string message = "key path is read-only"; - if (auto *SE = dyn_cast(immInfo.first)) { + if (auto *SE = dyn_cast(immutableExpr)) { if (auto *DRE = dyn_cast(getKeyPathArgument(SE))) { auto identifier = DRE->getDecl()->getBaseName().getIdentifier(); message = @@ -1583,7 +1583,7 @@ bool AssignmentFailure::diagnoseAsError() { } } emitDiagnostic(Loc, DeclDiagnostic, message) - .highlight(immInfo.first->getSourceRange()); + .highlight(immutableExpr->getSourceRange()); return true; } return false; @@ -1597,7 +1597,7 @@ bool AssignmentFailure::diagnoseAsError() { message += VD->getName().str().str(); message += "'"; - auto type = getType(immInfo.first); + auto type = getType(immutableExpr); if (isKnownKeyPathType(type)) message += " is read-only"; @@ -1616,26 +1616,54 @@ bool AssignmentFailure::diagnoseAsError() { } emitDiagnostic(Loc, DeclDiagnostic, message) - .highlight(immInfo.first->getSourceRange()); + .highlight(immutableExpr->getSourceRange()); - // If there is a masked instance variable of the same type, emit a - // note to fixit prepend a 'self.'. + // If there is a masked property of the same type, emit a + // note to fixit prepend a 'self.' or 'Type.'. if (auto typeContext = DC->getInnermostTypeContext()) { - UnqualifiedLookup lookup(VD->getFullName(), typeContext); - for (auto &result : lookup.Results) { - const VarDecl *typeVar = dyn_cast(result.getValueDecl()); - if (typeVar && typeVar != VD && typeVar->isSettable(DC) && - typeVar->isSetterAccessibleFrom(DC) && - typeVar->getType()->isEqual(VD->getType())) { - // But not in its own accessor. - auto AD = - dyn_cast_or_null(DC->getInnermostMethodContext()); - if (!AD || AD->getStorage() != typeVar) { - emitDiagnostic(Loc, diag::masked_instance_variable, - typeContext->getSelfTypeInContext()) - .fixItInsert(Loc, "self."); - } + SmallVector results; + DC->lookupQualified(typeContext->getSelfNominalTypeDecl(), + VD->getFullName(), + NL_QualifiedDefault | NL_RemoveNonVisible, results); + + auto foundProperty = llvm::find_if(results, [&](ValueDecl *decl) { + // We're looking for a settable property that is the same type as the + // var we found. + auto *var = dyn_cast(decl); + if (!var || var == VD) + return false; + + if (!var->isSettable(DC) || !var->isSetterAccessibleFrom(DC)) + return false; + + if (!var->getType()->isEqual(VD->getType())) + return false; + + // Don't suggest a property if we're in one of its accessors. + auto *methodDC = DC->getInnermostMethodContext(); + if (auto *AD = dyn_cast_or_null(methodDC)) + if (AD->getStorage() == var) + return false; + + return true; + }); + + if (foundProperty != results.end()) { + auto startLoc = immutableExpr->getStartLoc(); + auto *property = *foundProperty; + auto selfTy = typeContext->getSelfTypeInContext(); + + // If we found an instance property, suggest inserting "self.", + // otherwise suggest "Type." for a static property. + std::string fixItText; + if (property->isInstanceMember()) { + fixItText = "self."; + } else { + fixItText = selfTy->getString() + "."; } + emitDiagnostic(startLoc, diag::masked_mutable_property, + fixItText, property->getDescriptiveKind(), selfTy) + .fixItInsert(startLoc, fixItText); } } @@ -1656,7 +1684,7 @@ bool AssignmentFailure::diagnoseAsError() { message = "subscript is immutable"; emitDiagnostic(Loc, DeclDiagnostic, message) - .highlight(immInfo.first->getSourceRange()); + .highlight(immutableExpr->getSourceRange()); return true; } @@ -1678,7 +1706,7 @@ bool AssignmentFailure::diagnoseAsError() { message += " is not settable"; emitDiagnostic(Loc, diagID, message) - .highlight(immInfo.first->getSourceRange()); + .highlight(immutableExpr->getSourceRange()); return true; } } @@ -1688,13 +1716,13 @@ bool AssignmentFailure::diagnoseAsError() { // If a keypath was the problem but wasn't resolved into a vardecl // it is ambiguous or unable to be used for setting. - if (auto *KPE = dyn_cast_or_null(immInfo.first)) { + if (auto *KPE = dyn_cast_or_null(immutableExpr)) { emitDiagnostic(Loc, DeclDiagnostic, "immutable key path") .highlight(KPE->getSourceRange()); return true; } - if (auto LE = dyn_cast(immInfo.first)) { + if (auto LE = dyn_cast(immutableExpr)) { emitDiagnostic(Loc, DeclDiagnostic, "literals are not mutable") .highlight(LE->getSourceRange()); return true; @@ -1702,7 +1730,7 @@ bool AssignmentFailure::diagnoseAsError() { // If the expression is the result of a call, it is an rvalue, not a mutable // lvalue. - if (auto *AE = dyn_cast(immInfo.first)) { + if (auto *AE = dyn_cast(immutableExpr)) { // Handle literals, which are a call to the conversion function. auto argsTuple = dyn_cast(AE->getArg()->getSemanticsProvidingExpr()); @@ -1735,22 +1763,22 @@ bool AssignmentFailure::diagnoseAsError() { return true; } - if (auto contextualType = cs.getContextualType(immInfo.first)) { + if (auto contextualType = cs.getContextualType(immutableExpr)) { Type neededType = contextualType->getInOutObjectType(); - Type actualType = getType(immInfo.first)->getInOutObjectType(); + Type actualType = getType(immutableExpr)->getInOutObjectType(); if (!neededType->isEqual(actualType)) { if (DeclDiagnostic.ID != diag::cannot_pass_rvalue_inout_subelement.ID) { emitDiagnostic(Loc, DeclDiagnostic, "implicit conversion from '" + actualType->getString() + "' to '" + neededType->getString() + "' requires a temporary") - .highlight(immInfo.first->getSourceRange()); + .highlight(immutableExpr->getSourceRange()); } return true; } } - if (auto IE = dyn_cast(immInfo.first)) { + if (auto IE = dyn_cast(immutableExpr)) { emitDiagnostic(Loc, DeclDiagnostic, "result of conditional operator '? :' is never mutable") .highlight(IE->getQuestionLoc()) @@ -1759,7 +1787,7 @@ bool AssignmentFailure::diagnoseAsError() { } emitDiagnostic(Loc, TypeDiagnostic, getType(DestExpr)) - .highlight(immInfo.first->getSourceRange()); + .highlight(immutableExpr->getSourceRange()); return true; } @@ -1988,6 +2016,17 @@ bool ContextualFailure::diagnoseAsError() { Diag diagnostic; switch (path.back().getKind()) { case ConstraintLocator::ClosureResult: { + auto *closure = cast(getRawAnchor()); + if (closure->hasExplicitResultType() && + closure->getExplicitResultTypeLoc().getTypeRepr()) { + auto resultRepr = closure->getExplicitResultTypeLoc().getTypeRepr(); + emitDiagnostic(resultRepr->getStartLoc(), + diag::incorrect_explicit_closure_result, getFromType(), + getToType()) + .fixItReplace(resultRepr->getSourceRange(), getToType().getString()); + return true; + } + diagnostic = diag::cannot_convert_closure_result; break; } @@ -3163,6 +3202,17 @@ bool MissingMemberFailure::diagnoseAsError() { if (baseType->is()) diagnostic = diag::could_not_find_tuple_member; + bool hasUnresolvedPattern = false; + anchor->forEachChildExpr([&](Expr *expr) { + hasUnresolvedPattern |= isa(expr); + return hasUnresolvedPattern ? nullptr : expr; + }); + if (hasUnresolvedPattern && !baseType->getAs()) { + emitDiagnostic(anchor->getLoc(), + diag::cannot_match_unresolved_expr_pattern_with_value, baseType); + return; + } + emitDiagnostic(anchor->getLoc(), diagnostic, baseType, getName()) .highlight(baseExpr->getSourceRange()) .highlight(nameLoc.getSourceRange()); @@ -5151,23 +5201,9 @@ bool InvalidTupleSplatWithSingleParameterFailure::diagnoseAsError() { } } - // If the parameter is a generic parameter, it's hard to say - // whether use of a tuple is really intended here, so let's - // attach a fix-it to a note instead of the diagnostic message - // to indicate that it's not the only right solution possible. - if (auto *typeVar = ParamType->getAs()) { - if (typeVar->getImpl().getGenericParameter()) { - diagnostic.flush(); - - emitDiagnostic(argExpr->getLoc(), diag::note_maybe_forgot_to_form_tuple) - .fixItInsertAfter(newLeftParenLoc, "(") - .fixItInsert(argExpr->getEndLoc(), ")"); - } - } else { - diagnostic.highlight(argExpr->getSourceRange()) - .fixItInsertAfter(newLeftParenLoc, "(") - .fixItInsert(argExpr->getEndLoc(), ")"); - } + diagnostic.highlight(argExpr->getSourceRange()) + .fixItInsertAfter(newLeftParenLoc, "(") + .fixItInsert(argExpr->getEndLoc(), ")"); return true; } @@ -5295,6 +5331,9 @@ bool ArgumentMismatchFailure::diagnoseAsError() { if (diagnoseUseOfReferenceEqualityOperator()) return true; + if (diagnosePropertyWrapperMismatch()) + return true; + auto argType = getFromType(); auto paramType = getToType(); @@ -5534,6 +5573,32 @@ bool ArgumentMismatchFailure::diagnoseMisplacedMissingArgument() const { return failure.diagnoseSingleMissingArgument(); } +bool ArgumentMismatchFailure::diagnosePropertyWrapperMismatch() const { + auto argType = getFromType(); + auto paramType = getToType(); + + // Verify that this is an implicit call to a property wrapper initializer + // in a form of `init(wrappedValue:)` or deprecated `init(initialValue:)`. + auto *call = dyn_cast(getRawAnchor()); + if (!(call && call->isImplicit() && isa(call->getFn()) && + call->getNumArguments() == 1 && + (call->getArgumentLabels().front() == getASTContext().Id_wrappedValue || + call->getArgumentLabels().front() == getASTContext().Id_initialValue))) + return false; + + auto argExpr = cast(call->getArg())->getElement(0); + // If this is an attempt to initialize property wrapper with opaque value + // of error type, let's just ignore that problem since original mismatch + // has been diagnosed already. + if (argExpr->isImplicit() && isa(argExpr) && + argType->is()) + return true; + + emitDiagnostic(getLoc(), diag::cannot_convert_initializer_value, argType, + paramType); + return true; +} + void ExpandArrayIntoVarargsFailure::tryDropArrayBracketsFixIt( Expr *anchor) const { // If this is an array literal, offer to remove the brackets and pass the diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 4ead435893775..718cf3dc45cce 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -1845,6 +1845,11 @@ class ArgumentMismatchFailure : public ContextualFailure { /// reference equality operators `===` and `!==`. bool diagnoseUseOfReferenceEqualityOperator() const; + /// Tailored diagnostics for type mismatches associated with + /// property wrapper initialization via implicit `init(wrappedValue:)` + /// or now deprecated `init(initialValue:)`. + bool diagnosePropertyWrapperMismatch() const; + protected: /// \returns The position of the argument being diagnosed, starting at 1. unsigned getArgPosition() const { return Info->getArgPosition(); } diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 1fb5c64dce98e..40535f5fa1e90 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -702,39 +702,28 @@ CollectionElementContextualMismatch::create(ConstraintSystem &cs, Type srcType, CollectionElementContextualMismatch(cs, srcType, dstType, locator); } -bool ExplicitlySpecifyGenericArguments::diagnose(bool asNote) const { - auto &cs = getConstraintSystem(); - MissingGenericArgumentsFailure failure(cs, getParameters(), - getLocator()); - return failure.diagnose(asNote); -} +bool DefaultGenericArgument::coalesceAndDiagnose( + ArrayRef fixes, bool asNote) const { + llvm::SmallVector missingParams{Param}; -ConstraintFix * -ExplicitlySpecifyGenericArguments::coalescedWith(ArrayRef fixes) { - if (fixes.empty()) - return this; - - auto params = getParameters(); - llvm::SmallVector missingParams{params.begin(), - params.end()}; for (auto *otherFix : fixes) { - if (auto *fix = otherFix->getAs()) { - auto additionalParams = fix->getParameters(); - missingParams.append(additionalParams.begin(), additionalParams.end()); - } + if (auto *fix = otherFix->getAs()) + missingParams.push_back(fix->Param); } - return ExplicitlySpecifyGenericArguments::create(getConstraintSystem(), - missingParams, getLocator()); + auto &cs = getConstraintSystem(); + MissingGenericArgumentsFailure failure(cs, missingParams, getLocator()); + return failure.diagnose(asNote); } -ExplicitlySpecifyGenericArguments *ExplicitlySpecifyGenericArguments::create( - ConstraintSystem &cs, ArrayRef params, - ConstraintLocator *locator) { - unsigned size = totalSizeToAlloc(params.size()); - void *mem = cs.getAllocator().Allocate( - size, alignof(ExplicitlySpecifyGenericArguments)); - return new (mem) ExplicitlySpecifyGenericArguments(cs, params, locator); +bool DefaultGenericArgument::diagnose(bool asNote) const { + return coalesceAndDiagnose({}, asNote); +} + +DefaultGenericArgument * +DefaultGenericArgument::create(ConstraintSystem &cs, GenericTypeParamType *param, + ConstraintLocator *locator) { + return new (cs.getAllocator()) DefaultGenericArgument(cs, param, locator); } SkipUnhandledConstructInFunctionBuilder * @@ -790,8 +779,7 @@ bool AllowTupleSplatForSingleParameter::attempt( // Parameter type has to be either a tuple (with the same arity as // argument list), or a type variable. if (!(paramTy->is() && - paramTy->castTo()->getNumElements() == args.size()) && - !paramTy->is()) + paramTy->castTo()->getNumElements() == args.size())) return true; SmallVector argElts; @@ -803,9 +791,9 @@ bool AllowTupleSplatForSingleParameter::attempt( auto flags = arg.getParameterFlags(); // In situations where there is a single labeled parameter - // we need to form a tuple with omits first label e.g. + // we need to form a tuple which omits the label e.g. // - // func foo(x: T) {} + // func foo(x: (T, T)) {} // foo(x: 0, 1) // // We'd want to suggest argument list to be `x: (0, 1)` instead diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 2f5b11a99c604..438e499ea87bd 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -47,9 +47,11 @@ class Solution; /// Describes the kind of fix to apply to the given constraint before /// visiting it. +/// +/// Note: values 0 and 1 are reserved for empty and tombstone kinds. enum class FixKind : uint8_t { /// Introduce a '!' to force an optional unwrap. - ForceOptional, + ForceOptional = 2, /// Unwrap an optional base when we have a member access. UnwrapOptionalBase, @@ -181,10 +183,8 @@ enum class FixKind : uint8_t { /// function to `Void` to conform to expected result type. RemoveReturn, - /// Generic parameters could not be inferred and have to be explicitly - /// specified in the source. This fix groups all of the missing arguments - /// associated with single declaration. - ExplicitlySpecifyGenericArguments, + /// Default ambiguous generic arguments to \c Any + DefaultGenericArgument, /// Skip any unhandled constructs that occur within a closure argument that /// matches up with a @@ -252,14 +252,18 @@ class ConstraintFix { virtual std::string getName() const = 0; - /// Diagnose a failure associated with this fix given - /// root expression and information from constraint system. - virtual bool diagnose(bool asNote = false) const = 0; - - virtual ConstraintFix *coalescedWith(ArrayRef fixes) { - return this; + /// Coalesce this fix with the given secondary fixes and diagnose the failure. + /// + /// The default implementation ignores \c secondaryFixes and calls + /// \c diagnose. + virtual bool coalesceAndDiagnose(ArrayRef secondaryFixes, + bool asNote = false) const { + return diagnose(asNote); } + /// Diagnose a failure associated with this fix. + virtual bool diagnose(bool asNote = false) const = 0; + void print(llvm::raw_ostream &Out) const; SWIFT_DEBUG_DUMP; @@ -1249,49 +1253,32 @@ class CollectionElementContextualMismatch final : public ContextualMismatch { ConstraintLocator *locator); }; -class ExplicitlySpecifyGenericArguments final - : public ConstraintFix, - private llvm::TrailingObjects { - friend TrailingObjects; - - unsigned NumMissingParams; +class DefaultGenericArgument final : public ConstraintFix { + GenericTypeParamType *Param; - ExplicitlySpecifyGenericArguments(ConstraintSystem &cs, - ArrayRef params, - ConstraintLocator *locator) - : ConstraintFix(cs, FixKind::ExplicitlySpecifyGenericArguments, locator), - NumMissingParams(params.size()) { - assert(!params.empty()); - std::uninitialized_copy(params.begin(), params.end(), - getParametersBuf().begin()); - } + DefaultGenericArgument(ConstraintSystem &cs, GenericTypeParamType *param, + ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::DefaultGenericArgument, locator), + Param(param) {} public: static bool classof(const ConstraintFix *fix) { - return fix->getKind() == FixKind::ExplicitlySpecifyGenericArguments; + return fix->getKind() == FixKind::DefaultGenericArgument; } std::string getName() const override { - return "default missing generic arguments to `Any`"; + auto paramName = Param->getString(); + return "default generic argument '" + paramName + "' to 'Any'"; } - ArrayRef getParameters() const { - return {getTrailingObjects(), NumMissingParams}; - } + bool coalesceAndDiagnose(ArrayRef secondaryFixes, + bool asNote = false) const override; bool diagnose(bool asNote = false) const override; - ConstraintFix *coalescedWith(ArrayRef fixes) override; - - static ExplicitlySpecifyGenericArguments * - create(ConstraintSystem &cs, ArrayRef params, - ConstraintLocator *locator); - -private: - MutableArrayRef getParametersBuf() { - return {getTrailingObjects(), NumMissingParams}; - } + static DefaultGenericArgument *create(ConstraintSystem &cs, + GenericTypeParamType *param, + ConstraintLocator *locator); }; class SkipUnhandledConstructInFunctionBuilder final : public ConstraintFix { @@ -1553,4 +1540,23 @@ class TreatEphemeralAsNonEphemeral final : public AllowArgumentMismatch { } // end namespace constraints } // end namespace swift +namespace llvm { + template <> + struct DenseMapInfo { + using FixKind = swift::constraints::FixKind; + static inline FixKind getEmptyKey() { + return static_cast(0); + } + static inline FixKind getTombstoneKey() { + return static_cast(1); + } + static unsigned getHashValue(FixKind kind) { + return static_cast(kind); + } + static bool isEqual(FixKind lhs, FixKind rhs) { + return lhs == rhs; + } + }; +} + #endif // SWIFT_SEMA_CSFIX_H diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index c290dd916e1d5..973dcf627c137 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1331,7 +1331,7 @@ namespace { Type visitDeclQuoteExpr(DeclQuoteExpr *expr) { auto &tc = CS.getTypeChecker(); - return tc.getTypeOfQuoteDecl(expr->getLoc()); + return tc.getTypeOfQuoteDecl(CS.getASTContext(), expr->getLoc()); } Type visitDeclRefExpr(DeclRefExpr *E) { @@ -3771,6 +3771,8 @@ namespace { } // end anonymous namespace Expr *ConstraintSystem::generateConstraints(Expr *expr, DeclContext *dc) { + InputExprs.insert(expr); + // Remove implicit conversions from the expression. expr = expr->walk(SanitizeExpr(*this)); @@ -3793,7 +3795,7 @@ Type ConstraintSystem::generateConstraints(Pattern *pattern, } void ConstraintSystem::optimizeConstraints(Expr *e) { - if (getASTContext().LangOpts.DisableConstraintSolverPerformanceHacks) + if (getASTContext().TypeCheckerOpts.DisableConstraintSolverPerformanceHacks) return; SmallVector linkedExprs; @@ -3878,9 +3880,8 @@ getMemberDecls(InterestedMemberKind Kind) { ResolvedMemberResult swift::resolveValueMember(DeclContext &DC, Type BaseTy, DeclName Name) { ResolvedMemberResult Result; - // If the current ast context has no type checker, create one for it. - auto *TC = DC.getASTContext().getLegacyGlobalTypeChecker(); - assert(TC && "Must have type checker to make global query!"); + assert(DC.getASTContext().getLegacyGlobalTypeChecker() && + "Must have type checker to make global query!"); ConstraintSystem CS(&DC, None); // Look up all members of BaseTy with the given Name. diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp index a6c735e00c9b1..64b51dfebe7d7 100644 --- a/lib/Sema/CSRanking.cpp +++ b/lib/Sema/CSRanking.cpp @@ -35,7 +35,7 @@ void ConstraintSystem::increaseScore(ScoreKind kind, unsigned value) { unsigned index = static_cast(kind); CurrentScore.Data[index] += value; - if (getASTContext().LangOpts.DebugConstraintSolver && value > 0) { + if (getASTContext().TypeCheckerOpts.DebugConstraintSolver && value > 0) { auto &log = getASTContext().TypeCheckerDebug->getStream(); if (solverState) log.indent(solverState->depth * 2); @@ -91,7 +91,7 @@ void ConstraintSystem::increaseScore(ScoreKind kind, unsigned value) { } bool ConstraintSystem::worseThanBestSolution() const { - if (getASTContext().LangOpts.DisableConstraintSolverPerformanceHacks) + if (getASTContext().TypeCheckerOpts.DisableConstraintSolverPerformanceHacks) return false; if (retainAllSolutions()) @@ -101,7 +101,7 @@ bool ConstraintSystem::worseThanBestSolution() const { CurrentScore <= *solverState->BestScore) return false; - if (getASTContext().LangOpts.DebugConstraintSolver) { + if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); log.indent(solverState->depth * 2) << "(solution is worse than the best solution)\n"; @@ -389,7 +389,7 @@ llvm::Expected CompareDeclSpecializationRequest::evaluate( Evaluator &eval, DeclContext *dc, ValueDecl *decl1, ValueDecl *decl2, bool isDynamicOverloadComparison) const { auto &C = decl1->getASTContext(); - if (C.LangOpts.DebugConstraintSolver) { + if (C.TypeCheckerOpts.DebugConstraintSolver) { auto &log = C.TypeCheckerDebug->getStream(); log << "Comparing declarations\n"; decl1->print(log); @@ -401,7 +401,7 @@ llvm::Expected CompareDeclSpecializationRequest::evaluate( } auto completeResult = [&C](bool result) { - if (C.LangOpts.DebugConstraintSolver) { + if (C.TypeCheckerOpts.DebugConstraintSolver) { auto &log = C.TypeCheckerDebug->getStream(); log << "comparison result: " << (result ? "better" : "not better") << "\n"; @@ -710,9 +710,8 @@ static Type getUnlabeledType(Type type, ASTContext &ctx) { SolutionCompareResult ConstraintSystem::compareSolutions( ConstraintSystem &cs, ArrayRef solutions, - const SolutionDiff &diff, unsigned idx1, unsigned idx2, - llvm::DenseMap> &weights) { - if (cs.getASTContext().LangOpts.DebugConstraintSolver) { + const SolutionDiff &diff, unsigned idx1, unsigned idx2) { + if (cs.getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = cs.getASTContext().TypeCheckerDebug->getStream(); log.indent(cs.solverState->depth * 2) << "comparing solutions " << idx1 << " and " << idx2 <<"\n"; @@ -743,9 +742,9 @@ SolutionCompareResult ConstraintSystem::compareSolutions( auto getWeight = [&](ConstraintLocator *locator) -> unsigned { if (auto *anchor = locator->getAnchor()) { - auto weight = weights.find(anchor); - if (weight != weights.end()) - return weight->getSecond().first + 1; + auto weight = cs.getExprDepth(anchor); + if (weight) + return *weight + 1; } return 1; @@ -1180,7 +1179,7 @@ ConstraintSystem::findBestSolution(SmallVectorImpl &viable, if (viable.size() == 1) return 0; - if (getASTContext().LangOpts.DebugConstraintSolver) { + if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); log.indent(solverState->depth * 2) << "Comparing " << viable.size() << " viable solutions\n"; @@ -1197,7 +1196,7 @@ ConstraintSystem::findBestSolution(SmallVectorImpl &viable, SmallVector losers(viable.size(), false); unsigned bestIdx = 0; for (unsigned i = 1, n = viable.size(); i != n; ++i) { - switch (compareSolutions(*this, viable, diff, i, bestIdx, ExprWeights)) { + switch (compareSolutions(*this, viable, diff, i, bestIdx)) { case SolutionCompareResult::Identical: // FIXME: Might want to warn about this in debug builds, so we can // find a way to eliminate the redundancy in the search space. @@ -1221,7 +1220,7 @@ ConstraintSystem::findBestSolution(SmallVectorImpl &viable, if (i == bestIdx) continue; - switch (compareSolutions(*this, viable, diff, bestIdx, i, ExprWeights)) { + switch (compareSolutions(*this, viable, diff, bestIdx, i)) { case SolutionCompareResult::Identical: // FIXME: Might want to warn about this in debug builds, so we can // find a way to eliminate the redundancy in the search space. @@ -1273,7 +1272,7 @@ ConstraintSystem::findBestSolution(SmallVectorImpl &viable, if (losers[j]) continue; - switch (compareSolutions(*this, viable, diff, i, j, ExprWeights)) { + switch (compareSolutions(*this, viable, diff, i, j)) { case SolutionCompareResult::Identical: // FIXME: Dub one of these the loser arbitrarily? break; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 6c4be207b8296..cc2f23f5379d6 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -867,9 +867,7 @@ class ArgumentFailureTracker : public MatchCallArgumentListener { auto *argType = CS.createTypeVariable(argLoc, TVO_CanBindToInOut | TVO_CanBindToLValue | - TVO_CanBindToNoEscape); - - CS.recordPotentialHole(argType); + TVO_CanBindToNoEscape | TVO_CanBindToHole); Arguments.push_back(param.withType(argType)); ++NumSynthesizedArgs; @@ -3078,18 +3076,8 @@ bool ConstraintSystem::repairFailures( locator); } - // Let's not complain about argument type mismatch if we have a synthesized - // wrappedValue initializer, because we already emit a diagnostic for a - // type mismatch between the property's type and the wrappedValue type. - if (auto CE = dyn_cast(loc->getAnchor())) { - if (CE->isImplicit() && !CE->getArgumentLabels().empty() && - CE->getArgumentLabels().front() == getASTContext().Id_wrappedValue) { - break; - } - } - // If either type has a hole, consider this fixed. - if (lhs->hasUnresolvedType() || rhs->hasUnresolvedType()) + if (lhs->hasHole() || rhs->hasHole()) return true; conversionsOrFixes.push_back( @@ -3155,7 +3143,7 @@ bool ConstraintSystem::repairFailures( case ConstraintLocator::TypeParameterRequirement: case ConstraintLocator::ConditionalRequirement: { // If either type has a hole, consider this fixed. - if (lhs->hasUnresolvedType() || rhs->hasUnresolvedType()) + if (lhs->hasHole() || rhs->hasHole()) return true; // If dependent members are present here it's because @@ -3275,8 +3263,25 @@ bool ConstraintSystem::repairFailures( break; } + case ConstraintLocator::FunctionResult: { + auto *loc = getConstraintLocator(anchor, {path.begin(), path.end() - 1}); + // If this is a mismatch between contextual type and (trailing) + // closure with explicitly specified result type let's record it + // as contextual type mismatch. + if (loc->isLastElement() || + loc->isLastElement()) { + auto *argExpr = simplifyLocatorToAnchor(loc); + if (argExpr && isa(argExpr)) { + conversionsOrFixes.push_back(ContextualMismatch::create( + *this, lhs, rhs, + getConstraintLocator(argExpr, ConstraintLocator::ClosureResult))); + break; + } + } + LLVM_FALLTHROUGH; + } + case ConstraintLocator::Member: - case ConstraintLocator::FunctionResult: case ConstraintLocator::DynamicLookupResult: { // Most likely this is an attempt to use get-only subscript as mutating, // or assign a value of a result of function/member ref e.g. `foo() = 42` @@ -3415,7 +3420,7 @@ bool ConstraintSystem::repairFailures( } case ConstraintLocator::InstanceType: { - if (lhs->hasUnresolvedType() || rhs->hasUnresolvedType()) + if (lhs->hasHole() || rhs->hasHole()) return true; break; @@ -4954,6 +4959,12 @@ ConstraintSystem::simplifyFunctionComponentConstraint( // Track how many times we do this so that we can record a fix for each. ++unwrapCount; } + + if (simplified->isHole()) { + if (auto *typeVar = second->getAs()) + recordPotentialHole(typeVar); + return SolutionKind::Solved; + } } if (simplified->isTypeVariableOrMember()) { @@ -5284,10 +5295,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, return; } - // FIXME: Deal with broken recursion - if (!decl->hasInterfaceType()) - return; - // Dig out the instance type and figure out what members of the instance type // we are going to see. auto baseTy = candidate.getBaseType(); @@ -5659,10 +5666,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, return result; } - // FIXME: Deal with broken recursion - if (!cand->hasInterfaceType()) - continue; - result.addUnviable(getOverloadChoice(cand, /*isBridged=*/false, /*isUnwrappedOptional=*/false), MemberLookupResult::UR_Inaccessible); @@ -6743,9 +6746,12 @@ ConstraintSystem::simplifyKeyPathConstraint( } if (shouldAttemptFixes()) { - auto *componentLoc = getConstraintLocator( - keyPath, {LocatorPathElt::KeyPathComponent(i), - LocatorPathElt::KeyPathComponentResult()}); + auto typeVar = + llvm::find_if(componentTypeVars, [&](TypeVariableType *typeVar) { + auto *locator = typeVar->getImpl().getLocator(); + auto elt = locator->findLast(); + return elt && elt->getIndex() == i; + }); // If one of the components haven't been resolved, let's check // whether it has been determined to be a "hole" and if so, @@ -6753,7 +6759,8 @@ ConstraintSystem::simplifyKeyPathConstraint( // // This helps to, for example, diagnose problems with missing // members used as part of a key path. - if (isPotentialHoleAt(componentLoc)) { + if (typeVar != componentTypeVars.end() && + (*typeVar)->getImpl().canBindToHole()) { anyComponentsUnresolved = true; capability = ReadOnly; continue; @@ -6780,8 +6787,9 @@ ConstraintSystem::simplifyKeyPathConstraint( if (auto *fix = AllowInvalidRefInKeyPath::forRef( *this, choices[i].getDecl(), componentLoc)) { - if (!shouldAttemptFixes() || recordFix(fix)) - return SolutionKind::Error; + if (!hasFixFor(componentLoc, FixKind::AllowTypeOrInstanceMember)) + if (!shouldAttemptFixes() || recordFix(fix)) + return SolutionKind::Error; // If this was a method reference let's mark it as read-only. if (!storage) { @@ -7119,7 +7127,7 @@ Type ConstraintSystem::simplifyAppliedOverloads( // If we have a common result type, bind the expected result type to it. if (commonResultType && !commonResultType->is()) { ASTContext &ctx = getASTContext(); - if (ctx.LangOpts.DebugConstraintSolver) { + if (ctx.TypeCheckerOpts.DebugConstraintSolver) { auto &log = ctx.TypeCheckerDebug->getStream(); log.indent(solverState ? solverState->depth * 2 + 2 : 0) << "(common result type for $T" << fnTypeVar->getID() << " is " @@ -7151,25 +7159,6 @@ ConstraintSystem::simplifyApplicableFnConstraint( // following: $T1 -> $T2. auto func1 = type1->castTo(); - // Let's check if this member couldn't be found and is fixed - // to exist based on its usage. - if (auto *memberTy = type2->getAs()) { - if (isPotentialHole(memberTy)) { - auto *funcTy = type1->castTo(); - auto *locator = memberTy->getImpl().getLocator(); - // Bind type variable associated with member to a type of argument - // application, which makes it seem like member exists with the - // types of the parameters matching argument types exactly. - addConstraint(ConstraintKind::Bind, memberTy, funcTy, locator); - // There might be no contextual type for result of the application, - // in cases like `let _ = x.foo()`, so let's record a potential hole. - auto resultTy = funcTy->getResult(); - if (auto *typeVar = resultTy->getAs()) - recordPotentialHole(typeVar); - return SolutionKind::Solved; - } - } - // Before stripping lvalue-ness and optional types, save the original second // type for handling `func callAsFunction` and `@dynamicCallable` // applications. This supports the following cases: @@ -8197,7 +8186,7 @@ static bool isAugmentingFix(ConstraintFix *fix) { bool ConstraintSystem::recordFix(ConstraintFix *fix, unsigned impact) { auto &ctx = getASTContext(); - if (ctx.LangOpts.DebugConstraintSolver) { + if (ctx.TypeCheckerOpts.DebugConstraintSolver) { auto &log = ctx.TypeCheckerDebug->getStream(); log.indent(solverState ? solverState->depth * 2 + 2 : 0) << "(attempting fix "; @@ -8237,7 +8226,7 @@ bool ConstraintSystem::recordFix(ConstraintFix *fix, unsigned impact) { void ConstraintSystem::recordPotentialHole(TypeVariableType *typeVar) { assert(typeVar); - Holes.insert(typeVar->getImpl().getLocator()); + typeVar->getImpl().enableCanBindToHole(getSavedBindings()); } ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( @@ -8443,7 +8432,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::AllowAnyObjectKeyPathRoot: case FixKind::TreatKeyPathSubscriptIndexAsHashable: case FixKind::AllowInvalidRefInKeyPath: - case FixKind::ExplicitlySpecifyGenericArguments: + case FixKind::DefaultGenericArgument: case FixKind::GenericArgumentsMismatch: case FixKind::AllowMutatingMemberOnRValueBase: case FixKind::AllowTupleSplatForSingleParameter: diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index f30fb4e32ace3..a6fdc435cbc36 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -16,6 +16,7 @@ #include "CSStep.h" #include "ConstraintGraph.h" #include "ConstraintSystem.h" +#include "SolutionResult.h" #include "TypeCheckType.h" #include "swift/AST/ParameterList.h" #include "swift/AST/TypeWalker.h" @@ -68,8 +69,9 @@ Solution ConstraintSystem::finalize() { Solution solution(*this, CurrentScore); // Update the best score we've seen so far. + auto &ctx = getASTContext(); if (!retainAllSolutions()) { - assert(getASTContext().LangOpts.DisableConstraintSolverPerformanceHacks || + assert(ctx.TypeCheckerOpts.DisableConstraintSolverPerformanceHacks || !solverState->BestScore || CurrentScore <= *solverState->BestScore); if (!solverState->BestScore || CurrentScore <= *solverState->BestScore) { @@ -89,7 +91,7 @@ Solution ConstraintSystem::finalize() { break; case FreeTypeVariableBinding::UnresolvedType: - assignFixedType(tv, getASTContext().TheUnresolvedType); + assignFixedType(tv, ctx.TheUnresolvedType); break; } } @@ -283,7 +285,7 @@ bool ConstraintSystem::simplify(bool ContinueAfterFailures) { failedConstraint = constraint; } - if (getASTContext().LangOpts.DebugConstraintSolver) { + if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); log.indent(solverState ? solverState->depth * 2 : 0) << "(failed constraint "; @@ -361,12 +363,12 @@ ConstraintSystem::SolverState::SolverState( // If we're supposed to debug a specific constraint solver attempt, // turn on debugging now. - ASTContext &ctx = CS.getTypeChecker().Context; - LangOptions &langOpts = ctx.LangOpts; - OldDebugConstraintSolver = langOpts.DebugConstraintSolver; - if (langOpts.DebugConstraintSolverAttempt && - langOpts.DebugConstraintSolverAttempt == SolutionAttempt) { - langOpts.DebugConstraintSolver = true; + ASTContext &ctx = CS.getASTContext(); + auto &tyOpts = ctx.TypeCheckerOpts; + OldDebugConstraintSolver = tyOpts.DebugConstraintSolver; + if (tyOpts.DebugConstraintSolverAttempt && + tyOpts.DebugConstraintSolverAttempt == SolutionAttempt) { + tyOpts.DebugConstraintSolver = true; llvm::raw_ostream &dbgOut = ctx.TypeCheckerDebug->getStream(); dbgOut << "---Constraint system #" << SolutionAttempt << "---\n"; CS.print(dbgOut); @@ -408,8 +410,8 @@ ConstraintSystem::SolverState::~SolverState() { } // Restore debugging state. - LangOptions &langOpts = CS.getTypeChecker().Context.LangOpts; - langOpts.DebugConstraintSolver = OldDebugConstraintSolver; + TypeCheckerOptions &tyOpts = CS.getASTContext().TypeCheckerOpts; + tyOpts.DebugConstraintSolver = OldDebugConstraintSolver; // Write our local statistics back to the overall statistics. #define CS_STATISTIC(Name, Description) JOIN2(Overall,Name) += Name; @@ -436,7 +438,6 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs) numSavedBindings = cs.solverState->savedBindings.size(); numConstraintRestrictions = cs.ConstraintRestrictions.size(); numFixes = cs.Fixes.size(); - numHoles = cs.Holes.size(); numFixedRequirements = cs.FixedRequirements.size(); numDisjunctionChoices = cs.DisjunctionChoices.size(); numOpenedTypes = cs.OpenedTypes.size(); @@ -484,9 +485,6 @@ ConstraintSystem::SolverScope::~SolverScope() { // Remove any fixes. truncate(cs.Fixes, numFixes); - // Remove any holes encountered along the current path. - truncate(cs.Holes, numHoles); - // Remove any disjunction choices. truncate(cs.DisjunctionChoices, numDisjunctionChoices); @@ -573,7 +571,7 @@ bool ConstraintSystem::Candidate::solve( }; // Allocate new constraint system for sub-expression. - ConstraintSystem cs(DC, None, E); + ConstraintSystem cs(DC, None); cs.baseCS = &BaseCS; // Set up expression type checker timer for the candidate. @@ -595,7 +593,7 @@ bool ConstraintSystem::Candidate::solve( return false; auto &ctx = cs.getASTContext(); - if (ctx.LangOpts.DebugConstraintSolver) { + if (ctx.TypeCheckerOpts.DebugConstraintSolver) { auto &log = cs.getASTContext().TypeCheckerDebug->getStream(); log << "--- Solving candidate for shrinking at "; auto R = E->getSourceRange(); @@ -632,7 +630,7 @@ bool ConstraintSystem::Candidate::solve( cs.solveImpl(solutions); } - if (ctx.LangOpts.DebugConstraintSolver) { + if (ctx.TypeCheckerOpts.DebugConstraintSolver) { auto &log = cs.getASTContext().TypeCheckerDebug->getStream(); if (solutions.empty()) { log << "--- No Solutions ---\n"; @@ -716,7 +714,7 @@ void ConstraintSystem::Candidate::applySolutions( } void ConstraintSystem::shrink(Expr *expr) { - if (getASTContext().LangOpts.SolverDisableShrink) + if (getASTContext().TypeCheckerOpts.SolverDisableShrink) return; using DomainMap = llvm::SmallDenseMap>; @@ -1063,10 +1061,10 @@ void ConstraintSystem::shrink(Expr *expr) { } static bool debugConstraintSolverForExpr(ASTContext &C, Expr *expr) { - if (C.LangOpts.DebugConstraintSolver) + if (C.TypeCheckerOpts.DebugConstraintSolver) return true; - if (C.LangOpts.DebugConstraintSolverOnLines.empty()) + if (C.TypeCheckerOpts.DebugConstraintSolverOnLines.empty()) // No need to compute the line number to find out it's not present. return false; @@ -1082,7 +1080,7 @@ static bool debugConstraintSolverForExpr(ASTContext &C, Expr *expr) { assert(startLine <= endLine && "expr ends before it starts?"); - auto &lines = C.LangOpts.DebugConstraintSolverOnLines; + auto &lines = C.TypeCheckerOpts.DebugConstraintSolverOnLines; assert(std::is_sorted(lines.begin(), lines.end()) && "DebugConstraintSolverOnLines sorting invariant violated"); @@ -1101,7 +1099,7 @@ bool ConstraintSystem::solve(Expr *&expr, SmallVectorImpl &solutions, FreeTypeVariableBinding allowFreeTypeVariables) { llvm::SaveAndRestore debugForExpr( - getASTContext().LangOpts.DebugConstraintSolver, + getASTContext().TypeCheckerOpts.DebugConstraintSolver, debugConstraintSolverForExpr(getASTContext(), expr)); // Attempt to solve the constraint system. @@ -1124,10 +1122,27 @@ bool ConstraintSystem::solve(Expr *&expr, if (shouldSuppressDiagnostics()) return true; - // Try to provide a decent diagnostic. - if (salvage(solutions, expr)) { - // If salvage produced an error message, then it failed to salvage the - // expression, just bail out having reported the error. + // Try to fix the system or provide a decent diagnostic. + auto salvagedResult = salvage(); + switch (salvagedResult.getKind()) { + case SolutionResult::Kind::Success: + solutions.clear(); + solutions.push_back(std::move(salvagedResult).takeSolution()); + break; + + case SolutionResult::Kind::Error: + case SolutionResult::Kind::Ambiguous: + return true; + + case SolutionResult::Kind::UndiagnosedError: + diagnoseFailureForExpr(expr); + salvagedResult.markAsDiagnosed(); + return true; + + case SolutionResult::Kind::TooComplex: + getASTContext().Diags.diagnose(expr->getLoc(), diag::expression_too_complex) + .highlight(expr->getSourceRange()); + salvagedResult.markAsDiagnosed(); return true; } @@ -1140,7 +1155,7 @@ bool ConstraintSystem::solve(Expr *&expr, return true; } - if (getASTContext().LangOpts.DebugConstraintSolver) { + if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); if (solutions.size() == 1) { log << "---Solution---\n"; @@ -1162,7 +1177,7 @@ ConstraintSystem::solveImpl(Expr *&expr, ExprTypeCheckListener *listener, SmallVectorImpl &solutions, FreeTypeVariableBinding allowFreeTypeVariables) { - if (getASTContext().LangOpts.DebugConstraintSolver) { + if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); log << "---Constraint solving for the expression at "; auto R = expr->getSourceRange(); @@ -1234,7 +1249,7 @@ ConstraintSystem::solveImpl(Expr *&expr, return SolutionKind::Error; } - if (getASTContext().LangOpts.DebugConstraintSolver) { + if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); log << "---Initial constraints for the given expression---\n"; print(log, expr); @@ -1258,7 +1273,7 @@ bool ConstraintSystem::solve(SmallVectorImpl &solutions, // Solve the system. solveImpl(solutions); - if (getASTContext().LangOpts.DebugConstraintSolver) { + if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); log << "---Solver statistics---\n"; log << "Total number of scopes explored: " << solverState->NumStatesExplored << "\n"; @@ -1392,7 +1407,7 @@ ConstraintSystem::filterDisjunction( continue; } - if (ctx.LangOpts.DebugConstraintSolver) { + if (ctx.TypeCheckerOpts.DebugConstraintSolver) { auto &log = ctx.TypeCheckerDebug->getStream(); log.indent(solverState ? solverState->depth * 2 + 2 : 0) << "(disabled disjunction term "; @@ -1453,7 +1468,7 @@ ConstraintSystem::filterDisjunction( recordDisjunctionChoice(disjunction->getLocator(), choiceIdx); } - if (ctx.LangOpts.DebugConstraintSolver) { + if (ctx.TypeCheckerOpts.DebugConstraintSolver) { auto &log = ctx.TypeCheckerDebug->getStream(); log.indent(solverState ? solverState->depth * 2 + 2 : 0) << "(introducing single enabled disjunction term "; @@ -2150,7 +2165,7 @@ void ConstraintSystem::partitionDisjunction( } // Partition SIMD operators. - if (!getASTContext().LangOpts.SolverEnableOperatorDesignatedTypes && + if (!getASTContext().TypeCheckerOpts.SolverEnableOperatorDesignatedTypes && isOperatorBindOverload(Choices[0])) { forEachChoice(Choices, [&](unsigned index, Constraint *constraint) -> bool { if (!isOperatorBindOverload(constraint)) @@ -2175,7 +2190,7 @@ void ConstraintSystem::partitionDisjunction( } }; - if (getASTContext().LangOpts.SolverEnableOperatorDesignatedTypes && + if (getASTContext().TypeCheckerOpts.SolverEnableOperatorDesignatedTypes && isOperatorBindOverload(Choices[0])) { partitionForDesignatedTypes(Choices, forEachChoice, appendPartition); } @@ -2210,7 +2225,7 @@ Constraint *ConstraintSystem::selectDisjunction() { // disjunctions that we may not be able to short-circuit, allowing // us to eliminate behavior that is exponential in the number of // operators in the expression. - if (getASTContext().LangOpts.SolverEnableOperatorDesignatedTypes) { + if (getASTContext().TypeCheckerOpts.SolverEnableOperatorDesignatedTypes) { if (auto *disjunction = selectApplyDisjunction()) return disjunction; } diff --git a/lib/Sema/CSStep.cpp b/lib/Sema/CSStep.cpp index 0435fe3cac6fe..12c635155b2aa 100644 --- a/lib/Sema/CSStep.cpp +++ b/lib/Sema/CSStep.cpp @@ -415,13 +415,15 @@ StepResult ComponentStep::finalize(bool isSuccess) { void TypeVariableStep::setup() { ++CS.solverState->NumTypeVariablesBound; if (isDebugMode()) { + PrintOptions PO; + PO.PrintTypesForDebugging = true; auto &log = getDebugLogger(); log << "Initial bindings: "; interleave(InitialBindings.begin(), InitialBindings.end(), [&](const Binding &binding) { - log << TypeVar->getString() - << " := " << binding.BindingType->getString(); + log << TypeVar->getString(PO) + << " := " << binding.BindingType->getString(PO); }, [&log] { log << ", "; }); @@ -516,7 +518,7 @@ bool DisjunctionStep::shouldSkip(const DisjunctionChoice &choice) const { if (!attemptFixes && choice.isUnavailable()) return true; - if (ctx.LangOpts.DisableConstraintSolverPerformanceHacks) + if (ctx.TypeCheckerOpts.DisableConstraintSolverPerformanceHacks) return false; // Don't attempt to solve for generic operators if we already have @@ -605,7 +607,7 @@ bool DisjunctionStep::shortCircuitDisjunctionAt( if (currentChoice->getFix() && !lastSuccessfulChoice->getFix()) return true; - if (ctx.LangOpts.DisableConstraintSolverPerformanceHacks) + if (ctx.TypeCheckerOpts.DisableConstraintSolverPerformanceHacks) return false; if (auto restriction = currentChoice->getRestriction()) { @@ -633,7 +635,7 @@ bool DisjunctionStep::shortCircuitDisjunctionAt( isSIMDOperator(currentChoice->getOverloadChoice().getDecl()) && lastSuccessfulChoice->getKind() == ConstraintKind::BindOverload && !isSIMDOperator(lastSuccessfulChoice->getOverloadChoice().getDecl()) && - !ctx.LangOpts.SolverEnableOperatorDesignatedTypes) { + !ctx.TypeCheckerOpts.SolverEnableOperatorDesignatedTypes) { return true; } diff --git a/lib/Sema/CSStep.h b/lib/Sema/CSStep.h index 4af98a6ed91f3..ee3e120e86b38 100644 --- a/lib/Sema/CSStep.h +++ b/lib/Sema/CSStep.h @@ -234,7 +234,7 @@ class SolverStep { /// Check whether constraint solver is running in "debug" mode, /// which should output diagnostic information. bool isDebugMode() const { - return CS.getASTContext().LangOpts.DebugConstraintSolver; + return CS.getASTContext().TypeCheckerOpts.DebugConstraintSolver; } llvm::raw_ostream &getDebugLogger(bool indent = true) const { @@ -601,7 +601,9 @@ class TypeVariableStep final : public BindingStep { StepResult resume(bool prevFailed) override; void print(llvm::raw_ostream &Out) override { - Out << "TypeVariableStep for " << TypeVar->getString() << " with #" + PrintOptions PO; + PO.PrintTypesForDebugging = true; + Out << "TypeVariableStep for " << TypeVar->getString(PO) << " with #" << InitialBindings.size() << " initial bindings\n"; } diff --git a/lib/Sema/CalleeCandidateInfo.cpp b/lib/Sema/CalleeCandidateInfo.cpp index bfd548925d3dd..67b5127efac82 100644 --- a/lib/Sema/CalleeCandidateInfo.cpp +++ b/lib/Sema/CalleeCandidateInfo.cpp @@ -602,8 +602,7 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, auto ctors = TypeChecker::lookupConstructors( CS.DC, instanceType, NameLookupFlags::IgnoreAccessControl); for (auto ctor : ctors) { - if (ctor.getValueDecl()->getInterfaceType()) - candidates.push_back({ ctor.getValueDecl(), 1 }); + candidates.push_back({ ctor.getValueDecl(), 1 }); } } diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 5540f4a1beb36..1c95f667caa64 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -107,7 +107,6 @@ Expr *swift::buildArgumentForwardingExpr(ArrayRef params, } static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var, - SmallVectorImpl &defaultInits, unsigned paramSize, ASTContext &ctx) { // First and foremost, if this is a constant don't bother. if (var->isLet()) @@ -138,13 +137,6 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var, // We can add a default value now. - // Give this some bogus context right now, we'll fix it after making - // the constructor. - auto *initDC = new (ctx) DefaultArgumentInitializer( - arg->getDeclContext(), paramSize); - - defaultInits.push_back(initDC); - // If the variable has a type T? and no initial value, return a nil literal // default arg. All lazy variables return a nil literal as well. *Note* that // the type will always be a sugared T? because we don't default init an @@ -244,7 +236,7 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl, // Don't allow the parameter to accept temporary pointer conversions. arg->setNonEphemeralIfPossible(); - maybeAddMemberwiseDefaultArg(arg, var, defaultInits, params.size(), ctx); + maybeAddMemberwiseDefaultArg(arg, var, params.size(), ctx); params.push_back(arg); } @@ -266,11 +258,6 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl, if (ICK == ImplicitConstructorKind::Memberwise) { ctor->setIsMemberwiseInitializer(); - - // Fix default argument init contexts now that we have a constructor. - for (auto initDC : defaultInits) { - initDC->changeFunction(ctor, paramList); - } } // If we are defining a default initializer for a class that has a superclass, diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index a4a8098dc978f..1e743d565d9c7 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -21,7 +21,6 @@ #include "swift/Basic/Compiler.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/SaveAndRestore.h" #include using namespace swift; @@ -265,6 +264,10 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const { } void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const { + // Print all type variables as $T0 instead of _ here. + PrintOptions PO; + PO.PrintTypesForDebugging = true; + if (Kind == ConstraintKind::Disjunction) { Out << "disjunction"; if (shouldRememberChoice()) @@ -286,7 +289,7 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const { return; } - getFirstType()->print(Out); + Out << getFirstType()->getString(PO); bool skipSecond = false; @@ -315,17 +318,17 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const { case ConstraintKind::OneWayEqual: Out << " one-way bind to "; break; case ConstraintKind::KeyPath: Out << " key path from "; - getSecondType()->print(Out); + Out << getSecondType()->getString(PO); Out << " -> "; - getThirdType()->print(Out); + Out << getThirdType()->getString(PO); skipSecond = true; break; case ConstraintKind::KeyPathApplication: Out << " key path projecting "; - getSecondType()->print(Out); + Out << getSecondType()->getString(PO); Out << " -> "; - getThirdType()->print(Out); + Out << getThirdType()->getString(PO); skipSecond = true; break; case ConstraintKind::OptionalObject: @@ -396,7 +399,7 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const { } if (!skipSecond) - getSecondType()->print(Out); + Out << getSecondType()->getString(PO); if (auto restriction = getRestriction()) { Out << ' ' << getName(*restriction); @@ -420,9 +423,6 @@ void Constraint::dump(SourceManager *sm) const { } void Constraint::dump(ConstraintSystem *CS) const { - // Print all type variables as $T0 instead of _ here. - llvm::SaveAndRestore X(CS->getASTContext().LangOpts. - DebugConstraintSolver, true); // Disable MSVC warning: only for use within the debugger. #if SWIFT_COMPILER_IS_MSVC #pragma warning(push) diff --git a/lib/Sema/ConstraintGraph.cpp b/lib/Sema/ConstraintGraph.cpp index 66b309ed5a16b..3e210ca5f4fee 100644 --- a/lib/Sema/ConstraintGraph.cpp +++ b/lib/Sema/ConstraintGraph.cpp @@ -972,7 +972,7 @@ namespace { contractedCycle = false; for (const auto &edge : cycleEdges) { if (unionSets(edge.first, edge.second)) { - if (ctx.LangOpts.DebugConstraintSolver) { + if (ctx.TypeCheckerOpts.DebugConstraintSolver) { auto &log = ctx.TypeCheckerDebug->getStream(); if (cs.solverState) log.indent(cs.solverState->depth * 2); @@ -1255,7 +1255,7 @@ bool ConstraintGraph::contractEdges() { rep2->getImpl().canBindToLValue()) || // Allow l-value contractions when binding parameter types. isParamBindingConstraint)) { - if (CS.getASTContext().LangOpts.DebugConstraintSolver) { + if (CS.getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = CS.getASTContext().TypeCheckerDebug->getStream(); if (CS.solverState) log.indent(CS.solverState->depth * 2); @@ -1319,9 +1319,10 @@ void ConstraintGraph::incrementConstraintsPerContractionCounter() { #pragma mark Debugging output -void ConstraintGraphNode::print(llvm::raw_ostream &out, unsigned indent) const { +void ConstraintGraphNode::print(llvm::raw_ostream &out, unsigned indent, + PrintOptions PO) const { out.indent(indent); - TypeVar->print(out); + Type(TypeVar).print(out, PO); out << ":\n"; // Print constraints. @@ -1395,15 +1396,18 @@ void ConstraintGraphNode::print(llvm::raw_ostream &out, unsigned indent) const { } void ConstraintGraphNode::dump() const { - llvm::SaveAndRestore - debug(TypeVar->getASTContext().LangOpts.DebugConstraintSolver, true); - print(llvm::dbgs(), 0); + PrintOptions PO; + PO.PrintTypesForDebugging = true; + print(llvm::dbgs(), 0, PO); } void ConstraintGraph::print(ArrayRef typeVars, llvm::raw_ostream &out) { + PrintOptions PO; + PO.PrintTypesForDebugging = true; + for (auto typeVar : typeVars) { - (*this)[typeVar].print(out, 2); + (*this)[typeVar].print(out, 2, PO); out << "\n"; } } @@ -1413,8 +1417,6 @@ void ConstraintGraph::dump() { } void ConstraintGraph::dump(llvm::raw_ostream &out) { - llvm::SaveAndRestore - debug(CS.getASTContext().LangOpts.DebugConstraintSolver, true); print(CS.getTypeVariables(), out); } @@ -1422,6 +1424,8 @@ void ConstraintGraph::printConnectedComponents( ArrayRef typeVars, llvm::raw_ostream &out) { auto components = computeConnectedComponents(typeVars); + PrintOptions PO; + PO.PrintTypesForDebugging = true; for (const auto& component : components) { out.indent(2); out << component.solutionIndex << ": "; @@ -1432,7 +1436,7 @@ void ConstraintGraph::printConnectedComponents( // Print all of the type variables in this connected component. interleave(component.typeVars, [&](TypeVariableType *typeVar) { - typeVar->print(out); + Type(typeVar).print(out, PO); }, [&] { out << ' '; @@ -1452,8 +1456,6 @@ void ConstraintGraph::printConnectedComponents( } void ConstraintGraph::dumpConnectedComponents() { - llvm::SaveAndRestore - debug(CS.getASTContext().LangOpts.DebugConstraintSolver, true); printConnectedComponents(CS.getTypeVariables(), llvm::dbgs()); } @@ -1559,18 +1561,20 @@ void ConstraintGraphNode::verify(ConstraintGraph &cg) { } // Make sure that the adjacencies we expect are the adjacencies we have. + PrintOptions PO; + PO.PrintTypesForDebugging = true; for (auto adj : expectedAdjacencies) { auto knownAdj = AdjacencyInfo.find(adj.first); requireWithContext(knownAdj != AdjacencyInfo.end(), "missing adjacency information for type variable", [&] { - llvm::dbgs() << " type variable=" << adj.first->getString() << 'n'; + llvm::dbgs() << " type variable=" << adj.first->getString(PO) << 'n'; }); requireWithContext(adj.second == knownAdj->second.NumConstraints, "wrong number of adjacencies for type variable", [&] { - llvm::dbgs() << " type variable=" << adj.first->getString() + llvm::dbgs() << " type variable=" << adj.first->getString(PO) << " (" << adj.second << " vs. " << knownAdj->second.NumConstraints << ")\n"; @@ -1584,7 +1588,7 @@ void ConstraintGraphNode::verify(ConstraintGraph &cg) { requireWithContext(AdjacencyInfo.count(adj.first) > 0, "extraneous adjacency info for type variable", [&] { - llvm::dbgs() << " type variable=" << adj.first->getString() << '\n'; + llvm::dbgs() << " type variable=" << adj.first->getString(PO) << '\n'; }); } } diff --git a/lib/Sema/ConstraintGraph.h b/lib/Sema/ConstraintGraph.h index 0013309f993de..f3041fcb4fe6c 100644 --- a/lib/Sema/ConstraintGraph.h +++ b/lib/Sema/ConstraintGraph.h @@ -160,7 +160,8 @@ class ConstraintGraphNode { mutable SmallVector EquivalenceClass; /// Print this graph node. - void print(llvm::raw_ostream &out, unsigned indent) const; + void print(llvm::raw_ostream &out, unsigned indent, + PrintOptions PO = PrintOptions()) const; SWIFT_DEBUG_DUMP; diff --git a/lib/Sema/ConstraintLocator.cpp b/lib/Sema/ConstraintLocator.cpp index 5012f54b9f574..18a29bbde65bf 100644 --- a/lib/Sema/ConstraintLocator.cpp +++ b/lib/Sema/ConstraintLocator.cpp @@ -261,6 +261,9 @@ void ConstraintLocator::dump(ConstraintSystem *CS) const { void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const { + PrintOptions PO; + PO.PrintTypesForDebugging = true; + out << "locator@" << (void*) this << " ["; if (anchor) { @@ -295,7 +298,7 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const { switch (elt.getKind()) { case GenericParameter: { auto gpElt = elt.castTo(); - out << "generic parameter '" << gpElt.getType()->getString() << "'"; + out << "generic parameter '" << gpElt.getType()->getString(PO) << "'"; break; } case ApplyArgument: diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 071cb624f1d4a..b786ba4ea6d9f 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -19,6 +19,7 @@ #include "ConstraintGraph.h" #include "CSDiagnostics.h" #include "CSFix.h" +#include "SolutionResult.h" #include "TypeCheckType.h" #include "swift/AST/Initializer.h" #include "swift/AST/GenericEnvironment.h" @@ -35,10 +36,10 @@ using namespace constraints; #define DEBUG_TYPE "ConstraintSystem" ExpressionTimer::ExpressionTimer(Expr *E, ConstraintSystem &CS) - : E(E), WarnLimit(CS.getTypeChecker().getWarnLongExpressionTypeChecking()), + : E(E), Context(CS.getASTContext()), StartTime(llvm::TimeRecord::getCurrentTime()), - PrintDebugTiming(CS.getTypeChecker().getDebugTimeExpressions()), + PrintDebugTiming(CS.getASTContext().TypeCheckerOpts.DebugTimeExpressions), PrintWarning(true) { if (auto *baseCS = CS.baseCS) { // If we already have a timer in the base constraint @@ -66,22 +67,20 @@ ExpressionTimer::~ExpressionTimer() { if (!PrintWarning) return; + const auto WarnLimit = getWarnLimit(); if (WarnLimit != 0 && elapsedMS >= WarnLimit && E->getLoc().isValid()) Context.Diags.diagnose(E->getLoc(), diag::debug_long_expression, elapsedMS, WarnLimit) .highlight(E->getSourceRange()); } + ConstraintSystem::ConstraintSystem(DeclContext *dc, - ConstraintSystemOptions options, - Expr *expr) + ConstraintSystemOptions options) : Context(dc->getASTContext()), DC(dc), Options(options), Arena(dc->getASTContext(), Allocator), CG(*new ConstraintGraph(*this)) { - if (expr) - ExprWeights = expr->getDepthMap(); - assert(DC && "context required"); } @@ -498,6 +497,57 @@ ConstraintSystem::getCalleeLocator(ConstraintLocator *locator, return getConstraintLocator(anchor); } +/// Extend the given depth map by adding depths for all of the subexpressions +/// of the given expression. +static void extendDepthMap( + Expr *expr, + llvm::DenseMap> &depthMap) { + class RecordingTraversal : public ASTWalker { + public: + llvm::DenseMap> &DepthMap; + unsigned Depth = 0; + + explicit RecordingTraversal( + llvm::DenseMap> &depthMap) + : DepthMap(depthMap) {} + + std::pair walkToExprPre(Expr *E) override { + DepthMap[E] = {Depth, Parent.getAsExpr()}; + Depth++; + return { true, E }; + } + + Expr *walkToExprPost(Expr *E) override { + Depth--; + return E; + } + }; + + RecordingTraversal traversal(depthMap); + expr->walk(traversal); +} + +Optional> ConstraintSystem::getExprDepthAndParent( + Expr *expr) { + // Check whether the parent has this information. + if (baseCS && baseCS != this) { + if (auto known = baseCS->getExprDepthAndParent(expr)) + return *known; + } + + // Bring the set of expression weights up to date. + while (NumInputExprsInWeights < InputExprs.size()) { + extendDepthMap(InputExprs[NumInputExprsInWeights], ExprWeights); + ++NumInputExprsInWeights; + } + + auto e = ExprWeights.find(expr); + if (e != ExprWeights.end()) + return e->second; + + return None; +} + Type ConstraintSystem::openUnboundGenericType(UnboundGenericType *unbound, ConstraintLocatorBuilder locator, OpenedTypeMap &replacements) { @@ -628,8 +678,6 @@ Type ConstraintSystem::openUnboundGenericType( Type type, ConstraintLocatorBuilder locator) { assert(!type->getCanonicalType()->hasTypeParameter()); - checkNestedTypeConstraints(*this, type, locator); - if (!type->hasUnboundGenericType()) return type; @@ -987,6 +1035,8 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, TypeResolverContext::InExpression, /*isSpecialized=*/false); + checkNestedTypeConstraints(*this, type, locator); + // Open the type. type = openUnboundGenericType(type, locator); @@ -1120,7 +1170,8 @@ void ConstraintSystem::openGenericParameters(DeclContext *outerDC, auto *paramLocator = getConstraintLocator( locator.withPathElement(LocatorPathElt::GenericParameter(gp))); - auto typeVar = createTypeVariable(paramLocator, TVO_PrefersSubtypeBinding); + auto typeVar = createTypeVariable(paramLocator, TVO_PrefersSubtypeBinding | + TVO_CanBindToHole); auto result = replacements.insert(std::make_pair( cast(gp->getCanonicalType()), typeVar)); @@ -1242,6 +1293,9 @@ ConstraintSystem::getTypeOfMemberReference( auto memberTy = TypeChecker::substMemberTypeWithBase(DC->getParentModule(), typeDecl, baseObjTy); + + checkNestedTypeConstraints(*this, memberTy, locator); + // Open the type if it was a reference to a generic type. memberTy = openUnboundGenericType(memberTy, locator); @@ -1473,7 +1527,7 @@ Type ConstraintSystem::getEffectiveOverloadType(const OverloadChoice &overload, // Retrieve the interface type. auto type = decl->getInterfaceType(); - if (!type || type->hasError()) { + if (type->hasError()) { return Type(); } @@ -1645,7 +1699,6 @@ resolveOverloadForDeclWithSpecialTypeCheckingSemantics(ConstraintSystem &CS, auto bodyClosure = FunctionType::get(arg, result, FunctionType::ExtInfo(FunctionType::Representation::Swift, /*noescape*/ true, - // SWIFT_ENABLE_TENSORFLOW /*throws*/ true, DifferentiabilityKind::NonDifferentiable)); FunctionType::Param args[] = { @@ -1656,7 +1709,6 @@ resolveOverloadForDeclWithSpecialTypeCheckingSemantics(ConstraintSystem &CS, refType = FunctionType::get(args, result, FunctionType::ExtInfo(FunctionType::Representation::Swift, /*noescape*/ false, - // SWIFT_ENABLE_TENSORFLOW /*throws*/ true, DifferentiabilityKind::NonDifferentiable)); openedFullType = refType; @@ -1681,7 +1733,6 @@ resolveOverloadForDeclWithSpecialTypeCheckingSemantics(ConstraintSystem &CS, auto bodyClosure = FunctionType::get(bodyArgs, result, FunctionType::ExtInfo(FunctionType::Representation::Swift, /*noescape*/ true, - // SWIFT_ENABLE_TENSORFLOW /*throws*/ true, DifferentiabilityKind::NonDifferentiable)); FunctionType::Param args[] = { @@ -1691,7 +1742,6 @@ resolveOverloadForDeclWithSpecialTypeCheckingSemantics(ConstraintSystem &CS, refType = FunctionType::get(args, result, FunctionType::ExtInfo(FunctionType::Representation::Swift, /*noescape*/ false, - // SWIFT_ENABLE_TENSORFLOW /*throws*/ true, DifferentiabilityKind::NonDifferentiable)); openedFullType = refType; @@ -2247,12 +2297,14 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, } } - if (getASTContext().LangOpts.DebugConstraintSolver) { + if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { + PrintOptions PO; + PO.PrintTypesForDebugging = true; auto &log = getASTContext().TypeCheckerDebug->getStream(); log.indent(solverState ? solverState->depth * 2 : 2) << "(overload set choice binding " - << boundType->getString() << " := " - << refType->getString() << ")\n"; + << boundType->getString(PO) << " := " + << refType->getString(PO) << ")\n"; } // If this overload is disfavored, note that. @@ -2396,33 +2448,19 @@ bool OverloadChoice::isImplicitlyUnwrappedValueOrReturnValue() const { llvm_unreachable("unhandled kind"); } -bool ConstraintSystem::salvage(SmallVectorImpl &viable, Expr *expr) { +SolutionResult ConstraintSystem::salvage() { auto &ctx = getASTContext(); - if (ctx.LangOpts.DebugConstraintSolver) { + if (ctx.TypeCheckerOpts.DebugConstraintSolver) { auto &log = ctx.TypeCheckerDebug->getStream(); log << "---Attempting to salvage and emit diagnostics---\n"; } - // SWIFT_ENABLE_TENSORFLOW - if (DC->getParentModule()->getNameStr().startswith("__lldb_expr") && - viable.size() > 1) { - // TODO(https://bugs.swift.org/browse/SR-9814): - // If in LLDB repl mode, patch up the solution if we have ambiguity. - // - // This is a *temporary* short-term hack that simply returns the last - // solution. It seems to work for now and returns the lastly added - // definition during the repl session. However, this is extremely brittle and - // is not expected to work correctly all the time. - viable[0] = std::move(viable.back()); - viable.erase(viable.begin() + 1, viable.end()); - return false; - } - // Attempt to solve again, capturing all states that come from our attempts to // select overloads or bind type variables. // // FIXME: can this be removed? We need to arrange for recordFixes to be // eliminated. + SmallVector viable; viable.clear(); { @@ -2439,13 +2477,13 @@ bool ConstraintSystem::salvage(SmallVectorImpl &viable, Expr *expr) { if (*best != 0) viable[0] = std::move(viable[*best]); viable.erase(viable.begin() + 1, viable.end()); - return false; + return SolutionResult::forSolved(std::move(viable[0])); } // Before removing any "fixed" solutions, let's check // if ambiguity is caused by fixes and diagnose if possible. - if (diagnoseAmbiguityWithFixes(expr, viable)) - return true; + if (diagnoseAmbiguityWithFixes(viable)) + return SolutionResult::forAmbiguous(viable); // FIXME: If we were able to actually fix things along the way, // we may have to hunt for the best solution. For now, we don't care. @@ -2458,7 +2496,22 @@ bool ConstraintSystem::salvage(SmallVectorImpl &viable, Expr *expr) { // If there are multiple solutions, try to diagnose an ambiguity. if (viable.size() > 1) { - if (getASTContext().LangOpts.DebugConstraintSolver) { + // SWIFT_ENABLE_TENSORFLOW + if (DC->getParentModule()->getNameStr().startswith("__lldb_expr")) { + // TODO(https://bugs.swift.org/browse/SR-9814): + // If in LLDB repl mode, patch up the solution if we have ambiguity. + // + // This is a *temporary* short-term hack that simply returns the last + // solution. It seems to work for now and returns the lastly added + // definition during the repl session. However, this is extremely brittle and + // is not expected to work correctly all the time. + viable[0] = std::move(viable.back()); + viable.erase(viable.begin() + 1, viable.end()); + return SolutionResult::forSolved(std::move(viable[0])); + } + // SWIFT_ENABLE_TENSORFLOW + + if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) { auto &log = getASTContext().TypeCheckerDebug->getStream(); log << "---Ambiguity error: " << viable.size() << " solutions found---\n"; @@ -2470,24 +2523,19 @@ bool ConstraintSystem::salvage(SmallVectorImpl &viable, Expr *expr) { } } - if (diagnoseAmbiguity(expr, viable)) { - return true; + if (diagnoseAmbiguity(viable)) { + return SolutionResult::forAmbiguous(viable); } } // Fall through to produce diagnostics. } - if (getExpressionTooComplex(viable)) { - ctx.Diags.diagnose(expr->getLoc(), diag::expression_too_complex) - .highlight(expr->getSourceRange()); - return true; - } + if (getExpressionTooComplex(viable)) + return SolutionResult::forTooComplex(); - // If all else fails, diagnose the failure by looking through the system's - // constraints. - diagnoseFailureForExpr(expr); - return true; + // Could not produce a specific diagnostic; punt to the client. + return SolutionResult::forUndiagnosedError(); } static void diagnoseOperatorAmbiguity(ConstraintSystem &cs, @@ -2548,7 +2596,7 @@ static void diagnoseOperatorAmbiguity(ConstraintSystem &cs, } bool ConstraintSystem::diagnoseAmbiguityWithFixes( - Expr *expr, ArrayRef solutions) { + ArrayRef solutions) { if (solutions.empty()) return false; @@ -2701,8 +2749,30 @@ static DeclName getOverloadChoiceName(ArrayRef choices) { return name; } -bool ConstraintSystem::diagnoseAmbiguity(Expr *expr, - ArrayRef solutions) { +/// Extend the given index map with all of the subexpressions in the given +/// expression. +static void extendPreorderIndexMap( + Expr *expr, llvm::DenseMap &indexMap) { + class RecordingTraversal : public ASTWalker { + public: + llvm::DenseMap &IndexMap; + unsigned Index = 0; + + explicit RecordingTraversal(llvm::DenseMap &indexMap) + : IndexMap(indexMap) { } + + std::pair walkToExprPre(Expr *E) override { + IndexMap[E] = Index; + Index++; + return { true, E }; + } + }; + + RecordingTraversal traversal(indexMap); + expr->walk(traversal); +} + +bool ConstraintSystem::diagnoseAmbiguity(ArrayRef solutions) { // Produce a diff of the solutions. SolutionDiff diff(solutions); @@ -2721,8 +2791,10 @@ bool ConstraintSystem::diagnoseAmbiguity(Expr *expr, // Heuristically, all other things being equal, we should complain about the // ambiguous expression that (1) has the most overloads, (2) is deepest, or // (3) comes earliest in the expression. - auto depthMap = expr->getDepthMap(); - auto indexMap = expr->getPreorderIndexMap(); + llvm::DenseMap indexMap; + for (auto expr : InputExprs) { + extendPreorderIndexMap(expr, indexMap); + } for (unsigned i = 0, n = diff.overloads.size(); i != n; ++i) { auto &overload = diff.overloads[i]; @@ -2737,10 +2809,10 @@ bool ConstraintSystem::diagnoseAmbiguity(Expr *expr, continue; unsigned index = it->second; - auto e = depthMap.find(anchor); - if (e == depthMap.end()) + auto optDepth = getExprDepth(anchor); + if (!optDepth) continue; - unsigned depth = e->second.first; + unsigned depth = *optDepth; // If we don't have a name to hang on to, it'll be hard to diagnose this // overload. diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index b04e69f4a2d05..3446b103b9e46 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -71,9 +71,12 @@ namespace constraints { /// A handle that holds the saved state of a type variable, which /// can be restored. class SavedTypeVariableBinding { - /// The type variable and type variable options. - llvm::PointerIntPair TypeVarAndOptions; - + /// The type variable that we saved the state of. + TypeVariableType *TypeVar; + + /// The saved type variable options. + unsigned Options; + /// The parent or fixed type. llvm::PointerUnion ParentOrFixed; @@ -82,9 +85,6 @@ class SavedTypeVariableBinding { /// Restore the state of the type variable to the saved state. void restore(); - - TypeVariableType *getTypeVariable() { return TypeVarAndOptions.getPointer(); } - unsigned getOptions() { return TypeVarAndOptions.getInt(); } }; /// A set of saved type variable bindings. @@ -124,7 +124,6 @@ struct RestrictionOrFix { class ExpressionTimer { Expr* E; - unsigned WarnLimit; ASTContext &Context; llvm::TimeRecord StartTime; @@ -136,6 +135,9 @@ class ExpressionTimer { ~ExpressionTimer(); + unsigned getWarnLimit() const { + return Context.TypeCheckerOpts.WarnLongExpressionTypeChecking; + } llvm::TimeRecord startedAt() const { return StartTime; } /// Return the elapsed process time (including fractional seconds) @@ -169,9 +171,12 @@ enum TypeVariableOptions { /// Whether the type variable can be bound to a non-escaping type or not. TVO_CanBindToNoEscape = 0x04, + /// Whether the type variable can be bound to a hole type or not. + TVO_CanBindToHole = 0x08, + /// Whether a more specific deduction for this type variable implies a /// better solution to the constraint system. - TVO_PrefersSubtypeBinding = 0x08, + TVO_PrefersSubtypeBinding = 0x10, }; /// The implementation object for a type variable used within the @@ -238,6 +243,9 @@ class TypeVariableType::Implementation { /// Whether this type variable can bind to an inout type. bool canBindToNoEscape() const { return getRawOptions() & TVO_CanBindToNoEscape; } + /// Whether this type variable can bind to a hole type. + bool canBindToHole() const { return getRawOptions() & TVO_CanBindToHole; } + /// Whether this type variable prefers a subtype binding over a supertype /// binding. bool prefersSubtypeBinding() const { @@ -427,6 +435,14 @@ class TypeVariableType::Implementation { ~TVO_CanBindToNoEscape; } + void enableCanBindToHole(constraints::SavedTypeVariableBindings *record) { + auto &impl = getRepresentative(record)->getImpl(); + if (record) + impl.recordBinding(*record); + + impl.getTypeVariable()->Bits.TypeVariableType.Options |= TVO_CanBindToHole; + } + /// Print the type variable to the given output stream. void print(llvm::raw_ostream &OS); }; @@ -1022,6 +1038,12 @@ class ConstraintSystem { unsigned CountDisjunctions = 0; private: + /// The set of expressions for which we have generated constraints. + llvm::SetVector InputExprs; + + /// The number of input expressions whose parents and depths have + /// been entered into \c ExprWeights. + unsigned NumInputExprsInWeights = 0; llvm::DenseMap> ExprWeights; @@ -1107,13 +1129,6 @@ class ConstraintSystem { /// The set of fixes applied to make the solution work. llvm::SmallVector Fixes; - /// The set of "holes" in the constraint system encountered - /// along the current path identified by locator. A "hole" is - /// a type variable which type couldn't be determined due to - /// an inference failure e.g. missing member, ambiguous generic - /// parameter which hasn't been explicitly specified. - llvm::SmallSetVector Holes; - /// The set of remembered disjunction choices used to reach /// the current constraint system. std::vector> @@ -1250,7 +1265,7 @@ class ConstraintSystem { } unsigned threshold = - cs->getASTContext().LangOpts.SolverShrinkUnsolvedThreshold; + cs->getASTContext().TypeCheckerOpts.SolverShrinkUnsolvedThreshold; return unsolvedDisjunctions >= threshold; } }; @@ -1608,9 +1623,6 @@ class ConstraintSystem { /// The length of \c Fixes. unsigned numFixes; - /// The length of \c Holes. - unsigned numHoles; - /// The length of \c FixedRequirements. unsigned numFixedRequirements; @@ -1656,8 +1668,7 @@ class ConstraintSystem { }; ConstraintSystem(DeclContext *dc, - ConstraintSystemOptions options, - Expr *expr = nullptr); + ConstraintSystemOptions options); ~ConstraintSystem(); /// Retrieve the type checker associated with this constraint system. @@ -1696,9 +1707,12 @@ class ConstraintSystem { /// constraint system for further exploration. void applySolution(const Solution &solution); + // FIXME: Allows the type checker to apply solutions. + friend class swift::TypeChecker; + /// Emit the fixes computed as part of the solution, returning true if we were /// able to emit an error message, or false if none of the fixits worked out. - bool applySolutionFixes(Expr *E, const Solution &solution); + bool applySolutionFixes(const Solution &solution); /// If there is more than one viable solution, /// attempt to pick the best solution and remove all of the rest. @@ -1980,17 +1994,22 @@ class ConstraintSystem { getConstraintLocator(const ConstraintLocatorBuilder &builder); /// Lookup and return parent associated with given expression. - Expr *getParentExpr(Expr *expr) const { - auto e = ExprWeights.find(expr); - if (e != ExprWeights.end()) - return e->second.second; - - if (baseCS && baseCS != this) - return baseCS->getParentExpr(expr); - + Expr *getParentExpr(Expr *expr) { + if (auto result = getExprDepthAndParent(expr)) + return result->second; return nullptr; } + /// Retrieve the depth of the given expression. + Optional getExprDepth(Expr *expr) { + if (auto result = getExprDepthAndParent(expr)) + return result->first; + return None; + } + + /// Retrieve the depth and parent expression of the given expression. + Optional> getExprDepthAndParent(Expr *expr); + /// Returns a locator describing the callee for the anchor of a given locator. /// /// - For an unresolved dot/member anchor, this will be a locator describing @@ -2044,14 +2063,6 @@ class ConstraintSystem { void recordPotentialHole(TypeVariableType *typeVar); - bool isPotentialHole(TypeVariableType *typeVar) const { - return isPotentialHoleAt(typeVar->getImpl().getLocator()); - } - - bool isPotentialHoleAt(ConstraintLocator *locator) const { - return bool(Holes.count(locator)); - } - /// Determine whether constraint system already has a fix recorded /// for a particular location. bool hasFixFor(ConstraintLocator *locator, @@ -2070,17 +2081,8 @@ class ConstraintSystem { ValueDecl *findResolvedMemberRef(ConstraintLocator *locator); /// Try to salvage the constraint system by applying (speculative) - /// fixes to the underlying expression. - /// - /// \param viable the set of viable solutions produced by the initial - /// solution attempt. - /// - /// \param expr the expression we're trying to salvage. - /// - /// \returns false if we were able to salvage the system, in which case - /// \c viable[0] contains the resulting solution. Otherwise, emits a - /// diagnostic and returns true. - bool salvage(SmallVectorImpl &viable, Expr *expr); + /// fixes. + SolutionResult salvage(); /// Mine the active and inactive constraints in the constraint /// system to generate a plausible diagnosis of why the system could not be @@ -2093,8 +2095,8 @@ class ConstraintSystem { /// emits an error message. void diagnoseFailureForExpr(Expr *expr); - bool diagnoseAmbiguity(Expr *expr, ArrayRef solutions); - bool diagnoseAmbiguityWithFixes(Expr *expr, ArrayRef solutions); + bool diagnoseAmbiguity(ArrayRef solutions); + bool diagnoseAmbiguityWithFixes(ArrayRef solutions); /// Give the deprecation warning for referring to a global function /// when there's a method from a conditional conformance in a smaller/closer @@ -3418,13 +3420,12 @@ class ConstraintSystem { if (NumDefaultableBindings > 0) out << "#defaultable_bindings=" << NumDefaultableBindings << " "; + PrintOptions PO; + PO.PrintTypesForDebugging = true; out << "bindings={"; interleave(Bindings, [&](const PotentialBinding &binding) { auto type = binding.BindingType; - auto &ctx = type->getASTContext(); - llvm::SaveAndRestore debugConstraints( - ctx.LangOpts.DebugConstraintSolver, true); switch (binding.Kind) { case AllowedBindingKind::Exact: break; @@ -3440,7 +3441,7 @@ class ConstraintSystem { if (binding.DefaultedProtocol) out << "(default from " << binding.DefaultedProtocol->getName() << ") "; - out << type.getString(); + out << type.getString(PO); }, [&]() { out << "; "; }); out << "}"; @@ -3659,8 +3660,7 @@ class ConstraintSystem { /// \param idx2 The index of the second solution. static SolutionCompareResult compareSolutions(ConstraintSystem &cs, ArrayRef solutions, - const SolutionDiff &diff, unsigned idx1, unsigned idx2, - llvm::DenseMap> &weights); + const SolutionDiff &diff, unsigned idx1, unsigned idx2); public: /// Increase the score of the given kind for the current (partial) solution @@ -3717,13 +3717,13 @@ class ConstraintSystem { used += s.getTotalMemory(); } MaxMemory = std::max(used, MaxMemory); - auto threshold = getASTContext().LangOpts.SolverMemoryThreshold; + auto threshold = getASTContext().TypeCheckerOpts.SolverMemoryThreshold; if (MaxMemory > threshold) { return isExpressionAlreadyTooComplex= true; } const auto timeoutThresholdInMillis = - getTypeChecker().getExpressionTimeoutThresholdInSeconds(); + getASTContext().TypeCheckerOpts.ExpressionTimeoutThreshold; if (Timer && Timer->isExpired(timeoutThresholdInMillis)) { // Disable warnings about expressions that go over the warning // threshold since we're arbitrarily ending evaluation and @@ -3735,7 +3735,7 @@ class ConstraintSystem { // Bail out once we've looked at a really large number of // choices. - if (CountScopes > getASTContext().LangOpts.SolverBindingThreshold) { + if (CountScopes > getASTContext().TypeCheckerOpts.SolverBindingThreshold) { return isExpressionAlreadyTooComplex = true; } @@ -4175,8 +4175,10 @@ class TypeVariableBinding { bool attempt(ConstraintSystem &cs) const; void print(llvm::raw_ostream &Out, SourceManager *) const { - Out << "type variable " << TypeVar->getString() - << " := " << Binding.BindingType->getString(); + PrintOptions PO; + PO.PrintTypesForDebugging = true; + Out << "type variable " << TypeVar->getString(PO) + << " := " << Binding.BindingType->getString(PO); } }; diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index 0eddc4877b800..cc9e70612bf67 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -741,9 +741,8 @@ static FuncDecl *deriveEncodable_encode(DerivedConformance &derived) { encodeDecl->copyFormalAccessFrom(derived.Nominal, /*sourceIsParentContext*/ true); - C.addSynthesizedDecl(encodeDecl); - derived.addMembersToConformanceContext({encodeDecl}); + return encodeDecl; } @@ -1019,9 +1018,8 @@ static ValueDecl *deriveDecodable_init(DerivedConformance &derived) { initDecl->copyFormalAccessFrom(derived.Nominal, /*sourceIsParentContext*/ true); - C.addSynthesizedDecl(initDecl); - derived.addMembersToConformanceContext({initDecl}); + return initDecl; } diff --git a/lib/Sema/DerivedConformanceCodingKey.cpp b/lib/Sema/DerivedConformanceCodingKey.cpp index b794bb6e06e16..293670d347af1 100644 --- a/lib/Sema/DerivedConformanceCodingKey.cpp +++ b/lib/Sema/DerivedConformanceCodingKey.cpp @@ -145,9 +145,8 @@ static ValueDecl *deriveInitDecl(DerivedConformance &derived, Type paramType, initDecl->setAccess(derived.Nominal->getFormalAccess()); - C.addSynthesizedDecl(initDecl); - derived.addMembersToConformanceContext({initDecl}); + return initDecl; } @@ -176,9 +175,7 @@ static ValueDecl *deriveProperty(DerivedConformance &derived, Type type, // Synthesize the body. synthesizer(getterDecl); - auto *dc = cast(derived.ConformanceDecl); - dc->addMember(propDecl); - dc->addMember(pbDecl); + derived.addMembersToConformanceContext({propDecl, pbDecl}); return propDecl; } diff --git a/lib/Sema/DerivedConformanceDifferentiable.cpp b/lib/Sema/DerivedConformanceDifferentiable.cpp index ee1f8515c10e8..2a517bb88a35c 100644 --- a/lib/Sema/DerivedConformanceDifferentiable.cpp +++ b/lib/Sema/DerivedConformanceDifferentiable.cpp @@ -337,8 +337,6 @@ static ValueDecl *deriveDifferentiable_method( funcDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); derived.addMembersToConformanceContext({funcDecl}); - C.addSynthesizedDecl(funcDecl); - return funcDecl; } @@ -602,8 +600,6 @@ getOrSynthesizeTangentVectorStruct(DerivedConformance &derived, Identifier id) { structDecl->addMember(memberBinding); newMember->copyFormalAccessFrom(member, /*sourceIsParentContext*/ true); newMember->setSetterAccess(member->getFormalAccess()); - C.addSynthesizedDecl(newMember); - C.addSynthesizedDecl(memberBinding); // Now that this member is in the `TangentVector` type, it should be marked // `@differentiable` so that the differentiation transform will synthesize @@ -644,15 +640,12 @@ getOrSynthesizeTangentVectorStruct(DerivedConformance &derived, Identifier id) { // the memberwise constructor is synthesized during SILGen, which is too late. auto *initDecl = createMemberwiseImplicitConstructor(C, structDecl); structDecl->addMember(initDecl); - C.addSynthesizedDecl(initDecl); // After memberwise initializer is synthesized, mark members as implicit. for (auto *member : structDecl->getStoredProperties()) member->setImplicit(); derived.addMembersToConformanceContext({structDecl}); - C.addSynthesizedDecl(structDecl); - return structDecl; } @@ -683,7 +676,6 @@ static void addAssociatedTypeAliasDecl(Identifier name, aliasDecl->setGenericSignature(sourceDC->getGenericSignatureOfContext()); cast(sourceDC->getAsDecl())->addMember(aliasDecl); aliasDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); - Context.addSynthesizedDecl(aliasDecl); }; /// Diagnose stored properties in the nominal that do not have an explicit @@ -823,7 +815,6 @@ deriveDifferentiable_TangentVectorStruct(DerivedConformance &derived) { aliasDecl->setImplicit(); aliasDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); derived.addMembersToConformanceContext({aliasDecl}); - C.addSynthesizedDecl(aliasDecl); return selfType; } diff --git a/lib/Sema/DerivedConformanceElementaryFunctions.cpp b/lib/Sema/DerivedConformanceElementaryFunctions.cpp index 1ba996ad7e162..5eeb9cbc677fd 100644 --- a/lib/Sema/DerivedConformanceElementaryFunctions.cpp +++ b/lib/Sema/DerivedConformanceElementaryFunctions.cpp @@ -104,12 +104,10 @@ static ValueDecl *getElementaryFunctionRequirement( // it if it does not exist. static ConstructorDecl *getOrCreateEffectiveMemberwiseInitializer( ASTContext &ctx, NominalTypeDecl *nominal) { - auto &C = nominal->getASTContext(); if (auto *initDecl = nominal->getEffectiveMemberwiseInitializer()) return initDecl; auto *initDecl = createMemberwiseImplicitConstructor(ctx, nominal); nominal->addMember(initDecl); - C.addSynthesizedDecl(initDecl); return initDecl; } @@ -303,8 +301,6 @@ ElementaryFunction op) { operatorDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); derived.addMembersToConformanceContext({operatorDecl}); - C.addSynthesizedDecl(operatorDecl); - return operatorDecl; } diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp index 0e2efebaa115b..9459e241c4a4b 100644 --- a/lib/Sema/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp @@ -769,8 +769,6 @@ deriveEquatable_eq( eqDecl->copyFormalAccessFrom(derived.Nominal, /*sourceIsParentContext*/ true); - C.addSynthesizedDecl(eqDecl); - // Add the operator to the parent scope. derived.addMembersToConformanceContext({eqDecl}); @@ -890,9 +888,8 @@ deriveHashable_hashInto( hashDecl->copyFormalAccessFrom(derived.Nominal); - C.addSynthesizedDecl(hashDecl); - derived.addMembersToConformanceContext({hashDecl}); + return hashDecl; } @@ -1253,10 +1250,12 @@ static ValueDecl *deriveHashable_hashValue(DerivedConformance &derived) { auto *patDecl = PatternBindingDecl::createImplicit( C, StaticSpellingKind::None, hashValuePat, /*InitExpr*/ nullptr, parentDC); - C.addSynthesizedDecl(hashValueDecl); - C.addSynthesizedDecl(getterDecl); - derived.addMembersToConformanceContext({hashValueDecl, patDecl}); + // If any of the members we synthesized didn't typecheck, bail out. + if (derived.addMembersToConformanceContext({hashValueDecl, patDecl})) { + return nullptr; + } + return hashValueDecl; } diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp index adbdb86e42b95..091da1f3e0fc0 100644 --- a/lib/Sema/DerivedConformanceRawRepresentable.cpp +++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp @@ -43,6 +43,9 @@ static LiteralExpr *cloneRawLiteralExpr(ASTContext &C, LiteralExpr *expr) { /*implicit*/ true); if (floatLit->isNegative()) cast(clone)->setNegative(expr->getLoc()); + } else if (auto boolLit = dyn_cast(expr)) { + clone = new (C) BooleanLiteralExpr(boolLit->getValue(), expr->getLoc(), + /*implicit*/true); } else { llvm_unreachable("invalid raw literal expr"); } @@ -434,8 +437,6 @@ deriveRawRepresentable_init(DerivedConformance &derived) { // an instance without function call overhead. maybeMarkAsInlinable(derived, initDecl); - C.addSynthesizedDecl(initDecl); - derived.addMembersToConformanceContext({initDecl}); return initDecl; } diff --git a/lib/Sema/DerivedConformanceRingMathProtocols.cpp b/lib/Sema/DerivedConformanceRingMathProtocols.cpp index f874b1c393621..5ab1d55345018 100644 --- a/lib/Sema/DerivedConformanceRingMathProtocols.cpp +++ b/lib/Sema/DerivedConformanceRingMathProtocols.cpp @@ -79,13 +79,11 @@ static ValueDecl *getProtocolRequirement(ProtocolDecl *proto, Identifier name) { // it if it does not exist. static ConstructorDecl *getOrCreateEffectiveMemberwiseInitializer( ASTContext &ctx, NominalTypeDecl *nominal) { - auto &C = nominal->getASTContext(); if (auto *initDecl = nominal->getEffectiveMemberwiseInitializer()) return initDecl; auto *initDecl = createMemberwiseImplicitConstructor( ctx, nominal); nominal->addMember(initDecl); - C.addSynthesizedDecl(initDecl); return initDecl; } @@ -256,8 +254,6 @@ static ValueDecl *deriveMathOperator(DerivedConformance &derived, operatorDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); derived.addMembersToConformanceContext({operatorDecl}); - C.addSynthesizedDecl(operatorDecl); - return operatorDecl; } diff --git a/lib/Sema/DerivedConformanceTensorArrayProtocol.cpp b/lib/Sema/DerivedConformanceTensorArrayProtocol.cpp index 762b65b9b8ea0..4fc9f3eaec6d1 100644 --- a/lib/Sema/DerivedConformanceTensorArrayProtocol.cpp +++ b/lib/Sema/DerivedConformanceTensorArrayProtocol.cpp @@ -245,8 +245,6 @@ static ValueDecl *deriveTensorArrayProtocol_method( funcDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); derived.addMembersToConformanceContext({funcDecl}); - C.addSynthesizedDecl(funcDecl); - return funcDecl; } @@ -643,8 +641,6 @@ static ValueDecl initDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); derived.addMembersToConformanceContext({initDecl}); - C.addSynthesizedDecl(initDecl); - return initDecl; } diff --git a/lib/Sema/DerivedConformanceTensorGroup.cpp b/lib/Sema/DerivedConformanceTensorGroup.cpp index 45d5cfe6234e1..7ccafdd8d07da 100644 --- a/lib/Sema/DerivedConformanceTensorGroup.cpp +++ b/lib/Sema/DerivedConformanceTensorGroup.cpp @@ -339,8 +339,6 @@ static ValueDecl *deriveTensorGroup_constructor( initDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); derived.addMembersToConformanceContext({initDecl}); - C.addSynthesizedDecl(initDecl); - return initDecl; } diff --git a/lib/Sema/DerivedConformanceVectorProtocol.cpp b/lib/Sema/DerivedConformanceVectorProtocol.cpp index f441196d21318..565f8346cc5a9 100644 --- a/lib/Sema/DerivedConformanceVectorProtocol.cpp +++ b/lib/Sema/DerivedConformanceVectorProtocol.cpp @@ -227,7 +227,6 @@ static ValueDecl *deriveVectorProtocol_method( funcDecl->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/ true); derived.addMembersToConformanceContext({funcDecl}); - C.addSynthesizedDecl(funcDecl); // Returned nominal type must define a memberwise initializer. // Add memberwise initializer if necessary. @@ -237,7 +236,6 @@ static ValueDecl *deriveVectorProtocol_method( // constructor is synthesized during SILGen, which is too late. auto *initDecl = createMemberwiseImplicitConstructor(C, nominal); nominal->addMember(initDecl); - C.addSynthesizedDecl(initDecl); } return funcDecl; diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index 152dc77ad594f..6185624671cbf 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -35,12 +35,16 @@ DeclContext *DerivedConformance::getConformanceContext() const { return cast(ConformanceDecl); } -void DerivedConformance::addMembersToConformanceContext( +bool DerivedConformance::addMembersToConformanceContext( ArrayRef children) { auto IDC = cast(ConformanceDecl); + bool anyInvalid = false; for (auto child : children) { IDC->addMember(child); + TypeChecker::typeCheckDecl(child); + anyInvalid |= child->isInvalid(); } + return anyInvalid; } Type DerivedConformance::getProtocolType() const { @@ -136,7 +140,7 @@ bool DerivedConformance::derivesProtocolConformance(DeclContext *DC, } // hasOnlyCasesWithoutAssociatedValues will return true for empty enums; - // empty enumas are allowed to conform as well. + // empty enums are allowed to conform as well. return enumDecl->hasOnlyCasesWithoutAssociatedValues(); } @@ -486,50 +490,41 @@ DerivedConformance::createSelfDeclRef(AbstractFunctionDecl *fn) { AccessorDecl *DerivedConformance:: addGetterToReadOnlyDerivedProperty(VarDecl *property, Type propertyContextType) { - auto getter = - declareDerivedPropertyGetter(property, propertyContextType); - - property->setImplInfo(StorageImplInfo::getImmutableComputed()); - property->setAccessors(SourceLoc(), {getter}, SourceLoc()); - - return getter; -} - -std::pair -DerivedConformance::addGetterAndSetterToMutableDerivedProperty( - VarDecl *property, Type propertyContextType) { - auto *getter = declareDerivedPropertyGetter(property, propertyContextType); - auto *setter = declareDerivedPropertySetter(property, propertyContextType); - property->setImplInfo(StorageImplInfo::getMutableComputed()); - property->setAccessors(SourceLoc(), {getter, setter}, SourceLoc()); - return std::make_pair(getter, setter); -} - -AccessorDecl * -DerivedConformance::declareDerivedPropertyGetter(VarDecl *property, - Type propertyContextType) { auto &C = property->getASTContext(); auto parentDC = property->getDeclContext(); ParameterList *params = ParameterList::createEmpty(C); Type propertyInterfaceType = property->getInterfaceType(); - - auto getterDecl = AccessorDecl::create(C, + + auto getter = AccessorDecl::create(C, /*FuncLoc=*/SourceLoc(), /*AccessorKeywordLoc=*/SourceLoc(), AccessorKind::Get, property, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, TypeLoc::withoutLoc(propertyInterfaceType), parentDC); - getterDecl->setImplicit(); - getterDecl->setIsTransparent(false); + getter->setImplicit(); + getter->setIsTransparent(false); + + getter->copyFormalAccessFrom(property); - getterDecl->copyFormalAccessFrom(property); + property->setImplInfo(StorageImplInfo::getImmutableComputed()); + property->setAccessors(SourceLoc(), {getter}, SourceLoc()); - C.addSynthesizedDecl(getterDecl); + return getter; +} - return getterDecl; +// SWIFT_ENABLE_TENSORFLOW +std::pair +DerivedConformance::addGetterAndSetterToMutableDerivedProperty( + VarDecl *property, Type propertyContextType) { + auto *getter = addGetterToReadOnlyDerivedProperty(property, propertyContextType); + auto *setter = declareDerivedPropertySetter(property, propertyContextType); + property->setImplInfo(StorageImplInfo::getMutableComputed()); + property->setAccessors(SourceLoc(), {getter, setter}, SourceLoc()); + return std::make_pair(getter, setter); } +// SWIFT_ENABLE_TENSORFLOW END // SWIFT_ENABLE_TENSORFLOW AccessorDecl * @@ -570,7 +565,6 @@ DerivedConformance::declareDerivedPropertySetter(VarDecl *property, setterDecl->setGenericSignature(parentDC->getGenericSignatureOfContext()); setterDecl->copyFormalAccessFrom(property); - C.addSynthesizedDecl(setterDecl); return setterDecl; } diff --git a/lib/Sema/DerivedConformances.h b/lib/Sema/DerivedConformances.h index 943c2de826c22..6513cbbd74219 100644 --- a/lib/Sema/DerivedConformances.h +++ b/lib/Sema/DerivedConformances.h @@ -46,7 +46,10 @@ class DerivedConformance { DeclContext *getConformanceContext() const; /// Add \c children as members of the context that declares the conformance. - void addMembersToConformanceContext(ArrayRef children); + /// + /// \returns True if any of the added members were found to be invalid after type + /// checking. + bool addMembersToConformanceContext(ArrayRef children); /// Get the declared type of the protocol that this is conformance is for. Type getProtocolType() const; @@ -316,7 +319,7 @@ class DerivedConformance { /// Add a getter to a derived property. The property becomes read-only. static AccessorDecl * addGetterToReadOnlyDerivedProperty(VarDecl *property, - Type propertyContextType); + Type propertyContextType); // SWIFT_ENABLE_TENSORFLOW /// Add a getter and setter to a derived property. The property becomes @@ -325,16 +328,11 @@ class DerivedConformance { addGetterAndSetterToMutableDerivedProperty(VarDecl *property, Type propertyContextType); - /// Declare a getter for a derived property. - /// The getter will not be added to the property yet. - static AccessorDecl *declareDerivedPropertyGetter(VarDecl *property, - Type propertyContextType); - - /// SWIFT_ENABLE_TENSORFLOW /// Declare a setter for a derived property. /// The setter will not be added to the property yet. static AccessorDecl *declareDerivedPropertySetter(VarDecl *property, Type propertyContextType); + // SWIFT_ENABLE_TENSORFLOW END /// Build a reference to the 'self' decl of a derived function. static DeclRefExpr *createSelfDeclRef(AbstractFunctionDecl *fn); diff --git a/lib/Sema/InstrumenterSupport.cpp b/lib/Sema/InstrumenterSupport.cpp index af902e1c7a8fb..0e0c059bcf85b 100644 --- a/lib/Sema/InstrumenterSupport.cpp +++ b/lib/Sema/InstrumenterSupport.cpp @@ -116,9 +116,7 @@ bool InstrumenterBase::doTypeCheckImpl(ASTContext &Ctx, DeclContext *DC, DiagnosticSuppression suppression(Ctx.Diags); ErrorGatherer errorGatherer(Ctx.Diags); - auto *TC = Ctx.getLegacyGlobalTypeChecker(); - assert(TC && "Must have type checker installed!"); - TC->typeCheckExpression(parsedExpr, DC); + TypeChecker::typeCheckExpression(parsedExpr, DC); if (parsedExpr) { ErrorFinder errorFinder; diff --git a/lib/Sema/LookupVisibleDecls.cpp b/lib/Sema/LookupVisibleDecls.cpp index 5c841f276105a..d11baa031e2d1 100644 --- a/lib/Sema/LookupVisibleDecls.cpp +++ b/lib/Sema/LookupVisibleDecls.cpp @@ -15,6 +15,7 @@ // //===----------------------------------------------------------------------===// +#include "TypeChecker.h" #include "swift/AST/ASTContext.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/GenericSignatureBuilder.h" @@ -24,6 +25,7 @@ #include "swift/AST/ModuleNameLookup.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ProtocolConformance.h" +#include "swift/AST/PropertyWrappers.h" #include "swift/AST/SourceFile.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/STLExtras.h" @@ -203,6 +205,9 @@ static void collectVisibleMemberDecls(const DeclContext *CurrDC, LookupState LS, } } +static void +synthesizePropertyWrapperStorageWrapperProperties(IterableDeclContext *IDC); + /// Lookup members in extensions of \p LookupType, using \p BaseType as the /// underlying type when checking any constraints on the extensions. static void doGlobalExtensionLookup(Type BaseType, @@ -220,6 +225,8 @@ static void doGlobalExtensionLookup(Type BaseType, extension)), false)) continue; + synthesizePropertyWrapperStorageWrapperProperties(extension); + collectVisibleMemberDecls(CurrDC, LS, BaseType, extension, FoundDecls); } @@ -474,6 +481,49 @@ static void lookupTypeMembers(BaseTy, PT, Consumer, CurrDC, LS, Reason); } +// Generate '$' and '_' prefixed variables that have attached property +// wrappers. +static void +synthesizePropertyWrapperStorageWrapperProperties(IterableDeclContext *IDC) { + auto SF = IDC->getDecl()->getDeclContext()->getParentSourceFile(); + if (!SF || SF->Kind == SourceFileKind::Interface) + return; + + for (auto Member : IDC->getMembers()) + if (auto var = dyn_cast(Member)) + if (var->hasAttachedPropertyWrapper()) + (void)var->getPropertyWrapperBackingPropertyInfo(); +} + +/// Trigger synthesizing implicit member declarations to make them "visible". +static void synthesizeMemberDeclsForLookup(NominalTypeDecl *NTD, + const DeclContext *DC) { + // Synthesize the memberwise initializer for structs or default initializer + // for classes. + if (!NTD->getASTContext().evaluator.hasActiveRequest( + SynthesizeMemberwiseInitRequest{NTD})) + TypeChecker::addImplicitConstructors(NTD); + + // Check all conformances to trigger the synthesized decl generation. + // e.g. init(rawValue:) for RawRepresentable. + for (auto Conformance : NTD->getAllConformances()) { + auto Proto = Conformance->getProtocol(); + if (!Proto->isAccessibleFrom(DC)) + continue; + auto NormalConformance = dyn_cast( + Conformance->getRootConformance()); + if (!NormalConformance) + continue; + NormalConformance->forEachTypeWitness( + [](AssociatedTypeDecl *, Type, TypeDecl *) { return false; }, + /*useResolver=*/true); + NormalConformance->forEachValueWitness([](ValueDecl *, Witness) {}, + /*useResolver=*/true); + } + + synthesizePropertyWrapperStorageWrapperProperties(NTD); +} + static void lookupVisibleMemberDeclsImpl( Type BaseTy, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC, LookupState LS, DeclVisibilityKind Reason, GenericSignatureBuilder *GSB, @@ -583,6 +633,8 @@ static void lookupVisibleMemberDeclsImpl( if (!CurNominal) break; + synthesizeMemberDeclsForLookup(CurNominal, CurrDC); + // Look in for members of a nominal type. lookupTypeMembers(BaseTy, BaseTy, Consumer, CurrDC, LS, Reason); lookupDeclsFromProtocolsBeingConformedTo(BaseTy, Consumer, LS, CurrDC, diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index b38ad34fc3786..03574617d6ad8 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -19,6 +19,7 @@ #include "TypeCheckAvailability.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/NameLookupRequests.h" #include "swift/AST/Pattern.h" #include "swift/Basic/Defer.h" #include "swift/Basic/SourceManager.h" @@ -531,13 +532,15 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, } DeclContext *topLevelContext = DC->getModuleScopeContext(); - UnqualifiedLookup lookup(VD->getBaseName(), topLevelContext, - /*Loc=*/SourceLoc(), - UnqualifiedLookup::Flags::KnownPrivate); + auto descriptor = UnqualifiedLookupDescriptor( + VD->getBaseName(), topLevelContext, SourceLoc(), + UnqualifiedLookupFlags::KnownPrivate); + auto lookup = evaluateOrDefault(Ctx.evaluator, + UnqualifiedLookupRequest{descriptor}, {}); // Group results by module. Pick an arbitrary result from each module. llvm::SmallDenseMap resultsByModule; - for (auto &result : lookup.Results) { + for (auto &result : lookup) { const ValueDecl *value = result.getValueDecl(); resultsByModule.insert(std::make_pair(value->getModuleContext(),value)); } @@ -3417,7 +3420,20 @@ class ObjCSelectorWalker : public ASTWalker { name = bestMethod->getFullName(); } - out << nominal->getName().str() << "." << name.getBaseName(); + auto typeName = nominal->getName().str(); + // If we're inside a type Foo (or an extension of it) and the suggestion + // is going to be #selector(Foo.bar) (or #selector(SuperclassOfFoo.bar), + // then suggest the more natural #selector(self.bar) instead. + if (auto containingTypeContext = DC->getInnermostTypeContext()) { + auto methodNominalType = nominal->getDeclaredType(); + auto outerNomType = containingTypeContext->getSelfNominalTypeDecl() + ->getDeclaredType(); + if (methodNominalType->isEqual(outerNomType) || + methodNominalType->isExactSuperclassOf(outerNomType)) + typeName = "self"; + } + + out << typeName << "." << name.getBaseName(); auto argNames = name.getArgumentNames(); // Only print the parentheses if there are some argument diff --git a/lib/Sema/NameBinding.cpp b/lib/Sema/NameBinding.cpp index 4d17b4eefc760..4b86626e941da 100644 --- a/lib/Sema/NameBinding.cpp +++ b/lib/Sema/NameBinding.cpp @@ -398,7 +398,8 @@ static void insertPrecedenceGroupDecl(NameBinder &binder, SourceFile &SF, /// unresolved type names as well. This handles import directives and forward /// references. void swift::performNameBinding(SourceFile &SF, unsigned StartElem) { - SharedTimer timer("Name binding"); + FrontendStatsTracer tracer(SF.getASTContext().Stats, "Name binding"); + // Make sure we skip adding the standard library imports if the // source file is empty. if (SF.ASTStage == SourceFile::NameBound || SF.Decls.empty()) { diff --git a/lib/Sema/PCMacro.cpp b/lib/Sema/PCMacro.cpp index 7cd40b46ca930..34750d7159f40 100644 --- a/lib/Sema/PCMacro.cpp +++ b/lib/Sema/PCMacro.cpp @@ -665,14 +665,13 @@ class Instrumenter : InstrumenterBase { } // end anonymous namespace -void swift::performPCMacro(SourceFile &SF, TopLevelContext &TLC) { +void swift::performPCMacro(SourceFile &SF) { class ExpressionFinder : public ASTWalker { private: unsigned TmpNameIndex = 0; - TopLevelContext &TLC; public: - ExpressionFinder(TopLevelContext &TLC) : TLC(TLC) {} + ExpressionFinder() = default; bool walkToDeclPre(Decl *D) override { ASTContext &ctx = D->getASTContext(); @@ -692,7 +691,7 @@ void swift::performPCMacro(SourceFile &SF, TopLevelContext &TLC) { if (NewBody != Body) { TLCD->setBody(NewBody); TypeChecker::checkTopLevelErrorHandling(TLCD); - TypeChecker::contextualizeTopLevelCode(TLC, TLCD); + TypeChecker::contextualizeTopLevelCode(TLCD); } return false; } @@ -702,7 +701,7 @@ void swift::performPCMacro(SourceFile &SF, TopLevelContext &TLC) { } }; - ExpressionFinder EF(TLC); + ExpressionFinder EF; for (Decl *D : SF.Decls) { D->walk(EF); } diff --git a/lib/Sema/QuoteTransform.cpp b/lib/Sema/QuoteTransform.cpp index c014fec409427..c75834ba64b88 100644 --- a/lib/Sema/QuoteTransform.cpp +++ b/lib/Sema/QuoteTransform.cpp @@ -1224,7 +1224,8 @@ Expr *TypeChecker::quoteExpr(Expr *expr, DeclContext *dc) { assert(expr->getType()); Breadcrumbs bcs; - ASTQuoter astQuoter(*this, Context, bcs); + auto &ctx = dc->getASTContext(); + ASTQuoter astQuoter(*this, ctx, bcs); Expr *quotedExpr = astQuoter.visit(expr); if (!quotedExpr) { return nullptr; @@ -1240,19 +1241,18 @@ Expr *TypeChecker::quoteExpr(Expr *expr, DeclContext *dc) { return nullptr; } - auto quoteRef = - new (Context) UnresolvedDeclRefExpr(quoteClassType->getDecl()->getName(), - DeclRefKind::Ordinary, DeclNameLoc()); + auto quoteRef = new (ctx) UnresolvedDeclRefExpr( + quoteClassType->getDecl()->getName(), DeclRefKind::Ordinary, + DeclNameLoc()); SmallVector quoteTargs; for (auto targ : quoteClassType->getGenericArgs()) { - auto targRepr = new (Context) FixedTypeRepr(targ, SourceLoc()); + auto targRepr = new (ctx) FixedTypeRepr(targ, SourceLoc()); quoteTargs.push_back(TypeLoc(targRepr)); } auto quoteInit = UnresolvedSpecializeExpr::create( - Context, quoteRef, SourceLoc(), quoteTargs, SourceLoc()); + ctx, quoteRef, SourceLoc(), quoteTargs, SourceLoc()); quoteInit->setImplicit(); - Expr *quoteCall = - CallExpr::createImplicit(Context, quoteInit, {quotedExpr}, {}); + Expr *quoteCall = CallExpr::createImplicit(ctx, quoteInit, {quotedExpr}, {}); // TODO(TF-727): Improve error reporting when quoting fails. if (!typeCheckExpression(quoteCall, dc)) { @@ -1272,16 +1272,16 @@ Expr *TypeChecker::quoteExpr(Expr *expr, DeclContext *dc) { Type TypeChecker::getTypeOfQuoteExpr(Type exprType, SourceLoc loc) { assert(exprType); - if (!Context.getQuoteModule()) { - Context.Diags.diagnose(loc, diag::quote_literal_no_quote_module); + auto &ctx = exprType->getASTContext(); + if (!ctx.getQuoteModule()) { + ctx.Diags.diagnose(loc, diag::quote_literal_no_quote_module); return Type(); } if (auto fnExprType = exprType->getAs()) { auto n = fnExprType->getParams().size(); - auto quoteClass = Context.getFunctionQuoteDecl(n); + auto quoteClass = ctx.getFunctionQuoteDecl(n); if (!quoteClass) { - Context.Diags.diagnose(loc, diag::quote_literal_no_function_quote_class, - n); + ctx.Diags.diagnose(loc, diag::quote_literal_no_function_quote_class, n); return Type(); } SmallVector typeArgs; @@ -1295,9 +1295,9 @@ Type TypeChecker::getTypeOfQuoteExpr(Type exprType, SourceLoc loc) { typeArgs.push_back(fnExprType->getResult()); return BoundGenericClassType::get(quoteClass, Type(), typeArgs); } else { - auto quoteClass = Context.getQuoteDecl(); + auto quoteClass = ctx.getQuoteDecl(); if (!quoteClass) { - Context.Diags.diagnose(loc, diag::quote_literal_no_quote_class); + ctx.Diags.diagnose(loc, diag::quote_literal_no_quote_class); return Type(); } if (auto lvalueExprType = exprType->getAs()) { @@ -1309,19 +1309,19 @@ Type TypeChecker::getTypeOfQuoteExpr(Type exprType, SourceLoc loc) { Type TypeChecker::getTypeOfUnquoteExpr(Type exprType, SourceLoc loc) { assert(exprType); + auto &ctx = exprType->getASTContext(); if (auto genericType = exprType->getAs()) { auto classDecl = genericType->getDecl(); auto typeArgs = genericType->getGenericArgs(); - if (classDecl == Context.getQuoteDecl()) { + if (classDecl == ctx.getQuoteDecl()) { return typeArgs[0]; - } else if (classDecl == Context.getFunctionQuoteDecl(typeArgs.size() - 1)) { + } else if (classDecl == ctx.getFunctionQuoteDecl(typeArgs.size() - 1)) { SmallVector paramTypes; for (unsigned i = 0; i < typeArgs.size() - 1; ++i) { auto typeArg = typeArgs[i]; auto flags = ParameterTypeFlags(); if (auto genericTypeArg = typeArg->getAs()) { - if (genericTypeArg->getDecl() == - Context.getUnsafeMutablePointerDecl()) { + if (genericTypeArg->getDecl() == ctx.getUnsafeMutablePointerDecl()) { flags = flags.withInOut(true); } } @@ -1330,18 +1330,18 @@ Type TypeChecker::getTypeOfUnquoteExpr(Type exprType, SourceLoc loc) { } return FunctionType::get(paramTypes, typeArgs[typeArgs.size() - 1]); } else { - Context.Diags.diagnose(loc, diag::unquote_wrong_type); + ctx.Diags.diagnose(loc, diag::unquote_wrong_type); return Type(); } } else { - Context.Diags.diagnose(loc, diag::unquote_wrong_type); + ctx.Diags.diagnose(loc, diag::unquote_wrong_type); return Type(); } } Expr *TypeChecker::quoteDecl(Decl *decl, DeclContext *dc) { Breadcrumbs bcs; - ASTQuoter astQuoter(*this, Context, bcs); + ASTQuoter astQuoter(*this, dc->getASTContext(), bcs); Expr *quotedDecl = astQuoter.visit(decl); if (!quotedDecl) { return nullptr; @@ -1355,14 +1355,14 @@ Expr *TypeChecker::quoteDecl(Decl *decl, DeclContext *dc) { return quotedDecl; } -Type TypeChecker::getTypeOfQuoteDecl(SourceLoc loc) { - if (!Context.getQuoteModule()) { - Context.Diags.diagnose(loc, diag::quote_literal_no_quote_module); +Type TypeChecker::getTypeOfQuoteDecl(ASTContext &ctx, SourceLoc loc) { + if (!ctx.getQuoteModule()) { + ctx.Diags.diagnose(loc, diag::quote_literal_no_quote_module); return Type(); } - auto treeProto = Context.getTreeDecl(); + auto treeProto = ctx.getTreeDecl(); if (!treeProto) { - Context.Diags.diagnose(loc, diag::quote_literal_no_tree_proto); + ctx.Diags.diagnose(loc, diag::quote_literal_no_tree_proto); return Type(); } return treeProto->getDeclaredType(); diff --git a/lib/Sema/SolutionResult.h b/lib/Sema/SolutionResult.h new file mode 100644 index 0000000000000..8e3085a3a69c1 --- /dev/null +++ b/lib/Sema/SolutionResult.h @@ -0,0 +1,145 @@ +//===--- SolutionResult.h - Constraint System Solution ----------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2019 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the SolutionResult class. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_TYPECHECK_SOLUTION_RESULT_H +#define SWIFT_TYPECHECK_SOLUTION_RESULT_H + +#include "llvm/ADT/ArrayRef.h" + +namespace swift { + +using llvm::ArrayRef; +using llvm::makeArrayRef; + +namespace constraints { + +class Solution; + +/// Describes the result of solving a constraint system, after +/// potentially taking various corrective actions. +class SolutionResult { +public: + enum Kind : unsigned char { + /// The constraint system was successfully solved, and one can + /// retrieve the resulting solution. + Success, + /// The constraint system had multiple solutions, none of which + /// was better than the others. + Ambiguous, + /// The constraint system had no solution, and a diagnostic has + /// already been emitted. + Error, + /// The constraint system had no solution, but no diagnostic has + /// been emitted yet. + UndiagnosedError, + /// The constraint system was too complex to solve, but no + /// diagnostic has been emitted yet. + TooComplex, + }; + +private: + /// The kind of solution result. + Kind kind; + + /// Whether the client has emitted a diagnostic. + unsigned emittedDiagnostic : 1; + + /// The number of solutions owned by this result. + unsigned numSolutions = 0; + + /// A pointer to the set of solutions, of which there are + /// \c numSolutions entries. + Solution *solutions = nullptr; + + /// General constructor for the named constructors. + SolutionResult(Kind kind) : kind(kind) { + emittedDiagnostic = false; + } + +public: + SolutionResult(const SolutionResult &other) = delete; + + SolutionResult(SolutionResult &&other) + : kind(other.kind), numSolutions(other.numSolutions), + solutions(other.solutions) { + emittedDiagnostic = false; + other.kind = Error; + other.numSolutions = 0; + other.solutions = nullptr; + } + + SolutionResult &operator=(const SolutionResult &other) = delete; + SolutionResult &operator=(SolutionResult &&other) = delete; + + ~SolutionResult(); + + /// Produce a "solved" result, embedding the given solution. + static SolutionResult forSolved(Solution &&solution); + + /// Produce an "ambiguous" result, providing the set of + /// potential solutions. + static SolutionResult forAmbiguous(MutableArrayRef solutions); + + /// Produce a "too complex" failure, which was not yet been + /// diagnosed. + static SolutionResult forTooComplex() { + return SolutionResult(TooComplex); + } + + /// Produce a failure that has already been diagnosed. + static SolutionResult forError() { + return SolutionResult(Error); + } + + /// Produce a failure that has not yet been diagnosed. + static SolutionResult forUndiagnosedError() { + return SolutionResult(UndiagnosedError); + } + + Kind getKind() const{ return kind; } + + /// Retrieve the solution, where there is one. + const Solution &getSolution() const; + + /// Retrieve the solution, where there is one. + Solution &&takeSolution() &&; + + /// Retrieve the set of solutions when there is an ambiguity. + ArrayRef getAmbiguousSolutions() const; + + /// Whether this solution requires the client to produce a diagnostic. + bool requiresDiagnostic() const { + switch (kind) { + case Success: + case Ambiguous: + case Error: + return false; + + case UndiagnosedError: + case TooComplex: + return true; + } + } + + /// Note that the failure has been diagnosed. + void markAsDiagnosed() { + emittedDiagnostic = true; + } +}; + +} } + +#endif /* SWIFT_TYPECHECK_SOLUTION_RESULT_H */ diff --git a/lib/Sema/SourceLoader.cpp b/lib/Sema/SourceLoader.cpp index 3026605d6faf5..690631dc9f5cb 100644 --- a/lib/Sema/SourceLoader.cpp +++ b/lib/Sema/SourceLoader.cpp @@ -106,8 +106,8 @@ ModuleDecl *SourceLoader::loadModule(SourceLoc importLoc, /*isSystem=*/false); // Turn off debugging while parsing other modules. - llvm::SaveAndRestore turnOffDebug(Ctx.LangOpts.DebugConstraintSolver, - false); + llvm::SaveAndRestore + turnOffDebug(Ctx.TypeCheckerOpts.DebugConstraintSolver, false); unsigned bufferID; if (auto BufID = diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 17d3674514522..f07d01fb2624e 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2083,12 +2083,13 @@ void lookupReplacedDecl(DeclName replacedDeclName, auto *moduleScopeCtxt = declCtxt->getModuleScopeContext(); if (isa(declCtxt)) { - UnqualifiedLookup lookup(replacedDeclName, moduleScopeCtxt, - attr->getLocation()); - if (lookup.isSuccess()) { - for (auto entry : lookup.Results) { - results.push_back(entry.getValueDecl()); - } + auto &ctx = declCtxt->getASTContext(); + auto descriptor = UnqualifiedLookupDescriptor( + replacedDeclName, moduleScopeCtxt, attr->getLocation()); + auto lookup = evaluateOrDefault(ctx.evaluator, + UnqualifiedLookupRequest{descriptor}, {}); + for (auto entry : lookup) { + results.push_back(entry.getValueDecl()); } return; } @@ -2474,7 +2475,7 @@ void AttributeChecker::visitImplementsAttr(ImplementsAttr *attr) { void AttributeChecker::visitFrozenAttr(FrozenAttr *attr) { if (auto *ED = dyn_cast(D)) { if (!ED->getModuleContext()->isResilient()) { - diagnoseAndRemoveAttr(attr, diag::enum_frozen_nonresilient, attr); + attr->setInvalid(); return; } diff --git a/lib/Sema/TypeCheckCaptures.cpp b/lib/Sema/TypeCheckCaptures.cpp index 53efd0214509d..98c756e966296 100644 --- a/lib/Sema/TypeCheckCaptures.cpp +++ b/lib/Sema/TypeCheckCaptures.cpp @@ -612,7 +612,7 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) { // Compute captures for default argument expressions. if (auto *AFD = AFR.getAbstractFunctionDecl()) { for (auto *P : *AFD->getParameters()) { - if (auto E = P->getDefaultValue()) { + if (auto E = P->getTypeCheckedDefaultExpr()) { FindCapturedVars finder(Context, E->getLoc(), AFD, diff --git a/lib/Sema/TypeCheckCompilerEvaluable.cpp b/lib/Sema/TypeCheckCompilerEvaluable.cpp index f9ff32876a848..9fab534b23b25 100644 --- a/lib/Sema/TypeCheckCompilerEvaluable.cpp +++ b/lib/Sema/TypeCheckCompilerEvaluable.cpp @@ -241,7 +241,7 @@ void TypeChecker::checkFunctionBodyCompilerEvaluable(AbstractFunctionDecl *D) { assert(D->getBodyKind() == AbstractFunctionDecl::BodyKind::TypeChecked && "cannot check @compilerEvaluable body that is not type checked"); - CheckCompilerEvaluableBody Checker(this->Context, D); + CheckCompilerEvaluableBody Checker(D->getASTContext(), D); D->getBody()->walk(Checker); if (!Checker.getCompilerEvaluable()) { compilerEvaluableAttr->setInvalid(); diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 79c4495d1acb3..1f6cbed0f20cf 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -18,6 +18,7 @@ #include "ConstraintSystem.h" #include "MiscDiagnostics.h" +#include "SolutionResult.h" #include "TypeChecker.h" #include "TypeCheckType.h" #include "TypoCorrection.h" @@ -68,13 +69,12 @@ void TypeVariableType::Implementation::print(llvm::raw_ostream &OS) { } SavedTypeVariableBinding::SavedTypeVariableBinding(TypeVariableType *typeVar) - : TypeVarAndOptions(typeVar, typeVar->getImpl().getRawOptions()), + : TypeVar(typeVar), Options(typeVar->getImpl().getRawOptions()), ParentOrFixed(typeVar->getImpl().ParentOrFixed) { } void SavedTypeVariableBinding::restore() { - auto *typeVar = getTypeVariable(); - typeVar->getImpl().setRawOptions(getOptions()); - typeVar->getImpl().ParentOrFixed = ParentOrFixed; + TypeVar->getImpl().setRawOptions(Options); + TypeVar->getImpl().ParentOrFixed = ParentOrFixed; } GenericTypeParamType * @@ -2161,6 +2161,7 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc, auto &Context = dc->getASTContext(); FallbackDiagnosticListener diagListener(Context, options, listener); auto *TC = Context.getLegacyGlobalTypeChecker(); + assert(TC && "Must have a global type checker set"); return TC->typeCheckExpressionImpl(expr, dc, convertType, convertTypePurpose, options, diagListener, baseCS); } @@ -2171,6 +2172,7 @@ Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, TypeCheckExprOptions options, ExprTypeCheckListener &listener, ConstraintSystem *baseCS) { + auto &Context = dc->getASTContext(); FrontendStatsTracer StatsTracer(Context.Stats, "typecheck-expr", expr); PrettyStackTraceExpr stackTrace(Context, "type-checking", expr); @@ -2196,7 +2198,7 @@ Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, if (options.contains(TypeCheckExprFlags::SubExpressionDiagnostics)) csOptions |= ConstraintSystemFlags::SubExpressionDiagnostics; - ConstraintSystem cs(dc, csOptions, expr); + ConstraintSystem cs(dc, csOptions); cs.baseCS = baseCS; // Verify that a purpose was specified if a convertType was. Note that it is @@ -2260,6 +2262,9 @@ Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, if (!result) return Type(); + // Apply this solution to the constraint system. + cs.applySolution(solution); + // Apply the solution to the expression. result = cs.applySolution( solution, result, convertType.getType(), @@ -2277,7 +2282,7 @@ Type TypeChecker::typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, if (!result) return Type(); - if (getLangOpts().DebugConstraintSolver) { + if (Context.TypeCheckerOpts.DebugConstraintSolver) { auto &log = Context.TypeCheckerDebug->getStream(); log << "---Type-checked expression---\n"; result->dump(log); @@ -2466,7 +2471,7 @@ getTypeOfCompletionOperatorImpl(DeclContext *DC, Expr *expr, if (!expr) return nullptr; - if (Context.LangOpts.DebugConstraintSolver) { + if (Context.TypeCheckerOpts.DebugConstraintSolver) { auto &log = Context.TypeCheckerDebug->getStream(); log << "---Initial constraints for the given expression---\n"; expr->dump(log); @@ -2480,7 +2485,7 @@ getTypeOfCompletionOperatorImpl(DeclContext *DC, Expr *expr, return nullptr; auto &solution = viable[0]; - if (Context.LangOpts.DebugConstraintSolver) { + if (Context.TypeCheckerOpts.DebugConstraintSolver) { auto &log = Context.TypeCheckerDebug->getStream(); log << "---Solution---\n"; solution.dump(log); @@ -3451,7 +3456,7 @@ bool TypeChecker::convertToType(Expr *&expr, Type type, DeclContext *dc, cs.getConstraintLocator(expr)); auto &Context = dc->getASTContext(); - if (Context.LangOpts.DebugConstraintSolver) { + if (Context.TypeCheckerOpts.DebugConstraintSolver) { auto &log = Context.TypeCheckerDebug->getStream(); log << "---Initial constraints for the given expression---\n"; expr->dump(log); @@ -3461,13 +3466,34 @@ bool TypeChecker::convertToType(Expr *&expr, Type type, DeclContext *dc, // Attempt to solve the constraint system. SmallVector viable; - if ((cs.solve(viable) || viable.size() != 1) && - cs.salvage(viable, expr)) { - return true; + if ((cs.solve(viable) || viable.size() != 1)) { + // Try to fix the system or provide a decent diagnostic. + auto salvagedResult = cs.salvage(); + switch (salvagedResult.getKind()) { + case SolutionResult::Kind::Success: + viable.clear(); + viable.push_back(std::move(salvagedResult).takeSolution()); + break; + + case SolutionResult::Kind::Error: + case SolutionResult::Kind::Ambiguous: + return true; + + case SolutionResult::Kind::UndiagnosedError: + cs.diagnoseFailureForExpr(expr); + salvagedResult.markAsDiagnosed(); + return true; + + case SolutionResult::Kind::TooComplex: + Context.Diags.diagnose(expr->getLoc(), diag::expression_too_complex) + .highlight(expr->getSourceRange()); + salvagedResult.markAsDiagnosed(); + return true; + } } auto &solution = viable[0]; - if (Context.LangOpts.DebugConstraintSolver) { + if (Context.TypeCheckerOpts.DebugConstraintSolver) { auto &log = Context.TypeCheckerDebug->getStream(); log << "---Solution---\n"; solution.dump(log); @@ -3485,7 +3511,7 @@ bool TypeChecker::convertToType(Expr *&expr, Type type, DeclContext *dc, solution.setExprTypes(expr); - if (Context.LangOpts.DebugConstraintSolver) { + if (Context.TypeCheckerOpts.DebugConstraintSolver) { auto &log = Context.TypeCheckerDebug->getStream(); log << "---Type-checked expression---\n"; result->dump(log); @@ -3506,24 +3532,23 @@ void Solution::dump() const { } void Solution::dump(raw_ostream &out) const { - ASTContext &ctx = getConstraintSystem().getASTContext(); - llvm::SaveAndRestore debugSolver(ctx.LangOpts.DebugConstraintSolver, - true); + PrintOptions PO; + PO.PrintTypesForDebugging = true; - SourceManager *sm = &ctx.SourceMgr; + SourceManager *sm = &getConstraintSystem().getASTContext().SourceMgr; out << "Fixed score: " << FixedScore << "\n"; out << "Type variables:\n"; for (auto binding : typeBindings) { - auto &typeVar = binding.first->getImpl(); + auto &typeVar = binding.first; out.indent(2); - typeVar.print(out); + Type(typeVar).print(out, PO); out << " as "; binding.second.print(out); - if (auto *locator = typeVar.getLocator()) { + if (auto *locator = typeVar->getImpl().getLocator()) { out << " @ "; - locator->dump(&ctx.SourceMgr, out); + locator->dump(sm, out); } out << "\n"; } @@ -3545,30 +3570,30 @@ void Solution::dump(raw_ostream &out) const { choice.getDecl()->dumpRef(out); out << " as "; if (choice.getBaseType()) - out << choice.getBaseType()->getString() << "."; + out << choice.getBaseType()->getString(PO) << "."; out << choice.getDecl()->getBaseName() << ": " - << ovl.second.openedType->getString() << "\n"; + << ovl.second.openedType->getString(PO) << "\n"; break; case OverloadChoiceKind::BaseType: - out << "base type " << choice.getBaseType()->getString() << "\n"; + out << "base type " << choice.getBaseType()->getString(PO) << "\n"; break; case OverloadChoiceKind::KeyPathApplication: out << "key path application root " - << choice.getBaseType()->getString() << "\n"; + << choice.getBaseType()->getString(PO) << "\n"; break; case OverloadChoiceKind::DynamicMemberLookup: case OverloadChoiceKind::KeyPathDynamicMemberLookup: out << "dynamic member lookup root " - << choice.getBaseType()->getString() + << choice.getBaseType()->getString(PO) << " name='" << choice.getName() << "'\n"; break; case OverloadChoiceKind::TupleIndex: - out << "tuple " << choice.getBaseType()->getString() << " index " + out << "tuple " << choice.getBaseType()->getString(PO) << " index " << choice.getTupleIndex() << "\n"; break; } @@ -3598,9 +3623,9 @@ void Solution::dump(raw_ostream &out) const { out << " opens "; interleave(opened.second.begin(), opened.second.end(), [&](OpenedType opened) { - opened.first->print(out); + Type(opened.first).print(out, PO); out << " -> "; - opened.second->print(out); + Type(opened.second).print(out, PO); }, [&]() { out << ", "; @@ -3614,7 +3639,7 @@ void Solution::dump(raw_ostream &out) const { for (const auto &openedExistential : OpenedExistentialTypes) { out.indent(2); openedExistential.first->dump(sm, out); - out << " opens to " << openedExistential.second->getString(); + out << " opens to " << openedExistential.second->getString(PO); out << "\n"; } } @@ -3669,13 +3694,13 @@ void ConstraintSystem::print(raw_ostream &out, Expr *E) const { void ConstraintSystem::print(raw_ostream &out) const { // Print all type variables as $T0 instead of _ here. - llvm::SaveAndRestore X(getASTContext().LangOpts.DebugConstraintSolver, - true); + PrintOptions PO; + PO.PrintTypesForDebugging = true; out << "Score: " << CurrentScore << "\n"; - if (contextualType.getType()) { - out << "Contextual Type: " << contextualType.getType(); + if (auto ty = contextualType.getType()) { + out << "Contextual Type: " << ty.getString(PO); if (TypeRepr *TR = contextualType.getTypeRepr()) { out << " at "; TR->getSourceRange().print(out, getASTContext().SourceMgr, /*text*/false); @@ -3686,7 +3711,7 @@ void ConstraintSystem::print(raw_ostream &out) const { out << "Type Variables:\n"; for (auto tv : getTypeVariables()) { out.indent(2); - tv->getImpl().print(out); + Type(tv).print(out, PO); if (tv->getImpl().canBindToLValue()) out << " [lvalue allowed]"; if (tv->getImpl().canBindToInOut()) @@ -3697,13 +3722,13 @@ void ConstraintSystem::print(raw_ostream &out) const { if (rep == tv) { if (auto fixed = getFixedType(tv)) { out << " as "; - fixed->print(out); + Type(fixed).print(out, PO); } else { getPotentialBindings(tv).dump(out, 1); } } else { out << " equivalent to "; - rep->print(out); + Type(rep).print(out, PO); } if (auto *locator = tv->getImpl().getLocator()) { @@ -3717,14 +3742,14 @@ void ConstraintSystem::print(raw_ostream &out) const { out << "\nActive Constraints:\n"; for (auto &constraint : ActiveConstraints) { out.indent(2); - constraint.print(out, &getTypeChecker().Context.SourceMgr); + constraint.print(out, &getASTContext().SourceMgr); out << "\n"; } out << "\nInactive Constraints:\n"; for (auto &constraint : InactiveConstraints) { out.indent(2); - constraint.print(out, &getTypeChecker().Context.SourceMgr); + constraint.print(out, &getASTContext().SourceMgr); out << "\n"; } @@ -3732,7 +3757,7 @@ void ConstraintSystem::print(raw_ostream &out) const { out << "\nRetired Constraints:\n"; solverState->forEachRetired([&](Constraint &constraint) { out.indent(2); - constraint.print(out, &getTypeChecker().Context.SourceMgr); + constraint.print(out, &getASTContext().SourceMgr); out << "\n"; }); } @@ -3751,30 +3776,30 @@ void ConstraintSystem::print(raw_ostream &out) const { case OverloadChoiceKind::DeclViaBridge: case OverloadChoiceKind::DeclViaUnwrappedOptional: if (choice.getBaseType()) - out << choice.getBaseType()->getString() << "."; + out << choice.getBaseType()->getString(PO) << "."; out << choice.getDecl()->getBaseName() << ": " - << resolved->BoundType->getString() << " == " - << resolved->ImpliedType->getString() << "\n"; + << resolved->BoundType->getString(PO) << " == " + << resolved->ImpliedType->getString(PO) << "\n"; break; case OverloadChoiceKind::BaseType: - out << "base type " << choice.getBaseType()->getString() << "\n"; + out << "base type " << choice.getBaseType()->getString(PO) << "\n"; break; case OverloadChoiceKind::KeyPathApplication: out << "key path application root " - << choice.getBaseType()->getString() << "\n"; + << choice.getBaseType()->getString(PO) << "\n"; break; case OverloadChoiceKind::DynamicMemberLookup: case OverloadChoiceKind::KeyPathDynamicMemberLookup: out << "dynamic member lookup:" - << choice.getBaseType()->getString() << " name=" + << choice.getBaseType()->getString(PO) << " name=" << choice.getName() << "\n"; break; case OverloadChoiceKind::TupleIndex: - out << "tuple " << choice.getBaseType()->getString() << " index " + out << "tuple " << choice.getBaseType()->getString(PO) << " index " << choice.getTupleIndex() << "\n"; break; } @@ -3786,7 +3811,7 @@ void ConstraintSystem::print(raw_ostream &out) const { out << "\nDisjunction choices:\n"; for (auto &choice : DisjunctionChoices) { out.indent(2); - choice.first->dump(&getTypeChecker().Context.SourceMgr, out); + choice.first->dump(&getASTContext().SourceMgr, out); out << " is #" << choice.second << "\n"; } } @@ -3795,13 +3820,13 @@ void ConstraintSystem::print(raw_ostream &out) const { out << "\nOpened types:\n"; for (const auto &opened : OpenedTypes) { out.indent(2); - opened.first->dump(&getTypeChecker().Context.SourceMgr, out); + opened.first->dump(&getASTContext().SourceMgr, out); out << " opens "; interleave(opened.second.begin(), opened.second.end(), [&](OpenedType opened) { - opened.first->print(out); + Type(opened.first).print(out, PO); out << " -> "; - opened.second->print(out); + Type(opened.second).print(out, PO); }, [&]() { out << ", "; @@ -3814,8 +3839,8 @@ void ConstraintSystem::print(raw_ostream &out) const { out << "\nOpened existential types:\n"; for (const auto &openedExistential : OpenedExistentialTypes) { out.indent(2); - openedExistential.first->dump(&getTypeChecker().Context.SourceMgr, out); - out << " opens to " << openedExistential.second->getString(); + openedExistential.first->dump(&getASTContext().SourceMgr, out); + out << " opens to " << openedExistential.second->getString(PO); out << "\n"; } } @@ -3823,7 +3848,7 @@ void ConstraintSystem::print(raw_ostream &out) const { if (!DefaultedConstraints.empty()) { out << "\nDefaulted constraints: "; interleave(DefaultedConstraints, [&](ConstraintLocator *locator) { - locator->dump(&getTypeChecker().Context.SourceMgr, out); + locator->dump(&getASTContext().SourceMgr, out); }, [&] { out << ", "; }); @@ -3832,7 +3857,7 @@ void ConstraintSystem::print(raw_ostream &out) const { if (failedConstraint) { out << "\nFailed constraint:\n"; out.indent(2); - failedConstraint->print(out, &getTypeChecker().Context.SourceMgr); + failedConstraint->print(out, &getASTContext().SourceMgr); out << "\n"; } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 67fe513b5aec1..3eefd9ea5452f 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -75,7 +75,7 @@ namespace { /// Float and integer literals are additionally keyed by numeric equivalence. struct RawValueKey { enum class Kind : uint8_t { - String, Float, Int, Tombstone, Empty + String, Float, Int, Bool, Tombstone, Empty } kind; struct IntValueTy { @@ -101,6 +101,7 @@ struct RawValueKey { StringRef stringValue; IntValueTy intValue; FloatValueTy floatValue; + bool boolValue; }; explicit RawValueKey(LiteralExpr *expr) { @@ -136,6 +137,12 @@ struct RawValueKey { kind = Kind::String; stringValue = cast(expr)->getValue(); return; + + case ExprKind::BooleanLiteral: + kind = Kind::Bool; + boolValue = cast(expr)->getValue(); + return; + default: llvm_unreachable("not a valid literal expr for raw value"); } @@ -183,6 +190,8 @@ class DenseMapInfo { DenseMapInfo::getHashValue(k.intValue.v1); case RawValueKey::Kind::String: return DenseMapInfo::getHashValue(k.stringValue); + case RawValueKey::Kind::Bool: + return DenseMapInfo::getHashValue(k.boolValue); case RawValueKey::Kind::Empty: case RawValueKey::Kind::Tombstone: return 0; @@ -204,6 +213,8 @@ class DenseMapInfo { a.intValue.v1 == b.intValue.v1; case RawValueKey::Kind::String: return a.stringValue.equals(b.stringValue); + case RawValueKey::Kind::Bool: + return a.boolValue == b.boolValue; case RawValueKey::Kind::Empty: case RawValueKey::Kind::Tombstone: return true; @@ -563,119 +574,75 @@ static void checkGenericParams(GenericContext *ownerCtx) { [](Requirement, RequirementRepr *) { return false; }); } -/// Retrieve the set of protocols the given protocol inherits. -static llvm::TinyPtrVector -getInheritedForCycleCheck(ProtocolDecl *proto, ProtocolDecl **scratch) { - TinyPtrVector result; - - bool anyObject = false; - for (const auto &found : - getDirectlyInheritedNominalTypeDecls(proto, anyObject)) { - if (auto protoDecl = dyn_cast(found.second)) - result.push_back(protoDecl); - } - - return result; +static bool canSkipCircularityCheck(NominalTypeDecl *decl) { + // Don't bother checking imported or deserialized decls. + return decl->hasClangNode() || decl->wasDeserialized(); } -/// Retrieve the superclass of the given class. -static ArrayRef getInheritedForCycleCheck(ClassDecl *classDecl, - ClassDecl **scratch) { - if (classDecl->hasSuperclass()) { - *scratch = classDecl->getSuperclassDecl(); - return *scratch; - } - return { }; -} +llvm::Expected +HasCircularInheritanceRequest::evaluate(Evaluator &evaluator, + ClassDecl *decl) const { + if (canSkipCircularityCheck(decl) || !decl->hasSuperclass()) + return false; + + auto *superclass = decl->getSuperclassDecl(); + auto result = evaluator(HasCircularInheritanceRequest{superclass}); -/// Retrieve the raw type of the given enum. -static ArrayRef getInheritedForCycleCheck(EnumDecl *enumDecl, - EnumDecl **scratch) { - if (enumDecl->hasRawType()) { - *scratch = enumDecl->getRawType()->getEnumOrBoundGenericEnum(); - return *scratch ? ArrayRef(*scratch) : ArrayRef{}; + // If we have a cycle, handle it and return true. + if (!result) { + using Error = CyclicalRequestError; + llvm::handleAllErrors(result.takeError(), [](const Error &E) {}); + return true; } - return { }; + return result; } -/// Check for circular inheritance. -template -static void checkCircularity(T *decl, Diag circularDiag, - DescriptiveDeclKind declKind, - SmallVectorImpl &path) { - switch (decl->getCircularityCheck()) { - case CircularityCheck::Checked: - return; - - case CircularityCheck::Checking: { - // We're already checking this type, which means we have a cycle. - - // The beginning of the path might not be part of the cycle, so find - // where the cycle starts. - assert(!path.empty()); - - auto cycleStart = path.end() - 1; - while (*cycleStart != decl) { - assert(cycleStart != path.begin() && "Missing cycle start?"); - --cycleStart; - } - - // If the path length is 1 the type directly references itself. - if (path.end() - cycleStart == 1) { - path.back()->diagnose(circularDiag, path.back()->getName()); +llvm::Expected +HasCircularInheritedProtocolsRequest::evaluate(Evaluator &evaluator, + ProtocolDecl *decl) const { + if (canSkipCircularityCheck(decl)) + return false; - break; - } + bool anyObject = false; + auto inherited = getDirectlyInheritedNominalTypeDecls(decl, anyObject); + for (auto &found : inherited) { + auto *protoDecl = dyn_cast(found.second); + if (!protoDecl) + continue; - // Diagnose the cycle. - decl->diagnose(circularDiag, (*cycleStart)->getName()); - for (auto i = cycleStart + 1, iEnd = path.end(); i != iEnd; ++i) { - (*i)->diagnose(diag::kind_declname_declared_here, declKind, - (*i)->getName()); + // If we have a cycle, handle it and return true. + auto result = evaluator(HasCircularInheritedProtocolsRequest{protoDecl}); + if (!result) { + using Error = CyclicalRequestError; + llvm::handleAllErrors(result.takeError(), [](const Error &E) {}); + return true; } - break; - } - - case CircularityCheck::Unchecked: { - // Walk to the inherited class or protocols. - path.push_back(decl); - decl->setCircularityCheck(CircularityCheck::Checking); - T *scratch = nullptr; - for (auto inherited : getInheritedForCycleCheck(decl, &scratch)) { - checkCircularity(inherited, circularDiag, declKind, path); - } - decl->setCircularityCheck(CircularityCheck::Checked); - path.pop_back(); - break; - } + // If the underlying request handled a cycle and returned true, bail. + if (*result) + return true; } + return false; } -/// Expose TypeChecker's handling of GenericParamList to SIL parsing. -GenericEnvironment * -TypeChecker::handleSILGenericParams(GenericParamList *genericParams, - DeclContext *DC) { - if (genericParams == nullptr) - return nullptr; - - SmallVector nestedList; - for (; genericParams; genericParams = genericParams->getOuterParameters()) { - nestedList.push_back(genericParams); - } +llvm::Expected +HasCircularRawValueRequest::evaluate(Evaluator &evaluator, + EnumDecl *decl) const { + if (canSkipCircularityCheck(decl) || !decl->hasRawType()) + return false; - std::reverse(nestedList.begin(), nestedList.end()); + auto *inherited = decl->getRawType()->getEnumOrBoundGenericEnum(); + if (!inherited) + return false; - for (unsigned i = 0, e = nestedList.size(); i < e; ++i) { - auto genericParams = nestedList[i]; - genericParams->setDepth(i); + // If we have a cycle, handle it and return true. + auto result = evaluator(HasCircularRawValueRequest{inherited}); + if (!result) { + using Error = CyclicalRequestError; + llvm::handleAllErrors(result.takeError(), [](const Error &E) {}); + return true; } - - auto sig = TypeChecker::checkGenericSignature( - nestedList.back(), DC, - /*parentSig=*/nullptr, - /*allowConcreteGenericParams=*/true); - return (sig ? sig->getGenericEnvironment() : nullptr); + return result; } /// Check whether \c current is a redeclaration. @@ -754,10 +721,6 @@ static void checkRedeclaration(ASTContext &ctx, ValueDecl *current) { if (!conflicting(currentSig, otherSig)) continue; - // Skip invalid declarations. - if (other->isInvalid()) - continue; - // Skip declarations in other files. // In practice, this means we will warn on a private declaration that // shadows a non-private one, but only in the file where the shadowing @@ -766,6 +729,10 @@ static void checkRedeclaration(ASTContext &ctx, ValueDecl *current) { if (!other->isAccessibleFrom(currentDC)) continue; + // Skip invalid declarations. + if (other->isInvalid()) + continue; + // Thwart attempts to override the same declaration more than once. const auto *currentOverride = current->getOverriddenDecl(); const auto *otherOverride = other->getOverriddenDecl(); @@ -1302,10 +1269,18 @@ IsStaticRequest::evaluate(Evaluator &evaluator, FuncDecl *decl) const { decl->isOperator() && dc->isTypeContext()) { auto operatorName = decl->getFullName().getBaseIdentifier(); - decl->diagnose(diag::nonstatic_operator_in_type, - operatorName, dc->getDeclaredInterfaceType()) - .fixItInsert(decl->getAttributeInsertionLoc(/*forModifier=*/true), - "static "); + if (auto ED = dyn_cast(dc->getAsDecl())) { + decl->diagnose(diag::nonstatic_operator_in_extension, + operatorName, ED->getExtendedTypeRepr()) + .fixItInsert(decl->getAttributeInsertionLoc(/*forModifier=*/true), + "static "); + } else { + auto *NTD = cast(dc->getAsDecl()); + decl->diagnose(diag::nonstatic_operator_in_nominal, operatorName, + NTD->getName()) + .fixItInsert(decl->getAttributeInsertionLoc(/*forModifier=*/true), + "static "); + } result = true; } @@ -1684,11 +1659,10 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, { - auto *TC = ED->getASTContext().getLegacyGlobalTypeChecker(); - assert(TC && "Must have a global type checker set"); Expr *exprToCheck = prevValue; - if (TC->typeCheckExpression(exprToCheck, ED, TypeLoc::withoutLoc(rawTy), - CTP_EnumCaseRawValue)) { + if (TypeChecker::typeCheckExpression(exprToCheck, ED, + TypeLoc::withoutLoc(rawTy), + CTP_EnumCaseRawValue)) { TypeChecker::checkEnumElementErrorHandling(elt, exprToCheck); } } @@ -1700,6 +1674,7 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, continue; } + // If the raw values of the enum case are fixed, then we trust our callers // to have set things up correctly. This comes up with imported enums // and deserialized @objc enums which always have their raw values setup @@ -1990,8 +1965,7 @@ getParamIndex(const ParameterList *paramList, const ParamDecl *decl) { } static void checkInheritedDefaultValueRestrictions(ParamDecl *PD) { - if (PD->getDefaultArgumentKind() != DefaultArgumentKind::Inherited) - return; + assert(PD->getDefaultArgumentKind() == DefaultArgumentKind::Inherited); auto *DC = PD->getInnermostDeclContext(); const SourceFile *SF = DC->getParentSourceFile(); @@ -2027,30 +2001,78 @@ static void checkInheritedDefaultValueRestrictions(ParamDecl *PD) { /// Check the default arguments that occur within this pattern. static void checkDefaultArguments(ParameterList *params) { - for (auto *param : *params) { + // Force the default values in case they produce diagnostics. + for (auto *param : *params) + (void)param->getTypeCheckedDefaultExpr(); +} + +llvm::Expected +DefaultArgumentExprRequest::evaluate(Evaluator &evaluator, + ParamDecl *param) const { + if (param->getDefaultArgumentKind() == DefaultArgumentKind::Inherited) { + // Inherited default arguments don't have expressions, but we need to + // perform a couple of semantic checks to make sure they're valid. checkInheritedDefaultValueRestrictions(param); - if (!param->getDefaultValue() || - !param->hasInterfaceType() || - param->getInterfaceType()->hasError()) - continue; + return nullptr; + } - Expr *e = param->getDefaultValue(); - auto *initContext = param->getDefaultArgumentInitContext(); + auto &ctx = param->getASTContext(); + auto paramTy = param->getType(); + auto *initExpr = param->getStructuralDefaultExpr(); + assert(initExpr); - auto resultTy = - TypeChecker::typeCheckParameterDefault(e, initContext, param->getType(), - param->isAutoClosure()); + if (paramTy->hasError()) + return new (ctx) ErrorExpr(initExpr->getSourceRange(), ErrorType::get(ctx)); - if (resultTy) { - param->setDefaultValue(e); - } + auto *dc = param->getDefaultArgumentInitContext(); + assert(dc); + + if (!TypeChecker::typeCheckParameterDefault(initExpr, dc, paramTy, + param->isAutoClosure())) { + return new (ctx) ErrorExpr(initExpr->getSourceRange(), ErrorType::get(ctx)); + } - TypeChecker::checkInitializerErrorHandling(initContext, e); + TypeChecker::checkInitializerErrorHandling(dc, initExpr); - // Walk the checked initializer and contextualize any closures - // we saw there. - (void)TypeChecker::contextualizeInitializer(initContext, e); + // Walk the checked initializer and contextualize any closures + // we saw there. + (void)TypeChecker::contextualizeInitializer(dc, initExpr); + return initExpr; +} + +llvm::Expected +DefaultArgumentInitContextRequest::evaluate(Evaluator &eval, + ParamDecl *param) const { + auto &ctx = param->getASTContext(); + auto *parentDC = param->getDeclContext(); + auto *paramList = getParameterList(cast(parentDC->getAsDecl())); + + // In order to compute the initializer context for this parameter, we need to + // know its index in the parameter list. Therefore iterate over the parameters + // looking for it and fill in the other parameter's contexts while we're here. + Initializer *result = nullptr; + for (auto idx : indices(*paramList)) { + auto *otherParam = paramList->get(idx); + + // If this param doesn't need a context, we're done. + if (!otherParam->hasDefaultExpr() && !otherParam->getStoredProperty()) + continue; + + // If this param already has a context, continue using it. + if (otherParam->getCachedDefaultArgumentInitContext()) + continue; + + // Create a new initializer context. If this is for the parameter that + // kicked off the request, make a note of it for when we return. Otherwise + // cache the result ourselves. + auto *initDC = new (ctx) DefaultArgumentInitializer(parentDC, idx); + if (param == otherParam) + result = initDC; + else + eval.cacheOutput(DefaultArgumentInitContextRequest{otherParam}, std::move(initDC)); } + assert(result && "Didn't create init context?"); + return result; } PrecedenceGroupDecl *TypeChecker::lookupPrecedenceGroup(DeclContext *dc, @@ -2108,7 +2130,7 @@ llvm::Expected OperatorPrecedenceGroupRequest::evaluate(Evaluator &evaluator, InfixOperatorDecl *IOD) const { auto enableOperatorDesignatedTypes = - IOD->getASTContext().LangOpts.EnableOperatorDesignatedTypes; + IOD->getASTContext().TypeCheckerOpts.EnableOperatorDesignatedTypes; auto &Diags = IOD->getASTContext().Diags; PrecedenceGroupDecl *group = nullptr; @@ -2349,7 +2371,9 @@ class DeclChecker : public DeclVisitor { (void)IOD->getPrecedenceGroup(); } else { auto nominalTypes = OD->getDesignatedNominalTypes(); - if (nominalTypes.empty() && Ctx.LangOpts.EnableOperatorDesignatedTypes) { + const auto wantsDesignatedTypes = + Ctx.TypeCheckerOpts.EnableOperatorDesignatedTypes; + if (nominalTypes.empty() && wantsDesignatedTypes) { auto identifiers = OD->getIdentifiers(); auto identifierLocs = OD->getIdentifierLocs(); if (checkDesignatedTypes(OD, identifiers, identifierLocs, Ctx)) @@ -2780,13 +2804,8 @@ class DeclChecker : public DeclVisitor { checkGenericParams(ED); - { - // Check for circular inheritance of the raw type. - SmallVector path; - path.push_back(ED); - checkCircularity(ED, diag::circular_enum_inheritance, - DescriptiveDeclKind::Enum, path); - } + // Check for circular inheritance of the raw type. + (void)ED->hasCircularRawValue(); for (Decl *member : ED->getMembers()) visit(member); @@ -2952,13 +2971,8 @@ class DeclChecker : public DeclVisitor { checkGenericParams(CD); - { - // Check for circular inheritance. - SmallVector path; - path.push_back(CD); - checkCircularity(CD, diag::circular_class_inheritance, - DescriptiveDeclKind::Class, path); - } + // Check for circular inheritance. + (void)CD->hasCircularInheritance(); // Force lowering of stored properties. (void) CD->getStoredProperties(); @@ -3102,21 +3116,15 @@ class DeclChecker : public DeclVisitor { void visitProtocolDecl(ProtocolDecl *PD) { checkUnsupportedNestedType(PD); - auto *SF = PD->getParentSourceFile(); - { - // Check for circular inheritance within the protocol. - SmallVector path; - path.push_back(PD); - checkCircularity(PD, diag::circular_protocol_def, - DescriptiveDeclKind::Protocol, path); + // Check for circular inheritance within the protocol. + (void)PD->hasCircularInheritedProtocols(); - if (SF) { - if (auto *tracker = SF->getReferencedNameTracker()) { - bool isNonPrivate = - (PD->getFormalAccess() > AccessLevel::FilePrivate); - for (auto *parentProto : PD->getInheritedProtocols()) - tracker->addUsedMember({parentProto, Identifier()}, isNonPrivate); - } + auto *SF = PD->getParentSourceFile(); + if (SF) { + if (auto *tracker = SF->getReferencedNameTracker()) { + bool isNonPrivate = (PD->getFormalAccess() > AccessLevel::FilePrivate); + for (auto *parentProto : PD->getInheritedProtocols()) + tracker->addUsedMember({parentProto, Identifier()}, isNonPrivate); } } @@ -3135,7 +3143,7 @@ class DeclChecker : public DeclVisitor { if (!SF || SF->Kind != SourceFileKind::Interface) TypeChecker::inferDefaultWitnesses(PD); - if (PD->getASTContext().LangOpts.DebugGenericSignatures) { + if (PD->getASTContext().TypeCheckerOpts.DebugGenericSignatures) { auto requirementsSig = GenericSignature::get({PD->getProtocolSelfType()}, PD->getRequirementSignature()); @@ -3214,11 +3222,8 @@ class DeclChecker : public DeclVisitor { bool shouldSkipBodyTypechecking(const AbstractFunctionDecl *AFD) { - // FIXME: Remove TypeChecker dependency. - auto &TC = *Ctx.getLegacyGlobalTypeChecker(); - // Make sure we're in the mode that's skipping function bodies. - if (!TC.canSkipNonInlinableBodies()) + if (!getASTContext().TypeCheckerOpts.SkipNonInlinableFunctionBodies) return false; // Make sure there even _is_ a body that we can skip. @@ -3675,6 +3680,7 @@ void TypeChecker::typeCheckDecl(Decl *D) { // Returns 'nullptr' if this is the setter's 'newValue' parameter; // otherwise, returns the corresponding parameter of the subscript // declaration. + static ParamDecl *getOriginalParamFromAccessor(AbstractStorageDecl *storage, AccessorDecl *accessor, ParamDecl *param) { @@ -3972,11 +3978,8 @@ bool swift::isMemberOperator(FuncDecl *decl, Type type) { // Check the parameters for a reference to 'Self'. bool isProtocol = selfNominal && isa(selfNominal); for (auto param : *decl->getParameters()) { - auto paramType = param->getInterfaceType(); - if (!paramType) break; - // Look through a metatype reference, if there is one. - paramType = paramType->getMetatypeInstanceType(); + auto paramType = param->getInterfaceType()->getMetatypeInstanceType(); auto nominal = paramType->getAnyNominal(); if (type.isNull()) { @@ -4120,7 +4123,7 @@ ParamSpecifierRequest::evaluate(Evaluator &evaluator, if (isa(nestedRepr) && param->isDefaultArgument()) { auto &ctx = param->getASTContext(); - ctx.Diags.diagnose(param->getDefaultValue()->getLoc(), + ctx.Diags.diagnose(param->getStructuralDefaultExpr()->getLoc(), swift::diag::cannot_provide_default_value_inout, param->getName()); return ParamSpecifier::Default; diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp index 8d769cd58e648..59eccfb70903b 100644 --- a/lib/Sema/TypeCheckDeclObjC.cpp +++ b/lib/Sema/TypeCheckDeclObjC.cpp @@ -225,12 +225,10 @@ static void diagnoseFunctionParamNotRepresentable( AFD->diagnose(diag::objc_invalid_on_func_param_type, ParamIndex + 1, getObjCDiagnosticAttrKind(Reason)); } - if (Type ParamTy = P->getType()) { - SourceRange SR; - if (auto typeRepr = P->getTypeRepr()) - SR = typeRepr->getSourceRange(); - diagnoseTypeNotRepresentableInObjC(AFD, ParamTy, SR); - } + SourceRange SR; + if (auto typeRepr = P->getTypeRepr()) + SR = typeRepr->getSourceRange(); + diagnoseTypeNotRepresentableInObjC(AFD, P->getType(), SR); describeObjCReason(AFD, Reason); } diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 63b4ff3529ee4..76749888c8569 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -234,6 +234,11 @@ static bool areOverrideCompatibleSimple(ValueDecl *decl, return false; } + // Ignore declarations that are defined inside constrained extensions. + if (auto *ext = dyn_cast(parentDecl->getDeclContext())) + if (ext->isConstrainedExtension()) + return false; + // The declarations must be of the same kind. if (decl->getKind() != parentDecl->getKind()) return false; @@ -282,9 +287,6 @@ diagnoseMismatchedOptionals(const ValueDecl *member, Type paramTy = decl->getType(); Type parentParamTy = parentDecl->getType(); - if (!paramTy || !parentParamTy) - return; - auto *repr = decl->getTypeRepr(); if (!repr) return; @@ -1273,6 +1275,11 @@ bool swift::checkOverrides(ValueDecl *decl) { // Otherwise, we have more checking to do. } + // Members of constrained extensions are not considered to be overrides. + if (auto *ext = dyn_cast(decl->getDeclContext())) + if (ext->isConstrainedExtension()) + return false; + // Accessor methods get overrides through their storage declaration, and // all checking can be performed via that mechanism. if (isa(decl)) { @@ -1424,8 +1431,9 @@ namespace { UNINTERESTING_ATTR(DynamicReplacement) UNINTERESTING_ATTR(PrivateImport) - // SWIFT_ENABLE_TENSORFLOW + // Differentiation-related attributes. UNINTERESTING_ATTR(Differentiable) + // SWIFT_ENABLE_TENSORFLOW UNINTERESTING_ATTR(Derivative) UNINTERESTING_ATTR(Transpose) UNINTERESTING_ATTR(Differentiating) diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index f3a0b7571eb4a..7033d7531f8ff 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -467,7 +467,7 @@ GenericSignature TypeChecker::checkGenericSignature( // Debugging of the generic signature builder and generic signature // generation. - if (dc->getASTContext().LangOpts.DebugGenericSignatures) { + if (dc->getASTContext().TypeCheckerOpts.DebugGenericSignatures) { if (auto *VD = dyn_cast_or_null(dc->getAsDecl())) { VD->dumpRef(llvm::errs()); } else { @@ -589,7 +589,7 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, // Debugging of the generic signature builder and generic signature // generation. - if (GC->getASTContext().LangOpts.DebugGenericSignatures) { + if (GC->getASTContext().TypeCheckerOpts.DebugGenericSignatures) { PD->printContext(llvm::errs()); llvm::errs() << "\n"; llvm::errs() << "Generic signature: "; diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index 95e0b7c3fab82..e701a30ecbaa5 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -20,53 +20,13 @@ #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Initializer.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/NameLookupRequests.h" #include "swift/AST/ProtocolConformance.h" #include "swift/Basic/TopCollection.h" #include using namespace swift; -void LookupResult::filter( - llvm::function_ref pred) { - size_t index = 0; - size_t originalFirstOuter = IndexOfFirstOuterResult; - Results.erase(std::remove_if(Results.begin(), Results.end(), - [&](LookupResultEntry result) -> bool { - auto isInner = index < originalFirstOuter; - index++; - if (pred(result, !isInner)) - return false; - - // Need to remove this, which means, if it is - // an inner result, the outer results need to - // shift down. - if (isInner) - IndexOfFirstOuterResult--; - return true; - }), - Results.end()); -} - -void LookupResult::shiftDownResults() { - // Remove inner results. - Results.erase(Results.begin(), Results.begin() + IndexOfFirstOuterResult); - IndexOfFirstOuterResult = 0; - - if (Results.empty()) - return; - - // Compute IndexOfFirstOuterResult. - const DeclContext *dcInner = Results.front().getValueDecl()->getDeclContext(); - for (auto &&result : Results) { - const DeclContext *dc = result.getValueDecl()->getDeclContext(); - if (dc == dcInner || - (dc->isModuleScopeContext() && dcInner->isModuleScopeContext())) - ++IndexOfFirstOuterResult; - else - break; - } -} - namespace { /// Builder that helps construct a lookup result from the raw lookup /// data. @@ -248,17 +208,17 @@ namespace { }; } // end anonymous namespace -static UnqualifiedLookup::Options +static UnqualifiedLookupOptions convertToUnqualifiedLookupOptions(NameLookupOptions options) { - UnqualifiedLookup::Options newOptions; + UnqualifiedLookupOptions newOptions; if (options.contains(NameLookupFlags::KnownPrivate)) - newOptions |= UnqualifiedLookup::Flags::KnownPrivate; + newOptions |= UnqualifiedLookupFlags::KnownPrivate; if (options.contains(NameLookupFlags::ProtocolMembers)) - newOptions |= UnqualifiedLookup::Flags::AllowProtocolMembers; + newOptions |= UnqualifiedLookupFlags::AllowProtocolMembers; if (options.contains(NameLookupFlags::IgnoreAccessControl)) - newOptions |= UnqualifiedLookup::Flags::IgnoreAccessControl; + newOptions |= UnqualifiedLookupFlags::IgnoreAccessControl; if (options.contains(NameLookupFlags::IncludeOuterResults)) - newOptions |= UnqualifiedLookup::Flags::IncludeOuterResults; + newOptions |= UnqualifiedLookupFlags::IncludeOuterResults; return newOptions; } @@ -266,13 +226,17 @@ convertToUnqualifiedLookupOptions(NameLookupOptions options) { LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclName name, SourceLoc loc, NameLookupOptions options) { - UnqualifiedLookup lookup(name, dc, loc, - convertToUnqualifiedLookupOptions(options)); + auto ulOptions = convertToUnqualifiedLookupOptions(options); + + auto &ctx = dc->getASTContext(); + auto descriptor = UnqualifiedLookupDescriptor(name, dc, loc, ulOptions); + auto lookup = evaluateOrDefault(ctx.evaluator, + UnqualifiedLookupRequest{descriptor}, {}); LookupResult result; LookupResultBuilder builder(result, dc, options); - for (auto idx : indices(lookup.Results)) { - const auto &found = lookup.Results[idx]; + for (auto idx : indices(lookup.allResults())) { + const auto &found = lookup[idx]; // Determine which type we looked through to find this result. Type foundInType; @@ -287,7 +251,7 @@ LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclName name, } builder.add(found.getValueDecl(), found.getDeclContext(), foundInType, - /*isOuter=*/idx >= lookup.IndexOfFirstOuterResult); + /*isOuter=*/idx >= lookup.getIndexOfFirstOuterResult()); } return result; } @@ -296,18 +260,20 @@ LookupResult TypeChecker::lookupUnqualifiedType(DeclContext *dc, DeclName name, SourceLoc loc, NameLookupOptions options) { + auto &ctx = dc->getASTContext(); auto ulOptions = convertToUnqualifiedLookupOptions(options) | - UnqualifiedLookup::Flags::TypeLookup; + UnqualifiedLookupFlags::TypeLookup; { // Try lookup without ProtocolMembers first. - UnqualifiedLookup lookup( + auto desc = UnqualifiedLookupDescriptor( name, dc, loc, - ulOptions - UnqualifiedLookup::Flags::AllowProtocolMembers); + ulOptions - UnqualifiedLookupFlags::AllowProtocolMembers); - if (!lookup.Results.empty() || - !options.contains(NameLookupFlags::ProtocolMembers)) { - return LookupResult(lookup.Results, lookup.IndexOfFirstOuterResult); - } + auto lookup = + evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{desc}, {}); + if (!lookup.allResults().empty() || + !options.contains(NameLookupFlags::ProtocolMembers)) + return lookup; } { @@ -316,11 +282,10 @@ TypeChecker::lookupUnqualifiedType(DeclContext *dc, DeclName name, // FIXME: Fix the problem where if NominalTypeDecl::getAllProtocols() // is called too early, we start resolving extensions -- even those // which do provide not conformances. - UnqualifiedLookup lookup( + auto desc = UnqualifiedLookupDescriptor( name, dc, loc, - ulOptions | UnqualifiedLookup::Flags::AllowProtocolMembers); - - return LookupResult(lookup.Results, lookup.IndexOfFirstOuterResult); + ulOptions | UnqualifiedLookupFlags::AllowProtocolMembers); + return evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{desc}, {}); } } diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 521f5edec0953..7740c3db2b7d3 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -1488,10 +1488,7 @@ void TypeChecker::coerceParameterListToType(ParameterList *P, ClosureExpr *CE, if (param->isInvalid()) return true; - if (auto type = param->getType()) - return !isValidType(type); - - return true; + return !isValidType(param->getType()); }; auto handleParameter = [&](ParamDecl *param, Type ty, bool forceMutable) { diff --git a/lib/Sema/TypeCheckPropertyWrapper.cpp b/lib/Sema/TypeCheckPropertyWrapper.cpp index 4f0644c980370..e59c97d2117c2 100644 --- a/lib/Sema/TypeCheckPropertyWrapper.cpp +++ b/lib/Sema/TypeCheckPropertyWrapper.cpp @@ -546,7 +546,7 @@ PropertyWrapperBackingPropertyTypeRequest::evaluate( // Compute the type of the property to plug in to the wrapper type. Type propertyType = var->getType(); - if (!propertyType || propertyType->hasError()) + if (propertyType->hasError()) return Type(); using namespace constraints; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 5976b87b6f30d..f08bd9d8ff2e8 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -253,14 +253,6 @@ static bool checkObjCWitnessSelector(ValueDecl *req, ValueDecl *witness) { return false; } -static ParameterList *getParameterList(ValueDecl *value) { - if (auto func = dyn_cast(value)) - return func->getParameters(); - - auto subscript = cast(value); - return subscript->getIndices(); -} - // Find a standin declaration to place the diagnostic at for the // given accessor kind. static ValueDecl *getStandinForAccessor(AbstractStorageDecl *witness, @@ -2297,16 +2289,39 @@ ConformanceChecker::getReferencedAssociatedTypes(ValueDecl *req) { return known->second; // Collect the set of associated types rooted on Self in the - // signature. + // signature. Note that for references to nested types, we only + // want to consider the outermost dependent member type. + // + // For example, a requirement typed '(Iterator.Element) -> ()' + // is not considered to reference the associated type 'Iterator'. auto &assocTypes = ReferencedAssociatedTypes[req]; - llvm::SmallPtrSet knownAssocTypes; - req->getInterfaceType()->getCanonicalType().visit([&](CanType type) { - if (auto assocType = getReferencedAssocTypeOfProtocol(type, Proto)) { - if (knownAssocTypes.insert(assocType).second) { - assocTypes.push_back(assocType); + + class Walker : public TypeWalker { + ProtocolDecl *Proto; + llvm::SmallVectorImpl &assocTypes; + llvm::SmallPtrSet knownAssocTypes; + + public: + Walker(ProtocolDecl *Proto, + llvm::SmallVectorImpl &assocTypes) + : Proto(Proto), assocTypes(assocTypes) {} + + Action walkToTypePre(Type type) override { + if (type->is()) { + if (auto assocType = getReferencedAssocTypeOfProtocol(type, Proto)) { + if (knownAssocTypes.insert(assocType).second) + assocTypes.push_back(assocType); } + + return Action::SkipChildren; } - }); + + return Action::Continue; + } + }; + + Walker walker(Proto, assocTypes); + req->getInterfaceType()->getCanonicalType().walk(walker); return assocTypes; } @@ -2470,11 +2485,8 @@ static void diagnoseWitnessFixAccessLevel(DiagnosticEngine &diags, if (extAccess < requiredAccess) { shouldMoveToAnotherExtension = true; } else if (extAccess == requiredAccess) { - auto declAttr = decl->getAttrs().getAttribute(); - assert(declAttr && declAttr->getAccess() < requiredAccess && - "expect an explicitly specified access control level which is " - "less accessible than required."); - (void)declAttr; + assert(decl->getFormalAccess() < requiredAccess && + "witness is accessible?"); shouldUseDefaultAccess = true; } } @@ -4940,7 +4952,7 @@ void TypeChecker::checkConformancesInContext(DeclContext *dc, // Check all conformances. groupChecker.checkAllConformances(); - if (Context.LangOpts.DebugGenericSignatures) { + if (Context.TypeCheckerOpts.DebugGenericSignatures) { // Now that they're filled out, print out information about the conformances // here, when requested. for (auto conformance : conformances) { diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index 75214dcdae865..ffa58350ce96a 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -208,14 +208,14 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses( // because those have to be explicitly declared on the type somewhere // so won't be affected by whatever answer inference comes up with. auto selfTy = extension->getSelfInterfaceType(); - auto *tc = getASTContext().getLegacyGlobalTypeChecker(); for (const Requirement &reqt : extensionSig->getRequirements()) { switch (reqt.getKind()) { case RequirementKind::Conformance: case RequirementKind::Superclass: // FIXME: This is the wrong check if (selfTy->isEqual(reqt.getFirstType()) && - !tc->isSubtypeOf(conformance->getType(), reqt.getSecondType(), dc)) + !TypeChecker::isSubtypeOf(conformance->getType(), + reqt.getSecondType(), dc)) return false; break; diff --git a/lib/Sema/TypeCheckREPL.cpp b/lib/Sema/TypeCheckREPL.cpp index 0f45b17892870..cc76489d074d9 100644 --- a/lib/Sema/TypeCheckREPL.cpp +++ b/lib/Sema/TypeCheckREPL.cpp @@ -17,6 +17,7 @@ #include "TypeChecker.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/ASTWalker.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/Expr.h" #include "swift/AST/NameLookup.h" @@ -30,6 +31,36 @@ using namespace swift; namespace { + +/// Find available closure discriminators. +/// +/// The parser typically takes care of assigning unique discriminators to +/// closures, but the parser is unavailable to this transform. +class DiscriminatorFinder : public ASTWalker { + unsigned NextDiscriminator = 0; + +public: + Expr *walkToExprPost(Expr *E) override { + auto *ACE = dyn_cast(E); + if (!ACE) + return E; + + unsigned Discriminator = ACE->getDiscriminator(); + assert(Discriminator != AbstractClosureExpr::InvalidDiscriminator && + "Existing closures should have valid discriminators"); + if (Discriminator >= NextDiscriminator) + NextDiscriminator = Discriminator + 1; + return E; + } + + // Get the next available closure discriminator. + unsigned getNextDiscriminator() { + if (NextDiscriminator == AbstractClosureExpr::InvalidDiscriminator) + llvm::report_fatal_error("Out of valid closure discriminators"); + return NextDiscriminator++; + } +}; + struct REPLContext { ASTContext &Context; SourceFile &SF; @@ -182,14 +213,14 @@ struct PatternBindingPrintLHS : public ASTVisitor { namespace { class REPLChecker : public REPLContext { - TopLevelContext &TLC; + DiscriminatorFinder &DF; /// The index of the next response metavariable to bind to a REPL result. unsigned NextResponseVariableIndex = 0; public: - REPLChecker(SourceFile &SF, TopLevelContext &TLC) - : REPLContext(SF), TLC(TLC) {} + REPLChecker(SourceFile &SF, DiscriminatorFinder &DF) + : REPLContext(SF), DF(DF) {} void processREPLTopLevelExpr(Expr *E); void processREPLTopLevelPatternBinding(PatternBindingDecl *PBD); @@ -222,7 +253,7 @@ void REPLChecker::generatePrintOfExpression(StringRef NameStr, Expr *E) { Arg->setSpecifier(ParamSpecifier::Default); auto params = ParameterList::createWithoutLoc(Arg); - unsigned discriminator = TLC.claimNextClosureDiscriminator(); + unsigned discriminator = DF.getNextDiscriminator(); ClosureExpr *CE = new (Context) ClosureExpr(params, SourceLoc(), SourceLoc(), SourceLoc(), @@ -255,10 +286,8 @@ void REPLChecker::generatePrintOfExpression(StringRef NameStr, Expr *E) { BraceStmt *Body = builder.createBodyStmt(Loc, EndLoc); CE->setBody(Body, false); - // FIXME: Remove TypeChecker dependency. - auto &TC = *Context.getLegacyGlobalTypeChecker(); TypeChecker::typeCheckClosureBody(CE); - TC.ClosuresWithUncomputedCaptures.push_back(CE); + TypeChecker::computeCaptures(CE); auto *TheCall = CallExpr::createImplicit(Context, CE, { E }, { }); TheCall->getArg()->setType(AnyFunctionType::composeInput(Context, args, false)); @@ -431,13 +460,18 @@ Identifier REPLChecker::getNextResponseVariableName(DeclContext *DC) { /// processREPLTopLevel - This is called after we've parsed and typechecked some /// new decls at the top level. We inject code to print out expressions and /// pattern bindings the are evaluated. -void TypeChecker::processREPLTopLevel(SourceFile &SF, TopLevelContext &TLC, - unsigned FirstDecl) { +void TypeChecker::processREPLTopLevel(SourceFile &SF, unsigned FirstDecl) { + // Walk over all decls in the file to find the next available closure + // discriminator. + DiscriminatorFinder DF; + for (Decl *D : SF.Decls) + D->walk(DF); + // Move new declarations out. std::vector NewDecls(SF.Decls.begin()+FirstDecl, SF.Decls.end()); SF.Decls.resize(FirstDecl); - REPLChecker RC(SF, TLC); + REPLChecker RC(SF, DF); // Loop over each of the new decls, processing them, adding them back to // the Decls list. @@ -457,7 +491,7 @@ void TypeChecker::processREPLTopLevel(SourceFile &SF, TopLevelContext &TLC, if (auto *PBD = dyn_cast(D)) RC.processREPLTopLevelPatternBinding(PBD); - contextualizeTopLevelCode(TLC, TLCD); + TypeChecker::contextualizeTopLevelCode(TLCD); } SF.clearLookupCache(); diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 0ccb42c5a3e4d..941fb8c450d6d 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -178,13 +178,9 @@ namespace { class FunctionBodyTimer { AnyFunctionRef Function; llvm::TimeRecord StartTime = llvm::TimeRecord::getCurrentTime(); - unsigned WarnLimit; - bool ShouldDump; public: - FunctionBodyTimer(AnyFunctionRef Fn, bool shouldDump, - unsigned warnLimit) - : Function(Fn), WarnLimit(warnLimit), ShouldDump(shouldDump) {} + FunctionBodyTimer(AnyFunctionRef Fn) : Function(Fn) {} ~FunctionBodyTimer() { llvm::TimeRecord endTime = llvm::TimeRecord::getCurrentTime(false); @@ -195,7 +191,7 @@ namespace { ASTContext &ctx = Function.getAsDeclContext()->getASTContext(); auto *AFD = Function.getAbstractFunctionDecl(); - if (ShouldDump) { + if (ctx.TypeCheckerOpts.WarnLongFunctionBodies) { // Round up to the nearest 100th of a millisecond. llvm::errs() << llvm::format("%0.2f", ceil(elapsed * 100000) / 100) << "ms\t"; Function.getLoc().print(llvm::errs(), ctx.SourceMgr); @@ -210,6 +206,7 @@ namespace { llvm::errs() << "\n"; } + const auto WarnLimit = ctx.TypeCheckerOpts.DebugTimeFunctionBodies; if (WarnLimit != 0 && elapsedMS >= WarnLimit) { if (AFD) { ctx.Diags.diagnose(AFD, diag::debug_long_function_body, @@ -234,14 +231,14 @@ bool TypeChecker::contextualizeInitializer(Initializer *DC, Expr *E) { return CC.hasAutoClosures(); } -void TypeChecker::contextualizeTopLevelCode(TopLevelContext &TLC, - TopLevelCodeDecl *TLCD) { - unsigned nextDiscriminator = TLC.NextAutoClosureDiscriminator; +void TypeChecker::contextualizeTopLevelCode(TopLevelCodeDecl *TLCD) { + auto &Context = TLCD->DeclContext::getASTContext(); + unsigned nextDiscriminator = Context.NextAutoClosureDiscriminator; ContextualizeClosures CC(TLCD, nextDiscriminator); TLCD->getBody()->walk(CC); - assert(nextDiscriminator == TLC.NextAutoClosureDiscriminator && + assert(nextDiscriminator == Context.NextAutoClosureDiscriminator && "reentrant/concurrent invocation of contextualizeTopLevelCode?"); - TLC.NextAutoClosureDiscriminator = CC.NextDiscriminator; + Context.NextAutoClosureDiscriminator = CC.NextDiscriminator; } /// Emits an error with a fixit for the case of unnecessary cast over a @@ -1166,8 +1163,7 @@ class StmtChecker : public StmtVisitor { } assert(isa(initialCaseVarDecl->getParentPatternStmt())); - if (vd->getInterfaceType() && initialCaseVarDecl->getType() && - !initialCaseVarDecl->isInvalid() && + if (!initialCaseVarDecl->isInvalid() && !vd->getType()->isEqual(initialCaseVarDecl->getType())) { getASTContext().Diags.diagnose(vd->getLoc(), diag::type_mismatch_multiple_pattern_list, vd->getType(), initialCaseVarDecl->getType()); @@ -1283,9 +1279,6 @@ class StmtChecker : public StmtVisitor { } Stmt *visitSwitchStmt(SwitchStmt *switchStmt) { - // FIXME: Remove TypeChecker dependency. - auto &TC = *Ctx.getLegacyGlobalTypeChecker(); - // Type-check the subject expression. Expr *subjectExpr = switchStmt->getSubjectExpr(); auto resultTy = TypeChecker::typeCheckExpression(subjectExpr, DC); @@ -1424,7 +1417,8 @@ class StmtChecker : public StmtVisitor { } if (!switchStmt->isImplicit()) { - TC.checkSwitchExhaustiveness(switchStmt, DC, limitExhaustivityChecks); + TypeChecker::checkSwitchExhaustiveness(switchStmt, DC, + limitExhaustivityChecks); } return switchStmt; @@ -2112,9 +2106,9 @@ TypeCheckFunctionBodyUntilRequest::evaluate(Evaluator &evaluator, ctx.Stats->getFrontendCounters().NumFunctionsTypechecked++; Optional timer; - TypeChecker &tc = *ctx.getLegacyGlobalTypeChecker(); - if (tc.DebugTimeFunctionBodies || tc.WarnLongFunctionBodies) - timer.emplace(AFD, tc.DebugTimeFunctionBodies, tc.WarnLongFunctionBodies); + const auto &tyOpts = ctx.TypeCheckerOpts; + if (tyOpts.DebugTimeFunctionBodies || tyOpts.WarnLongFunctionBodies) + timer.emplace(AFD); BraceStmt *body = AFD->getBody(); if (!body || AFD->isBodyTypeChecked()) @@ -2206,11 +2200,10 @@ bool TypeChecker::typeCheckClosureBody(ClosureExpr *closure) { BraceStmt *body = closure->getBody(); - auto *TC = closure->getASTContext().getLegacyGlobalTypeChecker(); Optional timer; - if (TC->DebugTimeFunctionBodies || TC->WarnLongFunctionBodies) - timer.emplace(closure, TC->DebugTimeFunctionBodies, - TC->WarnLongFunctionBodies); + const auto &tyOpts = closure->getASTContext().TypeCheckerOpts; + if (tyOpts.DebugTimeFunctionBodies || tyOpts.WarnLongFunctionBodies) + timer.emplace(closure); bool HadError = StmtChecker(closure).typeCheckBody(body); if (body) { diff --git a/lib/Sema/TypeCheckSwitchStmt.cpp b/lib/Sema/TypeCheckSwitchStmt.cpp index 5f1b51f9ee806..0f09fc359c97b 100644 --- a/lib/Sema/TypeCheckSwitchStmt.cpp +++ b/lib/Sema/TypeCheckSwitchStmt.cpp @@ -885,16 +885,14 @@ namespace { }; ASTContext &Context; - unsigned CheckingThreshold; const SwitchStmt *Switch; const DeclContext *DC; APIntMap IntLiteralCache; llvm::DenseMap FloatLiteralCache; llvm::DenseMap StringLiteralCache; - SpaceEngine(ASTContext &C, unsigned Threashold, - const SwitchStmt *SS, const DeclContext *DC) - : Context(C), CheckingThreshold(Threashold), Switch(SS), DC(DC) {} + SpaceEngine(ASTContext &C, const SwitchStmt *SS, const DeclContext *DC) + : Context(C), Switch(SS), DC(DC) {} bool checkRedundantLiteral(const Pattern *Pat, Expr *&PrevPattern) { if (Pat->getKind() != PatternKind::Expr) { @@ -1010,7 +1008,8 @@ namespace { Space totalSpace = Space::forType(subjectType, Identifier()); Space coveredSpace = Space::forDisjunct(spaces); - unsigned minusCount = CheckingThreshold; + unsigned minusCount + = Context.TypeCheckerOpts.SwitchCheckingInvocationThreshold; auto diff = totalSpace.minus(coveredSpace, DC, &minusCount); if (!diff) { diagnoseMissingCases(RequiresDefault::SpaceTooLarge, Space(), @@ -1519,8 +1518,7 @@ namespace { void TypeChecker::checkSwitchExhaustiveness(const SwitchStmt *stmt, const DeclContext *DC, bool limited) { - SpaceEngine(Context, getSwitchCheckingInvocationThreshold(), stmt, DC) - .checkExhaustiveness(limited); + SpaceEngine(DC->getASTContext(), stmt, DC).checkExhaustiveness(limited); } void SpaceEngine::Space::dump() const { diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 63ad5da1b6cfd..bddddb31131ae 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -626,17 +626,107 @@ static bool isPointerToVoid(ASTContext &Ctx, Type Ty, bool &IsMutable) { return BGT->getGenericArgs().front()->isVoid(); } -Type TypeChecker::applyGenericArguments(Type type, - SourceLoc loc, - TypeResolution resolution, - GenericIdentTypeRepr *generic, - TypeResolutionOptions options) { +static Type checkConstrainedExtensionRequirements(Type type, + SourceLoc loc, + DeclContext *dc) { + // Even if the type is not generic, it might be inside of a generic + // context, so we need to check requirements. + GenericTypeDecl *decl; + Type parentTy; + if (auto *aliasTy = dyn_cast(type.getPointer())) { + decl = aliasTy->getDecl(); + parentTy = aliasTy->getParent(); + } else if (auto *nominalTy = type->getAs()) { + decl = nominalTy->getDecl(); + parentTy = nominalTy->getParent(); + } else { + return type; + } + + // FIXME: Some day the type might also have its own 'where' clause, even + // if its not generic. + + auto *ext = dyn_cast(decl->getDeclContext()); + if (!ext || !ext->isConstrainedExtension()) + return type; + + if (parentTy->hasUnboundGenericType() || + parentTy->hasTypeVariable()) { + return type; + } + + auto subMap = parentTy->getContextSubstitutions(ext); + + SourceLoc noteLoc = ext->getLoc(); + if (noteLoc.isInvalid()) + noteLoc = loc; + + auto genericSig = ext->getGenericSignature(); + auto result = + TypeChecker::checkGenericArguments( + dc, loc, noteLoc, type, + genericSig->getGenericParams(), + genericSig->getRequirements(), + QueryTypeSubstitutionMap{subMap}, + TypeChecker::LookUpConformance(dc), + None); + + switch (result) { + case RequirementCheckResult::Failure: + case RequirementCheckResult::SubstitutionFailure: + return ErrorType::get(dc->getASTContext()); + case RequirementCheckResult::Success: + return type; + } +} + +static void diagnoseUnboundGenericType(Type ty, SourceLoc loc); + +/// Apply generic arguments to the given type. +/// +/// If the type is itself not generic, this does nothing. +/// +/// This function emits diagnostics about an invalid type or the wrong number +/// of generic arguments, whereas applyUnboundGenericArguments requires this +/// to be in a correct and valid form. +/// +/// \param type The generic type to which to apply arguments. +/// \param resolution The type resolution to perform. +/// \param comp The arguments to apply with the angle bracket range for +/// diagnostics. +/// \param options The type resolution context. +/// +/// \returns A BoundGenericType bound to the given arguments, or null on +/// error. +/// +/// \see applyUnboundGenericArguments +static Type applyGenericArguments(Type type, + TypeResolution resolution, + ComponentIdentTypeRepr *comp, + TypeResolutionOptions options) { + auto dc = resolution.getDeclContext(); + auto loc = comp->getIdLoc(); + + auto *generic = dyn_cast(comp); + if (!generic) { + if (type->is() && + !options.is(TypeResolverContext::TypeAliasDecl) && + !options.contains(TypeResolutionFlags::AllowUnboundGenerics)) { + diagnoseUnboundGenericType(type, loc); + return ErrorType::get(type->getASTContext()); + } + + if (resolution.getStage() == TypeResolutionStage::Structural) + return type; + + return checkConstrainedExtensionRequirements(type, loc, dc); + } + if (type->hasError()) { generic->setInvalid(); return type; } - auto dc = resolution.getDeclContext(); auto &ctx = dc->getASTContext(); auto &diags = ctx.Diags; @@ -716,15 +806,14 @@ Type TypeChecker::applyGenericArguments(Type type, args.push_back(substTy); } - auto result = applyUnboundGenericArguments(unboundType, genericDecl, loc, - resolution, args); - if (!result) - return result; + auto result = TypeChecker::applyUnboundGenericArguments( + unboundType, genericDecl, loc, + resolution, args); if (!options.contains(TypeResolutionFlags::AllowUnavailable)) { if (options.isAnyExpr() || dc->getParent()->isLocalContext()) if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal) - diagnoseGenericTypeExportability(loc, result, dc); + TypeChecker::diagnoseGenericTypeExportability(loc, result, dc); } // Migration hack. @@ -908,41 +997,25 @@ static void maybeDiagnoseBadConformanceRef(DeclContext *dc, } /// Returns a valid type or ErrorType in case of an error. -static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, +static Type resolveTypeDecl(TypeDecl *typeDecl, DeclContext *foundDC, TypeResolution resolution, - GenericIdentTypeRepr *generic, + ComponentIdentTypeRepr *comp, TypeResolutionOptions options) { - // Resolve the type declaration to a specific type. How this occurs // depends on the current context and where the type was found. - Type type = TypeChecker::resolveTypeInContext(typeDecl, foundDC, resolution, - options, generic); - - if (type->is() && !generic && - !options.is(TypeResolverContext::TypeAliasDecl) && - !options.contains(TypeResolutionFlags::AllowUnboundGenerics)) { - diagnoseUnboundGenericType(type, loc); - return ErrorType::get(typeDecl->getASTContext()); - } + Type type = TypeChecker::resolveTypeInContext( + typeDecl, foundDC, resolution, options, + isa(comp)); if (type->hasError() && foundDC && (isa(typeDecl) || isa(typeDecl))) { auto fromDC = resolution.getDeclContext(); assert(fromDC && "No declaration context for type resolution?"); maybeDiagnoseBadConformanceRef(fromDC, foundDC->getDeclaredInterfaceType(), - loc, typeDecl); + comp->getIdLoc(), typeDecl); } - if (generic) { - // Apply the generic arguments to the type. - type = TypeChecker::applyGenericArguments(type, loc, resolution, generic, - options); - if (!type) - return nullptr; - } - - assert(type); - return type; + return applyGenericArguments(type, resolution, comp, options); } static std::string getDeclNameFromContext(DeclContext *dc, @@ -1217,9 +1290,8 @@ resolveTopLevelIdentTypeComponent(TypeResolution resolution, // that now. if (auto *typeDecl = comp->getBoundDecl()) { // Resolve the type declaration within this context. - return resolveTypeDecl(typeDecl, comp->getIdLoc(), - comp->getDeclContext(), resolution, - dyn_cast(comp), options); + return resolveTypeDecl(typeDecl, comp->getDeclContext(), resolution, + comp, options); } // Resolve the first component, which is the only one that requires @@ -1265,13 +1337,8 @@ resolveTopLevelIdentTypeComponent(TypeResolution resolution, auto *foundDC = entry.getDeclContext(); auto *typeDecl = cast(entry.getValueDecl()); - Type type = resolveTypeDecl(typeDecl, comp->getIdLoc(), - foundDC, resolution, - dyn_cast(comp), options); - - if (!type) - return type; - + Type type = resolveTypeDecl(typeDecl, foundDC, resolution, + comp, options); if (type->is()) return type; @@ -1355,23 +1422,6 @@ static Type resolveNestedIdentTypeComponent( auto &ctx = DC->getASTContext(); auto &diags = ctx.Diags; - auto maybeApplyGenericArgs = [&](Type memberType) { - // If there are generic arguments, apply them now. - if (auto genComp = dyn_cast(comp)) { - return TypeChecker::applyGenericArguments(memberType, comp->getIdLoc(), - resolution, genComp, options); - } - - if (memberType->is() && - !options.is(TypeResolverContext::TypeAliasDecl) && - !options.contains(TypeResolutionFlags::AllowUnboundGenerics)) { - diagnoseUnboundGenericType(memberType, comp->getLoc()); - return ErrorType::get(ctx); - } - - return memberType; - }; - auto maybeDiagnoseBadMemberType = [&](TypeDecl *member, Type memberType, AssociatedTypeDecl *inferredAssocType) { // Diagnose invalid cases. @@ -1406,22 +1456,17 @@ static Type resolveNestedIdentTypeComponent( // Diagnose a bad conformance reference if we need to. if (!options.contains(TypeResolutionFlags::SilenceErrors) && - inferredAssocType && memberType && memberType->hasError()) { + inferredAssocType && memberType->hasError()) { maybeDiagnoseBadConformanceRef(DC, parentTy, comp->getLoc(), inferredAssocType); } - // If we found a reference to an associated type or other member type that - // was marked invalid, just return ErrorType to silence downstream errors. - if (member->isInvalid()) - return ErrorType::get(ctx); - // At this point, we need to have resolved the type of the member. - if (!memberType || memberType->hasError()) + if (memberType->hasError()) return memberType; // If there are generic arguments, apply them now. - return maybeApplyGenericArgs(memberType); + return applyGenericArguments(memberType, resolution, comp, options); }; // Short-circuiting. @@ -1438,7 +1483,7 @@ static Type resolveNestedIdentTypeComponent( // type later on. if (!memberType->is() || memberType->castTo()->getAssocType()) { - return maybeApplyGenericArgs(memberType); + return applyGenericArguments(memberType, resolution, comp, options); } return memberType; @@ -2159,19 +2204,21 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, } } - // SWIFT_ENABLE_TENSORFLOW - DifferentiabilityKind diffkind = DifferentiabilityKind::NonDifferentiable; + if (attrs.has(TAK_differentiable) && + !Context.LangOpts.EnableExperimentalDifferentiableProgramming) { + diagnose(attrs.getLoc(TAK_differentiable), + diag::experimental_differentiable_programming_disabled); + } + + DifferentiabilityKind diffKind = DifferentiabilityKind::NonDifferentiable; if (attrs.has(TAK_differentiable)) { - diffkind = attrs.linear - ? DifferentiabilityKind::Linear - : DifferentiabilityKind::Normal; + diffKind = attrs.linear ? DifferentiabilityKind::Linear + : DifferentiabilityKind::Normal; } // Resolve the function type directly with these attributes. SILFunctionType::ExtInfo extInfo(rep, attrs.has(TAK_pseudogeneric), - // SWIFT_ENABLE_TENSORFLOW - attrs.has(TAK_noescape), - diffkind); + attrs.has(TAK_noescape), diffKind); ty = resolveSILFunctionType(fnRepr, options, coroutineKind, extInfo, calleeConvention, witnessMethodProtocol); @@ -2217,24 +2264,21 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, attrs.clearAttribute(TAK_autoclosure); } - // SWIFT_ENABLE_TENSORFLOW - DifferentiabilityKind diffkind = DifferentiabilityKind::NonDifferentiable; + if (attrs.has(TAK_differentiable) && + !Context.LangOpts.EnableExperimentalDifferentiableProgramming) { + diagnose(attrs.getLoc(TAK_differentiable), + diag::experimental_differentiable_programming_disabled); + } + + DifferentiabilityKind diffKind = DifferentiabilityKind::NonDifferentiable; if (attrs.has(TAK_differentiable)) { - if(!Context.LangOpts.EnableExperimentalDifferentiableProgramming) { - diagnose(attrs.getLoc(TAK_differentiable), - diag::experimental_differentiable_programming_disabled); - } else { - diffkind = attrs.linear - ? DifferentiabilityKind::Linear - : DifferentiabilityKind::Normal; - } + diffKind = attrs.linear ? DifferentiabilityKind::Linear + : DifferentiabilityKind::Normal; } // Resolve the function type directly with these attributes. - FunctionType::ExtInfo extInfo(rep, /*noescape=*/false, - // SWIFT_ENABLE_TENSORFLOW - fnRepr->throws(), - diffkind); + FunctionType::ExtInfo extInfo(rep, /*noescape=*/false, fnRepr->throws(), + diffKind); ty = resolveASTFunctionType(fnRepr, options, extInfo); if (!ty || ty->hasError()) @@ -2659,26 +2703,11 @@ Type TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, auto argTy = resolveType(repr->getGenericArguments()[i], options); genericArgMap.insert({params[i], argTy->getCanonicalType()}); } - - bool ok = true; + subMap = SubstitutionMap::get( genericSig, QueryTypeSubstitutionMap{genericArgMap}, - [&](CanType depTy, Type replacement, ProtocolDecl *proto) - -> ProtocolConformanceRef { - auto result = TypeChecker::conformsToProtocol( - replacement, proto, DC, - ConformanceCheckOptions()); - if (result.isInvalid()) { - ok = false; - return ProtocolConformanceRef(proto); - } - - return result; - }); - - if (!ok) - return ErrorType::get(Context); + TypeChecker::LookUpConformance(DC)); } auto layout = SILLayout::get(Context, genericSig, fields); diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 7c671c6c934ff..cac59416f76cf 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -55,17 +55,12 @@ using namespace swift; TypeChecker &TypeChecker::createForContext(ASTContext &ctx) { assert(!ctx.getLegacyGlobalTypeChecker() && "Cannot install more than one instance of the global type checker!"); - auto *TC = new TypeChecker(ctx); + auto *TC = new TypeChecker(); ctx.installGlobalTypeChecker(TC); ctx.addCleanup([=](){ delete TC; }); return *ctx.getLegacyGlobalTypeChecker(); } -TypeChecker::TypeChecker(ASTContext &Ctx) - : Context(Ctx) {} - -TypeChecker::~TypeChecker() {} - ProtocolDecl *TypeChecker::getProtocol(ASTContext &Context, SourceLoc loc, KnownProtocolKind kind) { auto protocol = Context.getProtocol(kind); @@ -294,7 +289,6 @@ static void bindExtensions(SourceFile &SF) { static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC) { unsigned currentFunctionIdx = 0; - unsigned currentSynthesizedDecl = SF.LastCheckedSynthesizedDecl; do { // Type check the body of each of the function in turn. Note that outside // functions must be visited before nested functions for type-checking to @@ -306,20 +300,7 @@ static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC) TypeChecker::typeCheckAbstractFunctionBody(AFD); } - - // Type check synthesized functions and their bodies. - for (unsigned n = SF.SynthesizedDecls.size(); - currentSynthesizedDecl != n; - ++currentSynthesizedDecl) { - auto decl = SF.SynthesizedDecls[currentSynthesizedDecl]; - TypeChecker::typeCheckDecl(decl); - } - - } while (currentFunctionIdx < TC.definedFunctions.size() || - currentSynthesizedDecl < SF.SynthesizedDecls.size()); - - // FIXME: Horrible hack. Store this somewhere more appropriate. - SF.LastCheckedSynthesizedDecl = currentSynthesizedDecl; + } while (currentFunctionIdx < TC.definedFunctions.size()); // Compute captures for functions and closures we visited. for (auto *closure : TC.ClosuresWithUncomputedCaptures) { @@ -342,19 +323,7 @@ static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC) TC.definedFunctions.clear(); } -void swift::typeCheckExternalDefinitions(SourceFile &SF) { - assert(SF.ASTStage == SourceFile::TypeChecked); - auto &Ctx = SF.getASTContext(); - typeCheckFunctionsAndExternalDecls(SF, createTypeChecker(Ctx)); -} - -void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, - OptionSet Options, - unsigned StartElem, - unsigned WarnLongFunctionBodies, - unsigned WarnLongExpressionTypeChecking, - unsigned ExpressionTimeoutThreshold, - unsigned SwitchCheckingInvocationThreshold) { +void swift::performTypeChecking(SourceFile &SF, unsigned StartElem) { if (SF.ASTStage == SourceFile::TypeChecked) return; @@ -362,12 +331,11 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, // because type-checking expressions mutates the AST and that throws off the // scope-based lookups. Only the top-level scopes because extensions have not // been bound yet. - if (SF.getASTContext().LangOpts.EnableASTScopeLookup && - SF.isSuitableForASTScopes()) + auto &Ctx = SF.getASTContext(); + if (Ctx.LangOpts.EnableASTScopeLookup && SF.isSuitableForASTScopes()) SF.getScope() .buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); - auto &Ctx = SF.getASTContext(); BufferIndirectlyCausingDiagnosticRAII cpr(SF); // Make sure we have a type checker. @@ -380,36 +348,14 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, // Could build scope maps here because the AST is stable now. { - SharedTimer timer("Type checking and Semantic analysis"); - - TC.setWarnLongFunctionBodies(WarnLongFunctionBodies); - TC.setWarnLongExpressionTypeChecking(WarnLongExpressionTypeChecking); - if (ExpressionTimeoutThreshold != 0) - TC.setExpressionTimeoutThreshold(ExpressionTimeoutThreshold); - - if (SwitchCheckingInvocationThreshold != 0) - TC.setSwitchCheckingInvocationThreshold( - SwitchCheckingInvocationThreshold); + FrontendStatsTracer tracer(Ctx.Stats, "Type checking and Semantic analysis"); - if (Options.contains(TypeCheckingFlags::DebugTimeFunctionBodies)) - TC.enableDebugTimeFunctionBodies(); - - if (Options.contains(TypeCheckingFlags::DebugTimeExpressions)) - TC.enableDebugTimeExpressions(); - - if (Options.contains(TypeCheckingFlags::ForImmediateMode)) - TC.setInImmediateMode(true); - - if (Options.contains(TypeCheckingFlags::SkipNonInlinableFunctionBodies)) + if (Ctx.TypeCheckerOpts.SkipNonInlinableFunctionBodies) // Disable this optimization if we're compiling SwiftOnoneSupport, because // we _definitely_ need to look inside every declaration to figure out // what gets prespecialized. - if (!SF.getParentModule()->isOnoneSupportModule()) - TC.setSkipNonInlinableBodies(true); - - // Lookup the swift module. This ensures that we record all known - // protocols in the AST. - (void) TC.getStdlibModule(&SF); + if (SF.getParentModule()->isOnoneSupportModule()) + Ctx.TypeCheckerOpts.SkipNonInlinableFunctionBodies = false; if (!Ctx.LangOpts.DisableAvailabilityChecking) { // Build the type refinement hierarchy for the primary @@ -420,14 +366,14 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, // Resolve extensions. This has to occur first during type checking, // because the extensions need to be wired into the AST for name lookup // to work. - bindExtensions(SF); + ::bindExtensions(SF); // Type check the top-level elements of the source file. for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) { if (auto *TLCD = dyn_cast(D)) { // Immediately perform global name-binding etc. TypeChecker::typeCheckTopLevelCodeDecl(TLCD); - TypeChecker::contextualizeTopLevelCode(TLC, TLCD); + TypeChecker::contextualizeTopLevelCode(TLCD); } else { TypeChecker::typeCheckDecl(D); } @@ -436,13 +382,13 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, // If we're in REPL mode, inject temporary result variables and other stuff // that the REPL needs to synthesize. if (SF.Kind == SourceFileKind::REPL && !Ctx.hadError()) - TypeChecker::processREPLTopLevel(SF, TLC, StartElem); + TypeChecker::processREPLTopLevel(SF, StartElem); typeCheckFunctionsAndExternalDecls(SF, TC); } // Checking that benefits from having the whole module available. - if (!(Options & TypeCheckingFlags::DelayWholeModuleChecking)) { + if (!Ctx.TypeCheckerOpts.DelayWholeModuleChecking) { performWholeModuleTypeChecking(SF); } @@ -450,7 +396,7 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, SF.ASTStage = SourceFile::TypeChecked; { - SharedTimer timer("AST verification"); + FrontendStatsTracer tracer(Ctx.Stats, "AST verification"); // Verify the SourceFile. verify(SF); @@ -465,7 +411,7 @@ void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC, // been cached, it will never be added to the ASTContext. The solution is to // skip verification and avoid caching it. #ifndef NDEBUG - if (!(Options & TypeCheckingFlags::DelayWholeModuleChecking) && + if (!Ctx.TypeCheckerOpts.DelayWholeModuleChecking && SF.Kind != SourceFileKind::REPL && SF.Kind != SourceFileKind::SIL && !Ctx.LangOpts.DebuggerSupport) { @@ -615,9 +561,28 @@ bool swift::performTypeLocChecking(ASTContext &Ctx, TypeLoc &T, /// Expose TypeChecker's handling of GenericParamList to SIL parsing. GenericEnvironment * -swift::handleSILGenericParams(ASTContext &Ctx, GenericParamList *genericParams, +swift::handleSILGenericParams(GenericParamList *genericParams, DeclContext *DC) { - return TypeChecker::handleSILGenericParams(genericParams, DC); + if (genericParams == nullptr) + return nullptr; + + SmallVector nestedList; + for (; genericParams; genericParams = genericParams->getOuterParameters()) { + nestedList.push_back(genericParams); + } + + std::reverse(nestedList.begin(), nestedList.end()); + + for (unsigned i = 0, e = nestedList.size(); i < e; ++i) { + auto genericParams = nestedList[i]; + genericParams->setDepth(i); + } + + auto sig = + TypeChecker::checkGenericSignature(nestedList.back(), DC, + /*parentSig=*/nullptr, + /*allowConcreteGenericParams=*/true); + return (sig ? sig->getGenericEnvironment() : nullptr); } void swift::typeCheckPatternBinding(PatternBindingDecl *PBD, @@ -733,7 +698,7 @@ TypeChecker &swift::createTypeChecker(ASTContext &Ctx) { } void TypeChecker::checkForForbiddenPrefix(ASTContext &C, DeclBaseName Name) { - if (C.LangOpts.DebugForbidTypecheckPrefix.empty()) + if (C.TypeCheckerOpts.DebugForbidTypecheckPrefix.empty()) return; // Don't touch special names or empty names. @@ -741,7 +706,7 @@ void TypeChecker::checkForForbiddenPrefix(ASTContext &C, DeclBaseName Name) { return; StringRef Str = Name.getIdentifier().str(); - if (Str.startswith(C.LangOpts.DebugForbidTypecheckPrefix)) { + if (Str.startswith(C.TypeCheckerOpts.DebugForbidTypecheckPrefix)) { std::string Msg = "forbidden typecheck occurred: "; Msg += Str; llvm::report_fatal_error(Msg); @@ -761,3 +726,7 @@ TypeChecker::getDeclTypeCheckingSemantics(ValueDecl *decl) { } return DeclTypeCheckingSemantics::Normal; } + +void swift::bindExtensions(SourceFile &SF) { + ::bindExtensions(SF); +} diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index b94501da3f216..5d2c3a37cd590 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -38,7 +38,6 @@ namespace swift { class GenericSignatureBuilder; class NominalTypeDecl; class NormalProtocolConformance; -class TopLevelContext; class TypeChecker; class TypeResolution; class TypeResolutionOptions; @@ -51,6 +50,7 @@ namespace constraints { enum class SolutionKind : char; class ConstraintSystem; class Solution; + class SolutionResult; } /// A mapping from substitutable types to the protocol-conformance @@ -76,81 +76,6 @@ enum class DeclTypeCheckingSemantics { OpenExistential, }; -/// The result of name lookup. -class LookupResult { -private: - /// The set of results found. - SmallVector Results; - size_t IndexOfFirstOuterResult = 0; - -public: - LookupResult() {} - - explicit LookupResult(const SmallVectorImpl &Results, - size_t indexOfFirstOuterResult) - : Results(Results.begin(), Results.end()), - IndexOfFirstOuterResult(indexOfFirstOuterResult) {} - - using iterator = SmallVectorImpl::iterator; - iterator begin() { return Results.begin(); } - iterator end() { - return Results.begin() + IndexOfFirstOuterResult; - } - unsigned size() const { return innerResults().size(); } - bool empty() const { return innerResults().empty(); } - - ArrayRef innerResults() const { - return llvm::makeArrayRef(Results).take_front(IndexOfFirstOuterResult); - } - - ArrayRef outerResults() const { - return llvm::makeArrayRef(Results).drop_front(IndexOfFirstOuterResult); - } - - const LookupResultEntry& operator[](unsigned index) const { - return Results[index]; - } - - LookupResultEntry front() const { return innerResults().front(); } - LookupResultEntry back() const { return innerResults().back(); } - - /// Add a result to the set of results. - void add(LookupResultEntry result, bool isOuter) { - Results.push_back(result); - if (!isOuter) { - IndexOfFirstOuterResult++; - assert(IndexOfFirstOuterResult == Results.size() && - "found an outer result before an inner one"); - } else { - assert(IndexOfFirstOuterResult > 0 && - "found outer results without an inner one"); - } - } - - void clear() { Results.clear(); } - - /// Determine whether the result set is nonempty. - explicit operator bool() const { - return !empty(); - } - - TypeDecl *getSingleTypeResult() const { - if (size() != 1) - return nullptr; - - return dyn_cast(front().getValueDecl()); - } - - /// Filter out any results that aren't accepted by the given predicate. - void - filter(llvm::function_ref pred); - - /// Shift down results by dropping inner results while keeping outer - /// results (if any), the innermost of which are recogized as inner - /// results afterwards. - void shiftDownResults(); -}; - /// An individual result of a name lookup for a type. struct LookupTypeResultEntry { TypeDecl *Member; @@ -542,53 +467,10 @@ class TypeChecker final { std::vector ClosuresWithUncomputedCaptures; private: - ASTContext &Context; - - /// If non-zero, warn when a function body takes longer than this many - /// milliseconds to type-check. - /// - /// Intended for debugging purposes only. - unsigned WarnLongFunctionBodies = 0; - - /// If non-zero, warn when type-checking an expression takes longer - /// than this many milliseconds. - /// - /// Intended for debugging purposes only. - unsigned WarnLongExpressionTypeChecking = 0; - - /// If non-zero, abort the expression type checker if it takes more - /// than this many seconds. - unsigned ExpressionTimeoutThreshold = 600; + TypeChecker() = default; + ~TypeChecker() = default; - /// If non-zero, abort the switch statement exhaustiveness checker if - /// the Space::minus function is called more than this many times. - /// - /// Why this number? Times out in about a second on a 2017 iMac, Retina 5K, - // 4.2 GHz Intel Core i7. - // (It's arbitrary, but will keep the compiler from taking too much time.) - unsigned SwitchCheckingInvocationThreshold = 200000; - - /// If true, the time it takes to type-check each function will be dumped - /// to llvm::errs(). - bool DebugTimeFunctionBodies = false; - - /// If true, the time it takes to type-check each expression will be - /// dumped to llvm::errs(). - bool DebugTimeExpressions = false; - - /// Indicate that the type checker is checking code that will be - /// immediately executed. This will suppress certain warnings - /// when executing scripts. - bool InImmediateMode = false; - - /// Indicate that the type checker should skip type-checking non-inlinable - /// function bodies. - bool SkipNonInlinableFunctionBodies = false; - - TypeChecker(ASTContext &Ctx); friend class ASTContext; - friend class constraints::ConstraintSystem; - friend class TypeCheckFunctionBodyUntilRequest; public: /// Create a new type checker instance for the given ASTContext, if it @@ -600,93 +482,6 @@ class TypeChecker final { public: TypeChecker(const TypeChecker&) = delete; TypeChecker& operator=(const TypeChecker&) = delete; - ~TypeChecker(); - - LangOptions &getLangOpts() const { return Context.LangOpts; } - - /// Dump the time it takes to type-check each function to llvm::errs(). - void enableDebugTimeFunctionBodies() { - DebugTimeFunctionBodies = true; - } - - /// Dump the time it takes to type-check each function to llvm::errs(). - void enableDebugTimeExpressions() { - DebugTimeExpressions = true; - } - - bool getDebugTimeExpressions() { - return DebugTimeExpressions; - } - - /// If \p timeInMS is non-zero, warn when a function body takes longer than - /// this many milliseconds to type-check. - /// - /// Intended for debugging purposes only. - void setWarnLongFunctionBodies(unsigned timeInMS) { - WarnLongFunctionBodies = timeInMS; - } - - /// If \p timeInMS is non-zero, warn when type-checking an expression - /// takes longer than this many milliseconds. - /// - /// Intended for debugging purposes only. - void setWarnLongExpressionTypeChecking(unsigned timeInMS) { - WarnLongExpressionTypeChecking = timeInMS; - } - - /// Return the current setting for the number of milliseconds - /// threshold we use to determine whether to warn about an - /// expression taking a long time. - unsigned getWarnLongExpressionTypeChecking() { - return WarnLongExpressionTypeChecking; - } - - /// Set the threshold that determines the upper bound for the number - /// of seconds we'll let the expression type checker run before - /// considering an expression "too complex". - void setExpressionTimeoutThreshold(unsigned timeInSeconds) { - ExpressionTimeoutThreshold = timeInSeconds; - } - - /// Return the current setting for the threshold that determines - /// the upper bound for the number of seconds we'll let the - /// expression type checker run before considering an expression - /// "too complex". - /// If zero, do not limit the checking. - unsigned getExpressionTimeoutThresholdInSeconds() { - return ExpressionTimeoutThreshold; - } - - /// Get the threshold that determines the upper bound for the number - /// of times we'll let the Space::minus routine run before - /// considering a switch statement "too complex". - /// If zero, do not limit the checking. - unsigned getSwitchCheckingInvocationThreshold() const { - return SwitchCheckingInvocationThreshold; - } - - /// Set the threshold that determines the upper bound for the number - /// of times we'll let the Space::minus routine run before - /// considering a switch statement "too complex". - void setSwitchCheckingInvocationThreshold(unsigned invocationCount) { - SwitchCheckingInvocationThreshold = invocationCount; - } - - void setSkipNonInlinableBodies(bool skip) { - SkipNonInlinableFunctionBodies = skip; - } - - bool canSkipNonInlinableBodies() const { - return SkipNonInlinableFunctionBodies; - } - - bool getInImmediateMode() { - return InImmediateMode; - } - - void setInImmediateMode(bool InImmediateMode) { - this->InImmediateMode = InImmediateMode; - } static Type getArraySliceType(SourceLoc loc, Type elementType); static Type getDictionaryType(SourceLoc loc, Type keyType, Type valueType); @@ -743,10 +538,6 @@ class TypeChecker final { static void checkUnsupportedProtocolType(ASTContext &ctx, GenericParamList *genericParams); - /// Expose TypeChecker's handling of GenericParamList to SIL parsing. - static GenericEnvironment * - handleSILGenericParams(GenericParamList *genericParams, DeclContext *DC); - /// Resolve a reference to the given type declaration within a particular /// context. /// @@ -765,28 +556,6 @@ class TypeChecker final { TypeResolutionOptions options, bool isSpecialized); - /// Apply generic arguments to the given type. - /// - /// This function emits diagnostics about an invalid type or the wrong number - /// of generic arguments, whereas applyUnboundGenericArguments requires this - /// to be in a correct and valid form. - /// - /// \param type The generic type to which to apply arguments. - /// \param loc The source location for diagnostic reporting. - /// \param resolution The type resolution to perform. - /// \param generic The arguments to apply with the angle bracket range for - /// diagnostics. - /// \param options The type resolution context. - /// - /// \returns A BoundGenericType bound to the given arguments, or null on - /// error. - /// - /// \see applyUnboundGenericArguments - static Type applyGenericArguments(Type type, SourceLoc loc, - TypeResolution resolution, - GenericIdentTypeRepr *generic, - TypeResolutionOptions options); - /// Apply generic arguments to the given type. /// /// This function requires a valid unbound generic type with the correct @@ -953,8 +722,7 @@ class TypeChecker final { static void typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD); - static void processREPLTopLevel(SourceFile &SF, TopLevelContext &TLC, - unsigned StartElem); + static void processREPLTopLevel(SourceFile &SF, unsigned StartElem); static void typeCheckDecl(Decl *D); @@ -1055,24 +823,17 @@ class TypeChecker final { /// struct or class. static void addImplicitConstructors(NominalTypeDecl *typeDecl); - /// \name Name lookup - /// - /// Routines that perform name lookup. - /// - /// During type checking, these routines should be used instead of - /// \c MemberLookup and \c UnqualifiedLookup, because these routines will - /// lazily introduce declarations and (FIXME: eventually) perform recursive - /// type-checking that the AST-level lookup routines don't. - /// - /// @{ -private: - Optional boolType; - public: /// Fold the given sequence expression into an (unchecked) expression /// tree. static Expr *foldSequence(SequenceExpr *expr, DeclContext *dc); +private: + /// Given an pre-folded expression, find LHS from the expression if a binary + /// operator \c name appended to the expression. + static Expr *findLHS(DeclContext *DC, Expr *E, Identifier name); + +public: /// Type check the given expression. /// /// \param expr The expression to type-check, which will be modified in @@ -1184,7 +945,7 @@ class TypeChecker final { /// /// TODO(TF-736): In the future, we may want to infer more precise type /// based on the shape of the quoted declaration. - Type getTypeOfQuoteDecl(SourceLoc loc); + Type getTypeOfQuoteDecl(ASTContext &ctx, SourceLoc loc); private: Type typeCheckExpressionImpl(Expr *&expr, DeclContext *dc, @@ -1254,8 +1015,9 @@ class TypeChecker final { /// \param limitChecking The checking process relies on the switch statement /// being well-formed. If it is not, pass true to this flag to run a limited /// form of analysis. - void checkSwitchExhaustiveness(const SwitchStmt *stmt, const DeclContext *DC, - bool limitChecking); + static void checkSwitchExhaustiveness(const SwitchStmt *stmt, + const DeclContext *DC, + bool limitChecking); /// Type check the given expression as a condition, which converts /// it to a logic value. @@ -1369,8 +1131,7 @@ class TypeChecker final { /// /// \returns true if any closures were found static bool contextualizeInitializer(Initializer *DC, Expr *init); - static void contextualizeTopLevelCode(TopLevelContext &TLC, - TopLevelCodeDecl *TLCD); + static void contextualizeTopLevelCode(TopLevelCodeDecl *TLCD); /// Return the type-of-reference of the given value. /// @@ -1534,6 +1295,12 @@ class TypeChecker final { static Type deriveTypeWitness(DeclContext *DC, NominalTypeDecl *nominal, AssociatedTypeDecl *assocType); + /// \name Name lookup + /// + /// Routines that perform name lookup. + /// + /// @{ + /// Perform unqualified name lookup at the given source location /// within a particular declaration context. /// @@ -1570,10 +1337,6 @@ class TypeChecker final { NameLookupOptions options = defaultMemberLookupOptions); - /// Check whether the given declaration can be written as a - /// member of the given base type. - static bool isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl); - /// Look up a member type within the given type. /// /// This routine looks for member types with the given name within the @@ -1610,9 +1373,9 @@ class TypeChecker final { Identifier name, SourceLoc nameLoc); - /// Given an pre-folded expression, find LHS from the expression if a binary - /// operator \c name appended to the expression. - static Expr *findLHS(DeclContext *DC, Expr *E, Identifier name); + /// Check whether the given declaration can be written as a + /// member of the given base type. + static bool isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl); /// @} diff --git a/lib/Serialization/BCReadingExtras.h b/lib/Serialization/BCReadingExtras.h index 1ef3e8e33ad8e..928a2cb82580b 100644 --- a/lib/Serialization/BCReadingExtras.h +++ b/lib/Serialization/BCReadingExtras.h @@ -13,7 +13,7 @@ #ifndef SWIFT_SERIALIZATION_BCREADINGEXTRAS_H #define SWIFT_SERIALIZATION_BCREADINGEXTRAS_H -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" namespace swift { namespace serialization { @@ -38,7 +38,8 @@ class BCOffsetRAII { ~BCOffsetRAII() { if (Cursor) - Cursor->JumpToBit(Offset); + cantFail(Cursor->JumpToBit(Offset), + "BCOffsetRAII must be able to go back"); } }; diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt index f569669e05960..44a2a90660bdf 100644 --- a/lib/Serialization/CMakeLists.txt +++ b/lib/Serialization/CMakeLists.txt @@ -6,7 +6,11 @@ add_swift_host_library(swiftSerialization STATIC SerializedModuleLoader.cpp SerializedSILLoader.cpp SerializeDoc.cpp - SerializeSIL.cpp) + SerializeSIL.cpp + + LLVM_LINK_COMPONENTS + BitstreamReader + ) target_link_libraries(swiftSerialization PRIVATE swiftClangImporter) diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index d0fe3b3c5325f..77a3da3633446 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -15,6 +15,7 @@ #include "ModuleFile.h" #include "ModuleFormat.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/AutoDiff.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/Expr.h" #include "swift/AST/ForeignErrorConvention.h" @@ -138,13 +139,13 @@ void ExtensionError::anchor() {} /// Skips a single record in the bitstream. /// -/// Returns true if the next entry is a record of type \p recordKind. /// Destroys the stream position if the next entry is not a record. static void skipRecord(llvm::BitstreamCursor &cursor, unsigned recordKind) { - auto next = cursor.advance(AF_DontPopBlockAtEnd); + auto next = llvm::cantFail( + cursor.advance(AF_DontPopBlockAtEnd)); assert(next.Kind == llvm::BitstreamEntry::Record); - unsigned kind = cursor.skipRecord(next.ID); + unsigned kind = llvm::cantFail(cursor.skipRecord(next.ID)); assert(kind == recordKind); (void)kind; } @@ -226,8 +227,10 @@ ParameterList *ModuleFile::readParameterList() { using namespace decls_block; SmallVector scratch; - auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); - unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch); + llvm::BitstreamEntry entry = + fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); + unsigned recordID = + fatalIfUnexpected(DeclTypeCursor.readRecord(entry.ID, scratch)); assert(recordID == PARAMETERLIST); (void) recordID; @@ -259,7 +262,8 @@ Expected ModuleFile::readPattern(DeclContext *owningDC) { SmallVector scratch; BCOffsetRAII restoreOffset(DeclTypeCursor); - auto next = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry next = + fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (next.Kind != llvm::BitstreamEntry::Record) fatal(); @@ -271,7 +275,8 @@ Expected ModuleFile::readPattern(DeclContext *owningDC) { pattern->setType(type); }; - unsigned kind = DeclTypeCursor.readRecord(next.ID, scratch); + unsigned kind = + fatalIfUnexpected(DeclTypeCursor.readRecord(next.ID, scratch)); switch (kind) { case decls_block::PAREN_PATTERN: { bool isImplicit; @@ -302,10 +307,10 @@ Expected ModuleFile::readPattern(DeclContext *owningDC) { SmallVector elements; for ( ; count > 0; --count) { scratch.clear(); - next = DeclTypeCursor.advance(); + next = fatalIfUnexpected(DeclTypeCursor.advance()); assert(next.Kind == llvm::BitstreamEntry::Record); - kind = DeclTypeCursor.readRecord(next.ID, scratch); + kind = fatalIfUnexpected(DeclTypeCursor.readRecord(next.ID, scratch)); assert(kind == decls_block::TUPLE_PATTERN_ELT); // FIXME: Add something for this record or remove it. @@ -397,10 +402,11 @@ SILLayout *ModuleFile::readSILLayout(llvm::BitstreamCursor &Cursor) { SmallVector scratch; - auto next = Cursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry next = + fatalIfUnexpected(Cursor.advance(AF_DontPopBlockAtEnd)); assert(next.Kind == llvm::BitstreamEntry::Record); - unsigned kind = Cursor.readRecord(next.ID, scratch); + unsigned kind = fatalIfUnexpected(Cursor.readRecord(next.ID, scratch)); switch (kind) { case decls_block::SIL_LAYOUT: { GenericSignatureID rawGenericSig; @@ -444,13 +450,14 @@ ModuleFile::readConformanceChecked(llvm::BitstreamCursor &Cursor, SmallVector scratch; - auto next = Cursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry next = + fatalIfUnexpected(Cursor.advance(AF_DontPopBlockAtEnd)); assert(next.Kind == llvm::BitstreamEntry::Record); if (getContext().Stats) getContext().Stats->getFrontendCounters().NumConformancesDeserialized++; - unsigned kind = Cursor.readRecord(next.ID, scratch); + unsigned kind = fatalIfUnexpected(Cursor.readRecord(next.ID, scratch)); switch (kind) { case INVALID_PROTOCOL_CONFORMANCE: { return ProtocolConformanceRef::forInvalid(); @@ -591,8 +598,8 @@ NormalProtocolConformance *ModuleFile::readNormalConformance( // Find the conformance record. BCOffsetRAII restoreOffset(DeclTypeCursor); - DeclTypeCursor.JumpToBit(conformanceEntry); - auto entry = DeclTypeCursor.advance(); + fatalIfNotSuccess(DeclTypeCursor.JumpToBit(conformanceEntry)); + llvm::BitstreamEntry entry = fatalIfUnexpected(DeclTypeCursor.advance()); if (entry.Kind != llvm::BitstreamEntry::Record) fatal(); @@ -602,9 +609,11 @@ NormalProtocolConformance *ModuleFile::readNormalConformance( ArrayRef rawIDs; SmallVector scratch; - unsigned kind = DeclTypeCursor.readRecord(entry.ID, scratch); + unsigned kind = + fatalIfUnexpected(DeclTypeCursor.readRecord(entry.ID, scratch)); if (kind != NORMAL_PROTOCOL_CONFORMANCE) fatal(); + NormalProtocolConformanceLayout::readRecord(scratch, protoID, contextID, typeCount, valueCount, conformanceCount, @@ -651,11 +660,13 @@ GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC) { SmallVector scratch; StringRef blobData; - auto next = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry next = + fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (next.Kind != llvm::BitstreamEntry::Record) return nullptr; - unsigned kind = DeclTypeCursor.readRecord(next.ID, scratch, &blobData); + unsigned kind = + fatalIfUnexpected(DeclTypeCursor.readRecord(next.ID, scratch, &blobData)); if (kind != GENERIC_PARAM_LIST) return nullptr; lastRecordOffset.reset(); @@ -700,12 +711,14 @@ llvm::Error ModuleFile::readGenericRequirementsChecked( lastRecordOffset.reset(); bool shouldContinue = true; - auto entry = Cursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry entry = + fatalIfUnexpected(Cursor.advance(AF_DontPopBlockAtEnd)); if (entry.Kind != llvm::BitstreamEntry::Record) break; scratch.clear(); - unsigned recordID = Cursor.readRecord(entry.ID, scratch, &blobData); + unsigned recordID = fatalIfUnexpected( + Cursor.readRecord(entry.ID, scratch, &blobData)); switch (recordID) { case GENERIC_REQUIREMENT: { uint8_t rawKind; @@ -829,29 +842,36 @@ llvm::Error ModuleFile::readGenericRequirementsChecked( } /// Advances past any records that might be part of a requirement signature. -static void skipGenericRequirements(llvm::BitstreamCursor &Cursor) { +static llvm::Error skipGenericRequirements(llvm::BitstreamCursor &Cursor) { using namespace decls_block; BCOffsetRAII lastRecordOffset(Cursor); while (true) { - auto entry = Cursor.advance(AF_DontPopBlockAtEnd); + Expected maybeEntry = + Cursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + return maybeEntry.takeError(); + llvm::BitstreamEntry entry = maybeEntry.get(); if (entry.Kind != llvm::BitstreamEntry::Record) break; - unsigned recordID = Cursor.skipRecord(entry.ID); - switch (recordID) { + Expected maybeRecordID = Cursor.skipRecord(entry.ID); + if (!maybeRecordID) + return maybeRecordID.takeError(); + switch (maybeRecordID.get()) { case GENERIC_REQUIREMENT: case LAYOUT_REQUIREMENT: break; default: // This record is not a generic requirement. - return; + return llvm::Error::success(); } lastRecordOffset.reset(); } + return llvm::Error::success(); } GenericSignature ModuleFile::getGenericSignature( @@ -879,18 +899,20 @@ ModuleFile::getGenericSignatureChecked(serialization::GenericSignatureID ID) { // Read the generic signature. BCOffsetRAII restoreOffset(DeclTypeCursor); - DeclTypeCursor.JumpToBit(sigOffset); + fatalIfNotSuccess(DeclTypeCursor.JumpToBit(sigOffset)); // Read the parameter types. SmallVector paramTypes; StringRef blobData; SmallVector scratch; - auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry entry = + fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (entry.Kind != llvm::BitstreamEntry::Record) fatal(); - unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData); + unsigned recordID = fatalIfUnexpected( + DeclTypeCursor.readRecord(entry.ID, scratch, &blobData)); switch (recordID) { case GENERIC_SIGNATURE: { ArrayRef rawParamIDs; @@ -902,6 +924,7 @@ ModuleFile::getGenericSignatureChecked(serialization::GenericSignatureID ID) { } break; } + case SIL_GENERIC_SIGNATURE: { ArrayRef rawParamIDs; SILGenericSignatureLayout::readRecord(scratch, rawParamIDs); @@ -977,16 +1000,18 @@ ModuleFile::getSubstitutionMapChecked(serialization::SubstitutionMapID id) { // Read the substitution map. BCOffsetRAII restoreOffset(DeclTypeCursor); - DeclTypeCursor.JumpToBit(substitutionsOrOffset); + fatalIfNotSuccess(DeclTypeCursor.JumpToBit(substitutionsOrOffset)); // Read the substitution map. - auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry entry = + fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (entry.Kind != llvm::BitstreamEntry::Record) fatal(); StringRef blobData; SmallVector scratch; - unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData); + unsigned recordID = fatalIfUnexpected( + DeclTypeCursor.readRecord(entry.ID, scratch, &blobData)); if (recordID != SUBSTITUTION_MAP) fatal(); @@ -1031,13 +1056,15 @@ ModuleFile::getSubstitutionMapChecked(serialization::SubstitutionMapID id) { bool ModuleFile::readDefaultWitnessTable(ProtocolDecl *proto) { using namespace decls_block; - auto entry = DeclTypeCursor.advance(); + llvm::BitstreamEntry entry = + fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (entry.Kind != llvm::BitstreamEntry::Record) return true; SmallVector witnessIDBuffer; - unsigned kind = DeclTypeCursor.readRecord(entry.ID, witnessIDBuffer); + unsigned kind = + fatalIfUnexpected(DeclTypeCursor.readRecord(entry.ID, witnessIDBuffer)); assert(kind == DEFAULT_WITNESS_TABLE); (void)kind; @@ -1122,11 +1149,8 @@ static void filterValues(Type expectedTy, ModuleDecl *expectedModule, return true; // If we're expecting a type, make sure this decl has the expected type. - if (canTy) { - auto ifaceTy = value->getInterfaceType(); - if (!ifaceTy || !ifaceTy->isEqual(canTy)) - return true; - } + if (canTy && !value->getInterfaceType()->isEqual(canTy)) + return true; if (value->isStatic() != isStatic) return true; @@ -1190,7 +1214,8 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { assert(baseModule && "missing dependency"); PrettyXRefTrace pathTrace(*baseModule); - auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry entry = + fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (entry.Kind != llvm::BitstreamEntry::Record) fatal(); @@ -1203,8 +1228,8 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { // In particular, operator path pieces represent actual operators here, but // filters on operator functions when they appear later on. scratch.clear(); - unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, - &blobData); + unsigned recordID = fatalIfUnexpected( + DeclTypeCursor.readRecord(entry.ID, scratch, &blobData)); switch (recordID) { case XREF_TYPE_PATH_PIECE: case XREF_VALUE_PATH_PIECE: { @@ -1232,7 +1257,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { auto maybeType = getTypeChecked(TID); if (!maybeType) { // FIXME: Don't throw away the inner error's information. - llvm::consumeError(maybeType.takeError()); + consumeError(maybeType.takeError()); return llvm::make_error("couldn't decode type", pathTrace, name); } @@ -1306,13 +1331,14 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { auto getXRefDeclNameForError = [&]() -> DeclName { DeclName result = pathTrace.getLastName(); while (--pathLen) { - auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry entry = + fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (entry.Kind != llvm::BitstreamEntry::Record) return Identifier(); scratch.clear(); - unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, - &blobData); + unsigned recordID = fatalIfUnexpected( + DeclTypeCursor.readRecord(entry.ID, scratch, &blobData)); switch (recordID) { case XREF_TYPE_PATH_PIECE: { IdentifierID IID; @@ -1375,13 +1401,14 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { // For remaining path pieces, filter or drill down into the results we have. while (--pathLen) { - auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry entry = + fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (entry.Kind != llvm::BitstreamEntry::Record) fatal(); scratch.clear(); - unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, - &blobData); + unsigned recordID = fatalIfUnexpected( + DeclTypeCursor.readRecord(entry.ID, scratch, &blobData)); switch (recordID) { case XREF_TYPE_PATH_PIECE: { if (values.size() == 1 && isa(values.front())) { @@ -1487,7 +1514,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) { auto maybeType = getTypeChecked(TID); if (!maybeType) { // FIXME: Don't throw away the inner error's information. - llvm::consumeError(maybeType.takeError()); + consumeError(maybeType.takeError()); return llvm::make_error("couldn't decode type", pathTrace, memberName); } @@ -1778,8 +1805,8 @@ DeclContext *ModuleFile::getLocalDeclContext(LocalDeclContextID DCID) { return declContextOrOffset; BCOffsetRAII restoreOffset(DeclTypeCursor); - DeclTypeCursor.JumpToBit(declContextOrOffset); - auto entry = DeclTypeCursor.advance(); + fatalIfNotSuccess(DeclTypeCursor.JumpToBit(declContextOrOffset)); + llvm::BitstreamEntry entry = fatalIfUnexpected(DeclTypeCursor.advance()); if (entry.Kind != llvm::BitstreamEntry::Record) fatal(); @@ -1788,8 +1815,8 @@ DeclContext *ModuleFile::getLocalDeclContext(LocalDeclContextID DCID) { SmallVector scratch; StringRef blobData; - unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, - &blobData); + unsigned recordID = fatalIfUnexpected( + DeclTypeCursor.readRecord(entry.ID, scratch, &blobData)); switch(recordID) { case decls_block::ABSTRACT_CLOSURE_EXPR_CONTEXT: { TypeID closureTypeID; @@ -3244,11 +3271,10 @@ class swift::DeclDeserializer { proto->setImplicit(); proto->setIsObjC(isObjC); - proto->setCircularityCheck(CircularityCheck::Checked); - proto->setLazyRequirementSignature(&MF, MF.DeclTypeCursor.GetCurrentBitNo()); - skipGenericRequirements(MF.DeclTypeCursor); + if (llvm::Error Err = skipGenericRequirements(MF.DeclTypeCursor)) + MF.fatal(std::move(Err)); proto->setMemberLoader(&MF, MF.DeclTypeCursor.GetCurrentBitNo()); @@ -3455,8 +3481,6 @@ class swift::DeclDeserializer { &MF, encodeLazyConformanceContextData(numConformances, MF.DeclTypeCursor.GetCurrentBitNo())); - - theClass->setCircularityCheck(CircularityCheck::Checked); return theClass; } @@ -3867,7 +3891,7 @@ ModuleFile::getDeclChecked(DeclID DID) { if (!declOrOffset.isComplete()) { ++NumDeclsLoaded; BCOffsetRAII restoreOffset(DeclTypeCursor); - DeclTypeCursor.JumpToBit(declOrOffset); + fatalIfNotSuccess(DeclTypeCursor.JumpToBit(declOrOffset)); Expected deserialized = DeclDeserializer(*this, declOrOffset).getDeclCheckedImpl(); @@ -3895,14 +3919,15 @@ llvm::Error DeclDeserializer::deserializeDeclAttributes() { StringRef blobData; while (true) { BCOffsetRAII restoreOffset(MF.DeclTypeCursor); - auto entry = MF.DeclTypeCursor.advance(); + llvm::BitstreamEntry entry = + MF.fatalIfUnexpected(MF.DeclTypeCursor.advance()); if (entry.Kind != llvm::BitstreamEntry::Record) { // We don't know how to serialize decls represented by sub-blocks. MF.fatal(); } - unsigned recordID = MF.DeclTypeCursor.readRecord(entry.ID, scratch, - &blobData); + unsigned recordID = MF.fatalIfUnexpected( + MF.DeclTypeCursor.readRecord(entry.ID, scratch, &blobData)); if (isDeclAttrRecord(recordID)) { DeclAttribute *Attr = nullptr; @@ -4262,7 +4287,8 @@ DeclDeserializer::getDeclCheckedImpl() { if (declOrOffset.isComplete()) return declOrOffset; - auto entry = MF.DeclTypeCursor.advance(); + llvm::BitstreamEntry entry = + MF.fatalIfUnexpected(MF.DeclTypeCursor.advance()); if (entry.Kind != llvm::BitstreamEntry::Record) { // We don't know how to serialize decls represented by sub-blocks. MF.fatal(); @@ -4270,8 +4296,8 @@ DeclDeserializer::getDeclCheckedImpl() { SmallVector scratch; StringRef blobData; - unsigned recordID = MF.DeclTypeCursor.readRecord(entry.ID, scratch, - &blobData); + unsigned recordID = MF.fatalIfUnexpected( + MF.DeclTypeCursor.readRecord(entry.ID, scratch, &blobData)); PrettyDeclDeserialization stackTraceEntry( &MF, declOrOffset, static_cast(recordID)); @@ -4352,6 +4378,26 @@ getActualFunctionTypeRepresentation(uint8_t rep) { } } +/// Translate from the Serialization differentiability kind enum values to the +/// AST strongly-typed enum. +/// +/// The former is guaranteed to be stable, but may not reflect this version of +/// the AST. +static Optional +getActualDifferentiabilityKind(uint8_t rep) { + switch (rep) { +#define CASE(THE_CC) \ + case (uint8_t)serialization::DifferentiabilityKind::THE_CC: \ + return swift::DifferentiabilityKind::THE_CC; + CASE(NonDifferentiable) + CASE(Normal) + CASE(Linear) +#undef CASE + default: + return None; + } +} + /// Translate from the Serialization function type repr enum values to the AST /// strongly-typed enum. /// @@ -4449,23 +4495,6 @@ Optional getActualParameterConvention(uint8_t raw) { return None; } -// SWIFT_ENABLE_TENSORFLOW -/// Translate from the serialization DifferentiabilityKind enumerators, -/// which are guaranteed to be stable, to the AST ones. -static Optional -getActualDifferentiabilityKind(uint8_t raw) { - switch (serialization::DifferentiabilityKind(raw)) { -#define CASE(ID) \ - case serialization::DifferentiabilityKind::ID: \ - return swift::DifferentiabilityKind::ID; - CASE(NonDifferentiable) - CASE(Normal) - CASE(Linear) -#undef CASE - } - return None; -} - /// Translate from the serialization SILParameterDifferentiability enumerators, /// which are guaranteed to be stable, to the AST ones. static Optional @@ -4686,13 +4715,14 @@ class swift::TypeDeserializer { // The tuple record itself is empty. Read all trailing elements. SmallVector elements; while (true) { - auto entry = MF.DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry entry = + MF.fatalIfUnexpected(MF.DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (entry.Kind != llvm::BitstreamEntry::Record) break; scratch.clear(); - unsigned recordID = MF.DeclTypeCursor.readRecord(entry.ID, scratch, - &blobData); + unsigned recordID = MF.fatalIfUnexpected( + MF.DeclTypeCursor.readRecord(entry.ID, scratch, &blobData)); if (recordID != decls_block::TUPLE_TYPE_ELT) break; @@ -4714,32 +4744,18 @@ class swift::TypeDeserializer { StringRef blobData, bool isGeneric) { TypeID resultID; - uint8_t rawRepresentation; - - // SWIFT_ENABLE_TENSORFLOW - bool noescape = false, throws = false; - uint8_t rawDiffKind = 0; - auto diffKind = DifferentiabilityKind::NonDifferentiable; + uint8_t rawRepresentation, rawDiffKind; + bool noescape = false, throws; GenericSignature genericSig = GenericSignature(); if (!isGeneric) { - decls_block::FunctionTypeLayout::readRecord(scratch, resultID, - rawRepresentation, - noescape, - // SWIFT_ENABLE_TENSORFLOW - throws, - rawDiffKind); - diffKind = DifferentiabilityKind(rawDiffKind); + decls_block::FunctionTypeLayout::readRecord( + scratch, resultID, rawRepresentation, noescape, throws, rawDiffKind); } else { GenericSignatureID rawGenericSig; - decls_block::GenericFunctionTypeLayout::readRecord(scratch, - resultID, - rawRepresentation, - throws, - // SWIFT_ENABLE_TENSORFLOW - rawDiffKind, - rawGenericSig); - diffKind = DifferentiabilityKind(rawDiffKind); + decls_block::GenericFunctionTypeLayout::readRecord( + scratch, resultID, rawRepresentation, throws, rawDiffKind, + rawGenericSig); genericSig = MF.getGenericSignature(rawGenericSig); } @@ -4747,9 +4763,12 @@ class swift::TypeDeserializer { if (!representation.hasValue()) MF.fatal(); - auto info = FunctionType::ExtInfo(*representation, noescape, - // SWIFT_ENABLE_TENSORFLOW - throws, diffKind); + auto diffKind = getActualDifferentiabilityKind(rawDiffKind); + if (!diffKind.hasValue()) + MF.fatal(); + + auto info = + FunctionType::ExtInfo(*representation, noescape, throws, *diffKind); auto resultTy = MF.getTypeChecked(resultID); if (!resultTy) @@ -4757,13 +4776,14 @@ class swift::TypeDeserializer { SmallVector params; while (true) { - auto entry = MF.DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry entry = + MF.fatalIfUnexpected(MF.DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (entry.Kind != llvm::BitstreamEntry::Record) break; scratch.clear(); - unsigned recordID = MF.DeclTypeCursor.readRecord(entry.ID, scratch, - &blobData); + unsigned recordID = MF.fatalIfUnexpected( + MF.DeclTypeCursor.readRecord(entry.ID, scratch, &blobData)); if (recordID != decls_block::FUNCTION_PARAM) break; @@ -5054,7 +5074,7 @@ class swift::TypeDeserializer { } BCOffsetRAII saveOffset(MF.DeclTypeCursor); - MF.DeclTypeCursor.JumpToBit(layoutOrOffset); + MF.fatalIfNotSuccess(MF.DeclTypeCursor.JumpToBit(layoutOrOffset)); auto layout = MF.readSILLayout(MF.DeclTypeCursor); if (!layout) MF.fatal(); @@ -5075,10 +5095,9 @@ class swift::TypeDeserializer { uint8_t rawCoroutineKind; uint8_t rawCalleeConvention; uint8_t rawRepresentation; + uint8_t rawDiffKind; bool pseudogeneric = false; bool noescape; - // SWIFT_ENABLE_TENSORFLOW - uint8_t rawDifferentiabilityKind; bool hasErrorResult; unsigned numParams; unsigned numYields; @@ -5092,8 +5111,7 @@ class swift::TypeDeserializer { rawRepresentation, pseudogeneric, noescape, - // SWIFT_ENABLE_TENSORFLOW - rawDifferentiabilityKind, + rawDiffKind, hasErrorResult, numParams, numYields, @@ -5106,12 +5124,11 @@ class swift::TypeDeserializer { = getActualSILFunctionTypeRepresentation(rawRepresentation); if (!representation.hasValue()) MF.fatal(); - auto differentiabilityKind = - getActualDifferentiabilityKind(rawDifferentiabilityKind); - if (!differentiabilityKind.hasValue()) + auto diffKind = getActualDifferentiabilityKind(rawDiffKind); + if (!diffKind.hasValue()) MF.fatal(); - SILFunctionType::ExtInfo extInfo(*representation, pseudogeneric, - noescape, *differentiabilityKind); + SILFunctionType::ExtInfo extInfo(*representation, pseudogeneric, noescape, + *diffKind); // Process the coroutine kind. auto coroutineKind = getActualSILCoroutineKind(rawCoroutineKind); @@ -5136,7 +5153,7 @@ class swift::TypeDeserializer { // SWIFT_ENABLE_TENSORFLOW auto paramDiff = swift::SILParameterDifferentiability::DifferentiableOrNotApplicable; - if (differentiabilityKind != DifferentiabilityKind::NonDifferentiable) { + if (diffKind != DifferentiabilityKind::NonDifferentiable) { auto paramDiffOpt = getActualSILParameterDifferentiability(rawParamDiff); if (!paramDiffOpt) { @@ -5174,8 +5191,7 @@ class swift::TypeDeserializer { // Bounds check. FIXME: overflow // SWIFT_ENABLE_TENSORFLOW unsigned entriesPerParam = - differentiabilityKind != DifferentiabilityKind::NonDifferentiable - ? 3 : 2; + diffKind != DifferentiabilityKind::NonDifferentiable ? 3 : 2; if (entriesPerParam * numParams + 2 * numResults + 2 * unsigned(hasErrorResult) > variableData.size()) { @@ -5192,7 +5208,7 @@ class swift::TypeDeserializer { auto rawConvention = variableData[nextVariableDataIndex++]; // SWIFT_ENABLE_TENSORFLOW uint64_t paramDiff = 0; - if (differentiabilityKind != DifferentiabilityKind::NonDifferentiable) + if (diffKind != DifferentiabilityKind::NonDifferentiable) paramDiff = variableData[nextVariableDataIndex++]; auto param = processParameter(typeID, rawConvention, paramDiff); if (!param) @@ -5319,7 +5335,7 @@ Expected ModuleFile::getTypeChecked(TypeID TID) { return typeOrOffset; BCOffsetRAII restoreOffset(DeclTypeCursor); - DeclTypeCursor.JumpToBit(typeOrOffset); + fatalIfNotSuccess(DeclTypeCursor.JumpToBit(typeOrOffset)); auto result = TypeDeserializer(*this).getTypeCheckedImpl(); if (!result) @@ -5344,7 +5360,8 @@ Expected TypeDeserializer::getTypeCheckedImpl() { if (auto s = ctx.Stats) s->getFrontendCounters().NumTypesDeserialized++; - auto entry = MF.DeclTypeCursor.advance(); + llvm::BitstreamEntry entry = + MF.fatalIfUnexpected(MF.DeclTypeCursor.advance()); if (entry.Kind != llvm::BitstreamEntry::Record) { // We don't know how to serialize types represented by sub-blocks. @@ -5353,8 +5370,8 @@ Expected TypeDeserializer::getTypeCheckedImpl() { SmallVector scratch; StringRef blobData; - unsigned recordID = MF.DeclTypeCursor.readRecord(entry.ID, scratch, - &blobData); + unsigned recordID = MF.fatalIfUnexpected( + MF.DeclTypeCursor.readRecord(entry.ID, scratch, &blobData)); switch (recordID) { #define CASE(RECORD_NAME) \ @@ -5466,14 +5483,15 @@ void ModuleFile::loadAllMembers(Decl *container, uint64_t contextData) { IDC = cast(container); BCOffsetRAII restoreOffset(DeclTypeCursor); - DeclTypeCursor.JumpToBit(contextData); - auto entry = DeclTypeCursor.advance(); + fatalIfNotSuccess(DeclTypeCursor.JumpToBit(contextData)); + llvm::BitstreamEntry entry = fatalIfUnexpected(DeclTypeCursor.advance()); if (entry.Kind != llvm::BitstreamEntry::Record) fatal(); SmallVector memberIDBuffer; - unsigned kind = DeclTypeCursor.readRecord(entry.ID, memberIDBuffer); + unsigned kind = + fatalIfUnexpected(DeclTypeCursor.readRecord(entry.ID, memberIDBuffer)); assert(kind == decls_block::MEMBERS); (void)kind; @@ -5523,7 +5541,7 @@ ModuleFile::loadAllConformances(const Decl *D, uint64_t contextData, = decodeLazyConformanceContextData(contextData); BCOffsetRAII restoreOffset(DeclTypeCursor); - DeclTypeCursor.JumpToBit(bitPosition); + fatalIfNotSuccess(DeclTypeCursor.JumpToBit(bitPosition)); while (numConformances--) { auto conf = readConformance(DeclTypeCursor); @@ -5555,8 +5573,8 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance, // Find the conformance record. BCOffsetRAII restoreOffset(DeclTypeCursor); - DeclTypeCursor.JumpToBit(contextData); - auto entry = DeclTypeCursor.advance(); + fatalIfNotSuccess(DeclTypeCursor.JumpToBit(contextData)); + llvm::BitstreamEntry entry = fatalIfUnexpected(DeclTypeCursor.advance()); assert(entry.Kind == llvm::BitstreamEntry::Record && "registered lazy loader incorrectly"); @@ -5566,7 +5584,8 @@ void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance, ArrayRef rawIDs; SmallVector scratch; - unsigned kind = DeclTypeCursor.readRecord(entry.ID, scratch); + unsigned kind = + fatalIfUnexpected(DeclTypeCursor.readRecord(entry.ID, scratch)); (void) kind; assert(kind == NORMAL_PROTOCOL_CONFORMANCE && "registered lazy loader incorrectly"); @@ -5757,7 +5776,7 @@ void ModuleFile::loadRequirementSignature(const ProtocolDecl *decl, uint64_t contextData, SmallVectorImpl &reqs) { BCOffsetRAII restoreOffset(DeclTypeCursor); - DeclTypeCursor.JumpToBit(contextData); + fatalIfNotSuccess(DeclTypeCursor.JumpToBit(contextData)); readGenericRequirements(reqs, DeclTypeCursor); } @@ -5786,11 +5805,13 @@ Optional ModuleFile::maybeReadInlinableBodyText() { BCOffsetRAII restoreOffset(DeclTypeCursor); StringRef blobData; - auto next = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry next = + fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (next.Kind != llvm::BitstreamEntry::Record) return None; - unsigned recKind = DeclTypeCursor.readRecord(next.ID, scratch, &blobData); + unsigned recKind = + fatalIfUnexpected(DeclTypeCursor.readRecord(next.ID, scratch, &blobData)); if (recKind != INLINABLE_BODY_TEXT) return None; @@ -5805,11 +5826,13 @@ Optional ModuleFile::maybeReadForeignErrorConvention() { BCOffsetRAII restoreOffset(DeclTypeCursor); - auto next = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); + llvm::BitstreamEntry next = + fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd)); if (next.Kind != llvm::BitstreamEntry::Record) return None; - unsigned recKind = DeclTypeCursor.readRecord(next.ID, scratch); + unsigned recKind = + fatalIfUnexpected(DeclTypeCursor.readRecord(next.ID, scratch)); switch (recKind) { case FOREIGN_ERROR_CONVENTION: restoreOffset.reset(); diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index c6e69837e5274..ce548e9118778 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -140,7 +140,7 @@ SILDeserializer::SILDeserializer( return; // Load any abbrev records at the start of the block. - SILCursor.advance(); + MF->fatalIfUnexpected(SILCursor.advance()); llvm::BitstreamCursor cursor = SILIndexCursor; // We expect SIL_FUNC_NAMES first, then SIL_VTABLE_NAMES, then @@ -149,14 +149,15 @@ SILDeserializer::SILDeserializer( // omitted if no entries exist in the module file. unsigned kind = 0; while (kind != sil_index_block::SIL_PROPERTY_OFFSETS) { - auto next = cursor.advance(); + llvm::BitstreamEntry next = MF->fatalIfUnexpected(cursor.advance()); if (next.Kind == llvm::BitstreamEntry::EndBlock) return; SmallVector scratch; StringRef blobData; unsigned prevKind = kind; - kind = cursor.readRecord(next.ID, scratch, &blobData); + kind = + MF->fatalIfUnexpected(cursor.readRecord(next.ID, scratch, &blobData)); assert((next.Kind == llvm::BitstreamEntry::Record && kind > prevKind && (kind == sil_index_block::SIL_FUNC_NAMES || @@ -194,9 +195,10 @@ SILDeserializer::SILDeserializer( } // Read SIL_FUNC|VTABLE|GLOBALVAR_OFFSETS record. - next = cursor.advance(); + next = MF->fatalIfUnexpected(cursor.advance()); scratch.clear(); - unsigned offKind = cursor.readRecord(next.ID, scratch, &blobData); + unsigned offKind = + MF->fatalIfUnexpected(cursor.readRecord(next.ID, scratch, &blobData)); (void)offKind; if (kind == sil_index_block::SIL_FUNC_NAMES) { assert((next.Kind == llvm::BitstreamEntry::Record && @@ -342,10 +344,15 @@ SILBasicBlock *SILDeserializer::getBBForReference(SILFunction *Fn, } /// Helper function to convert from Type to SILType. -static SILType getSILType(Type Ty, SILValueCategory Category) { +SILType SILDeserializer::getSILType(Type Ty, SILValueCategory Category, + SILFunction *inContext) { auto TyLoc = TypeLoc::withoutLoc(Ty); - return SILType::getPrimitiveType(TyLoc.getType()->getCanonicalType(), - Category); + if (!inContext) { + return SILType::getPrimitiveType(TyLoc.getType()->getCanonicalType(), + Category); + } + return inContext->getLoweredType(TyLoc.getType()->getCanonicalType()) + .getCategoryType(Category); } // SWIFT_ENABLE_TENSORFLOW @@ -483,9 +490,14 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, return cacheEntry.get(); BCOffsetRAII restoreOffset(SILCursor); - SILCursor.JumpToBit(cacheEntry.getOffset()); - - auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (llvm::Error Err = SILCursor.JumpToBit(cacheEntry.getOffset())) + return std::move(Err); + + llvm::Expected maybeEntry = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + return maybeEntry.takeError(); + llvm::BitstreamEntry entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::Error) { LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in readSILFunction.\n"); MF->fatal(); @@ -493,7 +505,11 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, SmallVector scratch; StringRef blobData; - unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); + llvm::Expected maybeKind = + SILCursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + unsigned kind = maybeKind.get(); assert(kind == SIL_FUNCTION && "expect a sil function"); (void)kind; @@ -526,10 +542,10 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, return llvm::make_error( name, takeErrorInfo(astType.takeError())); } - llvm::consumeError(astType.takeError()); + consumeError(astType.takeError()); return existingFn; } - auto ty = getSILType(astType.get(), SILValueCategory::Object); + auto ty = getSILType(astType.get(), SILValueCategory::Object, nullptr); if (!ty.is()) { LLVM_DEBUG(llvm::dbgs() << "not a function type for SILFunction\n"); MF->fatal(); @@ -662,11 +678,18 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, // Read and instantiate the specialize attributes. while (numSpecAttrs--) { - auto next = SILCursor.advance(AF_DontPopBlockAtEnd); + llvm::Expected maybeNext = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeNext) + return maybeNext.takeError(); + llvm::BitstreamEntry next = maybeNext.get(); assert(next.Kind == llvm::BitstreamEntry::Record); scratch.clear(); - kind = SILCursor.readRecord(next.ID, scratch); + llvm::Expected maybeKind = SILCursor.readRecord(next.ID, scratch); + if (!maybeKind) + return maybeKind.takeError(); + unsigned kind = maybeKind.get(); assert(kind == SIL_SPECIALIZE_ATTR && "Missing specialization attribute"); unsigned exported; @@ -693,7 +716,10 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, // If the next entry is the end of the block, then this function has // no contents. - entry = SILCursor.advance(AF_DontPopBlockAtEnd); + maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + return maybeEntry.takeError(); + entry = maybeEntry.get(); bool isEmptyFunction = (entry.Kind == llvm::BitstreamEntry::EndBlock); assert((!isEmptyFunction || !genericEnv) && "generic environment without body?!"); @@ -721,7 +747,10 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setGenericEnvironment(genericEnv); scratch.clear(); - kind = SILCursor.readRecord(entry.ID, scratch); + maybeKind = SILCursor.readRecord(entry.ID, scratch); + if (!maybeKind) + return maybeKind.takeError(); + kind = maybeKind.get(); SILBasicBlock *CurrentBB = nullptr; @@ -782,12 +811,19 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, // Fetch the next record. scratch.clear(); - entry = SILCursor.advance(AF_DontPopBlockAtEnd); + llvm::Expected maybeEntry = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + return maybeEntry.takeError(); + llvm::BitstreamEntry entry = maybeEntry.get(); // EndBlock means the end of this SILFunction. if (entry.Kind == llvm::BitstreamEntry::EndBlock) break; - kind = SILCursor.readRecord(entry.ID, scratch); + maybeKind = SILCursor.readRecord(entry.ID, scratch); + if (!maybeKind) + return maybeKind.takeError(); + kind = maybeKind.get(); } // If fn is empty, we failed to deserialize its body. Return nullptr to signal @@ -843,7 +879,7 @@ SILBasicBlock *SILDeserializer::readSILBasicBlock(SILFunction *Fn, auto ArgTy = MF->getType(TyID); SILArgument *Arg; auto ValueCategory = SILValueCategory(Args[I + 1] & 0xF); - SILType SILArgTy = getSILType(ArgTy, ValueCategory); + SILType SILArgTy = getSILType(ArgTy, ValueCategory, Fn); if (IsEntry) { Arg = CurrentBB->createFunctionArgument(SILArgTy); } else { @@ -1165,68 +1201,68 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, break; case SILInstructionKind::AllocStackInst: assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); - ResultVal = Builder.createAllocStack(Loc, - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory), - None, /*bool hasDynamicLifetime*/ Attr != 0); + ResultVal = Builder.createAllocStack( + Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), + None, /*bool hasDynamicLifetime*/ Attr != 0); break; case SILInstructionKind::MetatypeInst: assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); - ResultVal = Builder.createMetatype(Loc, - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); - break; - -#define ONETYPE_ONEOPERAND_INST(ID) \ - case SILInstructionKind::ID##Inst: \ - assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && \ - "Layout should be OneTypeOneOperand."); \ - ResultVal = Builder.create##ID(Loc, \ - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory), \ - getLocalValue(ValID, \ - getSILType(MF->getType(TyID2), \ - (SILValueCategory)TyCategory2))); \ - break; - ONETYPE_ONEOPERAND_INST(ValueMetatype) - ONETYPE_ONEOPERAND_INST(ExistentialMetatype) - ONETYPE_ONEOPERAND_INST(AllocValueBuffer) - ONETYPE_ONEOPERAND_INST(ProjectValueBuffer) - ONETYPE_ONEOPERAND_INST(ProjectExistentialBox) - ONETYPE_ONEOPERAND_INST(DeallocValueBuffer) + ResultVal = Builder.createMetatype( + Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); + break; + +#define ONETYPE_ONEOPERAND_INST(ID) \ + case SILInstructionKind::ID##Inst: \ + assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && \ + "Layout should be OneTypeOneOperand."); \ + ResultVal = Builder.create##ID( \ + Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), \ + getLocalValue(ValID, getSILType(MF->getType(TyID2), \ + (SILValueCategory)TyCategory2, Fn))); \ + break; + ONETYPE_ONEOPERAND_INST(ValueMetatype) + ONETYPE_ONEOPERAND_INST(ExistentialMetatype) + ONETYPE_ONEOPERAND_INST(AllocValueBuffer) + ONETYPE_ONEOPERAND_INST(ProjectValueBuffer) + ONETYPE_ONEOPERAND_INST(ProjectExistentialBox) + ONETYPE_ONEOPERAND_INST(DeallocValueBuffer) #undef ONETYPE_ONEOPERAND_INST case SILInstructionKind::DeallocBoxInst: assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); - ResultVal = Builder.createDeallocBox(Loc, - getLocalValue(ValID, - getSILType(MF->getType(TyID2), - (SILValueCategory)TyCategory2))); + ResultVal = Builder.createDeallocBox( + Loc, + getLocalValue(ValID, getSILType(MF->getType(TyID2), + (SILValueCategory)TyCategory2, Fn))); break; case SILInstructionKind::OpenExistentialAddrInst: assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); ResultVal = Builder.createOpenExistentialAddr( - Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), - (SILValueCategory)TyCategory2)), - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory), + Loc, + getLocalValue(ValID, getSILType(MF->getType(TyID2), + (SILValueCategory)TyCategory2, Fn)), + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), Attr == 0 ? OpenedExistentialAccess::Immutable : OpenedExistentialAccess::Mutable); break; -#define ONEOPERAND_ONETYPE_INST(ID) \ - case SILInstructionKind::ID##Inst: \ - assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && \ - "Layout should be OneTypeOneOperand."); \ - ResultVal = Builder.create##ID(Loc, \ - getLocalValue(ValID, \ - getSILType(MF->getType(TyID2), \ - (SILValueCategory)TyCategory2)), \ - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory));\ - break; - ONEOPERAND_ONETYPE_INST(OpenExistentialRef) - ONEOPERAND_ONETYPE_INST(OpenExistentialMetatype) - ONEOPERAND_ONETYPE_INST(OpenExistentialBox) - ONEOPERAND_ONETYPE_INST(OpenExistentialValue) - ONEOPERAND_ONETYPE_INST(OpenExistentialBoxValue) - // Conversion instructions. +#define ONEOPERAND_ONETYPE_INST(ID) \ + case SILInstructionKind::ID##Inst: \ + assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && \ + "Layout should be OneTypeOneOperand."); \ + ResultVal = Builder.create##ID( \ + Loc, \ + getLocalValue(ValID, getSILType(MF->getType(TyID2), \ + (SILValueCategory)TyCategory2, Fn)), \ + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); \ + break; + ONEOPERAND_ONETYPE_INST(OpenExistentialRef) + ONEOPERAND_ONETYPE_INST(OpenExistentialMetatype) + ONEOPERAND_ONETYPE_INST(OpenExistentialBox) + ONEOPERAND_ONETYPE_INST(OpenExistentialValue) + ONEOPERAND_ONETYPE_INST(OpenExistentialBoxValue) + // Conversion instructions. #define LOADABLE_REF_STORAGE(Name, ...) \ ONEOPERAND_ONETYPE_INST(RefTo##Name) \ ONEOPERAND_ONETYPE_INST(Name##ToRef) @@ -1254,11 +1290,11 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case SILInstructionKind::ProjectBoxInst: { assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); - ResultVal = Builder.createProjectBox(Loc, - getLocalValue(ValID, - getSILType(MF->getType(TyID2), - (SILValueCategory)TyCategory2)), - TyID); + ResultVal = Builder.createProjectBox( + Loc, + getLocalValue(ValID, getSILType(MF->getType(TyID2), + (SILValueCategory)TyCategory2, Fn)), + TyID); break; } case SILInstructionKind::ConvertEscapeToNoEscapeInst: { @@ -1268,8 +1304,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, ResultVal = Builder.createConvertEscapeToNoEscape( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), - (SILValueCategory)TyCategory2)), - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory), + (SILValueCategory)TyCategory2, Fn)), + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), isLifetimeGuaranteed); break; } @@ -1280,8 +1316,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, ResultVal = Builder.createConvertFunction( Loc, getLocalValue(ValID, getSILType(MF->getType(TyID2), - (SILValueCategory)TyCategory2)), - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory), + (SILValueCategory)TyCategory2, Fn)), + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), withoutActuallyEscaping); break; } @@ -1291,29 +1327,30 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, bool isStrict = Attr & 0x01; bool isInvariant = Attr & 0x02; ResultVal = Builder.createPointerToAddress( - Loc, - getLocalValue(ValID, getSILType(MF->getType(TyID2), - (SILValueCategory)TyCategory2)), - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory), - isStrict, isInvariant); + Loc, + getLocalValue(ValID, getSILType(MF->getType(TyID2), + (SILValueCategory)TyCategory2, Fn)), + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), isStrict, + isInvariant); break; } case SILInstructionKind::DeallocExistentialBoxInst: { assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND && "Layout should be OneTypeOneOperand."); - ResultVal = Builder.createDeallocExistentialBox(Loc, - MF->getType(TyID)->getCanonicalType(), - getLocalValue(ValID, - getSILType(MF->getType(TyID2), - (SILValueCategory)TyCategory2))); + ResultVal = Builder.createDeallocExistentialBox( + Loc, MF->getType(TyID)->getCanonicalType(), + getLocalValue(ValID, getSILType(MF->getType(TyID2), + (SILValueCategory)TyCategory2, Fn))); break; } case SILInstructionKind::RefToBridgeObjectInst: { - auto RefTy = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + auto RefTy = + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); auto Ref = getLocalValue(ValID, RefTy); - auto BitsTy = getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2); + auto BitsTy = + getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn); auto Bits = getLocalValue(ValID2, BitsTy); ResultVal = Builder.createRefToBridgeObject(Loc, Ref, Bits); @@ -1321,7 +1358,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::ObjCProtocolInst: { - auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); auto Proto = MF->getDecl(ValID); ResultVal = Builder.createObjCProtocol(Loc, cast(Proto), Ty); break; @@ -1333,15 +1370,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case SILInstructionKind::InitExistentialRefInst: case SILInstructionKind::AllocExistentialBoxInst: { - auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); auto Ty2 = MF->getType(TyID2); CanType ConcreteTy; if (OpCode != SILInstructionKind::InitExistentialMetatypeInst) ConcreteTy = MF->getType(ConcreteTyID)->getCanonicalType(); SILValue operand; if (OpCode != SILInstructionKind::AllocExistentialBoxInst) - operand = getLocalValue(ValID, - getSILType(Ty2, (SILValueCategory)TyCategory2)); + operand = getLocalValue( + ValID, getSILType(Ty2, (SILValueCategory)TyCategory2, Fn)); SmallVector conformances; while (NumConformances--) { @@ -1389,16 +1426,17 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, unsigned Flags = ListOfValues[0]; bool isObjC = (bool)(Flags & 1); bool canAllocOnStack = (bool)((Flags >> 1) & 1); - SILType ClassTy = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + SILType ClassTy = + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SmallVector Counts; SmallVector TailTypes; unsigned i = 1; for (; i + 2 < NumVals; i += 3) { SILType TailType = getSILType(MF->getType(ListOfValues[i]), - SILValueCategory::Object); + SILValueCategory::Object, Fn); TailTypes.push_back(TailType); - SILType CountType = getSILType(MF->getType(ListOfValues[i+2]), - SILValueCategory::Object); + SILType CountType = getSILType(MF->getType(ListOfValues[i + 2]), + SILValueCategory::Object, Fn); SILValue CountVal = getLocalValue(ListOfValues[i+1], CountType); Counts.push_back(CountVal); } @@ -1406,7 +1444,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, assert(i + 2 == NumVals); assert(!canAllocOnStack); SILType MetadataType = getSILType(MF->getType(ListOfValues[i+1]), - SILValueCategory::Object); + SILValueCategory::Object, Fn); SILValue MetadataOp = getLocalValue(ListOfValues[i], MetadataType); ResultVal = Builder.createAllocRefDynamic(Loc, MetadataOp, ClassTy, isObjC, TailTypes, Counts); @@ -1424,8 +1462,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // is represented with 2 IDs: ValueID and ValueResultNumber. auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - SILType FnTy = getSILType(Ty, SILValueCategory::Object); - SILType SubstFnTy = getSILType(Ty2, SILValueCategory::Object); + SILType FnTy = getSILType(Ty, SILValueCategory::Object, Fn); + SILType SubstFnTy = getSILType(Ty2, SILValueCategory::Object, Fn); SILFunctionConventions substConventions(SubstFnTy.castTo(), Builder.getModule()); assert(substConventions.getNumSILArguments() == ListOfValues.size() @@ -1454,8 +1492,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // two values in the list are the basic block identifiers. auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - SILType FnTy = getSILType(Ty, SILValueCategory::Object); - SILType SubstFnTy = getSILType(Ty2, SILValueCategory::Object); + SILType FnTy = getSILType(Ty, SILValueCategory::Object, nullptr); + SILType SubstFnTy = getSILType(Ty2, SILValueCategory::Object, Fn); SILBasicBlock *errorBB = getBBForReference(Fn, ListOfValues.back()); ListOfValues = ListOfValues.drop_back(); @@ -1480,14 +1518,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case SILInstructionKind::PartialApplyInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - SILType FnTy = getSILType(Ty, SILValueCategory::Object); - SILType closureTy = getSILType(Ty2, SILValueCategory::Object); + SILType FnTy = getSILType(Ty, SILValueCategory::Object, nullptr); + SILType closureTy = getSILType(Ty2, SILValueCategory::Object, Fn); SubstitutionMap Substitutions = MF->getSubstitutionMap(NumSubs); auto SubstFnTy = SILType::getPrimitiveObjectType( - FnTy.castTo() - ->substGenericArgs(Builder.getModule(), Substitutions)); + FnTy.castTo()->substGenericArgs( + Builder.getModule(), Substitutions, + Builder.getTypeExpansionContext())); SILFunctionConventions fnConv(SubstFnTy.castTo(), Builder.getModule()); @@ -1512,12 +1551,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::BuiltinInst: { auto ASTTy = MF->getType(TyID); - auto ResultTy = getSILType(ASTTy, (SILValueCategory)(unsigned)TyID2); + auto ResultTy = getSILType(ASTTy, (SILValueCategory)(unsigned)TyID2, Fn); SmallVector Args; for (unsigned i = 0, e = ListOfValues.size(); i < e; i += 3) { auto ArgASTTy = MF->getType(ListOfValues[i+1]); - auto ArgTy = getSILType(ArgASTTy, - (SILValueCategory)(unsigned)ListOfValues[i+2]); + auto ArgTy = getSILType( + ArgASTTy, (SILValueCategory)(unsigned)ListOfValues[i + 2], Fn); Args.push_back(getLocalValue(ListOfValues[i], ArgTy)); } SubstitutionMap Substitutions = MF->getSubstitutionMap(NumSubs); @@ -1543,7 +1582,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, for (auto i = numParamIndices; i < numParamIndices + numOperands * 3; i += 3) { auto astTy = MF->getType(ListOfValues[i]); - auto silTy = getSILType(astTy, (SILValueCategory)ListOfValues[i+1]); + auto silTy = getSILType(astTy, (SILValueCategory)ListOfValues[i+1], Fn); operands.push_back(getLocalValue(ListOfValues[i+2], silTy)); } Optional> derivativeFunctions = None; @@ -1568,7 +1607,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, for (auto i = numParamIndices; i < numParamIndices + numOperands * 3; i += 3) { auto astTy = MF->getType(ListOfValues[i]); - auto silTy = getSILType(astTy, (SILValueCategory)ListOfValues[i+1]); + auto silTy = getSILType(astTy, (SILValueCategory)ListOfValues[i+1], Fn); operands.push_back(getLocalValue(ListOfValues[i+2], silTy)); } Optional transposeFunction = None; @@ -1580,7 +1619,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::DifferentiableFunctionExtractInst: { auto astTy = MF->getType(TyID); - auto silTy = getSILType(astTy, SILValueCategory::Object); + auto silTy = getSILType(astTy, SILValueCategory::Object, Fn); auto val = getLocalValue(ValID, silTy); NormalDifferentiableFunctionTypeComponent extractee(Attr); Optional explicitExtracteeType = None; @@ -1593,7 +1632,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::LinearFunctionExtractInst: { auto astTy = MF->getType(TyID); - auto silTy = getSILType(astTy, SILValueCategory::Object); + auto silTy = getSILType(astTy, SILValueCategory::Object, Fn); auto val = getLocalValue(ValID, silTy); LinearDifferentiableFunctionTypeComponent extractee(Attr); ResultVal = Builder.createLinearFunctionExtract(Loc, extractee, val); @@ -1605,8 +1644,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, assert(witness && "SILDifferentiabilityWitness not found"); DifferentiabilityWitnessFunctionKind witnessKind(Attr); Optional explicitFnTy = None; + auto astTy = MF->getType(TyID); if (TyID) - explicitFnTy = getSILType(MF->getType(TyID), SILValueCategory::Object); + explicitFnTy = getSILType(astTy, SILValueCategory::Object, Fn); ResultVal = Builder.createDifferentiabilityWitnessFunction( Loc, witnessKind, witness, explicitFnTy); break; @@ -1632,10 +1672,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // Find the global variable. SILGlobalVariable *g = getGlobalForReference(Name); assert(g && "Can't deserialize global variable"); - SILType expectedType = (OpCode == SILInstructionKind::GlobalAddrInst ? - g->getLoweredType().getAddressType() : - g->getLoweredType()); - assert(expectedType == getSILType(Ty, (SILValueCategory)TyCategory) && + SILType expectedType = + (OpCode == SILInstructionKind::GlobalAddrInst + ? g->getLoweredTypeInContext(TypeExpansionContext(*Fn)) + .getAddressType() + : g->getLoweredTypeInContext(TypeExpansionContext(*Fn))); + assert(expectedType == getSILType(Ty, (SILValueCategory)TyCategory, Fn) && "Type of a global variable does not match GlobalAddr."); (void)Ty; (void)expectedType; @@ -1648,17 +1690,18 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::DeallocStackInst: { auto Ty = MF->getType(TyID); - ResultVal = Builder.createDeallocStack(Loc, - getLocalValue(ValID, - getSILType(Ty, (SILValueCategory)TyCategory))); + ResultVal = Builder.createDeallocStack( + Loc, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn))); break; } case SILInstructionKind::DeallocRefInst: { auto Ty = MF->getType(TyID); bool OnStack = (bool)Attr; - ResultVal = Builder.createDeallocRef(Loc, - getLocalValue(ValID, - getSILType(Ty, (SILValueCategory)TyCategory)), OnStack); + ResultVal = Builder.createDeallocRef( + Loc, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), + OnStack); break; } @@ -1667,81 +1710,87 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto Ty2 = MF->getType(TyID2); ResultVal = Builder.createDeallocPartialRef(Loc, getLocalValue(ValID, - getSILType(Ty, (SILValueCategory)TyCategory)), + getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, - getSILType(Ty2, (SILValueCategory)TyCategory2))); + getSILType(Ty2, (SILValueCategory)TyCategory2, Fn))); break; } case SILInstructionKind::FunctionRefInst: { auto Ty = MF->getType(TyID); StringRef FuncName = MF->getIdentifierText(ValID); ResultVal = Builder.createFunctionRef( - Loc, getFuncForReference(FuncName, - getSILType(Ty, (SILValueCategory)TyCategory))); + Loc, + getFuncForReference( + FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr))); break; } case SILInstructionKind::DynamicFunctionRefInst: { auto Ty = MF->getType(TyID); StringRef FuncName = MF->getIdentifierText(ValID); ResultVal = Builder.createDynamicFunctionRef( - Loc, getFuncForReference(FuncName, - getSILType(Ty, (SILValueCategory)TyCategory))); + Loc, + getFuncForReference( + FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr))); break; } case SILInstructionKind::PreviousDynamicFunctionRefInst: { auto Ty = MF->getType(TyID); StringRef FuncName = MF->getIdentifierText(ValID); ResultVal = Builder.createPreviousDynamicFunctionRef( - Loc, getFuncForReference(FuncName, - getSILType(Ty, (SILValueCategory)TyCategory))); + Loc, + getFuncForReference( + FuncName, getSILType(Ty, (SILValueCategory)TyCategory, nullptr))); break; } case SILInstructionKind::MarkDependenceInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createMarkDependence(Loc, - getLocalValue(ValID, - getSILType(Ty, (SILValueCategory)TyCategory)), + ResultVal = Builder.createMarkDependence( + Loc, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, - getSILType(Ty2, (SILValueCategory)TyCategory2))); + getSILType(Ty2, (SILValueCategory)TyCategory2, Fn))); break; } case SILInstructionKind::CopyBlockWithoutEscapingInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); ResultVal = Builder.createCopyBlockWithoutEscaping( - Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), - getLocalValue(ValID2, getSILType(Ty2, (SILValueCategory)TyCategory2))); + Loc, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), + getLocalValue(ValID2, + getSILType(Ty2, (SILValueCategory)TyCategory2, Fn))); break; } case SILInstructionKind::IndexAddrInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createIndexAddr(Loc, - getLocalValue(ValID, - getSILType(Ty, (SILValueCategory)TyCategory)), + ResultVal = Builder.createIndexAddr( + Loc, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, - getSILType(Ty2, (SILValueCategory)TyCategory2))); + getSILType(Ty2, (SILValueCategory)TyCategory2, Fn))); break; } case SILInstructionKind::TailAddrInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); auto ResultTy = MF->getType(TyID3); - ResultVal = Builder.createTailAddr(Loc, - getLocalValue(ValID, getSILType(Ty, SILValueCategory::Address)), - getLocalValue(ValID2, getSILType(Ty2, SILValueCategory::Object)), - getSILType(ResultTy, SILValueCategory::Address)); + ResultVal = Builder.createTailAddr( + Loc, + getLocalValue(ValID, getSILType(Ty, SILValueCategory::Address, Fn)), + getLocalValue(ValID2, getSILType(Ty2, SILValueCategory::Object, Fn)), + getSILType(ResultTy, SILValueCategory::Address, Fn)); break; } case SILInstructionKind::IndexRawPointerInst: { auto Ty = MF->getType(TyID); auto Ty2 = MF->getType(TyID2); - ResultVal = Builder.createIndexRawPointer(Loc, - getLocalValue(ValID, - getSILType(Ty, (SILValueCategory)TyCategory)), + ResultVal = Builder.createIndexRawPointer( + Loc, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), getLocalValue(ValID2, - getSILType(Ty2, (SILValueCategory)TyCategory2))); + getSILType(Ty2, (SILValueCategory)TyCategory2, Fn))); break; } case SILInstructionKind::IntegerLiteralInst: { @@ -1751,9 +1800,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, bool negate = text[0] == '-'; if (negate) text = text.drop_front(); APInt value = intTy->getWidth().parse(text, 10, negate); - ResultVal = Builder.createIntegerLiteral(Loc, - getSILType(Ty, (SILValueCategory)TyCategory), - value); + ResultVal = Builder.createIntegerLiteral( + Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), value); break; } case SILInstructionKind::FloatLiteralInst: { @@ -1767,9 +1815,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, APFloat value(floatTy->getAPFloatSemantics(), bits); - ResultVal = Builder.createFloatLiteral(Loc, - getSILType(Ty, (SILValueCategory)TyCategory), - value); + ResultVal = Builder.createFloatLiteral( + Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), value); break; } case SILInstructionKind::StringLiteralInst: { @@ -1781,8 +1828,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, break; } case SILInstructionKind::CondFailInst: { - SILValue Op = getLocalValue(ValID, getSILType(MF->getType(TyID), \ - (SILValueCategory)TyCategory)); + SILValue Op = getLocalValue( + ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); StringRef StringVal = MF->getIdentifierText(ValID2); ResultVal = Builder.createCondFail(Loc, Op, StringVal); break; @@ -1793,39 +1840,41 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SmallVector OpList; for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) { auto EltTy = MF->getType(ListOfValues[I]); - OpList.push_back( - getLocalValue(ListOfValues[I+2], - getSILType(EltTy, (SILValueCategory)ListOfValues[I+1]))); + OpList.push_back(getLocalValue( + ListOfValues[I + 2], + getSILType(EltTy, (SILValueCategory)ListOfValues[I + 1], Fn))); } ResultVal = Builder.createMarkFunctionEscape(Loc, OpList); break; } // Checked Conversion instructions. case SILInstructionKind::UnconditionalCheckedCastInst: { - SILValue Val = getLocalValue(ValID, - getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2)); - SILType Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + SILValue Val = + getLocalValue(ValID, getSILType(MF->getType(TyID2), + (SILValueCategory)TyCategory2, Fn)); + SILType Ty = + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); ResultVal = Builder.createUnconditionalCheckedCast(Loc, Val, Ty); break; } -#define UNARY_INSTRUCTION(ID) \ - case SILInstructionKind::ID##Inst: \ - assert(RecordKind == SIL_ONE_OPERAND && \ - "Layout should be OneOperand."); \ - ResultVal = Builder.create##ID(Loc, getLocalValue(ValID, \ - getSILType(MF->getType(TyID), \ - (SILValueCategory)TyCategory))); \ - break; +#define UNARY_INSTRUCTION(ID) \ + case SILInstructionKind::ID##Inst: \ + assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); \ + ResultVal = Builder.create##ID( \ + Loc, \ + getLocalValue(ValID, getSILType(MF->getType(TyID), \ + (SILValueCategory)TyCategory, Fn))); \ + break; -#define REFCOUNTING_INSTRUCTION(ID) \ - case SILInstructionKind::ID##Inst: \ - assert(RecordKind == SIL_ONE_OPERAND && \ - "Layout should be OneOperand."); \ - ResultVal = Builder.create##ID(Loc, getLocalValue(ValID, \ - getSILType(MF->getType(TyID), \ - (SILValueCategory)TyCategory)), \ - (Atomicity)Attr); \ +#define REFCOUNTING_INSTRUCTION(ID) \ + case SILInstructionKind::ID##Inst: \ + assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); \ + ResultVal = Builder.create##ID( \ + Loc, \ + getLocalValue(ValID, getSILType(MF->getType(TyID), \ + (SILValueCategory)TyCategory, Fn)), \ + (Atomicity)Attr); \ break; #define UNCHECKED_REF_STORAGE(Name, ...) \ @@ -1873,8 +1922,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, unsigned verificationType = Attr; ResultVal = Builder.createIsEscapingClosure( Loc, - getLocalValue( - ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)), + getLocalValue(ValID, getSILType(MF->getType(TyID), + (SILValueCategory)TyCategory, Fn)), verificationType); break; } @@ -1882,14 +1931,14 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case SILInstructionKind::DestructureTupleInst: { assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); SILValue Operand = getLocalValue( - ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); + ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); ResultVal = Builder.createDestructureTuple(Loc, Operand); break; } case SILInstructionKind::DestructureStructInst: { assert(RecordKind == SIL_ONE_OPERAND && "Layout should be OneOperand."); SILValue Operand = getLocalValue( - ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); + ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); ResultVal = Builder.createDestructureStruct(Loc, Operand); break; } @@ -1897,7 +1946,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto Ty = MF->getType(TyID); auto ResultKind = ValueOwnershipKind(Attr); ResultVal = Builder.createUncheckedOwnershipConversion( - Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), + Loc, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), ResultKind); break; } @@ -1906,35 +1956,35 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto Ty = MF->getType(TyID); auto Qualifier = LoadOwnershipQualifier(Attr); ResultVal = Builder.createLoad( - Loc, getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory)), + Loc, + getLocalValue(ValID, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), Qualifier); break; } -#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ - case SILInstructionKind::Load##Name##Inst: { \ - auto Ty = MF->getType(TyID); \ - bool isTake = (Attr > 0); \ - auto Val = getLocalValue(ValID, getSILType(Ty, \ - SILValueCategory(TyCategory)));\ - ResultVal = Builder.createLoad##Name(Loc, Val, IsTake_t(isTake)); \ - break; \ - } \ - case SILInstructionKind::Store##Name##Inst: { \ - auto Ty = MF->getType(TyID); \ - SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); \ - auto refType = addrType.castTo(); \ +#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \ + case SILInstructionKind::Load##Name##Inst: { \ + auto Ty = MF->getType(TyID); \ + bool isTake = (Attr > 0); \ + auto Val = getLocalValue( \ + ValID, getSILType(Ty, SILValueCategory(TyCategory), Fn)); \ + ResultVal = Builder.createLoad##Name(Loc, Val, IsTake_t(isTake)); \ + break; \ + } \ + case SILInstructionKind::Store##Name##Inst: { \ + auto Ty = MF->getType(TyID); \ + SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); \ + auto refType = addrType.castTo(); \ auto ValType = SILType::getPrimitiveObjectType(refType.getReferentType()); \ - bool isInit = (Attr > 0); \ - ResultVal = Builder.createStore##Name(Loc, \ - getLocalValue(ValID, ValType), \ - getLocalValue(ValID2, addrType), \ - IsInitialization_t(isInit)); \ - break; \ + bool isInit = (Attr > 0); \ + ResultVal = Builder.createStore##Name(Loc, getLocalValue(ValID, ValType), \ + getLocalValue(ValID2, addrType), \ + IsInitialization_t(isInit)); \ + break; \ } #include "swift/AST/ReferenceStorage.def" case SILInstructionKind::MarkUninitializedInst: { - auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + auto Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); auto Kind = (MarkUninitializedInst::Kind)Attr; auto Val = getLocalValue(ValID, Ty); ResultVal = Builder.createMarkUninitialized(Loc, Val, Kind); @@ -1942,7 +1992,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::StoreInst: { auto Ty = MF->getType(TyID); - SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); + SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); SILType ValType = addrType.getObjectType(); auto Qualifier = StoreOwnershipQualifier(Attr); ResultVal = Builder.createStore(Loc, getLocalValue(ValID, ValType), @@ -1951,7 +2001,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::StoreBorrowInst: { auto Ty = MF->getType(TyID); - SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); + SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); SILType ValType = addrType.getObjectType(); ResultVal = Builder.createStoreBorrow(Loc, getLocalValue(ValID, ValType), getLocalValue(ValID2, addrType)); @@ -1959,7 +2009,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::BeginAccessInst: { SILValue op = getLocalValue( - ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); + ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); auto accessKind = SILAccessKind(Attr & 0x3); auto enforcement = SILAccessEnforcement((Attr >> 2) & 0x3); bool noNestedConflict = (Attr >> 4) & 0x01; @@ -1971,16 +2021,17 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::EndAccessInst: { SILValue op = getLocalValue( - ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); + ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); bool aborted = Attr & 0x1; ResultVal = Builder.createEndAccess(Loc, op, aborted); break; } case SILInstructionKind::BeginUnpairedAccessInst: { SILValue source = getLocalValue( - ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); - SILValue buffer = getLocalValue( - ValID2, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2)); + ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); + SILValue buffer = + getLocalValue(ValID2, getSILType(MF->getType(TyID2), + (SILValueCategory)TyCategory2, Fn)); auto accessKind = SILAccessKind(Attr & 0x3); auto enforcement = SILAccessEnforcement((Attr >> 2) & 0x03); bool noNestedConflict = (Attr >> 4) & 0x01; @@ -1992,7 +2043,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::EndUnpairedAccessInst: { SILValue op = getLocalValue( - ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory)); + ValID, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); bool aborted = Attr & 0x1; auto enforcement = SILAccessEnforcement((Attr >> 1) & 0x03); bool fromBuiltin = (Attr >> 3) & 0x01; @@ -2002,7 +2053,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::CopyAddrInst: { auto Ty = MF->getType(TyID); - SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); + SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); bool isInit = (Attr & 0x2) > 0; bool isTake = (Attr & 0x1) > 0; ResultVal = Builder.createCopyAddr(Loc, @@ -2014,7 +2065,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::AssignInst: { auto Ty = MF->getType(TyID); - SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory); + SILType addrType = getSILType(Ty, (SILValueCategory)TyCategory, Fn); SILType valType = addrType.getObjectType(); auto qualifier = AssignOwnershipQualifier(Attr); ResultVal = Builder.createAssign(Loc, @@ -2030,14 +2081,14 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, "Layout should be OneTypeValues."); auto Ty = MF->getType(TyID); // BoundTy ResultVal = Builder.createBindMemory( - Loc, - getLocalValue(ListOfValues[2], - getSILType(MF->getType(ListOfValues[0]), - (SILValueCategory)ListOfValues[1])), - getLocalValue(ListOfValues[5], - getSILType(MF->getType(ListOfValues[3]), - (SILValueCategory)ListOfValues[4])), - getSILType(Ty, (SILValueCategory)TyCategory)); + Loc, + getLocalValue(ListOfValues[2], + getSILType(MF->getType(ListOfValues[0]), + (SILValueCategory)ListOfValues[1], Fn)), + getLocalValue(ListOfValues[5], + getSILType(MF->getType(ListOfValues[3]), + (SILValueCategory)ListOfValues[4], Fn)), + getSILType(Ty, (SILValueCategory)TyCategory, Fn)); break; } case SILInstructionKind::StructElementAddrInst: @@ -2045,9 +2096,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // Use SILOneValueOneOperandLayout. VarDecl *Field = cast(MF->getDecl(ValID)); auto Ty = MF->getType(TyID); - auto Val = getLocalValue(ValID2, - getSILType(Ty, (SILValueCategory)TyCategory)); - auto ResultTy = Val->getType().getFieldType(Field, SILMod); + auto Val = + getLocalValue(ValID2, getSILType(Ty, (SILValueCategory)TyCategory, Fn)); + auto ResultTy = Val->getType().getFieldType( + Field, SILMod, Builder.getTypeExpansionContext()); if (OpCode == SILInstructionKind::StructElementAddrInst) ResultVal = Builder.createStructElementAddr(Loc, Val, Field, ResultTy.getAddressType()); @@ -2063,35 +2115,33 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SmallVector OpList; for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) { auto EltTy = MF->getType(ListOfValues[I]); - OpList.push_back( - getLocalValue(ListOfValues[I+2], - getSILType(EltTy, (SILValueCategory)ListOfValues[I+1]))); + OpList.push_back(getLocalValue( + ListOfValues[I + 2], + getSILType(EltTy, (SILValueCategory)ListOfValues[I + 1], Fn))); } - ResultVal = Builder.createStruct(Loc, - getSILType(Ty, (SILValueCategory)TyCategory), - OpList); + ResultVal = Builder.createStruct( + Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), OpList); break; } case SILInstructionKind::TupleElementAddrInst: case SILInstructionKind::TupleExtractInst: { // Use OneTypeOneOperand layout where the field number is stored in TypeID. auto Ty2 = MF->getType(TyID2); - SILType ST = getSILType(Ty2, (SILValueCategory)TyCategory2); + SILType ST = getSILType(Ty2, (SILValueCategory)TyCategory2, Fn); TupleType *TT = ST.castTo(); auto ResultTy = TT->getElement(TyID).getType(); switch (OpCode) { default: llvm_unreachable("Out of sync with parent switch"); case SILInstructionKind::TupleElementAddrInst: - ResultVal = Builder.createTupleElementAddr(Loc, - getLocalValue(ValID, ST), - TyID, getSILType(ResultTy, SILValueCategory::Address)); + ResultVal = Builder.createTupleElementAddr( + Loc, getLocalValue(ValID, ST), TyID, + getSILType(ResultTy, SILValueCategory::Address, Fn)); break; case SILInstructionKind::TupleExtractInst: - ResultVal = Builder.createTupleExtract(Loc, - getLocalValue(ValID,ST), - TyID, - getSILType(ResultTy, SILValueCategory::Object)); + ResultVal = Builder.createTupleExtract( + Loc, getLocalValue(ValID, ST), TyID, + getSILType(ResultTy, SILValueCategory::Object, Fn)); break; } break; @@ -2107,11 +2157,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, Type EltTy = TT->getElement(I).getType(); OpList.push_back( getLocalValue(ListOfValues[I], - getSILType(EltTy, SILValueCategory::Object))); + getSILType(EltTy, SILValueCategory::Object, Fn))); } - ResultVal = Builder.createTuple(Loc, - getSILType(Ty, (SILValueCategory)TyCategory), - OpList); + ResultVal = Builder.createTuple( + Loc, getSILType(Ty, (SILValueCategory)TyCategory, Fn), OpList); break; } case SILInstructionKind::ObjectInst: { @@ -2121,9 +2170,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SmallVector Args; for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) Args.push_back( - getLocalValue(ListOfValues[I+2], - getSILType(MF->getType(ListOfValues[I]), - (SILValueCategory)ListOfValues[I+1]))); + getLocalValue(ListOfValues[I + 2], + getSILType(MF->getType(ListOfValues[I]), + (SILValueCategory)ListOfValues[I + 1], Fn))); ResultVal = Builder.createBranch(Loc, getBBForReference(Fn, TyID), Args); @@ -2135,9 +2184,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // for condition, the list has value for condition, true basic block ID, // false basic block ID, number of true arguments, and a list of true|false // arguments. - SILValue Cond = getLocalValue(ListOfValues[0], - getSILType(MF->getType(TyID), - (SILValueCategory)TyCategory)); + SILValue Cond = getLocalValue( + ListOfValues[0], + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); unsigned NumTrueArgs = ListOfValues[3]; unsigned StartOfTrueArg = 4; @@ -2145,16 +2194,16 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SmallVector TrueArgs; for (unsigned I = StartOfTrueArg, E = StartOfFalseArg; I < E; I += 3) TrueArgs.push_back( - getLocalValue(ListOfValues[I+2], - getSILType(MF->getType(ListOfValues[I]), - (SILValueCategory)ListOfValues[I+1]))); + getLocalValue(ListOfValues[I + 2], + getSILType(MF->getType(ListOfValues[I]), + (SILValueCategory)ListOfValues[I + 1], Fn))); SmallVector FalseArgs; for (unsigned I = StartOfFalseArg, E = ListOfValues.size(); I < E; I += 3) FalseArgs.push_back( - getLocalValue(ListOfValues[I+2], - getSILType(MF->getType(ListOfValues[I]), - (SILValueCategory)ListOfValues[I+1]))); + getLocalValue(ListOfValues[I + 2], + getSILType(MF->getType(ListOfValues[I]), + (SILValueCategory)ListOfValues[I + 1], Fn))); ResultVal = Builder.createCondBranch(Loc, Cond, getBBForReference(Fn, ListOfValues[1]), TrueArgs, @@ -2167,9 +2216,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // default basic block ID. Use SILOneTypeValuesLayout: the type is // for condition, the list has value for condition, hasDefault, default // basic block ID, a list of (DeclID, BasicBlock ID). - SILValue Cond = getLocalValue(ListOfValues[0], - getSILType(MF->getType(TyID), - (SILValueCategory)TyCategory)); + SILValue Cond = getLocalValue( + ListOfValues[0], + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); SILBasicBlock *DefaultBB = nullptr; if (ListOfValues[1]) @@ -2196,12 +2245,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // basic block ID, a list of (DeclID, BasicBlock ID). SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), - (SILValueCategory)TyCategory)); + (SILValueCategory)TyCategory, Fn)); Type ResultLoweredTy = MF->getType(ListOfValues[1]); SILValueCategory ResultCategory = (SILValueCategory)ListOfValues[2]; - SILType ResultTy = getSILType(ResultLoweredTy, ResultCategory); - + SILType ResultTy = getSILType(ResultLoweredTy, ResultCategory, Fn); + SILValue DefaultVal = nullptr; if (ListOfValues[3]) DefaultVal = getLocalValue(ListOfValues[4], ResultTy); @@ -2226,9 +2275,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // for condition, the list contains value for condition, hasDefault, default // basic block ID, a list of (Value ID, BasicBlock ID). SILType ResultTy = getSILType(MF->getType(TyID), - (SILValueCategory)TyCategory); - SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), - (SILValueCategory)TyCategory)); + (SILValueCategory)TyCategory, Fn); + SILValue Cond = getLocalValue( + ListOfValues[0], + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); SILBasicBlock *DefaultBB = nullptr; if (ListOfValues[1]) @@ -2248,12 +2298,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // for condition, the list has value for condition, result type, // hasDefault, default, // basic block ID, a list of (Value ID, Value ID). - SILValue Cond = getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), - (SILValueCategory)TyCategory)); + SILValue Cond = getLocalValue( + ListOfValues[0], + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); Type ResultLoweredTy = MF->getType(ListOfValues[1]); SILValueCategory ResultCategory = (SILValueCategory)ListOfValues[2]; - SILType ResultTy = getSILType(ResultLoweredTy, ResultCategory); + SILType ResultTy = getSILType(ResultLoweredTy, ResultCategory, Fn); SILValue DefaultVal = nullptr; if (ListOfValues[3]) @@ -2275,21 +2326,21 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // (DeclID + hasOperand), and an operand. SILValue Operand; if (Attr) - Operand = getLocalValue(ValID2, - getSILType(MF->getType(TyID2), - (SILValueCategory)TyCategory2)); - ResultVal = Builder.createEnum(Loc, Operand, - cast(MF->getDecl(ValID)), - getSILType(MF->getType(TyID), - (SILValueCategory)TyCategory)); + Operand = + getLocalValue(ValID2, getSILType(MF->getType(TyID2), + (SILValueCategory)TyCategory2, Fn)); + ResultVal = Builder.createEnum( + Loc, Operand, cast(MF->getDecl(ValID)), + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)); break; } case SILInstructionKind::InitEnumDataAddrInst: { // Use SILOneValueOneOperandLayout. EnumElementDecl *Elt = cast(MF->getDecl(ValID)); SILType OperandTy = getSILType(MF->getType(TyID), - (SILValueCategory) TyCategory); - SILType ResultTy = OperandTy.getEnumElementType(Elt, SILMod); + (SILValueCategory) TyCategory, Fn); + SILType ResultTy = OperandTy.getEnumElementType( + Elt, SILMod, Builder.getTypeExpansionContext()); ResultVal = Builder.createInitEnumDataAddr(Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); @@ -2298,9 +2349,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case SILInstructionKind::UncheckedEnumDataInst: { // Use SILOneValueOneOperandLayout. EnumElementDecl *Elt = cast(MF->getDecl(ValID)); - SILType OperandTy = getSILType(MF->getType(TyID), - (SILValueCategory) TyCategory); - SILType ResultTy = OperandTy.getEnumElementType(Elt, SILMod); + SILType OperandTy = + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); + SILType ResultTy = OperandTy.getEnumElementType( + Elt, SILMod, Builder.getTypeExpansionContext()); ResultVal = Builder.createUncheckedEnumData(Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); @@ -2309,9 +2361,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case SILInstructionKind::UncheckedTakeEnumDataAddrInst: { // Use SILOneValueOneOperandLayout. EnumElementDecl *Elt = cast(MF->getDecl(ValID)); - SILType OperandTy = getSILType(MF->getType(TyID), - (SILValueCategory) TyCategory); - SILType ResultTy = OperandTy.getEnumElementType(Elt, SILMod); + SILType OperandTy = + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); + SILType ResultTy = OperandTy.getEnumElementType( + Elt, SILMod, Builder.getTypeExpansionContext()); ResultVal = Builder.createUncheckedTakeEnumDataAddr(Loc, getLocalValue(ValID2, OperandTy), Elt, ResultTy); @@ -2321,10 +2374,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // Use SILOneValueOneOperandLayout. EnumElementDecl *Elt = cast(MF->getDecl(ValID)); auto Ty = MF->getType(TyID); - ResultVal = Builder.createInjectEnumAddr(Loc, - getLocalValue(ValID2, - getSILType(Ty, (SILValueCategory)TyCategory)), - Elt); + ResultVal = Builder.createInjectEnumAddr( + Loc, + getLocalValue(ValID2, getSILType(Ty, (SILValueCategory)TyCategory, Fn)), + Elt); break; } case SILInstructionKind::RefElementAddrInst: { @@ -2332,8 +2385,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, VarDecl *Field = cast(MF->getDecl(ValID)); auto Ty = MF->getType(TyID); auto Val = getLocalValue(ValID2, - getSILType(Ty, (SILValueCategory)TyCategory)); - auto ResultTy = Val->getType().getFieldType(Field, SILMod); + getSILType(Ty, (SILValueCategory)TyCategory, Fn)); + auto ResultTy = Val->getType().getFieldType( + Field, SILMod, Builder.getTypeExpansionContext()); ResultVal = Builder.createRefElementAddr(Loc, Val, Field, ResultTy); break; @@ -2344,10 +2398,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, assert(Attr == 0); assert((SILValueCategory)TyCategory == SILValueCategory::Address); ResultVal = Builder.createRefTailAddr( - Loc, - getLocalValue(ValID, getSILType(MF->getType(TyID2), - (SILValueCategory)TyCategory2)), - getSILType(MF->getType(TyID), SILValueCategory::Address)); + Loc, + getLocalValue(ValID, getSILType(MF->getType(TyID2), + (SILValueCategory)TyCategory2, Fn)), + getSILType(MF->getType(TyID), SILValueCategory::Address, Fn)); break; } case SILInstructionKind::ClassMethodInst: @@ -2358,11 +2412,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel), and an operand. unsigned NextValueIndex = 0; SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex); - SILType Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + SILType Ty = + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); assert(ListOfValues.size() >= NextValueIndex + 2 && "Out of entries for MethodInst"); - SILType operandTy = getSILType(MF->getType(ListOfValues[NextValueIndex]), - (SILValueCategory)ListOfValues[NextValueIndex+1]); + SILType operandTy = + getSILType(MF->getType(ListOfValues[NextValueIndex]), + (SILValueCategory)ListOfValues[NextValueIndex + 1], Fn); NextValueIndex += 2; switch (OpCode) { @@ -2397,15 +2453,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, "Out of entries for MethodInst"); CanType Ty = MF->getType(TyID)->getCanonicalType(); - SILType OperandTy = getSILType(MF->getType(TyID2), - (SILValueCategory)TyCategory2); + SILType OperandTy = + getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn); auto Conformance = MF->readConformance(SILCursor); // Read the optional opened existential. SILValue ExistentialOperand; if (TyID3) { SILType ExistentialOperandTy = - getSILType(MF->getType(TyID3), (SILValueCategory)TyCategory3); + getSILType(MF->getType(TyID3), (SILValueCategory)TyCategory3, Fn); if (ValID3) ExistentialOperand = getLocalValue(ValID3, ExistentialOperandTy); } @@ -2420,11 +2476,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, SILDeclRef DRef = getSILDeclRef(MF, ListOfValues, NextValueIndex); assert(ListOfValues.size() == NextValueIndex + 2 && "Wrong number of entries for DynamicMethodBranchInst"); - ResultVal = Builder.createDynamicMethodBranch(Loc, - getLocalValue(ListOfValues[0], getSILType(MF->getType(TyID), - (SILValueCategory)TyCategory)), - DRef, getBBForReference(Fn, ListOfValues[NextValueIndex]), - getBBForReference(Fn, ListOfValues[NextValueIndex+1])); + ResultVal = Builder.createDynamicMethodBranch( + Loc, + getLocalValue( + ListOfValues[0], + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn)), + DRef, getBBForReference(Fn, ListOfValues[NextValueIndex]), + getBBForReference(Fn, ListOfValues[NextValueIndex + 1])); break; } case SILInstructionKind::CheckedCastBranchInst: { @@ -2434,10 +2492,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, "expect 7 numbers for CheckedCastBranchInst"); bool isExact = ListOfValues[0] != 0; SILType opTy = getSILType(MF->getType(ListOfValues[2]), - (SILValueCategory)ListOfValues[3]); + (SILValueCategory)ListOfValues[3], Fn); SILValue op = getLocalValue(ListOfValues[1], opTy); - SILType castTy = getSILType(MF->getType(TyID), - (SILValueCategory)TyCategory); + SILType castTy = + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); auto *successBB = getBBForReference(Fn, ListOfValues[4]); auto *failureBB = getBBForReference(Fn, ListOfValues[5]); @@ -2451,10 +2509,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, assert(ListOfValues.size() == 5 && "expect 6 numbers for CheckedCastValueBranchInst"); SILType opTy = getSILType(MF->getType(ListOfValues[1]), - (SILValueCategory)ListOfValues[2]); + (SILValueCategory)ListOfValues[2], Fn); SILValue op = getLocalValue(ListOfValues[0], opTy); SILType castTy = - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); auto *successBB = getBBForReference(Fn, ListOfValues[3]); auto *failureBB = getBBForReference(Fn, ListOfValues[4]); @@ -2464,8 +2522,9 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::UnconditionalCheckedCastValueInst: { SILValue Val = getLocalValue( - ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2)); - SILType Ty = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + ValID, getSILType(MF->getType(TyID2), (SILValueCategory)TyCategory2, Fn)); + SILType Ty = + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); ResultVal = Builder.createUnconditionalCheckedCastValue(Loc, Val, Ty); break; } @@ -2473,12 +2532,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, // ignore attr. CanType sourceType = MF->getType(ListOfValues[0])->getCanonicalType(); SILType srcAddrTy = getSILType(MF->getType(ListOfValues[2]), - (SILValueCategory)ListOfValues[3]); + (SILValueCategory)ListOfValues[3], Fn); SILValue src = getLocalValue(ListOfValues[1], srcAddrTy); CanType targetType = MF->getType(ListOfValues[4])->getCanonicalType(); SILType destAddrTy = - getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILValue dest = getLocalValue(ListOfValues[5], destAddrTy); ResultVal = Builder.createUnconditionalCheckedCastAddr(Loc, src, sourceType, @@ -2490,12 +2549,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, CanType sourceType = MF->getType(ListOfValues[1])->getCanonicalType(); SILType srcAddrTy = getSILType(MF->getType(ListOfValues[3]), - (SILValueCategory)ListOfValues[4]); + (SILValueCategory)ListOfValues[4], Fn); SILValue src = getLocalValue(ListOfValues[2], srcAddrTy); CanType targetType = MF->getType(ListOfValues[5])->getCanonicalType(); SILType destAddrTy = - getSILType(MF->getType(TyID), (SILValueCategory) TyCategory); + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILValue dest = getLocalValue(ListOfValues[6], destAddrTy); auto *successBB = getBBForReference(Fn, ListOfValues[7]); @@ -2510,12 +2569,12 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, CanType sourceType = MF->getType(ListOfValues[0])->getCanonicalType(); // ignore attr. SILType srcAddrTy = getSILType(MF->getType(ListOfValues[2]), - (SILValueCategory)ListOfValues[3]); + (SILValueCategory)ListOfValues[3], Fn); SILValue src = getLocalValue(ListOfValues[1], srcAddrTy); CanType targetType = MF->getType(ListOfValues[4])->getCanonicalType(); SILType destAddrTy = - getSILType(MF->getType(TyID), (SILValueCategory) TyCategory); + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILValue dest = getLocalValue(ListOfValues[5], destAddrTy); ResultVal = Builder.createUncheckedRefCastAddr(Loc, src, sourceType, @@ -2525,16 +2584,16 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case SILInstructionKind::InitBlockStorageHeaderInst: { assert(ListOfValues.size() == 5 && "expected 5 values for InitBlockStorageHeader"); - SILType blockTy - = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + SILType blockTy = + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); SILType storageTy = getSILType(MF->getType(ListOfValues[1]), - SILValueCategory::Address); + SILValueCategory::Address, Fn); SILValue storage = getLocalValue(ListOfValues[0], storageTy); - SILType invokeTy = getSILType(MF->getType(ListOfValues[3]), - SILValueCategory::Object); + SILType invokeTy = + getSILType(MF->getType(ListOfValues[3]), SILValueCategory::Object, Fn); SILValue invoke = getLocalValue(ListOfValues[2], invokeTy); @@ -2562,8 +2621,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, for (unsigned I = 0, E = ListOfValues.size(); I < E; I += 3) { auto valueTy = MF->getType(ListOfValues[I]); auto valueCategory = (SILValueCategory) ListOfValues[I+1]; - yieldedValues.push_back( - getLocalValue(ListOfValues[I+2], getSILType(valueTy, valueCategory))); + yieldedValues.push_back(getLocalValue( + ListOfValues[I + 2], getSILType(valueTy, valueCategory, Fn))); } ResultVal = Builder.createYield(Loc, yieldedValues, resumeBB, unwindBB); @@ -2571,8 +2630,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, } case SILInstructionKind::KeyPathInst: { unsigned nextValue = 0; - SILType kpTy - = getSILType(MF->getType(TyID), (SILValueCategory)TyCategory); + SILType kpTy = + getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn); auto rootTy = MF->getType(ListOfValues[nextValue++]); auto valueTy = MF->getType(ListOfValues[nextValue++]); @@ -2615,7 +2674,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, auto opValue = ListOfValues[nextValue++]; auto opTy = MF->getType(ListOfValues[nextValue++]); auto opCat = (SILValueCategory)ListOfValues[nextValue++]; - operands.push_back(getLocalValue(opValue, getSILType(opTy, opCat))); + operands.push_back(getLocalValue(opValue, getSILType(opTy, opCat, Fn))); } ResultVal = Builder.createKeyPath(Loc, pattern, subMap, operands, kpTy); @@ -2643,7 +2702,7 @@ SILFunction *SILDeserializer::lookupSILFunction(SILFunction *InFunc) { /*declarationOnly*/ false); if (!maybeFunc) { // Ignore the error; treat it as if we didn't have a definition. - llvm::consumeError(maybeFunc.takeError()); + consumeError(maybeFunc.takeError()); return nullptr; } @@ -2676,9 +2735,14 @@ bool SILDeserializer::hasSILFunction(StringRef Name, return !Linkage || cacheEntry.get()->getLinkage() == *Linkage; BCOffsetRAII restoreOffset(SILCursor); - SILCursor.JumpToBit(cacheEntry.getOffset()); - - auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (llvm::Error Err = SILCursor.JumpToBit(cacheEntry.getOffset())) + MF->fatal(std::move(Err)); + + llvm::Expected maybeEntry = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + llvm::BitstreamEntry entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::Error) { LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in hasSILFunction.\n"); MF->fatal(); @@ -2686,7 +2750,11 @@ bool SILDeserializer::hasSILFunction(StringRef Name, SmallVector scratch; StringRef blobData; - unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); + llvm::Expected maybeKind = + SILCursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + unsigned kind = maybeKind.get(); assert(kind == SIL_FUNCTION && "expect a sil function"); (void)kind; @@ -2740,7 +2808,7 @@ SILFunction *SILDeserializer::lookupSILFunction(StringRef name, if (!maybeFunc) { // Ignore the error; treat it as if we didn't have a definition. - llvm::consumeError(maybeFunc.takeError()); + consumeError(maybeFunc.takeError()); return nullptr; } @@ -2775,8 +2843,13 @@ SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) { return globalVarOrOffset; BCOffsetRAII restoreOffset(SILCursor); - SILCursor.JumpToBit(globalVarOrOffset); - auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (llvm::Error Err = SILCursor.JumpToBit(globalVarOrOffset)) + MF->fatal(std::move(Err)); + llvm::Expected maybeEntry = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + llvm::BitstreamEntry entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::Error) { LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in readGlobalVar.\n"); return nullptr; @@ -2784,7 +2857,11 @@ SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) { SmallVector scratch; StringRef blobData; - unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); + llvm::Expected maybeKind = + SILCursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + unsigned kind = maybeKind.get(); assert(kind == SIL_GLOBALVAR && "expect a sil global var"); (void)kind; @@ -2809,7 +2886,7 @@ SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) { SILGlobalVariable *v = SILGlobalVariable::create( SILMod, linkage.getValue(), isSerialized ? IsSerialized : IsNotSerialized, - Name.str(), getSILType(Ty, SILValueCategory::Object), + Name.str(), getSILType(Ty, SILValueCategory::Object, nullptr), None, dID ? cast(MF->getDecl(dID)): nullptr); v->setLet(IsLet); @@ -2848,7 +2925,7 @@ void SILDeserializer::getAllSILFunctions() { false/*errorIfEmptyBody*/); if (!maybeFunc) { // Ignore the error; treat it as if we didn't have a definition. - llvm::consumeError(maybeFunc.takeError()); + consumeError(maybeFunc.takeError()); } } } @@ -2863,8 +2940,13 @@ SILVTable *SILDeserializer::readVTable(DeclID VId) { return vTableOrOffset; BCOffsetRAII restoreOffset(SILCursor); - SILCursor.JumpToBit(vTableOrOffset); - auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (llvm::Error Err = SILCursor.JumpToBit(vTableOrOffset)) + MF->fatal(std::move(Err)); + llvm::Expected maybeEntry = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + llvm::BitstreamEntry entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::Error) { LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in readVTable.\n"); return nullptr; @@ -2872,7 +2954,11 @@ SILVTable *SILDeserializer::readVTable(DeclID VId) { SmallVector scratch; StringRef blobData; - unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); + llvm::Expected maybeKind = + SILCursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + unsigned kind = maybeKind.get(); assert(kind == SIL_VTABLE && "expect a sil vtable"); (void)kind; @@ -2890,11 +2976,17 @@ SILVTable *SILDeserializer::readVTable(DeclID VId) { // Fetch the next record. scratch.clear(); - entry = SILCursor.advance(AF_DontPopBlockAtEnd); + maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::EndBlock) // This vtable has no contents. return nullptr; - kind = SILCursor.readRecord(entry.ID, scratch); + maybeKind = SILCursor.readRecord(entry.ID, scratch); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + kind = maybeKind.get(); std::vector vtableEntries; // Another SIL_VTABLE record means the end of this VTable. @@ -2920,11 +3012,17 @@ SILVTable *SILDeserializer::readVTable(DeclID VId) { // Fetch the next record. scratch.clear(); - entry = SILCursor.advance(AF_DontPopBlockAtEnd); + maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::EndBlock) // EndBlock means the end of this VTable. break; - kind = SILCursor.readRecord(entry.ID, scratch); + maybeKind = SILCursor.readRecord(entry.ID, scratch); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + kind = maybeKind.get(); } // If we've already serialized the module, don't mark the witness table @@ -2970,8 +3068,13 @@ SILProperty *SILDeserializer::readProperty(DeclID PId) { return propOrOffset.get(); BCOffsetRAII restoreOffset(SILCursor); - SILCursor.JumpToBit(propOrOffset.getOffset()); - auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (llvm::Error Err = SILCursor.JumpToBit(propOrOffset.getOffset())) + MF->fatal(std::move(Err)); + llvm::Expected maybeEntry = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + llvm::BitstreamEntry entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::Error) { LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in readProperty.\n"); return nullptr; @@ -2979,7 +3082,11 @@ SILProperty *SILDeserializer::readProperty(DeclID PId) { SmallVector scratch; StringRef blobData; - unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); + llvm::Expected maybeKind = + SILCursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + unsigned kind = maybeKind.get(); assert(kind == SIL_PROPERTY && "expect a sil_property"); (void)kind; @@ -3009,7 +3116,10 @@ void SILDeserializer::readWitnessTableEntries( std::vector &conditionalConformances) { SmallVector scratch; - unsigned kind = SILCursor.readRecord(entry.ID, scratch); + llvm::Expected maybeKind = SILCursor.readRecord(entry.ID, scratch); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + unsigned kind = maybeKind.get(); // Another record means the end of this WitnessTable. while (kind != SIL_WITNESS_TABLE && @@ -3074,11 +3184,18 @@ void SILDeserializer::readWitnessTableEntries( // Fetch the next record. scratch.clear(); - entry = SILCursor.advance(AF_DontPopBlockAtEnd); + llvm::Expected maybeEntry = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::EndBlock) // EndBlock means the end of this WitnessTable. break; - kind = SILCursor.readRecord(entry.ID, scratch); + maybeKind = SILCursor.readRecord(entry.ID, scratch); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + kind = maybeKind.get(); } } @@ -3094,8 +3211,13 @@ SILWitnessTable *SILDeserializer::readWitnessTable(DeclID WId, return wTableOrOffset.get(); BCOffsetRAII restoreOffset(SILCursor); - SILCursor.JumpToBit(wTableOrOffset.getOffset()); - auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (llvm::Error Err = SILCursor.JumpToBit(wTableOrOffset.getOffset())) + MF->fatal(std::move(Err)); + llvm::Expected maybeEntry = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + llvm::BitstreamEntry entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::Error) { LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in readWitnessTable.\n"); return nullptr; @@ -3103,7 +3225,11 @@ SILWitnessTable *SILDeserializer::readWitnessTable(DeclID WId, SmallVector scratch; StringRef blobData; - unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); + llvm::Expected maybeKind = + SILCursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + unsigned kind = maybeKind.get(); assert(kind == SIL_WITNESS_TABLE && "expect a sil witnesstable"); (void)kind; @@ -3170,7 +3296,10 @@ SILWitnessTable *SILDeserializer::readWitnessTable(DeclID WId, // Fetch the next record. scratch.clear(); - entry = SILCursor.advance(AF_DontPopBlockAtEnd); + maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::EndBlock) return nullptr; @@ -3237,8 +3366,13 @@ readDefaultWitnessTable(DeclID WId, SILDefaultWitnessTable *existingWt) { return wTableOrOffset.get(); BCOffsetRAII restoreOffset(SILCursor); - SILCursor.JumpToBit(wTableOrOffset.getOffset()); - auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (llvm::Error Err = SILCursor.JumpToBit(wTableOrOffset.getOffset())) + MF->fatal(std::move(Err)); + llvm::Expected maybeEntry = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + llvm::BitstreamEntry entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::Error) { LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in " "readDefaultWitnessTable.\n"); @@ -3247,7 +3381,11 @@ readDefaultWitnessTable(DeclID WId, SILDefaultWitnessTable *existingWt) { SmallVector scratch; StringRef blobData; - unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); + llvm::Expected maybeKind = + SILCursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + unsigned kind = maybeKind.get(); assert(kind == SIL_DEFAULT_WITNESS_TABLE && "expect a sil default witness table"); (void)kind; @@ -3294,7 +3432,10 @@ readDefaultWitnessTable(DeclID WId, SILDefaultWitnessTable *existingWt) { // Fetch the next record. scratch.clear(); - entry = SILCursor.advance(AF_DontPopBlockAtEnd); + maybeEntry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::EndBlock) return nullptr; @@ -3354,17 +3495,26 @@ SILDeserializer::readDifferentiabilityWitness(DeclID DId) { return diffWitnessOrOffset.get(); BCOffsetRAII restoreOffset(SILCursor); - SILCursor.JumpToBit(diffWitnessOrOffset.getOffset()); - auto entry = SILCursor.advance(AF_DontPopBlockAtEnd); + if (auto err = SILCursor.JumpToBit(diffWitnessOrOffset.getOffset())) + MF->fatal(std::move(err)); + llvm::Expected maybeEntry = + SILCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) + MF->fatal(maybeEntry.takeError()); + auto entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::Error) { - LLVM_DEBUG(llvm::dbgs() - << "Cursor advance error in readDifferentiabilityWitness.\n"); + LLVM_DEBUG(llvm::dbgs() << "Cursor advance error in " + "readDefaultWitnessTable.\n"); return nullptr; } SmallVector scratch; StringRef blobData; - unsigned kind = SILCursor.readRecord(entry.ID, scratch, &blobData); + llvm::Expected maybeKind = + SILCursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) + MF->fatal(maybeKind.takeError()); + unsigned kind = maybeKind.get(); assert(kind == SIL_DIFFERENTIABILITY_WITNESS && "Expected sil_differentiability_witness"); (void)kind; diff --git a/lib/Serialization/DeserializeSIL.h b/lib/Serialization/DeserializeSIL.h index 33f0cb4a22760..0600c58a09e3d 100644 --- a/lib/Serialization/DeserializeSIL.h +++ b/lib/Serialization/DeserializeSIL.h @@ -117,6 +117,9 @@ namespace swift { SILValue getLocalValue(serialization::ValueID Id, SILType Type); + SILType getSILType(Type ty, SILValueCategory category, + SILFunction *inContext); + // SWIFT_ENABLE_TENSORFLOW SILDifferentiabilityWitness *getSILDifferentiabilityWitnessForReference( StringRef mangledKey); diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index 3d97cc57621eb..710254f943a47 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -44,16 +44,31 @@ static_assert(IsTriviallyDestructible::value, static bool checkModuleSignature(llvm::BitstreamCursor &cursor, ArrayRef signature) { - for (unsigned char byte : signature) - if (cursor.AtEndOfStream() || cursor.Read(8) != byte) + for (unsigned char byte : signature) { + if (cursor.AtEndOfStream()) return false; + if (Expected maybeRead = + cursor.Read(8)) { + if (maybeRead.get() != byte) + return false; + } else { + consumeError(maybeRead.takeError()); + return false; + } + } return true; } static bool enterTopLevelModuleBlock(llvm::BitstreamCursor &cursor, unsigned ID, bool shouldReadBlockInfo = true) { - auto next = cursor.advance(); + Expected maybeNext = cursor.advance(); + if (!maybeNext) { + // FIXME this drops the error on the floor. + consumeError(maybeNext.takeError()); + return false; + } + llvm::BitstreamEntry next = maybeNext.get(); if (next.Kind != llvm::BitstreamEntry::SubBlock) return false; @@ -72,7 +87,12 @@ static bool enterTopLevelModuleBlock(llvm::BitstreamCursor &cursor, if (next.ID != ID) return false; - cursor.EnterSubBlock(ID); + if (llvm::Error Err = cursor.EnterSubBlock(ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + return false; + } + return true; } @@ -83,7 +103,13 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor, SmallVectorImpl &scratch, ExtendedValidationInfo &extendedInfo) { while (!cursor.AtEndOfStream()) { - auto entry = cursor.advance(); + Expected maybeEntry = cursor.advance(); + if (!maybeEntry) { + // FIXME this drops the error on the floor. + consumeError(maybeEntry.takeError()); + return false; + } + llvm::BitstreamEntry entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::EndBlock) break; @@ -100,7 +126,14 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor, scratch.clear(); StringRef blobData; - unsigned kind = cursor.readRecord(entry.ID, scratch, &blobData); + Expected maybeKind = + cursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) { + // FIXME this drops the error on the floor. + consumeError(maybeKind.takeError()); + return false; + } + unsigned kind = maybeKind.get(); switch (kind) { case options_block::SDK_PATH: extendedInfo.setSDKPath(blobData); @@ -145,7 +178,14 @@ validateControlBlock(llvm::BitstreamCursor &cursor, bool versionSeen = false; while (!cursor.AtEndOfStream()) { - auto entry = cursor.advance(); + Expected maybeEntry = cursor.advance(); + if (!maybeEntry) { + // FIXME this drops the error on the floor. + consumeError(maybeEntry.takeError()); + result.status = Status::Malformed; + return result; + } + llvm::BitstreamEntry entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::EndBlock) break; @@ -156,7 +196,12 @@ validateControlBlock(llvm::BitstreamCursor &cursor, if (entry.Kind == llvm::BitstreamEntry::SubBlock) { if (entry.ID == OPTIONS_BLOCK_ID && extendedInfo) { - cursor.EnterSubBlock(OPTIONS_BLOCK_ID); + if (llvm::Error Err = cursor.EnterSubBlock(OPTIONS_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + result.status = Status::Malformed; + return result; + } if (!readOptionsBlock(cursor, scratch, *extendedInfo)) { result.status = Status::Malformed; return result; @@ -174,7 +219,15 @@ validateControlBlock(llvm::BitstreamCursor &cursor, scratch.clear(); StringRef blobData; - unsigned kind = cursor.readRecord(entry.ID, scratch, &blobData); + Expected maybeKind = + cursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) { + // FIXME this drops the error on the floor. + consumeError(maybeKind.takeError()); + result.status = Status::Malformed; + return result; + } + unsigned kind = maybeKind.get(); switch (kind) { case control_block::METADATA: { if (versionSeen) { @@ -247,7 +300,13 @@ static bool validateInputBlock( SmallString<256> dependencyFullPathBuffer; while (!cursor.AtEndOfStream()) { - auto entry = cursor.advance(); + Expected maybeEntry = cursor.advance(); + if (!maybeEntry) { + // FIXME this drops the error on the floor. + consumeError(maybeEntry.takeError()); + return true; + } + llvm::BitstreamEntry entry = maybeEntry.get(); if (entry.Kind == llvm::BitstreamEntry::EndBlock) break; @@ -256,7 +315,14 @@ static bool validateInputBlock( scratch.clear(); StringRef blobData; - unsigned kind = cursor.readRecord(entry.ID, scratch, &blobData); + Expected maybeKind = + cursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) { + // FIXME this drops the error on the floor. + consumeError(maybeKind.takeError()); + return true; + } + unsigned kind = maybeKind.get(); switch (kind) { case input_block::FILE_DEPENDENCY: { bool isHashBased = scratch[2] != 0; @@ -323,12 +389,25 @@ ValidationInfo serialization::validateSerializedAST( llvm::BitstreamEntry topLevelEntry; while (!cursor.AtEndOfStream()) { - topLevelEntry = cursor.advance(AF_DontPopBlockAtEnd); + Expected maybeEntry = + cursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) { + // FIXME this drops the error on the floor. + consumeError(maybeEntry.takeError()); + result.status = Status::Malformed; + return result; + } + topLevelEntry = maybeEntry.get(); if (topLevelEntry.Kind != llvm::BitstreamEntry::SubBlock) break; if (topLevelEntry.ID == CONTROL_BLOCK_ID) { - cursor.EnterSubBlock(CONTROL_BLOCK_ID); + if (llvm::Error Err = cursor.EnterSubBlock(CONTROL_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + result.status = Status::Malformed; + return result; + } result = validateControlBlock(cursor, scratch, {SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR}, @@ -338,7 +417,12 @@ ValidationInfo serialization::validateSerializedAST( } else if (dependencies && result.status == Status::Valid && topLevelEntry.ID == INPUT_BLOCK_ID) { - cursor.EnterSubBlock(INPUT_BLOCK_ID); + if (llvm::Error Err = cursor.EnterSubBlock(INPUT_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + result.status = Status::Malformed; + return result; + } if (validateInputBlock(cursor, scratch, *dependencies)) { result.status = Status::Malformed; return result; @@ -827,13 +911,23 @@ ModuleFile::readObjCMethodTable(ArrayRef fields, StringRef blobData) { } bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) { - cursor.EnterSubBlock(INDEX_BLOCK_ID); + if (llvm::Error Err = cursor.EnterSubBlock(INDEX_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + return false; + } SmallVector scratch; StringRef blobData; while (!cursor.AtEndOfStream()) { - auto entry = cursor.advance(); + Expected maybeEntry = cursor.advance(); + if (!maybeEntry) { + // FIXME this drops the error on the floor. + consumeError(maybeEntry.takeError()); + return false; + } + llvm::BitstreamEntry entry = maybeEntry.get(); switch (entry.Kind) { case llvm::BitstreamEntry::EndBlock: return true; @@ -844,13 +938,25 @@ bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) { case llvm::BitstreamEntry::SubBlock: if (entry.ID == DECL_MEMBER_TABLES_BLOCK_ID) { DeclMemberTablesCursor = cursor; - DeclMemberTablesCursor.EnterSubBlock(DECL_MEMBER_TABLES_BLOCK_ID); + if (llvm::Error Err = DeclMemberTablesCursor.EnterSubBlock( + DECL_MEMBER_TABLES_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + return false; + } llvm::BitstreamEntry subentry; do { // Scan forward, to load the cursor with any abbrevs we'll need while // seeking inside this block later. - subentry = DeclMemberTablesCursor.advance( - llvm::BitstreamCursor::AF_DontPopBlockAtEnd); + Expected maybeEntry = + DeclMemberTablesCursor.advance( + llvm::BitstreamCursor::AF_DontPopBlockAtEnd); + if (!maybeEntry) { + // FIXME this drops the error on the floor. + consumeError(maybeEntry.takeError()); + return false; + } + subentry = maybeEntry.get(); } while (!DeclMemberTablesCursor.AtEndOfStream() && subentry.Kind != llvm::BitstreamEntry::Record && subentry.Kind != llvm::BitstreamEntry::EndBlock); @@ -862,7 +968,14 @@ bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) { case llvm::BitstreamEntry::Record: scratch.clear(); blobData = {}; - unsigned kind = cursor.readRecord(entry.ID, scratch, &blobData); + Expected maybeKind = + cursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) { + // FIXME this drops the error on the floor. + consumeError(maybeKind.takeError()); + return false; + } + unsigned kind = maybeKind.get(); switch (kind) { case index_block::DECL_OFFSETS: @@ -1044,13 +1157,23 @@ ModuleFile::readGroupTable(ArrayRef Fields, StringRef BlobData) { } bool ModuleFile::readCommentBlock(llvm::BitstreamCursor &cursor) { - cursor.EnterSubBlock(COMMENT_BLOCK_ID); + if (llvm::Error Err = cursor.EnterSubBlock(COMMENT_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + return false; + } SmallVector scratch; StringRef blobData; while (!cursor.AtEndOfStream()) { - auto entry = cursor.advance(); + Expected maybeEntry = cursor.advance(); + if (!maybeEntry) { + // FIXME this drops the error on the floor. + consumeError(maybeEntry.takeError()); + return false; + } + llvm::BitstreamEntry entry = maybeEntry.get(); switch (entry.Kind) { case llvm::BitstreamEntry::EndBlock: return true; @@ -1066,7 +1189,14 @@ bool ModuleFile::readCommentBlock(llvm::BitstreamCursor &cursor) { case llvm::BitstreamEntry::Record: scratch.clear(); - unsigned kind = cursor.readRecord(entry.ID, scratch, &blobData); + Expected maybeKind = + cursor.readRecord(entry.ID, scratch, &blobData); + if (!maybeKind) { + // FIXME this drops the error on the floor. + consumeError(maybeKind.takeError()); + return false; + } + unsigned kind = maybeKind.get(); switch (kind) { case comment_block::DECL_COMMENTS: @@ -1181,13 +1311,24 @@ bool ModuleFile::readModuleDocIfPresent() { ValidationInfo info; while (!docCursor.AtEndOfStream()) { - topLevelEntry = docCursor.advance(AF_DontPopBlockAtEnd); + Expected maybeEntry = + docCursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) { + // FIXME this drops the error on the floor. + consumeError(maybeEntry.takeError()); + return false; + } + topLevelEntry = maybeEntry.get(); if (topLevelEntry.Kind != llvm::BitstreamEntry::SubBlock) break; switch (topLevelEntry.ID) { case CONTROL_BLOCK_ID: { - docCursor.EnterSubBlock(CONTROL_BLOCK_ID); + if (llvm::Error Err = docCursor.EnterSubBlock(CONTROL_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + return false; + } info = validateControlBlock(docCursor, scratch, {SWIFTDOC_VERSION_MAJOR, @@ -1270,14 +1411,21 @@ ModuleFile::readDeclUSRsTable(ArrayRef fields, StringRef blobData) { } bool ModuleFile::readDeclLocsBlock(llvm::BitstreamCursor &cursor) { - cursor.EnterSubBlock(DECL_LOCS_BLOCK_ID); + if (llvm::Error Err = cursor.EnterSubBlock(CONTROL_BLOCK_ID)) { + consumeError(std::move(Err)); + return false; + } SmallVector scratch; StringRef blobData; while (!cursor.AtEndOfStream()) { - auto entry = cursor.advance(); - switch (entry.Kind) { + Expected entry = cursor.advance(); + if (!entry) { + consumeError(entry.takeError()); + return false; + } + switch (entry->Kind) { case llvm::BitstreamEntry::EndBlock: return true; @@ -1292,9 +1440,13 @@ bool ModuleFile::readDeclLocsBlock(llvm::BitstreamCursor &cursor) { case llvm::BitstreamEntry::Record: scratch.clear(); - unsigned kind = cursor.readRecord(entry.ID, scratch, &blobData); - - switch (kind) { + Expected kind = + cursor.readRecord(entry->ID, scratch, &blobData); + if (!kind) { + consumeError(kind.takeError()); + return false; + } + switch (*kind) { case decl_locs_block::BASIC_DECL_LOCS: BasicDeclLocsData = blobData; break; @@ -1326,20 +1478,28 @@ bool ModuleFile::readModuleSourceInfoIfPresent() { } SmallVector scratch; - llvm::BitstreamEntry topLevelEntry; bool hasValidControlBlock = false; ValidationInfo info; + unsigned kind = llvm::BitstreamEntry::Error; while (!infoCursor.AtEndOfStream()) { - topLevelEntry = infoCursor.advance(AF_DontPopBlockAtEnd); - if (topLevelEntry.Kind != llvm::BitstreamEntry::SubBlock) + Expected topLevelEntry = + infoCursor.advance(AF_DontPopBlockAtEnd); + if (!topLevelEntry) { + consumeError(topLevelEntry.takeError()); + return false; + } + kind = topLevelEntry->Kind; + if (kind != llvm::BitstreamEntry::SubBlock) break; - switch (topLevelEntry.ID) { + switch (topLevelEntry->ID) { case CONTROL_BLOCK_ID: { - infoCursor.EnterSubBlock(CONTROL_BLOCK_ID); - + if (llvm::Error Err = infoCursor.EnterSubBlock(CONTROL_BLOCK_ID)) { + consumeError(std::move(Err)); + return false; + } info = validateControlBlock(infoCursor, scratch, {SWIFTSOURCEINFO_VERSION_MAJOR, SWIFTSOURCEINFO_VERSION_MINOR}, @@ -1368,7 +1528,7 @@ bool ModuleFile::readModuleSourceInfoIfPresent() { } } - if (topLevelEntry.Kind != llvm::BitstreamEntry::EndBlock) + if (kind != llvm::BitstreamEntry::EndBlock) return false; return true; @@ -1405,13 +1565,26 @@ ModuleFile::ModuleFile( llvm::BitstreamEntry topLevelEntry; while (!cursor.AtEndOfStream()) { - topLevelEntry = cursor.advance(AF_DontPopBlockAtEnd); + Expected maybeEntry = + cursor.advance(AF_DontPopBlockAtEnd); + if (!maybeEntry) { + // FIXME this drops the error diagnostic on the floor. + consumeError(maybeEntry.takeError()); + info.status = error(Status::Malformed); + return; + } + topLevelEntry = maybeEntry.get(); if (topLevelEntry.Kind != llvm::BitstreamEntry::SubBlock) break; switch (topLevelEntry.ID) { case CONTROL_BLOCK_ID: { - cursor.EnterSubBlock(CONTROL_BLOCK_ID); + if (llvm::Error Err = cursor.EnterSubBlock(CONTROL_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + info.status = error(Status::Malformed); + return; + } info = validateControlBlock(cursor, scratch, {SWIFTMODULE_VERSION_MAJOR, @@ -1436,13 +1609,33 @@ ModuleFile::ModuleFile( return; } - cursor.EnterSubBlock(INPUT_BLOCK_ID); + if (llvm::Error Err = cursor.EnterSubBlock(INPUT_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + info.status = error(Status::Malformed); + return; + } - auto next = cursor.advance(); + Expected maybeNext = cursor.advance(); + if (!maybeNext) { + // FIXME this drops the error on the floor. + consumeError(maybeNext.takeError()); + info.status = error(Status::Malformed); + return; + } + llvm::BitstreamEntry next = maybeNext.get(); while (next.Kind == llvm::BitstreamEntry::Record) { scratch.clear(); StringRef blobData; - unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); + Expected maybeKind = + cursor.readRecord(next.ID, scratch, &blobData); + if (!maybeKind) { + // FIXME this drops the error on the floor. + consumeError(maybeKind.takeError()); + info.status = error(Status::Malformed); + return; + } + unsigned kind = maybeKind.get(); switch (kind) { case input_block::IMPORTED_MODULE: { unsigned rawImportControl; @@ -1504,7 +1697,14 @@ ModuleFile::ModuleFile( break; } - next = cursor.advance(); + maybeNext = cursor.advance(); + if (!maybeNext) { + // FIXME this drops the error on the floor. + consumeError(maybeNext.takeError()); + info.status = error(Status::Malformed); + return; + } + next = maybeNext.get(); } if (next.Kind != llvm::BitstreamEntry::EndBlock) @@ -1522,8 +1722,22 @@ ModuleFile::ModuleFile( // The decls-and-types block is lazily loaded. Save the cursor and load // any abbrev records at the start of the block. DeclTypeCursor = cursor; - DeclTypeCursor.EnterSubBlock(DECLS_AND_TYPES_BLOCK_ID); - if (DeclTypeCursor.advance().Kind == llvm::BitstreamEntry::Error) + if (llvm::Error Err = + DeclTypeCursor.EnterSubBlock(DECLS_AND_TYPES_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + info.status = error(Status::Malformed); + return; + } + + Expected maybeCursor = DeclTypeCursor.advance(); + if (!maybeCursor) { + // FIXME this drops the error on the floor. + consumeError(maybeCursor.takeError()); + info.status = error(Status::Malformed); + return; + } + if (maybeCursor.get().Kind == llvm::BitstreamEntry::Error) info.status = error(Status::Malformed); // With the main cursor, skip over the block and continue. @@ -1540,13 +1754,34 @@ ModuleFile::ModuleFile( return; } - cursor.EnterSubBlock(IDENTIFIER_DATA_BLOCK_ID); + if (llvm::Error Err = cursor.EnterSubBlock(IDENTIFIER_DATA_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + info.status = error(Status::Malformed); + return; + } - auto next = cursor.advanceSkippingSubblocks(); + Expected maybeNext = + cursor.advanceSkippingSubblocks(); + if (!maybeNext) { + // FIXME this drops the error on the floor. + consumeError(maybeNext.takeError()); + info.status = error(Status::Malformed); + return; + } + llvm::BitstreamEntry next = maybeNext.get(); while (next.Kind == llvm::BitstreamEntry::Record) { scratch.clear(); StringRef blobData; - unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); + Expected maybeKind = + cursor.readRecord(next.ID, scratch, &blobData); + if (!maybeKind) { + // FIXME this drops the error on the floor. + consumeError(maybeKind.takeError()); + info.status = error(Status::Malformed); + return; + } + unsigned kind = maybeKind.get(); switch (kind) { case identifier_block::IDENTIFIER_DATA: @@ -1559,7 +1794,14 @@ ModuleFile::ModuleFile( break; } - next = cursor.advanceSkippingSubblocks(); + maybeNext = cursor.advanceSkippingSubblocks(); + if (!maybeNext) { + // FIXME this drops the error on the floor. + consumeError(maybeNext.takeError()); + info.status = error(Status::Malformed); + return; + } + next = maybeNext.get(); } if (next.Kind != llvm::BitstreamEntry::EndBlock) { @@ -1581,7 +1823,12 @@ ModuleFile::ModuleFile( case SIL_INDEX_BLOCK_ID: { // Save the cursor. SILIndexCursor = cursor; - SILIndexCursor.EnterSubBlock(SIL_INDEX_BLOCK_ID); + if (llvm::Error Err = SILIndexCursor.EnterSubBlock(SIL_INDEX_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + info.status = error(Status::Malformed); + return; + } // With the main cursor, skip over the block and continue. if (cursor.SkipBlock()) { @@ -1594,7 +1841,12 @@ ModuleFile::ModuleFile( case SIL_BLOCK_ID: { // Save the cursor. SILCursor = cursor; - SILCursor.EnterSubBlock(SIL_BLOCK_ID); + if (llvm::Error Err = SILCursor.EnterSubBlock(SIL_BLOCK_ID)) { + // FIXME this drops the error on the floor. + consumeError(std::move(Err)); + info.status = error(Status::Malformed); + return; + } // With the main cursor, skip over the block and continue. if (cursor.SkipBlock()) { @@ -2138,16 +2390,17 @@ ModuleFile::loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N, DeclMembersTables[subTableOffset]; if (!subTable) { BCOffsetRAII restoreOffset(DeclMemberTablesCursor); - DeclMemberTablesCursor.JumpToBit(subTableOffset); - auto entry = DeclMemberTablesCursor.advance(); + fatalIfNotSuccess(DeclMemberTablesCursor.JumpToBit(subTableOffset)); + llvm::BitstreamEntry entry = + fatalIfUnexpected(DeclMemberTablesCursor.advance()); if (entry.Kind != llvm::BitstreamEntry::Record) { fatal(); return None; } SmallVector scratch; StringRef blobData; - unsigned kind = DeclMemberTablesCursor.readRecord(entry.ID, scratch, - &blobData); + unsigned kind = fatalIfUnexpected( + DeclMemberTablesCursor.readRecord(entry.ID, scratch, &blobData)); assert(kind == decl_member_tables_block::DECL_MEMBERS); (void)kind; subTable = readDeclMembersTable(scratch, blobData); @@ -2166,7 +2419,7 @@ ModuleFile::loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N, } else { if (!getContext().LangOpts.EnableDeserializationRecovery) fatal(mem.takeError()); - llvm::consumeError(mem.takeError()); + consumeError(mem.takeError()); // Treat this as a cache-miss to the caller and let them attempt // to refill through the normal loadAllMembers() path. @@ -2293,7 +2546,7 @@ void ModuleFile::getTopLevelDecls(SmallVectorImpl &results) { if (!declOrError) { if (!getContext().LangOpts.EnableDeserializationRecovery) fatal(declOrError.takeError()); - llvm::consumeError(declOrError.takeError()); + consumeError(declOrError.takeError()); continue; } results.push_back(declOrError.get()); diff --git a/lib/Serialization/ModuleFile.h b/lib/Serialization/ModuleFile.h index c73b3a6b6ad4b..a18febcfdab1b 100644 --- a/lib/Serialization/ModuleFile.h +++ b/lib/Serialization/ModuleFile.h @@ -26,7 +26,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/TinyPtrVector.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" @@ -474,6 +474,15 @@ class ModuleFile /// Emits one last diagnostic, logs the error, and then aborts for the stack /// trace. LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error error); + void fatalIfNotSuccess(llvm::Error error) { + if (error) + fatal(std::move(error)); + } + template T fatalIfUnexpected(llvm::Expected expected) { + if (expected) + return std::move(expected.get()); + fatal(expected.takeError()); + } LLVM_ATTRIBUTE_NORETURN void fatal() { fatal(llvm::make_error( diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index e9888d0507f08..34aaadc818edb 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -22,7 +22,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/Types.h" #include "llvm/Bitcode/RecordLayout.h" -#include "llvm/Bitcode/BitCodes.h" +#include "llvm/Bitstream/BitCodes.h" #include "llvm/ADT/PointerEmbeddedInt.h" namespace swift { @@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 526; // deleted SIL [differentiable] attr +const uint16_t SWIFTMODULE_VERSION_MINOR = 527; // tensorflow merge; function type differentiability /// A standard hash seed used for all string hashes in a serialized module. /// @@ -223,6 +223,15 @@ enum class FunctionTypeRepresentation : uint8_t { }; using FunctionTypeRepresentationField = BCFixed<4>; +// These IDs must \em not be renumbered or reordered without incrementing +// the module version. +enum class DifferentiabilityKind : uint8_t { + NonDifferentiable = 0, + Normal, + Linear, +}; +using DifferentiabilityKindField = BCFixed<2>; + enum class ForeignErrorConventionKind : uint8_t { ZeroResult, NonZeroResult, @@ -326,16 +335,6 @@ enum class ParameterConvention : uint8_t { }; using ParameterConventionField = BCFixed<4>; -// SWIFT_ENABLE_TENSORFLOW -// These IDs must \em not be renumbered or reordered without incrementing the -// module version. -enum class DifferentiabilityKind : uint8_t { - NonDifferentiable = 0, - Normal = 1, - Linear = 2 -}; -using DifferentiabilityKindField = BCFixed<2>; - // These IDs must \em not be renumbered or reordered without incrementing // the module version. enum class SILParameterDifferentiability : uint8_t { @@ -892,9 +891,8 @@ namespace decls_block { TypeIDField, // output FunctionTypeRepresentationField, // representation BCFixed<1>, // noescape? - // SWIFT_ENABLE_TENSORFLOW - BCFixed<1>, // throws? - BCFixed<2> // differentiability kind + BCFixed<1>, // throws? + DifferentiabilityKindField // differentiability kind // trailed by parameters >; @@ -968,8 +966,7 @@ namespace decls_block { TypeIDField, // output FunctionTypeRepresentationField, // representation BCFixed<1>, // throws? - // SWIFT_ENABLE_TENSORFLOW - BCFixed<2>, // differentiable & linear? + DifferentiabilityKindField, // differentiability kind GenericSignatureIDField // generic signture // trailed by parameters @@ -982,7 +979,6 @@ namespace decls_block { SILFunctionTypeRepresentationField, // representation BCFixed<1>, // pseudogeneric? BCFixed<1>, // noescape? - // SWIFT_ENABLE_TENSORFLOW DifferentiabilityKindField, // differentiability kind BCFixed<1>, // error result? BCVBR<6>, // number of parameters @@ -1758,7 +1754,6 @@ namespace decls_block { GenericSignatureIDField // specialized signature >; - // SWIFT_ENABLE_TENSORFLOW using DifferentiableDeclAttrLayout = BCRecordLayout< Differentiable_DECL_ATTR, BCFixed<1>, // Implicit flag. @@ -1792,7 +1787,7 @@ namespace decls_block { BCArray> // Differentiation parameter indices' bitvector. >; -#define SIMPLE_DECL_ATTR(X, CLASS, ...) \ +#define SIMPLE_DECL_ATTR(X, CLASS, ...) \ using CLASS##DeclAttrLayout = BCRecordLayout< \ CLASS##_DECL_ATTR, \ BCFixed<1> /* implicit flag */ \ diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index be8839c629d3a..ca55df9515c66 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -15,11 +15,13 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/AutoDiff.h" #include "swift/AST/DiagnosticsCommon.h" #include "swift/AST/Expr.h" #include "swift/AST/FileSystem.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" +#include "swift/AST/IndexSubset.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/LinkLibrary.h" @@ -44,8 +46,8 @@ #include "swift/Strings.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Bitcode/RecordLayout.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Config/config.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Chrono.h" @@ -2305,7 +2307,6 @@ class Serializer::DeclSerializer : public DeclVisitor { break; } - // SWIFT_ENABLE_TENSORFLOW case DAK_Differentiable: { auto abbrCode = S.DeclTypeAbbrCodes[DifferentiableDeclAttrLayout::Code]; auto *attr = cast(DA); @@ -3651,6 +3652,18 @@ static uint8_t getRawStableFunctionTypeRepresentation( llvm_unreachable("bad calling convention"); } +/// Translate from the AST differentiability kind enum to the Serialization enum +/// values, which are guaranteed to be stable. +static uint8_t getRawStableDifferentiabilityKind( + swift::DifferentiabilityKind diffKind) { + switch (diffKind) { + SIMPLE_CASE(DifferentiabilityKind, NonDifferentiable) + SIMPLE_CASE(DifferentiabilityKind, Normal) + SIMPLE_CASE(DifferentiabilityKind, Linear) + } + llvm_unreachable("bad differentiability kind"); +} + /// Translate from the AST function representation enum to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t getRawStableSILFunctionTypeRepresentation( @@ -3680,19 +3693,6 @@ static uint8_t getRawStableSILCoroutineKind( llvm_unreachable("bad kind"); } -// SWIFT_ENABLE_TENSORFLOW -/// Translate from the AST differentiability kind enum to the Serialization enum -/// values, which are guaranteed to be stable. -static uint8_t getRawStableDifferentiabilityKind( - swift::DifferentiabilityKind kind) { - switch (kind) { - SIMPLE_CASE(DifferentiabilityKind, NonDifferentiable) - SIMPLE_CASE(DifferentiabilityKind, Normal) - SIMPLE_CASE(DifferentiabilityKind, Linear) - } - llvm_unreachable("bad differentiability kind"); -} - /// Translate from the AST ownership enum to the Serialization enum /// values, which are guaranteed to be stable. static uint8_t @@ -3999,15 +3999,13 @@ class Serializer::TypeSerializer : public TypeVisitor { void visitFunctionType(const FunctionType *fnTy) { using namespace decls_block; - unsigned abbrCode = S.DeclTypeAbbrCodes[FunctionTypeLayout::Code]; FunctionTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(fnTy->getResult()), getRawStableFunctionTypeRepresentation(fnTy->getRepresentation()), fnTy->isNoEscape(), - // SWIFT_ENABLE_TENSORFLOW fnTy->throws(), - (uint8_t)fnTy->getDifferentiabilityKind()); + getRawStableDifferentiabilityKind(fnTy->getDifferentiabilityKind())); serializeFunctionTypeParams(fnTy); } @@ -4015,14 +4013,13 @@ class Serializer::TypeSerializer : public TypeVisitor { void visitGenericFunctionType(const GenericFunctionType *fnTy) { using namespace decls_block; assert(!fnTy->isNoEscape()); - auto genericSig = fnTy->getGenericSignature(); unsigned abbrCode = S.DeclTypeAbbrCodes[GenericFunctionTypeLayout::Code]; GenericFunctionTypeLayout::emitRecord(S.Out, S.ScratchRecord, abbrCode, S.addTypeRef(fnTy->getResult()), getRawStableFunctionTypeRepresentation(fnTy->getRepresentation()), - // SWIFT_ENABLE_TENSORFLOW - fnTy->throws(), fnTy->isDifferentiable(), + fnTy->throws(), + getRawStableDifferentiabilityKind(fnTy->getDifferentiabilityKind()), S.addGenericSignatureRef(genericSig)); serializeFunctionTypeParams(fnTy); @@ -4048,11 +4045,8 @@ class Serializer::TypeSerializer : public TypeVisitor { using namespace decls_block; auto representation = fnTy->getRepresentation(); - // SWIFT_ENABLE_TENSORFLOW auto stableRepresentation = - getRawStableSILFunctionTypeRepresentation(representation); - auto stableDifferentiabilityKind = - getRawStableDifferentiabilityKind(fnTy->getDifferentiabilityKind()); + getRawStableSILFunctionTypeRepresentation(representation); SmallVector variableData; for (auto param : fnTy->getParameters()) { @@ -4089,15 +4083,17 @@ class Serializer::TypeSerializer : public TypeVisitor { auto stableCalleeConvention = getRawStableParameterConvention(fnTy->getCalleeConvention()); + auto stableDiffKind = + getRawStableDifferentiabilityKind(fnTy->getDifferentiabilityKind()); + unsigned abbrCode = S.DeclTypeAbbrCodes[SILFunctionTypeLayout::Code]; SILFunctionTypeLayout::emitRecord( S.Out, S.ScratchRecord, abbrCode, stableCoroutineKind, stableCalleeConvention, stableRepresentation, fnTy->isPseudogeneric(), fnTy->isNoEscape(), - // SWIFT_ENABLE_TENSORFLOW - stableDifferentiabilityKind, fnTy->hasErrorResult(), - fnTy->getParameters().size(), fnTy->getNumYields(), - fnTy->getNumResults(), S.addGenericSignatureRef(sig), variableData); + stableDiffKind, fnTy->hasErrorResult(), fnTy->getParameters().size(), + fnTy->getNumYields(), fnTy->getNumResults(), + S.addGenericSignatureRef(sig), variableData); if (auto conformance = fnTy->getWitnessMethodConformanceOrInvalid()) S.writeConformance(conformance, S.DeclTypeAbbrCodes); @@ -4879,7 +4875,8 @@ void swift::serializeToBuffers( assert(!StringRef::withNullAsEmpty(options.OutputPath).empty()); { - SharedTimer timer("Serialization, swiftmodule, to buffer"); + FrontendStatsTracer tracer(getContext(DC).Stats, + "Serialization, swiftmodule, to buffer"); llvm::SmallString<1024> buf; llvm::raw_svector_ostream stream(buf); Serializer::writeToStream(stream, DC, M, options); @@ -4897,7 +4894,8 @@ void swift::serializeToBuffers( } if (!StringRef::withNullAsEmpty(options.DocOutputPath).empty()) { - SharedTimer timer("Serialization, swiftdoc, to buffer"); + FrontendStatsTracer tracer(getContext(DC).Stats, + "Serialization, swiftdoc, to buffer"); llvm::SmallString<1024> buf; llvm::raw_svector_ostream stream(buf); writeDocToStream(stream, DC, options.GroupInfoPath); @@ -4913,7 +4911,8 @@ void swift::serializeToBuffers( } if (!StringRef::withNullAsEmpty(options.SourceInfoOutputPath).empty()) { - SharedTimer timer("Serialization, swiftsourceinfo, to buffer"); + FrontendStatsTracer tracer(getContext(DC).Stats, + "Serialization, swiftsourceinfo, to buffer"); llvm::SmallString<1024> buf; llvm::raw_svector_ostream stream(buf); writeSourceInfoToStream(stream, DC); @@ -4968,7 +4967,8 @@ void swift::serialize(ModuleOrSourceFile DC, bool hadError = withOutputFile(getContext(DC).Diags, options.OutputPath, [&](raw_ostream &out) { - SharedTimer timer("Serialization, swiftmodule"); + FrontendStatsTracer tracer(getContext(DC).Stats, + "Serialization, swiftmodule"); Serializer::writeToStream(out, DC, M, options); return false; }); @@ -4979,7 +4979,8 @@ void swift::serialize(ModuleOrSourceFile DC, (void)withOutputFile(getContext(DC).Diags, options.DocOutputPath, [&](raw_ostream &out) { - SharedTimer timer("Serialization, swiftdoc"); + FrontendStatsTracer tracer(getContext(DC).Stats, + "Serialization, swiftdoc"); writeDocToStream(out, DC, options.GroupInfoPath); return false; }); @@ -4989,7 +4990,8 @@ void swift::serialize(ModuleOrSourceFile DC, (void)withOutputFile(getContext(DC).Diags, options.SourceInfoOutputPath, [&](raw_ostream &out) { - SharedTimer timer("Serialization, swiftsourceinfo"); + FrontendStatsTracer tracer(getContext(DC).Stats, + "Serialization, swiftsourceinfo"); writeSourceInfoToStream(out, DC); return false; }); diff --git a/lib/Syntax/README.md b/lib/Syntax/README.md index 795b3c12cda7d..f6399b9767c4a 100644 --- a/lib/Syntax/README.md +++ b/lib/Syntax/README.md @@ -260,7 +260,7 @@ pieces of syntax that aren't really relevant to the semantics of the program, such as whitespace and comments. These are modeled as collections and, with the exception of comments, are sort of "run-length" encoded. For example, a sequence of four spaces is represented by `{ Kind: TriviaKind::Space, Count: 4 }`, not -the literal text `" "`. +the literal text `"    "`. Some examples of the "atoms" of `Trivia`: @@ -505,7 +505,7 @@ following fields: | Key | Type | Description | | --- | ---- | ----------- | -| `kind` | `String` | The `SyntaxKind` of this child. This must have a corresponding `Node` with that kind. | +| `kind` | `String` | The `SyntaxKind` of this child. This must have a corresponding `Node` with that kind (or corresponding `Token` in both `include/swift/Syntax/TokenKinds.def` and `SYNTAX_TOKENS`). | | `is_optional` | `Bool?` | Whether this child is required in a fully-formed object, or if it is allowed to remain `missing`. Defaults to `false` if not present. | `token_choices` | `[String]?` | A list of `Token`s which are considered "valid" values for `Token` children. | | `text_choices` | `[String]?` | A list of valid textual values for tokens. If this is not provided, any textual value is accepted for tokens like `IdentifierToken`. | @@ -513,7 +513,7 @@ following fields: #### Tokens A `Token` represents one of the `tok::` enums in -`include/Syntax/TokenKinds.def`. `Token.py` has a top-level array of token +`include/swift/Syntax/TokenKinds.def`. `Token.py` has a top-level array of token declarations. The `Token` class has the following fields. | Key | Type | Description | diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index 5b811979652aa..bfacf0d8f6d45 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -19,6 +19,7 @@ #include "swift/AST/Availability.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/PropertyWrappers.h" @@ -643,16 +644,44 @@ void TBDGenVisitor::addFirstFileSymbols() { } } -/// Converts a version tuple into a packed version, ignoring components beyond -/// major, minor, and subminor. -static llvm::MachO::PackedVersion -convertToPacked(const version::Version &version) { - // FIXME: Warn if version is greater than 3 components? - unsigned major = 0, minor = 0, subminor = 0; - if (version.size() > 0) major = version[0]; - if (version.size() > 1) minor = version[1]; - if (version.size() > 2) subminor = version[2]; - return llvm::MachO::PackedVersion(major, minor, subminor); +/// The kind of version being parsed, used for diagnostics. +/// Note: Must match the order in DiagnosticsFrontend.def +enum DylibVersionKind_t: unsigned { + CurrentVersion, + CompatibilityVersion +}; + +/// Converts a version string into a packed version, truncating each component +/// if necessary to fit all 3 into a 32-bit packed structure. +/// +/// For example, the version '1219.37.11' will be packed as +/// +/// Major (1,219) Minor (37) Patch (11) +/// ┌───────────────────┬──────────┬──────────┐ +/// │ 00001100 11000011 │ 00100101 │ 00001011 │ +/// └───────────────────┴──────────┴──────────┘ +/// +/// If an individual component is greater than the highest number that can be +/// represented in its alloted space, it will be truncated to the maximum value +/// that fits in the alloted space, which matches the behavior of the linker. +static Optional +parsePackedVersion(DylibVersionKind_t kind, StringRef versionString, + ASTContext &ctx) { + if (versionString.empty()) + return None; + + llvm::MachO::PackedVersion version; + auto result = version.parse64(versionString); + if (!result.first) { + ctx.Diags.diagnose(SourceLoc(), diag::tbd_err_invalid_version, + (unsigned)kind, versionString); + return None; + } + if (result.second) { + ctx.Diags.diagnose(SourceLoc(), diag::tbd_warn_truncating_version, + (unsigned)kind, versionString); + } + return version; } static bool isApplicationExtensionSafe(const LangOptions &LangOpts) { @@ -677,16 +706,20 @@ static void enumeratePublicSymbolsAndWrite(ModuleDecl *M, FileUnit *singleFile, file.setApplicationExtensionSafe( isApplicationExtensionSafe(M->getASTContext().LangOpts)); file.setInstallName(opts.InstallName); - if (auto currentVersion = opts.CurrentVersion) { - file.setCurrentVersion(convertToPacked(*currentVersion)); - } - if (auto compatibilityVersion = opts.CompatibilityVersion) { - file.setCompatibilityVersion(convertToPacked(*compatibilityVersion)); - } file.setTwoLevelNamespace(); file.setSwiftABIVersion(irgen::getSwiftABIVersion()); file.setInstallAPI(opts.IsInstallAPI); + if (auto packed = parsePackedVersion(CurrentVersion, + opts.CurrentVersion, ctx)) { + file.setCurrentVersion(*packed); + } + + if (auto packed = parsePackedVersion(CompatibilityVersion, + opts.CompatibilityVersion, ctx)) { + file.setCompatibilityVersion(*packed); + } + llvm::MachO::Target target(triple); file.addTarget(target); diff --git a/stdlib/public/Darwin/Foundation/Data.swift b/stdlib/public/Darwin/Foundation/Data.swift index bf8ed4b6a3580..031c714a93f11 100644 --- a/stdlib/public/Darwin/Foundation/Data.swift +++ b/stdlib/public/Darwin/Foundation/Data.swift @@ -106,10 +106,10 @@ internal final class __DataStorage { @usableFromInline var _bytes: UnsafeMutableRawPointer? @usableFromInline var _length: Int @usableFromInline var _capacity: Int - @usableFromInline var _needToZero: Bool - @usableFromInline var _deallocator: ((UnsafeMutableRawPointer, Int) -> Void)? @usableFromInline var _offset: Int - + @usableFromInline var _deallocator: ((UnsafeMutableRawPointer, Int) -> Void)? + @usableFromInline var _needToZero: Bool + @inlinable // This is @inlinable as trivially computable. var bytes: UnsafeRawPointer? { return UnsafeRawPointer(_bytes)?.advanced(by: -_offset) diff --git a/stdlib/public/Darwin/Foundation/DateInterval.swift b/stdlib/public/Darwin/Foundation/DateInterval.swift index 6ee7f4afe01fc..13b45c1271e28 100644 --- a/stdlib/public/Darwin/Foundation/DateInterval.swift +++ b/stdlib/public/Darwin/Foundation/DateInterval.swift @@ -54,10 +54,7 @@ public struct DateInterval : ReferenceConvertible, Comparable, Hashable, Codable /// /// - precondition: `end >= start` public init(start: Date, end: Date) { - if end < start { - fatalError("Reverse intervals are not allowed") - } - + precondition(end >= start, "Reverse intervals are not allowed") self.start = start duration = end.timeIntervalSince(start) } diff --git a/stdlib/public/Darwin/Foundation/IndexSet.swift b/stdlib/public/Darwin/Foundation/IndexSet.swift index 157e9bfaf8218..4c82ebc5f5168 100644 --- a/stdlib/public/Darwin/Foundation/IndexSet.swift +++ b/stdlib/public/Darwin/Foundation/IndexSet.swift @@ -442,16 +442,23 @@ public struct IndexSet : ReferenceConvertible, Equatable, BidirectionalCollectio /// Union the `IndexSet` with `other`. public func union(_ other: IndexSet) -> IndexSet { - // This algorithm is naïve but it works. We could avoid calling insert in some cases. - - var result = IndexSet() - for r in self.rangeView { - result.insert(integersIn: r) + var result: IndexSet + var dense: IndexSet + + // Prepare to make a copy of the more sparse IndexSet to prefer copy over repeated inserts + if self.rangeView.count > other.rangeView.count { + result = self + dense = other + } else { + result = other + dense = self } - - for r in other.rangeView { - result.insert(integersIn: r) + + // Insert each range from the less sparse IndexSet + dense.rangeView.forEach { + result.insert(integersIn: $0) } + return result } diff --git a/stdlib/public/Darwin/Foundation/NSStringAPI.swift b/stdlib/public/Darwin/Foundation/NSStringAPI.swift index 8aa1929268b92..3019b5190bae2 100644 --- a/stdlib/public/Darwin/Foundation/NSStringAPI.swift +++ b/stdlib/public/Darwin/Foundation/NSStringAPI.swift @@ -1671,7 +1671,7 @@ extension StringProtocol where Index == String.Index { /// Returns `true` if `other` is non-empty and contained within `self` by /// case-sensitive, non-literal search. Otherwise, returns `false`. /// - /// Equivalent to `self.rangeOfString(other) != nil` + /// Equivalent to `self.range(of: other) != nil` public func contains(_ other: T) -> Bool { let r = self.range(of: other) != nil if #available(macOS 10.10, iOS 8.0, *) { diff --git a/stdlib/public/Reflection/TypeRefBuilder.cpp b/stdlib/public/Reflection/TypeRefBuilder.cpp index d16ad510bf3e5..5452dd11cc008 100644 --- a/stdlib/public/Reflection/TypeRefBuilder.cpp +++ b/stdlib/public/Reflection/TypeRefBuilder.cpp @@ -253,11 +253,18 @@ TypeRefBuilder::getBuiltinTypeInfo(const TypeRef *TR) { for (auto Info : ReflectionInfos) { for (auto BuiltinTypeDescriptor : Info.Builtin) { - assert(BuiltinTypeDescriptor->Size > 0); - assert(BuiltinTypeDescriptor->getAlignment() > 0); - assert(BuiltinTypeDescriptor->Stride > 0); + if (BuiltinTypeDescriptor->Stride <= 0) + continue; if (!BuiltinTypeDescriptor->hasMangledTypeName()) continue; + + auto Alignment = BuiltinTypeDescriptor->getAlignment(); + if (Alignment <= 0) + continue; + // Reject any alignment that's not a power of two. + if (Alignment & (Alignment - 1)) + continue; + auto CandidateMangledName = readTypeRef(BuiltinTypeDescriptor, BuiltinTypeDescriptor->TypeName); if (!reflectionNameMatches(CandidateMangledName, MangledName)) diff --git a/stdlib/public/core/AnyHashable.swift b/stdlib/public/core/AnyHashable.swift index 3947fc81e924f..722074bf05ed6 100644 --- a/stdlib/public/core/AnyHashable.swift +++ b/stdlib/public/core/AnyHashable.swift @@ -120,7 +120,7 @@ internal struct _ConcreteHashableBox: _AnyHashableBox { /// AnyHashable(Set(["a", "b"])): "a set of strings" /// ] /// print(descriptions[AnyHashable(42)]!) // prints "an Int" -/// print(descriptions[AnyHashable(43)]) // prints "nil" +/// print(descriptions[AnyHashable(45)]) // prints "nil" /// print(descriptions[AnyHashable(Int8(43))]!) // prints "an Int8" /// print(descriptions[AnyHashable(Set(["a", "b"]))]!) // prints "a set of strings" @frozen diff --git a/stdlib/public/core/Random.swift b/stdlib/public/core/Random.swift index 58bfeff2da169..1d32a55527cd6 100644 --- a/stdlib/public/core/Random.swift +++ b/stdlib/public/core/Random.swift @@ -144,6 +144,7 @@ extension RandomNumberGenerator { /// - Apple platforms use `arc4random_buf(3)`. /// - Linux platforms use `getrandom(2)` when available; otherwise, they read /// from `/dev/urandom`. +/// - Windows uses `BCryptGenRandom`. @frozen public struct SystemRandomNumberGenerator: RandomNumberGenerator { /// Creates a new instance of the system's default random number generator. diff --git a/stdlib/public/core/RangeReplaceableCollection.swift b/stdlib/public/core/RangeReplaceableCollection.swift index c6ae18393087c..29fd24bf1b081 100644 --- a/stdlib/public/core/RangeReplaceableCollection.swift +++ b/stdlib/public/core/RangeReplaceableCollection.swift @@ -1135,8 +1135,6 @@ extension RangeReplaceableCollection { public mutating func removeAll( where shouldBeRemoved: (Element) throws -> Bool ) rethrows { - // FIXME: Switch to using RRC.filter once stdlib is compiled for 4.0 - // self = try filter { try !predicate($0) } - self = try Self(self.lazy.filter { try !shouldBeRemoved($0) }) + self = try filter { try !shouldBeRemoved($0) } } } diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index c25154c8d061a..373f4038292e4 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -37,6 +37,7 @@ #include "llvm/Support/Compiler.h" #if SWIFT_OBJC_INTEROP #include "swift/Runtime/ObjCBridge.h" +#include "SwiftObject.h" #include "SwiftValue.h" #endif @@ -2330,9 +2331,10 @@ static bool swift_dynamicCastImpl(OpaqueValue *dest, OpaqueValue *src, case MetadataKind::Class: case MetadataKind::ObjCClassWrapper: #if SWIFT_OBJC_INTEROP - // If the destination type is an NSError, and the source type is an - // Error, then the cast can succeed by NSError bridging. - if (targetType == getNSErrorMetadata()) { + // If the destination type is an NSError or NSObject, and the source type + // is an Error, then the cast can succeed by NSError bridging. + if (targetType == getNSErrorMetadata() || + targetType == getNSObjectMetadata()) { // Don't rebridge if the source is already some kind of NSError. if (srcType->isAnyClass() && swift_dynamicCastObjCClass(*reinterpret_cast(src), diff --git a/stdlib/public/runtime/SwiftObject.h b/stdlib/public/runtime/SwiftObject.h index 5b1bbcca2ab29..1f266c4efadeb 100644 --- a/stdlib/public/runtime/SwiftObject.h +++ b/stdlib/public/runtime/SwiftObject.h @@ -29,6 +29,7 @@ #if SWIFT_OBJC_INTEROP +#if __OBJC__ // Source code: "SwiftObject" // Real class name: mangled "Swift._SwiftObject" @@ -83,5 +84,13 @@ id getDescription(OpaqueValue *value, const Metadata *type); } #endif +#endif + +namespace swift { + +/// Get the NSObject metadata. +const Metadata *getNSObjectMetadata(); + +} #endif diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm index 182e479a7e683..95ba09346ba44 100644 --- a/stdlib/public/runtime/SwiftObject.mm +++ b/stdlib/public/runtime/SwiftObject.mm @@ -1552,6 +1552,11 @@ void swift_objc_swift3ImplicitObjCEntrypoint(id self, SEL selector, free(nullTerminatedFilename); } +const Metadata *swift::getNSObjectMetadata() { + return SWIFT_LAZY_CONSTANT( + swift_getObjCClassMetadata((const ClassMetadata *)[NSObject class])); +} + #endif const ClassMetadata *swift::getRootSuperclass() { diff --git a/test/AutoDiff/ModuleInterface/differentiation.swift b/test/AutoDiff/ModuleInterface/differentiation.swift new file mode 100644 index 0000000000000..6b3a791fb9ca3 --- /dev/null +++ b/test/AutoDiff/ModuleInterface/differentiation.swift @@ -0,0 +1,8 @@ +// RUN: %target-swift-frontend -typecheck -emit-module-interface-path %t.swiftinterface -enable-library-evolution -enable-experimental-differentiable-programming %s +// RUN: %FileCheck %s < %t.swiftinterface + +public func a(f: @differentiable (Float) -> Float) {} +// CHECK: public func a(f: @differentiable (Swift.Float) -> Swift.Float) + +public func b(f: @differentiable(linear) (Float) -> Float) {} +// CHECK: public func b(f: @differentiable(linear) (Swift.Float) -> Swift.Float) diff --git a/test/AutoDiff/Parse/differentiable_attr_parse.swift b/test/AutoDiff/Parse/differentiable_attr_parse.swift new file mode 100644 index 0000000000000..354d385ba3604 --- /dev/null +++ b/test/AutoDiff/Parse/differentiable_attr_parse.swift @@ -0,0 +1,180 @@ +// RUN: %target-swift-frontend -parse -verify %s + +/// Good + +struct Foo { + @differentiable + var x: Float +} + +@differentiable(vjp: foo(_:_:)) // okay +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@differentiable(vjp: foo(_:_:) where T : FloatingPoint) // okay +func bar(_ x: T, _: T) -> T { + return 1 + x +} + +@differentiable(wrt: (self, x, y), vjp: foo(_:_:)) // okay +func bar(_ x: Float, _ y: Float) -> Float { + return 1 + x +} + +@differentiable(wrt: (self, x, y), jvp: bar, vjp: foo(_:_:)) // okay +func bar(_ x: Float, _ y: Float) -> Float { + return 1 + x +} + +@differentiable // okay +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@differentiable(wrt: x) // okay +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@differentiable(wrt: (x)) // okay +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@differentiable(wrt: self) // okay +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@_transparent +@differentiable // okay +@inlinable +func playWellWithOtherAttrs(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@_transparent +@differentiable(wrt: (self), vjp: _vjpSquareRoot) // okay +public func squareRoot() -> Self { + var lhs = self + lhs.formSquareRoot() + return lhs +} + +@differentiable(linear) // okay +func identity(_ x: Float) -> Float { + return x +} + +@differentiable(linear, wrt: x) // okay +func slope2(_ x: Float) -> Float { + return 2 * x +} + +@differentiable(wrt: y) // ok +func two(x: Float, y: Float) -> Float { + return x + y +} + +@differentiable(wrt: (x, y)) // ok +func two(x: Float, y: Float) -> Float { + return x + y +} + +@differentiable(wrt: (0, y)) // ok +func two(x: Float, y: Float) -> Float { + return x + y +} + +@differentiable(wrt: (x, 1)) // ok +func two(x: Float, y: Float) -> Float { + return x + y +} + +@differentiable(wrt: (0, 1)) // ok +func two(x: Float, y: Float) -> Float { + return x + y +} + +/// Bad + +@differentiable(3) // expected-error {{expected either 'wrt:' or a function specifier label, e.g. 'jvp:', or 'vjp:'}} +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@differentiable(foo(_:_:)) // expected-error {{expected either 'wrt:' or a function specifier label, e.g. 'jvp:', or 'vjp:'}} +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@differentiable(vjp: foo(_:_:), 3) // expected-error {{expected either 'wrt:' or a function specifier label, e.g. 'jvp:', or 'vjp:'}} +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@differentiable(wrt: (x), foo(_:_:)) // expected-error {{expected either 'wrt:' or a function specifier label, e.g. 'jvp:', or 'vjp:'}} +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@differentiable(wrt: x, y) // expected-error {{expected either 'wrt:' or a function specifier label, e.g. 'jvp:', or 'vjp:'}} +func bar(_ x: Float, _ y: Float) -> Float { + return 1 + x +} + +@differentiable(wrt: 0, 1) // expected-error {{expected either 'wrt:' or a function specifier label, e.g. 'jvp:', or 'vjp:'}} +func two(x: Float, y: Float) -> Float { + return x + y +} + +@differentiable(wrt: 0, y) // expected-error {{expected either 'wrt:' or a function specifier label, e.g. 'jvp:', or 'vjp:'}} +func two(x: Float, y: Float) -> Float { + return x + y +} + +@differentiable(wrt: 0,) // expected-error {{unexpected ',' separator}} +func two(x: Float, y: Float) -> Float { + return x + y +} + +@differentiable(vjp: foo(_:_:) // expected-error {{expected ')' in 'differentiable' attribute}} +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@differentiable(vjp: foo(_:_:) where T) // expected-error {{expected ':' or '==' to indicate a conformance or same-type requirement}} +func bar(_ x: T, _: T) -> T { + return 1 + x +} + +@differentiable(,) // expected-error {{expected either 'wrt:' or a function specifier label, e.g. 'jvp:', or 'vjp:'}} +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@differentiable(vjp: foo(_:_:),) // expected-error {{unexpected ',' separator}} +func bar(_ x: Float, _: Float) -> Float { + return 1 + x +} + +@differentiable(vjp: foo(_:_:), where T) // expected-error {{unexpected ',' separator}} +func bar(_ x: T, _: T) -> T { + return 1 + x +} + +@differentiable(wrt: x, linear) // expected-error {{expected either 'wrt:' or a function specifier label, e.g. 'jvp:', or 'vjp:'}} +func slope4(_ x: Float) -> Float { + return 4 * x +} + +@differentiable(wrt: x, linear, vjp: const5) // expected-error {{expected either 'wrt:' or a function specifier label, e.g. 'jvp:', or 'vjp:'}} +func slope5(_ x: Float) -> Float { + return 5 * x +} + +@differentiable(wrt: x, vjp: const6, linear) // expected-error {{expected either 'wrt:' or a function specifier label, e.g. 'jvp:', or 'vjp:'}} +func slope5(_ x: Float) -> Float { + return 6 * x +} diff --git a/test/AutoDiff/SIL/Serialization/differentiation.swift b/test/AutoDiff/SIL/Serialization/differentiation.swift new file mode 100644 index 0000000000000..e72bdd001b680 --- /dev/null +++ b/test/AutoDiff/SIL/Serialization/differentiation.swift @@ -0,0 +1,28 @@ +// RUN: %empty-directory(%t) +// RUN: %target-sil-opt %s -emit-sib -o %t/tmp.sib -module-name differentiation -enable-experimental-differentiable-programming +// RUN: %target-sil-opt %t/tmp.sib -o %t/tmp.2.sib -module-name differentiation -enable-experimental-differentiable-programming +// RUN: %target-sil-opt %t/tmp.2.sib -module-name differentiation -emit-sorted-sil -enable-experimental-differentiable-programming | %FileCheck %s + +sil_stage raw + +import Swift + +sil @a : $@convention(thin) (@differentiable (Float) -> Float) -> @differentiable (Float) -> Float { +bb0(%0 : $@differentiable (Float) -> Float): + return %0 : $@differentiable (Float) -> Float +} + +// CHECK-LABEL: sil @a : $@convention(thin) (@differentiable (Float) -> Float) -> @differentiable (Float) -> Float { +// CHECK: bb0([[ARG:%.*]] : $@differentiable (Float) -> Float): +// CHECK: return [[ARG]] : $@differentiable (Float) -> Float +// CHECK: } + +sil @b : $@convention(thin) (@differentiable(linear) (Float) -> Float) -> @differentiable(linear) (Float) -> Float { +bb0(%0 : $@differentiable(linear) (Float) -> Float): + return %0 : $@differentiable(linear) (Float) -> Float +} + +// CHECK-LABEL: sil @b : $@convention(thin) (@differentiable(linear) (Float) -> Float) -> @differentiable(linear) (Float) -> Float { +// CHECK: bb0([[ARG:%.*]] : $@differentiable(linear) (Float) -> Float): +// CHECK: return [[ARG]] : $@differentiable(linear) (Float) -> Float +// CHECK: } diff --git a/test/AutoDiff/Serialization/differentiable_attr.swift b/test/AutoDiff/Serialization/differentiable_attr.swift new file mode 100644 index 0000000000000..ba540be5f19a1 --- /dev/null +++ b/test/AutoDiff/Serialization/differentiable_attr.swift @@ -0,0 +1,133 @@ +// SWIFT_ENABLE_TENSORFLOW + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend %s -emit-module -parse-as-library -o %t +// RUN: llvm-bcanalyzer %t/differentiable_attr.swiftmodule | %FileCheck %s -check-prefix=BCANALYZER +// RUN: %target-sil-opt -disable-sil-linking -enable-sil-verify-all %t/differentiable_attr.swiftmodule -o - | %FileCheck %s +// REQUIRES: differentiable_programming + +// TODO(TF-836): Enable this test. +// Blocked by TF-828: `@differentiating` attribute type-checking. +// SWIFT_ENABLE_TENSORFLOW +// This test currently only fails on `master` branch. +// Disable the XFAIL on `tensorflow` branch. +// XFAI: * +// SWIFT_ENABLE_TENSORFLOW END + +// BCANALYZER-NOT: UnknownCode + +import _Differentiation + +// CHECK: @differentiable(wrt: x, jvp: jvpSimple, vjp: vjpSimple) +// CHECK-NEXT: func simple(x: Float) -> Float +@differentiable(jvp: jvpSimple, vjp: vjpSimple) +func simple(x: Float) -> Float { + return x +} + +// CHECK: @differentiable(linear, wrt: x) +// CHECK-NEXT: func simple2(x: Float) -> Float +@differentiable(linear) +func simple2(x: Float) -> Float { + return x +} + +// CHECK: @differentiable(linear, wrt: x) +// CHECK-NEXT: func simple4(x: Float) -> Float +@differentiable(linear, wrt: x) +func simple4(x: Float) -> Float { + return x +} + +func jvpSimple(x: Float) -> (Float, (Float) -> Float) { + return (x, { v in v }) +} + +func vjpSimple(x: Float) -> (Float, (Float) -> Float) { + return (x, { v in v }) +} + +// CHECK: @differentiable(wrt: x) +// CHECK-NEXT: func testWrtClause(x: Float, y: Float) -> Float +@differentiable(wrt: x) +func testWrtClause(x: Float, y: Float) -> Float { + return x + y +} + +struct InstanceMethod : Differentiable { + // CHECK: @differentiable(wrt: (self, y)) + // CHECK-NEXT: func testWrtClause(x: Float, y: Float) -> Float + @differentiable(wrt: (self, y)) + func testWrtClause(x: Float, y: Float) -> Float { + return x + y + } + + struct TangentVector: Differentiable, AdditiveArithmetic { + typealias TangentVector = Self + static func ==(_: Self, _: Self) -> Bool { fatalError() } + static var zero: Self { fatalError() } + static func +(_: Self, _: Self) -> Self { fatalError() } + static func -(_: Self, _: Self) -> Self { fatalError() } + } + mutating func move(along direction: TangentVector) {} +} + +// CHECK: @differentiable(wrt: x where T : Differentiable) +// CHECK-NEXT: func testOnlyWhereClause(x: T) -> T where T : Numeric +@differentiable(where T : Differentiable) +func testOnlyWhereClause(x: T) -> T { + return x +} + +// CHECK: @differentiable(wrt: x, vjp: vjpTestWhereClause where T : Differentiable) +// CHECK-NEXT: func testWhereClause(x: T) -> T where T : Numeric +@differentiable(vjp: vjpTestWhereClause where T : Differentiable) +func testWhereClause(x: T) -> T { + return x +} +func vjpTestWhereClause(x: T) -> (T, (T.TangentVector) -> T.TangentVector) + where T : Numeric, T : Differentiable +{ + return (x, { v in v }) +} + +protocol P {} +extension P { + // CHECK: @differentiable(wrt: self, vjp: vjpTestWhereClauseMethod where Self : Differentiable) + // CHECK-NEXT: func testWhereClauseMethod() -> Self + @differentiable(wrt: self, vjp: vjpTestWhereClauseMethod where Self : Differentiable) + func testWhereClauseMethod() -> Self { + return self + } +} +extension P where Self : Differentiable { + func vjpTestWhereClauseMethod() -> (Self, (Self.TangentVector) -> Self.TangentVector) { + return (self, { v in v }) + } +} + +// CHECK: @differentiable(wrt: x, vjp: vjpTestWhereClauseMethodTypeConstraint where T : Differentiable, T == T.TangentVector) +// CHECK-NEXT: func testWhereClauseMethodTypeConstraint(x: T) -> T where T : Numeric +@differentiable(vjp: vjpTestWhereClauseMethodTypeConstraint where T : Differentiable, T == T.TangentVector) +func testWhereClauseMethodTypeConstraint(x: T) -> T { + return x +} +func vjpTestWhereClauseMethodTypeConstraint(x: T) -> (T, (T) -> T) + where T : Numeric, T : Differentiable, T == T.TangentVector +{ + return (x, { v in v }) +} + +extension P { + // CHECK: @differentiable(wrt: self, vjp: vjpTestWhereClauseMethodTypeConstraint where Self : Differentiable, Self == Self.TangentVector) + // CHECK-NEXT: func testWhereClauseMethodTypeConstraint() -> Self + @differentiable(wrt: self, vjp: vjpTestWhereClauseMethodTypeConstraint where Self.TangentVector == Self, Self : Differentiable) + func testWhereClauseMethodTypeConstraint() -> Self { + return self + } +} +extension P where Self : Differentiable, Self == Self.TangentVector { + func vjpTestWhereClauseMethodTypeConstraint() -> (Self, (Self.TangentVector) -> Self.TangentVector) { + return (self, { v in v }) + } +} diff --git a/test/AutoDiff/Serialization/differentiation.swift b/test/AutoDiff/Serialization/differentiation.swift new file mode 100644 index 0000000000000..d5f1276c3f494 --- /dev/null +++ b/test/AutoDiff/Serialization/differentiation.swift @@ -0,0 +1,12 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend %s -emit-module -parse-as-library -enable-experimental-differentiable-programming -o %t +// RUN: llvm-bcanalyzer %t/differentiation.swiftmodule | %FileCheck %s -check-prefix=BCANALYZER +// RUN: %target-sil-opt -disable-sil-linking -enable-sil-verify-all %t/differentiation.swiftmodule -enable-experimental-differentiable-programming -o - | %FileCheck %s + +// BCANALYZER-NOT: UnknownCode + +func a(_ f: @differentiable (Float) -> Float) {} +// CHECK: func a(_ f: @differentiable (Float) -> Float) + +func b(_ f: @differentiable(linear) (Float) -> Float) {} +// CHECK: func b(_ f: @differentiable(linear) (Float) -> Float) diff --git a/test/AutoDiff/control_flow_sil.swift b/test/AutoDiff/control_flow_sil.swift index 3f18db2ccb379..e3edc17211a39 100644 --- a/test/AutoDiff/control_flow_sil.swift +++ b/test/AutoDiff/control_flow_sil.swift @@ -47,27 +47,21 @@ func cond(_ x: Float) -> Float { // CHECK-SIL-LABEL: sil hidden [ossa] @AD__cond__vjp_src_0_wrt_0 : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { // CHECK-SIL: bb0([[INPUT_ARG:%.*]] : $Float): // CHECK-SIL: [[BB0_PB_STRUCT:%.*]] = struct $_AD__cond_bb0__PB__src_0_wrt_0 () -// CHECK-SIL: cond_br {{%.*}}, bb1, bb3 +// CHECK-SIL: cond_br {{%.*}}, bb1, bb2 // CHECK-SIL: bb1: // CHECK-SIL: [[BB1_PRED:%.*]] = enum $_AD__cond_bb1__Pred__src_0_wrt_0, #_AD__cond_bb1__Pred__src_0_wrt_0.bb0!enumelt.1, [[BB0_PB_STRUCT]] -// CHECK-SIL: br bb2([[BB1_PRED]] : $_AD__cond_bb1__Pred__src_0_wrt_0) - -// CHECK-SIL: bb2([[BB1_PRED_ARG:%.*]] : $_AD__cond_bb1__Pred__src_0_wrt_0) // CHECK-SIL: [[BB1_PB_STRUCT:%.*]] = struct $_AD__cond_bb1__PB__src_0_wrt_0 // CHECK-SIL: [[BB3_PRED_PRED1:%.*]] = enum $_AD__cond_bb3__Pred__src_0_wrt_0, #_AD__cond_bb3__Pred__src_0_wrt_0.bb1!enumelt.1, [[BB1_PB_STRUCT]] -// CHECK-SIL: br bb5({{.*}} : $Float, [[BB3_PRED_PRED1]] : $_AD__cond_bb3__Pred__src_0_wrt_0) +// CHECK-SIL: br bb3({{.*}} : $Float, [[BB3_PRED_PRED1]] : $_AD__cond_bb3__Pred__src_0_wrt_0) -// CHECK-SIL: bb3: +// CHECK-SIL: bb2: // CHECK-SIL: [[BB2_PRED:%.*]] = enum $_AD__cond_bb2__Pred__src_0_wrt_0, #_AD__cond_bb2__Pred__src_0_wrt_0.bb0!enumelt.1, [[BB0_PB_STRUCT]] -// CHECK-SIL: br bb4([[BB2_PRED]] : $_AD__cond_bb2__Pred__src_0_wrt_0) - -// CHECK-SIL: bb4([[BB2_PRED_ARG:%.*]] : $_AD__cond_bb2__Pred__src_0_wrt_0) // CHECK-SIL: [[BB2_PB_STRUCT:%.*]] = struct $_AD__cond_bb2__PB__src_0_wrt_0 // CHECK-SIL: [[BB3_PRED_PRED2:%.*]] = enum $_AD__cond_bb3__Pred__src_0_wrt_0, #_AD__cond_bb3__Pred__src_0_wrt_0.bb2!enumelt.1, [[BB2_PB_STRUCT]] -// CHECK-SIL: br bb5({{.*}} : $Float, [[BB3_PRED_PRED2]] : $_AD__cond_bb3__Pred__src_0_wrt_0) +// CHECK-SIL: br bb3({{.*}} : $Float, [[BB3_PRED_PRED2]] : $_AD__cond_bb3__Pred__src_0_wrt_0) -// CHECK-SIL: bb5([[ORIG_RES:%.*]] : $Float, [[BB3_PRED_ARG:%.*]] : @owned $_AD__cond_bb3__Pred__src_0_wrt_0) +// CHECK-SIL: bb3([[ORIG_RES:%.*]] : $Float, [[BB3_PRED_ARG:%.*]] : @owned $_AD__cond_bb3__Pred__src_0_wrt_0) // CHECK-SIL: [[BB3_PB_STRUCT:%.*]] = struct $_AD__cond_bb3__PB__src_0_wrt_0 // CHECK-SIL: [[PULLBACK_REF:%.*]] = function_ref @AD__cond__pullback_src_0_wrt_0 // CHECK-SIL: [[PB:%.*]] = partial_apply [callee_guaranteed] [[PULLBACK_REF]]([[BB3_PB_STRUCT]]) @@ -145,6 +139,70 @@ func loop_generic(_ x: T) -> T { return result } +// Test `switch_enum`. + +enum Enum { + case a(Float) + case b(Float, Float) +} +@differentiable +@_silgen_name("enum_notactive") +func enum_notactive(_ e: Enum, _ x: Float) -> Float { + switch e { + case let .a(a): return x * a + case let .b(b1, b2): return x * b1 * b2 + } +} + +// ECK-SIL-LABEL: sil hidden [ossa] @AD__cond__vjp_src_0_wrt_0 : $@convention(thin) (Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { +// ECK-SIL: bb0([[INPUT_ARG:%.*]] : $Float): +// ECK-SIL: [[BB0_PB_STRUCT:%.*]] = struct $_AD__cond_bb0__PB__src_0_wrt_0 () +// ECK-SIL: cond_br {{%.*}}, bb1, bb2 + +// ECK-SIL: bb1: +// ECK-SIL: [[BB1_PRED:%.*]] = enum $_AD__cond_bb1__Pred__src_0_wrt_0, #_AD__cond_bb1__Pred__src_0_wrt_0.bb0!enumelt.1, [[BB0_PB_STRUCT]] +// ECK-SIL: [[BB1_PB_STRUCT:%.*]] = struct $_AD__cond_bb1__PB__src_0_wrt_0 +// ECK-SIL: [[BB3_PRED_PRED1:%.*]] = enum $_AD__cond_bb3__Pred__src_0_wrt_0, #_AD__cond_bb3__Pred__src_0_wrt_0.bb1!enumelt.1, [[BB1_PB_STRUCT]] +// ECK-SIL: br bb3({{.*}} : $Float, [[BB3_PRED_PRED1]] : $_AD__cond_bb3__Pred__src_0_wrt_0) + +// ECK-SIL: bb2: +// ECK-SIL: [[BB2_PRED:%.*]] = enum $_AD__cond_bb2__Pred__src_0_wrt_0, #_AD__cond_bb2__Pred__src_0_wrt_0.bb0!enumelt.1, [[BB0_PB_STRUCT]] +// ECK-SIL: [[BB2_PB_STRUCT:%.*]] = struct $_AD__cond_bb2__PB__src_0_wrt_0 +// ECK-SIL: [[BB3_PRED_PRED2:%.*]] = enum $_AD__cond_bb3__Pred__src_0_wrt_0, #_AD__cond_bb3__Pred__src_0_wrt_0.bb2!enumelt.1, [[BB2_PB_STRUCT]] +// ECK-SIL: br bb3({{.*}} : $Float, [[BB3_PRED_PRED2]] : $_AD__cond_bb3__Pred__src_0_wrt_0) + +// ECK-SIL: bb3([[ORIG_RES:%.*]] : $Float, [[BB3_PRED_ARG:%.*]] : @owned $_AD__cond_bb3__Pred__src_0_wrt_0) +// ECK-SIL: [[BB3_PB_STRUCT:%.*]] = struct $_AD__cond_bb3__PB__src_0_wrt_0 +// ECK-SIL: [[PULLBACK_REF:%.*]] = function_ref @AD__cond__pullback_src_0_wrt_0 +// ECK-SIL: [[PB:%.*]] = partial_apply [callee_guaranteed] [[PULLBACK_REF]]([[BB3_PB_STRUCT]]) +// ECK-SIL: [[VJP_RESULT:%.*]] = tuple ([[ORIG_RES]] : $Float, [[PB]] : $@callee_guaranteed (Float) -> Float) +// ECK-SIL: return [[VJP_RESULT]] + +// CHECK-SIL-LABEL: sil hidden [ossa] @AD__enum_notactive__vjp_src_0_wrt_1 : $@convention(thin) (Enum, Float) -> (Float, @owned @callee_guaranteed (Float) -> Float) { +// CHECK-SIL: bb0([[ENUM_ARG:%.*]] : $Enum, [[X_ARG:%.*]] : $Float): +// CHECK-SIL: [[BB0_PB_STRUCT:%.*]] = struct $_AD__enum_notactive_bb0__PB__src_0_wrt_1 () +// CHECK-SIL: switch_enum [[ENUM_ARG]] : $Enum, case #Enum.a!enumelt.1: bb1, case #Enum.b!enumelt.1: bb2 + +// CHECK-SIL: bb1([[ENUM_A:%.*]] : $Float): +// CHECK-SIL: [[BB1_PRED_PRED0:%.*]] = enum $_AD__enum_notactive_bb1__Pred__src_0_wrt_1, #_AD__enum_notactive_bb1__Pred__src_0_wrt_1.bb0!enumelt.1, %4 : $_AD__enum_notactive_bb0__PB__src_0_wrt_1 +// CHECK-SIL: [[BB1_PB_STRUCT:%.*]] = struct $_AD__enum_notactive_bb1__PB__src_0_wrt_1 ({{.*}}) +// CHECK-SIL: [[BB3_PRED_PRED1:%.*]] = enum $_AD__enum_notactive_bb3__Pred__src_0_wrt_1, #_AD__enum_notactive_bb3__Pred__src_0_wrt_1.bb1!enumelt.1, [[BB1_PB_STRUCT]] : $_AD__enum_notactive_bb1__PB__src_0_wrt_1 +// CHECK-SIL: br bb3({{.*}} : $Float, [[BB3_PRED_PRED1]] : $_AD__enum_notactive_bb3__Pred__src_0_wrt_1) + +// CHECK-SIL: bb2([[ENUM_B:%.*]] : $(Float, Float)): +// CHECK-SIL: [[BB2_PRED_PRED0:%.*]] = enum $_AD__enum_notactive_bb2__Pred__src_0_wrt_1, #_AD__enum_notactive_bb2__Pred__src_0_wrt_1.bb0!enumelt.1, %4 : $_AD__enum_notactive_bb0__PB__src_0_wrt_1 +// CHECK-SIL: [[BB2_PB_STRUCT:%.*]] = struct $_AD__enum_notactive_bb2__PB__src_0_wrt_1 ({{.*}}) +// CHECK-SIL: [[BB3_PRED_PRED2:%.*]] = enum $_AD__enum_notactive_bb3__Pred__src_0_wrt_1, #_AD__enum_notactive_bb3__Pred__src_0_wrt_1.bb2!enumelt.1, [[BB2_PB_STRUCT]] : $_AD__enum_notactive_bb2__PB__src_0_wrt_1 +// CHECK-SIL: br bb3({{.*}} : $Float, [[BB3_PRED_PRED2]] : $_AD__enum_notactive_bb3__Pred__src_0_wrt_1) + +// CHECK-SIL: bb3([[ORIG_RES:%.*]] : $Float, [[BB3_PRED_ARG:%.*]] : @owned $_AD__enum_notactive_bb3__Pred__src_0_wrt_1) +// CHECK-SIL: [[BB3_PB_STRUCT:%.*]] = struct $_AD__enum_notactive_bb3__PB__src_0_wrt_1 +// CHECK-SIL: [[PULLBACK_REF:%.*]] = function_ref @AD__enum_notactive__pullback_src_0_wrt_1 +// CHECK-SIL: [[PB:%.*]] = partial_apply [callee_guaranteed] [[PULLBACK_REF]]([[BB3_PB_STRUCT]]) +// CHECK-SIL: [[VJP_RESULT:%.*]] = tuple ([[ORIG_RES]] : $Float, [[PB]] : $@callee_guaranteed (Float) -> Float) +// CHECK-SIL: return [[VJP_RESULT]] +// CHECK-SIL: } + // Test control flow + tuple buffer. // Verify that pullback buffers are not allocated for address projections. diff --git a/test/AutoDiff/differentiable_protocol.swift b/test/AutoDiff/stdlib/differentiable_protocol.swift similarity index 100% rename from test/AutoDiff/differentiable_protocol.swift rename to test/AutoDiff/stdlib/differentiable_protocol.swift diff --git a/test/ClangImporter/Inputs/custom-modules/EnumExhaustivity.h b/test/ClangImporter/Inputs/custom-modules/EnumExhaustivity.h index b7d0f2271a940..c7048060a9957 100644 --- a/test/ClangImporter/Inputs/custom-modules/EnumExhaustivity.h +++ b/test/ClangImporter/Inputs/custom-modules/EnumExhaustivity.h @@ -5,6 +5,9 @@ enum _name _name; \ enum __attribute__((enum_extensibility(closed))) _name + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmicrosoft-enum-forward-reference" typedef MY_ENUM(RegularEnum) { RegularEnumA, RegularEnumB @@ -47,3 +50,4 @@ enum __attribute__((enum_extensibility(closed))) UnavailableCases { UnavailableCasesB, UnavailableCasesThisIsTheUnavailableOne __attribute__((availability(swift, unavailable))) }; +#pragma clang diagnostic pop \ No newline at end of file diff --git a/test/ClangImporter/pcm-emit-and-import.swift b/test/ClangImporter/pcm-emit-and-import.swift new file mode 100644 index 0000000000000..c48ccb22eed30 --- /dev/null +++ b/test/ClangImporter/pcm-emit-and-import.swift @@ -0,0 +1,15 @@ +// Emit the explicit module. +// RUN: %empty-directory(%t) +// RUN: %target-swift-emit-pcm -module-name script -o %t/script.pcm %S/Inputs/custom-modules/module.map + +// Verify some of the output of the -dump-pcm flag. +// RUN: %swift-dump-pcm %t/script.pcm | %FileCheck %s --check-prefix=CHECK-DUMP +// CHECK-DUMP: Information for module file '{{.*}}/script.pcm': +// CHECK-DUMP: Module name: script +// CHECK-DUMP: Module map file: {{.*[/\\]}}Inputs{{/|\\}}custom-modules{{/|\\}}module.map + +// Compile a source file that imports the explicit module. +// RUN: %target-swift-frontend -typecheck -verify -Xcc -fmodule-file=%t/script.pcm %s + +import script +var _ : ScriptTy diff --git a/test/ClangImporter/serialization-sil.swift b/test/ClangImporter/serialization-sil.swift index 172a43662c548..afb46c8cd8f86 100644 --- a/test/ClangImporter/serialization-sil.swift +++ b/test/ClangImporter/serialization-sil.swift @@ -12,32 +12,39 @@ public func testPartialApply(_ obj: Test) { // CHECK: dynamic_method_br [[CURRIED1_OBJ:%.+]] : $@opened([[CURRIED1_EXISTENTIAL:.+]]) Test, #Test.normalObject!1.foreign, [[CURRIED1_TRUE:[^,]+]], [[CURRIED1_FALSE:[^,]+]] // CHECK: [[CURRIED1_FALSE]]: // CHECK: [[CURRIED1_TRUE]]([[CURRIED1_METHOD:%.+]] : $@convention(objc_method) (@opened([[CURRIED1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject): - // CHECK: [[CURRIED1_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[CURRIED1_METHOD]]([[CURRIED1_OBJ]]) : $@convention(objc_method) (@opened([[CURRIED1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject - // CHECK: [[CURRIED1_THUNK:%.+]] = function_ref @$syXlIego_ypIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @owned AnyObject) -> @out Any - // CHECK: = partial_apply [callee_guaranteed] [[CURRIED1_THUNK]]([[CURRIED1_PARTIAL]]) + // CHECK: [[CURRIED1_OBJECT_COPY:%.*]] = copy_value [[CURRIED1_OBJ]] + // CHECK: [[CURRIED1_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[CURRIED1_METHOD]]([[CURRIED1_OBJECT_COPY]]) : $@convention(objc_method) (@opened([[CURRIED1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject + // CHECK: [[CURRIED1_THUNK:%.+]] = function_ref @$syXlIego_ypIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @owned AnyObject) -> @out Any + // CHECK: = partial_apply [callee_guaranteed] [[CURRIED1_THUNK]]([[CURRIED1_PARTIAL]]) curried1() } if let curried2 = obj.innerPointer { // CHECK: dynamic_method_br [[CURRIED2_OBJ:%.+]] : $@opened([[CURRIED2_EXISTENTIAL:.+]]) Test, #Test.innerPointer!1.foreign, [[CURRIED2_TRUE:[^,]+]], [[CURRIED2_FALSE:[^,]+]] // CHECK: [[CURRIED2_FALSE]]: // CHECK: [[CURRIED2_TRUE]]([[CURRIED2_METHOD:%.+]] : $@convention(objc_method) (@opened([[CURRIED2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutableRawPointer): - // CHECK: [[CURRIED2_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[CURRIED2_METHOD]]([[CURRIED2_OBJ]]) : $@convention(objc_method) (@opened([[CURRIED2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutableRawPointer + // CHECK: [[CURRIED2_OBJ_COPY:%.*]] = copy_value [[CURRIED2_OBJ]] + // CHECK: [[CURRIED2_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[CURRIED2_METHOD]]([[CURRIED2_OBJ_COPY]]) : $@convention(objc_method) (@opened([[CURRIED2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutableRawPointer curried2() } if let prop1 = obj.normalObjectProp { // CHECK: dynamic_method_br [[PROP1_OBJ:%.+]] : $@opened([[PROP1_EXISTENTIAL:.+]]) Test, #Test.normalObjectProp!getter.1.foreign, [[PROP1_TRUE:[^,]+]], [[PROP1_FALSE:[^,]+]] // CHECK: [[PROP1_FALSE]]: // CHECK: [[PROP1_TRUE]]([[PROP1_METHOD:%.+]] : $@convention(objc_method) (@opened([[PROP1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject): - // CHECK: [[PROP1_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[PROP1_METHOD]]([[PROP1_OBJ]]) : $@convention(objc_method) (@opened([[PROP1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject - // CHECK: = apply [[PROP1_PARTIAL]]() : $@callee_guaranteed () -> @owned AnyObject + // CHECK: [[PROP1_OBJ_COPY:%.*]] = copy_value [[PROP1_OBJ]] + // CHECK: [[PROP1_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[PROP1_METHOD]]([[PROP1_OBJ_COPY]]) : $@convention(objc_method) (@opened([[PROP1_EXISTENTIAL]]) Test) -> @autoreleased AnyObject + // CHECK: [[PROP1_PARTIAL_COPY:%.*]] = copy_value [[PROP1_PARTIAL]] + // CHECK: [[PROP1_PARTIAL_COPY_BORROW:%.*]] = begin_borrow [[PROP1_PARTIAL_COPY]] + // CHECK: = apply [[PROP1_PARTIAL_COPY_BORROW]]() : $@callee_guaranteed () -> @owned AnyObject _ = prop1 } if let prop2 = obj.innerPointerProp { // CHECK: dynamic_method_br [[PROP2_OBJ:%.+]] : $@opened([[PROP2_EXISTENTIAL:.+]]) Test, #Test.innerPointerProp!getter.1.foreign, [[PROP2_TRUE:[^,]+]], [[PROP2_FALSE:[^,]+]] // CHECK: [[PROP2_FALSE]]: // CHECK: [[PROP2_TRUE]]([[PROP2_METHOD:%.+]] : $@convention(objc_method) (@opened([[PROP2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutableRawPointer): - // CHECK: [[PROP2_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[PROP2_METHOD]]([[PROP2_OBJ]]) : $@convention(objc_method) (@opened([[PROP2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutableRawPointer - // CHECK: = apply [[PROP2_PARTIAL]]() : $@callee_guaranteed () -> UnsafeMutableRawPointer + // CHECK: [[PROP2_OBJ_COPY:%.*]] = copy_value [[PROP2_OBJ]] + // CHECK: [[PROP2_PARTIAL:%.+]] = partial_apply [callee_guaranteed] [[PROP2_METHOD]]([[PROP2_OBJ_COPY]]) : $@convention(objc_method) (@opened([[PROP2_EXISTENTIAL]]) Test) -> @unowned_inner_pointer UnsafeMutableRawPointer + // CHECK: [[PROP2_PARTIAL_BORROW:%.*]] = begin_borrow [[PROP2_PARTIAL]] + // CHECK: = apply [[PROP2_PARTIAL_BORROW]]() : $@callee_guaranteed () -> UnsafeMutableRawPointer _ = prop2 } } // CHECK: // end sil function '$s4Test16testPartialApplyyySoAA_pF' diff --git a/test/Constraints/closures.swift b/test/Constraints/closures.swift index e5fb5935039a1..ea01170a3e090 100644 --- a/test/Constraints/closures.swift +++ b/test/Constraints/closures.swift @@ -765,7 +765,7 @@ overloaded { print("hi"); print("bye") } // multiple expression closure without func not_overloaded(_ handler: () -> Int) {} not_overloaded { } // empty body -// expected-error@-1 {{cannot convert value of type '() -> ()' to expected argument type '() -> Int'}} +// expected-error@-1 {{cannot convert value of type '()' to closure result type 'Int'}} not_overloaded { print("hi") } // single-expression closure // expected-error@-1 {{cannot convert value of type '()' to closure result type 'Int'}} @@ -786,7 +786,7 @@ func test() -> Int? { } var fn: () -> [Int] = {} -// expected-error@-1 {{cannot convert value of type '() -> ()' to specified type '() -> [Int]'}} +// expected-error@-1 {{cannot convert value of type '()' to closure result type '[Int]'}} fn = {} // expected-error@-1 {{cannot assign value of type '() -> ()' to type '() -> [Int]'}} diff --git a/test/Constraints/conditionally_defined_types.swift b/test/Constraints/conditionally_defined_types.swift index b1b51a6defae5..2107fa6e6faca 100644 --- a/test/Constraints/conditionally_defined_types.swift +++ b/test/Constraints/conditionally_defined_types.swift @@ -15,7 +15,7 @@ struct Z2: AssociatedType { } struct SameType {} -extension SameType where T == X { // expected-note 5 {{where 'T' = 'Y'}} +extension SameType where T == X { // expected-note 13{{requirement specified as 'T' == 'X' [with T = Y]}} typealias TypeAlias1 = T typealias TypeAlias2 = Y typealias TypeAlias3 = (T, U) // expected-note {{requirement specified as 'T' == 'X' [with T = Y]}} @@ -36,25 +36,24 @@ let _ = SameType.Decl3.self let _ = SameType.Decl4.self let _ = SameType.Decl5.self -let _ = SameType.TypeAlias1.self // expected-error {{referencing type alias 'TypeAlias1' on 'SameType' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.TypeAlias2.self // expected-error {{referencing type alias 'TypeAlias2' on 'SameType' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.TypeAlias1.self // expected-error {{'SameType.TypeAlias1' (aka 'X') requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.TypeAlias2.self // expected-error {{'SameType.TypeAlias2' (aka 'Y') requires the types 'Y' and 'X' be equivalent}} let _ = SameType.TypeAlias3.self // expected-error {{'SameType.TypeAlias3' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.self // expected-error {{referencing struct 'Decl1' on 'SameType' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl2.self // expected-error {{referencing enum 'Decl2' on 'SameType' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl3.self // expected-error {{referencing class 'Decl3' on 'SameType' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl2.self // expected-error {{'SameType.Decl2' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl3.self // expected-error {{'SameType.Decl3' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.self // expected-error {{'SameType.Decl4' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl5.self // expected-error {{'SameType.Decl5' requires the types 'Y' and 'X' be equivalent}} -extension SameType: AssociatedType where T == X {} // expected-note {{where 'T' = 'Y'}} - -// (Y first here, because there were issues caused by running associated type -// inference for the first time) -let _ = SameType.T.self // expected-error {{referencing type alias 'T' on 'SameType' requires the types 'Y' and 'X' be equivalent}} +extension SameType: AssociatedType where T == X {} +// expected-note@-1 {{requirement specified as 'T' == 'X' [with T = Y]}} let _ = SameType.T.self +let _ = SameType.T.self // expected-error {{'SameType.T' (aka 'X') requires the types 'Y' and 'X' be equivalent}} + struct Conforms {} -extension Conforms where T: P { // expected-note 5 {{where 'T' = 'Y'}} +extension Conforms where T: P { typealias TypeAlias1 = T typealias TypeAlias2 = Y typealias TypeAlias3 = (T, U) @@ -75,33 +74,33 @@ let _ = Conforms.Decl3.self let _ = Conforms.Decl4.self let _ = Conforms.Decl5.self -let _ = Conforms.TypeAlias1.self // expected-error {{referencing type alias 'TypeAlias1' on 'Conforms' requires that 'Y' conform to 'P'}} -let _ = Conforms.TypeAlias2.self // expected-error {{referencing type alias 'TypeAlias2' on 'Conforms' requires that 'Y' conform to 'P'}} +let _ = Conforms.TypeAlias1.self // expected-error {{type 'Y' does not conform to protocol 'P'}} +let _ = Conforms.TypeAlias2.self // expected-error {{type 'Y' does not conform to protocol 'P'}} let _ = Conforms.TypeAlias3.self // expected-error {{type 'Y' does not conform to protocol 'P'}} -let _ = Conforms.Decl1.self // expected-error {{referencing struct 'Decl1' on 'Conforms' requires that 'Y' conform to 'P'}} -let _ = Conforms.Decl2.self // expected-error {{referencing enum 'Decl2' on 'Conforms' requires that 'Y' conform to 'P'}} -let _ = Conforms.Decl3.self // expected-error {{referencing class 'Decl3' on 'Conforms' requires that 'Y' conform to 'P'}} +let _ = Conforms.Decl1.self // expected-error {{type 'Y' does not conform to protocol 'P'}} +let _ = Conforms.Decl2.self // expected-error {{type 'Y' does not conform to protocol 'P'}} +let _ = Conforms.Decl3.self // expected-error {{type 'Y' does not conform to protocol 'P'}} let _ = Conforms.Decl4.self // expected-error {{type 'Y' does not conform to protocol 'P'}} let _ = Conforms.Decl5.self // expected-error {{type 'Y' does not conform to protocol 'P'}} -extension Conforms: AssociatedType where T: P {} // expected-note {{where 'T' = 'Y'}} +extension Conforms: AssociatedType where T: P {} -let _ = Conforms.T.self // expected-error {{referencing type alias 'T' on 'Conforms' requires that 'Y' conform to 'P'}} +let _ = Conforms.T.self // expected-error {{type 'Y' does not conform to protocol 'P'}} let _ = Conforms.T.self // Now, even more nesting! -extension SameType.Decl1 { // expected-note 5 {{where 'T' = 'Y'}} +extension SameType.Decl1 { typealias TypeAlias1 = T typealias TypeAlias2 = Y - typealias TypeAlias3 = (T, U) // expected-note {{requirement specified as 'T' == 'X' [with T = Y]}} + typealias TypeAlias3 = (T, U) struct Decl1 {} enum Decl2 {} class Decl3 {} - struct Decl4 {} // expected-note {{requirement specified as 'T' == 'X' [with T = Y]}} - enum Decl5 {} // expected-note {{requirement specified as 'T' == 'X' [with T = Y]}} + struct Decl4 {} + enum Decl5 {} } let _ = SameType.Decl1.TypeAlias1.self @@ -113,16 +112,16 @@ let _ = SameType.Decl1.Decl3.self let _ = SameType.Decl1.Decl4.self let _ = SameType.Decl1.Decl5.self -let _ = SameType.Decl1.TypeAlias1.self // expected-error {{referencing type alias 'TypeAlias1' on 'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.TypeAlias2.self // expected-error {{referencing type alias 'TypeAlias2' on 'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.TypeAlias3.self // expected-error {{'SameType.Decl1.TypeAlias3' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl1.self // expected-error {{referencing struct 'Decl1' on 'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl2.self // expected-error {{referencing enum 'Decl2' on 'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl3.self // expected-error {{referencing class 'Decl3' on 'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl4.self // expected-error {{'SameType.Decl1.Decl4' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl1.Decl5.self // expected-error {{'SameType.Decl1.Decl5' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.TypeAlias1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.TypeAlias2.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.TypeAlias3.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl1.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl2.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl3.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl4.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl1.Decl5.self // expected-error {{'SameType.Decl1' requires the types 'Y' and 'X' be equivalent}} -extension SameType.Decl4 where U == X { // expected-note 5 {{where 'U' = 'Y'}} +extension SameType.Decl4 where U == X { // expected-note 5 {{requirement specified as 'U' == 'X' [with U = Y]}} typealias TypeAlias1 = T typealias TypeAlias2 = Y typealias TypeAlias3 = (T, U, V) // expected-note {{requirement specified as 'U' == 'X' [with U = Y]}} @@ -145,12 +144,12 @@ let _ = SameType.Decl4.Decl3.self let _ = SameType.Decl4.Decl4.self let _ = SameType.Decl4.Decl5.self -let _ = SameType.Decl4.TypeAlias1.self // expected-error {{referencing type alias 'TypeAlias1' on 'SameType.Decl4' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.TypeAlias2.self // expected-error {{referencing type alias 'TypeAlias2' on 'SameType.Decl4' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.TypeAlias1.self // expected-error {{'SameType.Decl4.TypeAlias1' (aka 'X') requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.TypeAlias2.self // expected-error {{'SameType.Decl4.TypeAlias2' (aka 'Y') requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.TypeAlias3.self // expected-error {{'SameType.Decl4.TypeAlias3' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.Decl1.self // expected-error {{referencing struct 'Decl1' on 'SameType.Decl4' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.Decl2.self // expected-error {{referencing enum 'Decl2' on 'SameType.Decl4' requires the types 'Y' and 'X' be equivalent}} -let _ = SameType.Decl4.Decl3.self // expected-error {{referencing class 'Decl3' on 'SameType.Decl4' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.Decl1.self // expected-error {{'SameType.Decl4.Decl1' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.Decl2.self // expected-error {{'SameType.Decl4.Decl2' requires the types 'Y' and 'X' be equivalent}} +let _ = SameType.Decl4.Decl3.self // expected-error {{'SameType.Decl4.Decl3' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.Decl4.self // expected-error {{'SameType.Decl4.Decl4' requires the types 'Y' and 'X' be equivalent}} let _ = SameType.Decl4.Decl5.self // expected-error {{'SameType.Decl4.Decl5' requires the types 'Y' and 'X' be equivalent}} @@ -174,9 +173,6 @@ let _ = SameType.Decl4.Decl5.self // expected-error {{'SameType.Decl // Finally, extra complicated: extension Conforms.Decl4 where U: AssociatedType, U.T: P { -// expected-note@-1 5 {{where 'U' = 'Y'}} -// expected-note@-2 5 {{'U.T' = 'Z2.T' (aka 'Y')}} -// expected-note@-3 5 {{'U.T' = 'Y.T'}} typealias TypeAlias1 = T typealias TypeAlias2 = Y typealias TypeAlias3 = (T, U, V) @@ -200,34 +196,29 @@ let _ = Conforms.Decl4.Decl5.self // Two different forms of badness, corresponding to the two requirements: let _ = Conforms.Decl4.TypeAlias1.self -// expected-error@-1 {{referencing type alias 'TypeAlias1' on 'Conforms.Decl4' requires that 'Y.T' conform to 'P'}} -// expected-error@-2 {{referencing type alias 'TypeAlias1' on 'Conforms.Decl4' requires that 'Y' conform to 'AssociatedType'}} +// expected-error@-1 {{type 'Y' does not conform to protocol 'AssociatedType'}} let _ = Conforms.Decl4.TypeAlias2.self -// expected-error@-1 {{referencing type alias 'TypeAlias2' on 'Conforms.Decl4' requires that 'Y.T' conform to 'P'}} -// expected-error@-2 {{referencing type alias 'TypeAlias2' on 'Conforms.Decl4' requires that 'Y' conform to 'AssociatedType'}} +// expected-error@-1 {{type 'Y' does not conform to protocol 'AssociatedType'}} let _ = Conforms.Decl4.TypeAlias3.self // expected-error {{type 'Y' does not conform to protocol 'AssociatedType'}} let _ = Conforms.Decl4.Decl1.self -// expected-error@-1 {{referencing struct 'Decl1' on 'Conforms.Decl4' requires that 'Y.T' conform to 'P'}} -// expected-error@-2 {{referencing struct 'Decl1' on 'Conforms.Decl4' requires that 'Y' conform to 'AssociatedType'}} +// expected-error@-1 {{type 'Y' does not conform to protocol 'AssociatedType'}} let _ = Conforms.Decl4.Decl2.self -// expected-error@-1 {{referencing enum 'Decl2' on 'Conforms.Decl4' requires that 'Y.T' conform to 'P'}} -// expected-error@-2 {{referencing enum 'Decl2' on 'Conforms.Decl4' requires that 'Y' conform to 'AssociatedType'}} +// expected-error@-1 {{type 'Y' does not conform to protocol 'AssociatedType'}} let _ = Conforms.Decl4.Decl3.self -// expected-error@-1 {{referencing class 'Decl3' on 'Conforms.Decl4' requires that 'Y.T' conform to 'P'}} -// expected-error@-2 {{referencing class 'Decl3' on 'Conforms.Decl4' requires that 'Y' conform to 'AssociatedType'}} +// expected-error@-1 {{type 'Y' does not conform to protocol 'AssociatedType'}} let _ = Conforms.Decl4.Decl4.self // expected-error {{type 'Y' does not conform to protocol 'AssociatedType'}} let _ = Conforms.Decl4.Decl5.self // expected-error {{type 'Y' does not conform to protocol 'AssociatedType'}} -let _ = Conforms.Decl4.TypeAlias1.self // expected-error {{referencing type alias 'TypeAlias1' on 'Conforms.Decl4' requires that 'Z2.T' (aka 'Y') conform to 'P'}} -let _ = Conforms.Decl4.TypeAlias2.self // expected-error {{referencing type alias 'TypeAlias2' on 'Conforms.Decl4' requires that 'Z2.T' (aka 'Y') conform to 'P'}} +let _ = Conforms.Decl4.TypeAlias1.self // expected-error {{type 'Z2.T' (aka 'Y') does not conform to protocol 'P'}} +let _ = Conforms.Decl4.TypeAlias2.self // expected-error {{type 'Z2.T' (aka 'Y') does not conform to protocol 'P'}} let _ = Conforms.Decl4.TypeAlias3.self // expected-error {{type 'Z2.T' (aka 'Y') does not conform to protocol 'P'}} -let _ = Conforms.Decl4.Decl1.self // expected-error {{referencing struct 'Decl1' on 'Conforms.Decl4' requires that 'Z2.T' (aka 'Y') conform to 'P'}} -let _ = Conforms.Decl4.Decl2.self // expected-error {{referencing enum 'Decl2' on 'Conforms.Decl4' requires that 'Z2.T' (aka 'Y') conform to 'P'}} -let _ = Conforms.Decl4.Decl3.self // expected-error {{referencing class 'Decl3' on 'Conforms.Decl4' requires that 'Z2.T' (aka 'Y') conform to 'P'}} +let _ = Conforms.Decl4.Decl1.self // expected-error {{type 'Z2.T' (aka 'Y') does not conform to protocol 'P'}} +let _ = Conforms.Decl4.Decl2.self // expected-error {{type 'Z2.T' (aka 'Y') does not conform to protocol 'P'}} +let _ = Conforms.Decl4.Decl3.self // expected-error {{type 'Z2.T' (aka 'Y') does not conform to protocol 'P'}} let _ = Conforms.Decl4.Decl4.self // expected-error {{type 'Z2.T' (aka 'Y') does not conform to protocol 'P'}} let _ = Conforms.Decl4.Decl5.self // expected-error {{type 'Z2.T' (aka 'Y') does not conform to protocol 'P'}} diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index 3f2d8da2d752f..c03c1ab8c347a 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -454,6 +454,7 @@ CurriedClass.method3(c)(1.0, b: 1) // expected-error {{cannot convert valu CurriedClass.method3(c)(1) // expected-error {{missing argument for parameter 'b' in call}} CurriedClass.method3(c)(c: 1.0) // expected-error {{incorrect argument labels in call (have 'c:', expected '_:b:')}} // expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Int'}} +// expected-error@-2 {{missing argument for parameter #1 in call}} extension CurriedClass { @@ -1295,6 +1296,7 @@ rdar43525641(1, c: 2, 3) // Ok struct Array {} let foo: Swift.Array = Array() // expected-error {{cannot convert value of type 'Array' to specified type 'Array'}} +// expected-error@-1 {{generic parameter 'Element' could not be inferred}} struct Error {} let bar: Swift.Error = Error() //expected-error {{value of type 'diagnostics.Error' does not conform to specified type 'Swift.Error'}} diff --git a/test/Constraints/enum_cases.swift b/test/Constraints/enum_cases.swift index ea97b7ac0086b..2b162eb03d9db 100644 --- a/test/Constraints/enum_cases.swift +++ b/test/Constraints/enum_cases.swift @@ -96,15 +96,17 @@ foo(Foo.a, Foo.b) // Ok in Swift 4 because we strip labels from the arguments // rdar://problem/32551313 - Useless SE-0110 diagnostic -enum E_32551313 { +enum E_32551313 { // expected-note {{'R' declared as parameter to type 'E_32551313'}} case Left(L) case Right(R) } struct Foo_32551313 { + // FIXME(diagnostics): We should be able to figure out L and R from contextual type static func bar() -> E_32551313<(String, Foo_32551313?), (String, String)>? { - return E_32551313.Left("", Foo_32551313()) // expected-error {{enum case 'Left' expects a single parameter of type 'L' [with L = (String, Foo_32551313?)]}} - // expected-note@-1 {{did you mean to pass a tuple?}} {{28-28=(}} {{46-46=)}} + return E_32551313.Left("", Foo_32551313()) // expected-error {{extra argument in call}} + // expected-error@-1 {{generic parameter 'R' could not be inferred}} expected-note@-1 {{explicitly specify the generic arguments to fix this issue}} + // expected-error@-2 {{cannot convert return expression of type 'E_32551313' to return type 'E_32551313<(String, Foo_32551313?), (String, String)>?'}} } } diff --git a/test/Constraints/fixes.swift b/test/Constraints/fixes.swift index 028977eeafde7..9cb8e4aded51d 100644 --- a/test/Constraints/fixes.swift +++ b/test/Constraints/fixes.swift @@ -198,14 +198,14 @@ func moreComplexUnwrapFixes() { // expected-note@-2{{force-unwrap using '!'}}{{12-12=!}} takeOpt(t.optS.value) // expected-error{{value of optional type 'T?' must be unwrapped to refer to member 'optS' of wrapped base type 'T'}} - // expected-note@-1{{chain the optional using '?'}}{{17-17=?}} + // expected-note@-1{{chain the optional using '?'}}{{12-12=?}} // expected-error@-2{{value of optional type 'S?' must be unwrapped to refer to member 'value' of wrapped base type 'S'}} - // expected-note@-3{{chain the optional using '?'}}{{12-12=?}} + // expected-note@-3{{chain the optional using '?'}}{{17-17=?}} takeNon(t.optS.value) // expected-error{{value of optional type 'T?' must be unwrapped to refer to member 'optS' of wrapped base type 'T'}} - // expected-note@-1{{chain the optional using '?'}}{{17-17=?}} + // expected-note@-1{{chain the optional using '?'}}{{12-12=?}} // expected-error@-2{{value of optional type 'S?' must be unwrapped to refer to member 'value' of wrapped base type 'S'}} - // expected-note@-3{{chain the optional using '?'}}{{12-12=?}} + // expected-note@-3{{chain the optional using '?'}}{{17-17=?}} // expected-note@-4{{force-unwrap using '!'}}{{17-17=!}} takeNon(os?.value) // expected-error{{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}} diff --git a/test/Constraints/function_builder_diags.swift b/test/Constraints/function_builder_diags.swift index 4d8924fb5e33a..45485a2983d99 100644 --- a/test/Constraints/function_builder_diags.swift +++ b/test/Constraints/function_builder_diags.swift @@ -214,3 +214,14 @@ func erroneousSR11350(x: Int) { }).domap(0) // expected-error{{value of type 'Optional<()>' has no member 'domap'}} } } + +func extraArg() { + tuplify(true) { _ in + 1 + 2 + 3 + 4 + 5 + 6 // expected-error {{extra argument in call}} + } +} diff --git a/test/Constraints/protocols.swift b/test/Constraints/protocols.swift index 477c43aafbc7f..eef0fe619afe3 100644 --- a/test/Constraints/protocols.swift +++ b/test/Constraints/protocols.swift @@ -212,6 +212,7 @@ func staticExistential(_ p: P.Type, pp: P.Protocol) { // Instance member of existential metatype -- not allowed _ = p.bar // expected-error{{instance member 'bar' cannot be used on type 'P'}} _ = p.mut // expected-error{{instance member 'mut' cannot be used on type 'P'}} + // expected-error@-1 {{partial application of 'mutating' method is not allowed}} // Static member of metatype -- not allowed _ = pp.tum // expected-error{{static member 'tum' cannot be used on protocol metatype 'P.Protocol'}} diff --git a/test/Constraints/rdar39931339.swift b/test/Constraints/rdar39931339.swift index b0c3e5d09b6bb..40add2eb11c18 100644 --- a/test/Constraints/rdar39931339.swift +++ b/test/Constraints/rdar39931339.swift @@ -6,26 +6,23 @@ struct S {} class C : P {} -extension S where T : P { -// expected-note@-1 {{where 'T' = 'T'}} -// expected-note@-2 {{where 'T' = 'Int'}} +extension S where T : P { // expected-note {{where 'T' = 'T'}} typealias A = Int typealias B = S } -extension S where T == Float { // expected-note {{where 'T' = 'Int'}} +extension S where T == Float { // expected-note {{requirement specified as 'T' == 'Float' [with T = Int]}} typealias C = Int } class A {} -extension A where T == [U], U: P { // expected-note {{where 'U' = 'Float'}} +extension A where T == [U], U: P { typealias S1 = Int } extension A where T == [U], U == Int { -// expected-note@-1 {{where 'U' = 'String'}} -// expected-note@-2 {{where 'T' = '[String]'}} +// expected-note@-1 {{requirement specified as 'T' == '[Int]' [with T = [String]]}} typealias S2 = Int } @@ -33,15 +30,14 @@ class B : A<[U], U> {} _ = B.S1() // Ok _ = B.S2() // Ok -_ = B.S1() // expected-error {{referencing type alias 'S1' on 'A' requires that 'Float' conform to 'P'}} +_ = B.S1() // expected-error {{type 'Float' does not conform to protocol 'P'}} _ = B.S2() -// expected-error@-1 {{referencing type alias 'S2' on 'A' requires the types '[String]' and '[Int]' be equivalent}} -// expected-error@-2 {{referencing type alias 'S2' on 'A' requires the types 'String' and 'Int' be equivalent}} +// expected-error@-1 {{'B.S2' (aka 'Int') requires the types '[String]' and '[Int]' be equivalent}} _ = S.A() // Ok -_ = S.A() // expected-error {{referencing type alias 'A' on 'S' requires that 'Int' conform to 'P'}} +_ = S.A() // expected-error {{type 'Int' does not conform to protocol 'P'}} _ = S.B() // expected-error {{type 'String' does not conform to protocol 'P'}} -_ = S.C() // expected-error {{referencing type alias 'C' on 'S' requires the types 'Int' and 'Float' be equivalent}} +_ = S.C() // expected-error {{'S.C' (aka 'Int') requires the types 'Int' and 'Float' be equivalent}} func foo(_ s: S.Type) { _ = s.A() // expected-error {{referencing type alias 'A' on 'S' requires that 'T' conform to 'P'}} diff --git a/test/Constraints/requirement_failures_in_contextual_type.swift b/test/Constraints/requirement_failures_in_contextual_type.swift index f3eeff105f65f..d7896b494bc93 100644 --- a/test/Constraints/requirement_failures_in_contextual_type.swift +++ b/test/Constraints/requirement_failures_in_contextual_type.swift @@ -2,8 +2,8 @@ struct A {} -extension A where T == Int32 { // expected-note 2 {{where 'T' = 'Int'}} - struct B : ExpressibleByIntegerLiteral { // expected-note {{where 'T' = 'Int'}} +extension A where T == Int32 { // expected-note 3{{requirement specified as 'T' == 'Int32' [with T = Int]}} + struct B : ExpressibleByIntegerLiteral { typealias E = Int typealias IntegerLiteralType = Int @@ -14,8 +14,8 @@ extension A where T == Int32 { // expected-note 2 {{where 'T' = 'Int'}} } let _: A.B = 0 -// expected-error@-1 {{referencing struct 'B' on 'A' requires the types 'Int' and 'Int32' be equivalent}} +// expected-error@-1 {{'A.B' requires the types 'Int' and 'Int32' be equivalent}} let _: A.C = 0 -// expected-error@-1 {{referencing type alias 'C' on 'A' requires the types 'Int' and 'Int32' be equivalent}} +// expected-error@-1 {{'A.C' (aka 'Int') requires the types 'Int' and 'Int32' be equivalent}} let _: A.B.E = 0 -// expected-error@-1 {{referencing type alias 'E' on 'A.B' requires the types 'Int' and 'Int32' be equivalent}} +// expected-error@-1 {{'A.B' requires the types 'Int' and 'Int32' be equivalent}} diff --git a/test/Constraints/tuple_arguments.swift b/test/Constraints/tuple_arguments.swift index a1e694ff37250..7ac39a8445752 100644 --- a/test/Constraints/tuple_arguments.swift +++ b/test/Constraints/tuple_arguments.swift @@ -69,12 +69,12 @@ func genericTuple(_ x: (T, U)) {} do { generic(3) - generic(3, 4) // expected-error {{global function 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{11-11=(}} {{15-15=)}} + generic(3, 4) // expected-error {{extra argument in call}} generic((3)) generic((3, 4)) genericLabeled(x: 3) - genericLabeled(x: 3, 4) // expected-error {{global function 'genericLabeled' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{20-20=(}} {{25-25=)}} + genericLabeled(x: 3, 4) // expected-error {{extra argument in call}} genericLabeled(x: (3)) genericLabeled(x: (3, 4)) @@ -92,7 +92,7 @@ do { let d = (a, b) generic(a) - generic(a, b) // expected-error {{global function 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{11-11=(}} {{15-15=)}} + generic(a, b) // expected-error {{extra argument in call}} generic((a)) generic(c) generic((a, b)) @@ -114,7 +114,7 @@ do { var d = (a, b) generic(a) - generic(a, b) // expected-error {{global function 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{11-11=(}} {{15-15=)}} + generic(a, b) // expected-error {{extra argument in call}} generic((a)) generic(c) generic((a, b)) @@ -256,12 +256,12 @@ do { let s = Concrete() s.generic(3) - s.generic(3, 4) // expected-error {{instance method 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{13-13=(}} {{17-17=)}} + s.generic(3, 4) // expected-error {{extra argument in call}} s.generic((3)) s.generic((3, 4)) s.genericLabeled(x: 3) - s.genericLabeled(x: 3, 4) // expected-error {{instance method 'genericLabeled' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{22-22=(}} {{27-27=)}} + s.genericLabeled(x: 3, 4) // expected-error {{extra argument in call}} s.genericLabeled(x: (3)) s.genericLabeled(x: (3, 4)) @@ -281,7 +281,7 @@ do { let d = (a, b) s.generic(a) - s.generic(a, b) // expected-error {{instance method 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{13-13=(}} {{17-17=)}} + s.generic(a, b) // expected-error {{extra argument in call}} s.generic((a)) s.generic((a, b)) s.generic(d) @@ -304,7 +304,7 @@ do { var d = (a, b) s.generic(a) - s.generic(a, b) // expected-error {{instance method 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{13-13=(}} {{17-17=)}} + s.generic(a, b) // expected-error {{extra argument in call}} s.generic((a)) s.generic((a, b)) s.generic(d) @@ -390,12 +390,12 @@ do { var s = Concrete() s.mutatingGeneric(3) - s.mutatingGeneric(3, 4) // expected-error {{instance method 'mutatingGeneric' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{21-21=(}} {{25-25=)}} + s.mutatingGeneric(3, 4) // expected-error {{extra argument in call}} s.mutatingGeneric((3)) s.mutatingGeneric((3, 4)) s.mutatingGenericLabeled(x: 3) - s.mutatingGenericLabeled(x: 3, 4) // expected-error {{instance method 'mutatingGenericLabeled' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{30-30=(}} {{35-35=)}} + s.mutatingGenericLabeled(x: 3, 4) // expected-error {{extra argument in call}} s.mutatingGenericLabeled(x: (3)) s.mutatingGenericLabeled(x: (3, 4)) @@ -415,7 +415,7 @@ do { let d = (a, b) s.mutatingGeneric(a) - s.mutatingGeneric(a, b) // expected-error {{instance method 'mutatingGeneric' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{21-21=(}} {{25-25=)}} + s.mutatingGeneric(a, b) // expected-error {{extra argument in call}} s.mutatingGeneric((a)) s.mutatingGeneric((a, b)) s.mutatingGeneric(d) @@ -438,7 +438,7 @@ do { var d = (a, b) s.mutatingGeneric(a) - s.mutatingGeneric(a, b) // expected-error {{instance method 'mutatingGeneric' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{21-21=(}} {{25-25=)}} + s.mutatingGeneric(a, b) // expected-error {{extra argument in call}} s.mutatingGeneric((a)) s.mutatingGeneric((a, b)) s.mutatingGeneric(d) @@ -929,10 +929,10 @@ struct GenericInitLabeledTuple { } do { - _ = GenericInit(3, 4) // expected-error {{initializer expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{19-19=(}} {{23-23=)}} + _ = GenericInit(3, 4) // expected-error {{extra argument in call}} _ = GenericInit((3, 4)) - _ = GenericInitLabeled(x: 3, 4) // expected-error {{initializer expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{28-28=(}} {{33-33=)}} + _ = GenericInitLabeled(x: 3, 4) // expected-error {{extra argument in call}} _ = GenericInitLabeled(x: (3, 4)) _ = GenericInitTwo(3, 4) @@ -967,7 +967,7 @@ do { let b = 4 let c = (a, b) - _ = GenericInit(a, b) // expected-error {{initializer expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{19-19=(}} {{23-23=)}} + _ = GenericInit(a, b) // expected-error {{extra argument in call}} _ = GenericInit((a, b)) _ = GenericInit(c) @@ -1003,7 +1003,7 @@ do { var b = 4 var c = (a, b) - _ = GenericInit(a, b) // expected-error {{initializer expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{19-19=(}} {{23-23=)}} + _ = GenericInit(a, b) // expected-error {{extra argument in call}} _ = GenericInit((a, b)) _ = GenericInit(c) @@ -1127,12 +1127,12 @@ enum GenericEnum { } do { - _ = GenericEnum.one(3, 4) // expected-error {{enum case 'one' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{23-23=(}} {{27-27=)}} + _ = GenericEnum.one(3, 4) // expected-error {{extra argument in call}} _ = GenericEnum.one((3, 4)) - _ = GenericEnum.labeled(x: 3, 4) // expected-error {{enum case 'labeled' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{29-29=(}} {{34-34=)}} + _ = GenericEnum.labeled(x: 3, 4) // expected-error {{extra argument in call}} _ = GenericEnum.labeled(x: (3, 4)) - _ = GenericEnum.labeled(3, 4) // expected-error {{enum case 'labeled' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{27-27=(}} {{31-31=)}} + _ = GenericEnum.labeled(3, 4) // expected-error {{extra argument in call}} _ = GenericEnum.labeled((3, 4)) // expected-error {{missing argument label 'x:' in call}} _ = GenericEnum.two(3, 4) @@ -1163,7 +1163,7 @@ do { let b = 4 let c = (a, b) - _ = GenericEnum.one(a, b) // expected-error {{enum case 'one' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{23-23=(}} {{27-27=)}} + _ = GenericEnum.one(a, b) // expected-error {{extra argument in call}} _ = GenericEnum.one((a, b)) _ = GenericEnum.one(c) @@ -1199,7 +1199,7 @@ do { var b = 4 var c = (a, b) - _ = GenericEnum.one(a, b) // expected-error {{enum case 'one' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{23-23=(}} {{27-27=)}} + _ = GenericEnum.one(a, b) // expected-error {{extra argument in call}} _ = GenericEnum.one((a, b)) _ = GenericEnum.one(c) diff --git a/test/DebugInfo/LoadableByAddress.swift b/test/DebugInfo/LoadableByAddress.swift index 540e48c5e3ada..34697d63e5305 100644 --- a/test/DebugInfo/LoadableByAddress.swift +++ b/test/DebugInfo/LoadableByAddress.swift @@ -1,4 +1,3 @@ -// SWIFT_ENABLE_TENSORFLOW // RUN: %target-swift-frontend %s -module-name A -emit-ir -g -o - | %FileCheck %s // REQUIRES: CPU=x86_64 public struct Continuation { diff --git a/test/DebugInfo/inlined-generics-basic.swift b/test/DebugInfo/inlined-generics-basic.swift index d1f6fbb686973..93f13e5d05955 100644 --- a/test/DebugInfo/inlined-generics-basic.swift +++ b/test/DebugInfo/inlined-generics-basic.swift @@ -43,8 +43,8 @@ public class C { let r : R init(_ _r: R) { r = _r } - // SIL: // C.f(_:) - // IR: define {{.*}} @"$s1A1CC1fyyqd__lF" + // SIL-LABEL: // C.f(_:) + // IR-LABEL: define {{.*}} @"$s1A1CC1fyyqd__lF" #sourceLocation(file: "f.swift", line: 1) public func f(_ s: S) { // SIL: debug_value_addr %0 : $*S, let, name "s", argno 1,{{.*}} scope [[F]] @@ -57,7 +57,13 @@ public class C { // IR: call {{.*}}3use #sourceLocation(file: "f.swift", line: 2) g(s) - // IR: dbg.value({{.*}}, metadata ![[GR_T:[0-9]+]] + // Jump-threading removes the basic block containing debug_value + // "t" before the second call to `g(r)`. When this happens, the + // ref_element_addr in that removed block is left with a single + // debug_value use, so they are both deleted. This means we have + // no debug value for "t" in the call to `g(r)`. + // dbg.value({{.*}}, metadata ![[GR_T:[0-9]+]] + // IR: dbg.value({{.*}}, metadata ![[GR_U:[0-9]+]] // IR: call {{.*}}3use #sourceLocation(file: "f.swift", line: 3) @@ -81,6 +87,8 @@ public class C { g(false) } } +// SIL-LABEL: } // end sil function '$s1A1CC1fyyqd__lF' +// IR-LABEL: ret void // IR: ![[BOOL:[0-9]+]] = !DICompositeType({{.*}}name: "Bool" // IR: ![[LET_BOOL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[BOOL]]) @@ -96,9 +104,12 @@ public class C { // IR: ![[SP_GS_T]] = {{.*}}linkageName: "$s1A1gyyxlFqd___Ti5" // IR: ![[GS_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GS_U:[0-9]+]], {{.*}} type: ![[LET_TAU_1_0]]) // IR: ![[SP_GS_U]] = {{.*}}linkageName: "$s1A1hyyxlFqd___Ti5" -// IR: ![[GR_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GR_T:[0-9]+]], {{.*}}type: ![[LET_TAU_0_0]]) + +// Debug info for this variable is removed. See the note above the call to g(r). +// ![[GR_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GR_T:[0-9]+]], {{.*}}type: ![[LET_TAU_0_0]]) // S has the same generic parameter numbering s T and U. -// IR: ![[SP_GR_T]] = {{.*}}linkageName: "$s1A1gyyxlF" +// ![[SP_GR_T]] = {{.*}}linkageName: "$s1A1gyyxlF" + // IR: ![[GR_U]] = !DILocalVariable(name: "u", {{.*}} scope: ![[SP_GR_U:[0-9]+]], {{.*}}type: ![[LET_TAU_0_0]]) // IR: ![[SP_GR_U]] = {{.*}}linkageName: "$s1A1hyyxlF" // IR: ![[GRS_T]] = !DILocalVariable(name: "t", {{.*}} scope: ![[SP_GRS_T:[0-9]+]], {{.*}}type: ![[LET_TUPLE:[0-9]+]] diff --git a/test/DebugInfo/mandatoryinlining-wrongdebugscope.swift b/test/DebugInfo/mandatoryinlining-wrongdebugscope.swift index feb8bc8113227..7a8ab9aa9e7a6 100644 --- a/test/DebugInfo/mandatoryinlining-wrongdebugscope.swift +++ b/test/DebugInfo/mandatoryinlining-wrongdebugscope.swift @@ -2,9 +2,9 @@ // RUN: -sil-print-after=mandatory-inlining \ // RUN: -Xllvm -sil-print-debuginfo -o /dev/null 2>&1 | %FileCheck %s -// CHECK: strong_release {{.*}} : $@callee_guaranteed () -> (), loc {{.*}}:21:5, scope 9 -// CHECK: strong_release {{.*}} : $@callee_guaranteed () -> @out (), loc {{.*}}:18:17, scope 9 -// CHECK: strong_release {{.*}} : $@callee_guaranteed () -> (), loc {{.*}}:21:5, scope 9 +// CHECK: destroy_value {{.*}} : $@callee_guaranteed () -> (), loc {{.*}}:21:5, scope 9 +// CHECK: destroy_value {{.*}} : $@callee_guaranteed () -> @out (), loc {{.*}}:18:17, scope 9 +// CHECK: destroy_value {{.*}} : $@callee_guaranteed () -> (), loc {{.*}}:21:5, scope 9 func patatino(_ function: @escaping (d) -> i, g: d...) -> () -> i { return { typealias h = ([d]) -> i diff --git a/test/Driver/sanitize_recover.swift b/test/Driver/sanitize_recover.swift new file mode 100644 index 0000000000000..ca7ca240acb41 --- /dev/null +++ b/test/Driver/sanitize_recover.swift @@ -0,0 +1,19 @@ +// RUN: not %swiftc_driver -driver-print-jobs -sanitize=address -sanitize-recover=foo %s 2>&1 | %FileCheck -check-prefix=SAN_RECOVER_INVALID_ARG %s +// RUN: not %swiftc_driver -driver-print-jobs -sanitize=address -sanitize-recover=thread %s 2>&1 | %FileCheck -check-prefix=SAN_RECOVER_UNSUPPORTED_ARG %s +// RUN: %swiftc_driver -v -sanitize-recover=address %s -o %t 2>&1 | %FileCheck -check-prefix=SAN_RECOVER_MISSING_INSTRUMENTATION_OPTION %s +// RUN: %swiftc_driver -driver-print-jobs -sanitize=address -sanitize-recover=address %s 2>&1 | %FileCheck -check-prefix=ASAN_WITH_RECOVER %s +// RUN: %swiftc_driver -driver-print-jobs -sanitize=address %s 2>&1 | %FileCheck -check-prefix=ASAN_WITHOUT_RECOVER --implicit-check-not='-sanitize-recover=address' %s +// REQUIRES: asan_runtime + +// SAN_RECOVER_INVALID_ARG: unsupported argument 'foo' to option '-sanitize-recover=' +// SAN_RECOVER_UNSUPPORTED_ARG: unsupported argument 'thread' to option '-sanitize-recover=' + +// SAN_RECOVER_MISSING_INSTRUMENTATION_OPTION: warning: option '-sanitize-recover=address' has no effect when 'address' sanitizer is disabled. Use -sanitize=address to enable the sanitizer +// SAN_RECOVER_MISSING_INSTRUMENTATION_OPTION-NOT: warning: option '-sanitize-recover=address' has no effect when 'address' sanitizer is disabled. Use -sanitize=address to enable the sanitizer + +// ASAN_WITH_RECOVER: swift +// ASAN_WITH_RECOVER-DAG: -sanitize=address +// ASAN_WITH_RECOVER-DAG: -sanitize-recover=address + +// ASAN_WITHOUT_RECOVER: swift +// ASAN_WITHOUT_RECOVER: -sanitize=address diff --git a/test/FixCode/fixits-apply-objc.swift b/test/FixCode/fixits-apply-objc.swift index 2a3f2920e1042..505bce01daccb 100644 --- a/test/FixCode/fixits-apply-objc.swift +++ b/test/FixCode/fixits-apply-objc.swift @@ -4,6 +4,95 @@ import ObjectiveC // REQUIRES: objc_interop +@objc class Selectors { + func takeSel(_: Selector) {} + @objc func mySel() {} + func test() { + takeSel("mySel") + takeSel(Selector("mySel")) + } +} + +@objc class OtherClass { + func test(s: Selectors) { + s.takeSel("mySel") + s.takeSel(Selector("mySel")) + } +} + +@objc class Base { + @objc func baseSel() {} +} + +@objc class Outer { + func takeSel(_: Selector) {} + @objc func outerSel() {} + + @objc class Inner: Base { + func takeSel(_: Selector) {} + + @objc func innerSel() {} + + func test(s: Selectors, o: Outer) { + s.takeSel("mySel") + s.takeSel(Selector("mySel")) + + takeSel("innerSel") + takeSel(Selector("innerSel")) + + takeSel("baseSel") + takeSel(Selector("baseSel")) + + o.takeSel("outerSel") + o.takeSel(Selector("outerSel")) + } + } + + func test(s: Selectors, i: Inner) { + s.takeSel("mySel") + s.takeSel(Selector("mySel")) + + i.takeSel("innerSel") + i.takeSel(Selector("innerSel")) + + i.takeSel("baseSel") + i.takeSel(Selector("baseSel")) + + takeSel("outerSel") + takeSel(Selector("outerSel")) + } +} + +extension Outer { + func test2(s: Selectors, i: Inner) { + s.takeSel("mySel") + s.takeSel(Selector("mySel")) + + i.takeSel("innerSel") + i.takeSel(Selector("innerSel")) + + i.takeSel("baseSel") + i.takeSel(Selector("baseSel")) + + takeSel("outerSel") + takeSel(Selector("outerSel")) + } +} + +func freeTest(s: Selectors, o: Outer, i: Outer.Inner) { + s.takeSel("mySel") + s.takeSel(Selector("mySel")) + + i.takeSel("innerSel") + i.takeSel(Selector("innerSel")) + + i.takeSel("baseSel") + i.takeSel(Selector("baseSel")) + + o.takeSel("outerSel") + o.takeSel(Selector("outerSel")) +} + func foo(an : Any) { let a1 : AnyObject a1 = an diff --git a/test/FixCode/fixits-apply-objc.swift.result b/test/FixCode/fixits-apply-objc.swift.result index 607a3bd8723fa..a3c0aca923034 100644 --- a/test/FixCode/fixits-apply-objc.swift.result +++ b/test/FixCode/fixits-apply-objc.swift.result @@ -4,6 +4,95 @@ import ObjectiveC // REQUIRES: objc_interop +@objc class Selectors { + func takeSel(_: Selector) {} + @objc func mySel() {} + func test() { + takeSel(#selector(self.mySel)) + takeSel(#selector(self.mySel)) + } +} + +@objc class OtherClass { + func test(s: Selectors) { + s.takeSel(#selector(Selectors.mySel)) + s.takeSel(#selector(Selectors.mySel)) + } +} + +@objc class Base { + @objc func baseSel() {} +} + +@objc class Outer { + func takeSel(_: Selector) {} + @objc func outerSel() {} + + @objc class Inner: Base { + func takeSel(_: Selector) {} + + @objc func innerSel() {} + + func test(s: Selectors, o: Outer) { + s.takeSel(#selector(Selectors.mySel)) + s.takeSel(#selector(Selectors.mySel)) + + takeSel(#selector(self.innerSel)) + takeSel(#selector(self.innerSel)) + + takeSel(#selector(self.baseSel)) + takeSel(#selector(self.baseSel)) + + o.takeSel(#selector(Outer.outerSel)) + o.takeSel(#selector(Outer.outerSel)) + } + } + + func test(s: Selectors, i: Inner) { + s.takeSel(#selector(Selectors.mySel)) + s.takeSel(#selector(Selectors.mySel)) + + i.takeSel(#selector(Inner.innerSel)) + i.takeSel(#selector(Inner.innerSel)) + + i.takeSel(#selector(Base.baseSel)) + i.takeSel(#selector(Base.baseSel)) + + takeSel(#selector(self.outerSel)) + takeSel(#selector(self.outerSel)) + } +} + +extension Outer { + func test2(s: Selectors, i: Inner) { + s.takeSel(#selector(Selectors.mySel)) + s.takeSel(#selector(Selectors.mySel)) + + i.takeSel(#selector(Inner.innerSel)) + i.takeSel(#selector(Inner.innerSel)) + + i.takeSel(#selector(Base.baseSel)) + i.takeSel(#selector(Base.baseSel)) + + takeSel(#selector(self.outerSel)) + takeSel(#selector(self.outerSel)) + } +} + +func freeTest(s: Selectors, o: Outer, i: Outer.Inner) { + s.takeSel(#selector(Selectors.mySel)) + s.takeSel(#selector(Selectors.mySel)) + + i.takeSel(#selector(Inner.innerSel)) + i.takeSel(#selector(Inner.innerSel)) + + i.takeSel(#selector(Base.baseSel)) + i.takeSel(#selector(Base.baseSel)) + + o.takeSel(#selector(Outer.outerSel)) + o.takeSel(#selector(Outer.outerSel)) +} + func foo(an : Any) { let a1 : AnyObject a1 = an as AnyObject diff --git a/test/Frontend/sil-merge-partial-modules.swift b/test/Frontend/sil-merge-partial-modules.swift index 55a84cd6b0940..249941e100b1e 100644 --- a/test/Frontend/sil-merge-partial-modules.swift +++ b/test/Frontend/sil-merge-partial-modules.swift @@ -42,11 +42,11 @@ public class CircleManager : ShapeManager { // CHECK-LABEL: sil [canonical] @$s4test14publicFunctionyyF : $@convention(thin) () -> () -// CHECK-LABEL: sil [serialized] [canonical] @$s4test17inlinableFunctionyyF : $@convention(thin) () -> () { +// CHECK-LABEL: sil [serialized] [canonical] [ossa] @$s4test17inlinableFunctionyyF : $@convention(thin) () -> () { // CHECK: function_ref @$s4test17inlinableFunctionyyFyycfU_ // CHECK: } -// CHECK-LABEL: sil shared [serialized] [canonical] @$s4test17inlinableFunctionyyFyycfU_ : $@convention(thin) () -> () { +// CHECK-LABEL: sil shared [serialized] [canonical] [ossa] @$s4test17inlinableFunctionyyFyycfU_ : $@convention(thin) () -> () { // CHECK: function_ref @$s4test17versionedFunctionyyF // CHECK: } @@ -54,15 +54,15 @@ public class CircleManager : ShapeManager { // CHECK-LABEL: sil [canonical] @$s4test9RectangleV4areaSfvg : $@convention(method) (Rectangle) -> Float -// CHECK-LABEL: sil [serialized] [canonical] @$s4test9RectangleV4drawyyF : $@convention(method) (Rectangle) -> () { +// CHECK-LABEL: sil [serialized] [canonical] [ossa] @$s4test9RectangleV4drawyyF : $@convention(method) (Rectangle) -> () { // CHECK: function_ref @$s4test14publicFunctionyyF // CHECK: } -// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] [canonical] @$s4test9RectangleVAA5ShapeA2aDP4areaSfvgTW : $@convention(witness_method: Shape) (@in_guaranteed Rectangle) -> Float { +// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s4test9RectangleVAA5ShapeA2aDP4areaSfvgTW : $@convention(witness_method: Shape) (@in_guaranteed Rectangle) -> Float { // CHECK: function_ref @$s4test9RectangleV4areaSfvg // CHECK: } -// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] [canonical] @$s4test9RectangleVAA5ShapeA2aDP4drawyyFTW : $@convention(witness_method: Shape) (@in_guaranteed Rectangle) -> () { +// CHECK-LABEL: sil shared [transparent] [serialized] [thunk] [canonical] [ossa] @$s4test9RectangleVAA5ShapeA2aDP4drawyyFTW : $@convention(witness_method: Shape) (@in_guaranteed Rectangle) -> () { // CHECK: function_ref @$s4test9RectangleV4drawyyF // CHECK: } diff --git a/test/IDE/complete_after_super.swift b/test/IDE/complete_after_super.swift index 01c2353d49270..5727dd9892051 100644 --- a/test/IDE/complete_after_super.swift +++ b/test/IDE/complete_after_super.swift @@ -491,7 +491,7 @@ class SemanticContextDerived1 : SemanticContextBase1 { // SEMANTIC_CONTEXT_OVERRIDDEN_DECL_2-NEXT: Decl[InstanceMethod]/CurrNominal: instanceFunc1({#(a): Int#})[#Void#]{{; name=.+$}} // SEMANTIC_CONTEXT_OVERRIDDEN_DECL_2-NEXT: End completions } - func instanceFunc1() { + override func instanceFunc1() { #^SEMANTIC_CONTEXT_OVERRIDDEN_DECL_3^# // SEMANTIC_CONTEXT_OVERRIDDEN_DECL_3: Begin completions // SEMANTIC_CONTEXT_OVERRIDDEN_DECL_3-DAG: Decl[InstanceMethod]/CurrNominal: instanceFunc1()[#Void#]{{; name=.+$}} @@ -504,7 +504,7 @@ class SemanticContextDerived1 : SemanticContextBase1 { // SEMANTIC_CONTEXT_OVERRIDDEN_DECL_4-NEXT: Decl[InstanceMethod]/CurrNominal: instanceFunc1({#(a): Int#})[#Void#]{{; name=.+$}} // SEMANTIC_CONTEXT_OVERRIDDEN_DECL_4-NEXT: End completions } - func instanceFunc1(_ a: Int) { + override func instanceFunc1(_ a: Int) { super.#^SEMANTIC_CONTEXT_OVERRIDDEN_DECL_5^# // SEMANTIC_CONTEXT_OVERRIDDEN_DECL_5: Begin completions // SEMANTIC_CONTEXT_OVERRIDDEN_DECL_5-NEXT: Decl[InstanceMethod]/CurrNominal: instanceFunc1()[#Void#]{{; name=.+$}} diff --git a/test/IDE/complete_decl_attribute.swift b/test/IDE/complete_decl_attribute.swift index 0fb734ee172fa..0a253bf1dcf3d 100644 --- a/test/IDE/complete_decl_attribute.swift +++ b/test/IDE/complete_decl_attribute.swift @@ -132,8 +132,8 @@ struct MyStruct {} // ON_GLOBALVAR-DAG: Keyword/None: inlinable[#Var Attribute#]; name=inlinable // ON_GLOBALVAR-DAG: Keyword/None: usableFromInline[#Var Attribute#]; name=usableFromInline // ON_GLOBALVAR-DAG: Keyword/None: GKInspectable[#Var Attribute#]; name=GKInspectable -// SWIFT_ENABLE_TENSORFLOW // ON_GLOBALVAR-DAG: Keyword/None: differentiable[#Var Attribute#]; name=differentiable +// SWIFT_ENABLE_TENSORFLOW // ON_GLOBALVAR-DAG: Keyword/None: noDerivative[#Var Attribute#]; name=noDerivative // ON_GLOBALVAR-NOT: Keyword // ON_GLOBALVAR: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct @@ -164,8 +164,8 @@ struct _S { // ON_PROPERTY-DAG: Keyword/None: inlinable[#Var Attribute#]; name=inlinable // ON_PROPERTY-DAG: Keyword/None: usableFromInline[#Var Attribute#]; name=usableFromInline // ON_PROPERTY-DAG: Keyword/None: GKInspectable[#Var Attribute#]; name=GKInspectable -// SWIFT_ENABLE_TENSORFLOW // ON_PROPERTY-DAG: Keyword/None: differentiable[#Var Attribute#]; name=differentiable +// SWIFT_ENABLE_TENSORFLOW // ON_PROPERTY-DAG: Keyword/None: noDerivative[#Var Attribute#]; name=noDerivative // ON_PROPERTY-NOT: Keyword // ON_PROPERTY: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct @@ -186,8 +186,8 @@ struct _S { // ON_METHOD-DAG: Keyword/None: usableFromInline[#Func Attribute#]; name=usableFromInline // ON_METHOD-DAG: Keyword/None: discardableResult[#Func Attribute#]; name=discardableResult // ON_METHOD-DAG: Keyword/None: IBSegueAction[#Func Attribute#]; name=IBSegueAction -// SWIFT_ENABLE_TENSORFLOW // ON_METHOD-DAG: Keyword/None: differentiable[#Func Attribute#]; name=differentiable +// SWIFT_ENABLE_TENSORFLOW // ON_METHOD-DAG: Keyword/None: derivative[#Func Attribute#]; name=derivative // ON_METHOD-DAG: Keyword/None: compilerEvaluable[#Func Attribute#]; name=compilerEvaluable // ON_METHOD-DAG: Keyword/None: quoted[#Func Attribute#]; name=quoted @@ -247,8 +247,8 @@ struct _S { // ON_MEMBER_LAST-DAG: Keyword/None: IBSegueAction[#Declaration Attribute#]; name=IBSegueAction // ON_MEMBER_LAST-DAG: Keyword/None: propertyWrapper[#Declaration Attribute#]; name=propertyWrapper // ON_MEMBER_LAST-DAG: Keyword/None: _functionBuilder[#Declaration Attribute#]; name=_functionBuilder -// SWIFT_ENABLE_TENSORFLOW // ON_MEMBER_LAST-DAG: Keyword/None: differentiable[#Declaration Attribute#]; name=differentiable +// SWIFT_ENABLE_TENSORFLOW // ON_MEMBER_LAST-DAG: Keyword/None: derivative[#Declaration Attribute#]; name=derivative // ON_MEMBER_LAST-DAG: Keyword/None: differentiating[#Declaration Attribute#]; name=differentiating // ON_MEMBER_LAST-DAG: Keyword/None: compilerEvaluable[#Declaration Attribute#]; name=compilerEvaluable diff --git a/test/IDE/complete_expr_postfix_begin.swift b/test/IDE/complete_expr_postfix_begin.swift index 407ddfee8b7a8..5d8029ea6fc74 100644 --- a/test/IDE/complete_expr_postfix_begin.swift +++ b/test/IDE/complete_expr_postfix_begin.swift @@ -75,8 +75,8 @@ // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_TUPLE_1 | %FileCheck %s -check-prefix=IN_TUPLE_1 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IN_TUPLE_2 | %FileCheck %s -check-prefix=IN_TUPLE_2 -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_1 | %FileCheck %s -check-prefix=OWN_INIT_1 -// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_2 | %FileCheck %s -check-prefix=OWN_INIT_2 +// RUN-FIXME(rdar56755598): %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_1 | %FileCheck %s -check-prefix=OWN_INIT_1 +// RUN-FIXME(rdar56755598): %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_2 | %FileCheck %s -check-prefix=OWN_INIT_2 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_3 | %FileCheck %s -check-prefix=OWN_INIT_3 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_4 | %FileCheck %s -check-prefix=OWN_INIT_4 // RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OWN_INIT_5 | %FileCheck %s -check-prefix=OWN_INIT_5 diff --git a/test/IDE/complete_multifile.swift b/test/IDE/complete_multifile.swift new file mode 100644 index 0000000000000..3b73ee7abea2d --- /dev/null +++ b/test/IDE/complete_multifile.swift @@ -0,0 +1,93 @@ +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s + +// RUN: %target-swift-ide-test -code-completion -source-filename %t/Main.swift %t/Library.swift -code-completion-token=POINT_PAREN | %FileCheck --check-prefix=POINT_PAREN %s +// RUN: %target-swift-ide-test -code-completion -source-filename %t/Main.swift %t/Library.swift -code-completion-token=POINT_DOT | %FileCheck --check-prefix=POINT_DOT %s +// RUN: %target-swift-ide-test -code-completion -source-filename %t/Main.swift %t/Library.swift -code-completion-token=LENS_DOT | %FileCheck --check-prefix=LENS_DOT %s +// RUN: %target-swift-ide-test -code-completion -source-filename %t/Main.swift %t/Library.swift -code-completion-token=MYENUM_DOT | %FileCheck --check-prefix=MYENUM_DOT %s +// RUN: %target-swift-ide-test -code-completion -source-filename %t/Main.swift %t/Library.swift -code-completion-token=HASWRAPPED_DOT| %FileCheck --check-prefix=HASWRAPPED_DOT %s + +// BEGIN Library.swift + +public struct Point { + var x: Int + var y: Int +} + +@dynamicMemberLookup +struct Lens { + var obj: T + init(_ obj: T) { self.obj = obj } + + subscript(dynamicMember member: WritableKeyPath) -> Lens { + get { return Lens(obj[keyPath: member]) } + set { obj[keyPath: member] = newValue.obj } + } +} + +enum MyEnum: String { + case foo = "foo" + case bar = "bar" +} + +@propertyWrapper +struct Wrap { + var wrappedValue: T + + public var projectedValue: Self { + get { self } + set { self = newValue } + } +} + +struct HasWrapped { + @Wrap + var wrapped: Int = 1 +} + +// BEGIN Main.swift + +func testStructDefaultInit() { + Point(#^POINT_PAREN^# +// POINT_PAREN: Begin completions, 1 items +// POINT_PAREN-DAG: Decl[Constructor]/CurrNominal: ['(']{#x: Int#}, {#y: Int#}[')'][#Point#]; +// POINT_PAREN: End completions + func sync() {} + Point.#^POINT_DOT^# +// POINT_DOT: Begin completions, 3 items +// POINT_DOT-DAG: Keyword[self]/CurrNominal: self[#Point.Type#]; +// POINT_DOT-DAG: Keyword/CurrNominal: Type[#Point.Type#]; +// POINT_DOT-DAG: Decl[Constructor]/CurrNominal: init({#x: Int#}, {#y: Int#})[#Point#]; +// POINT_DOT: End completions +} + +func testDynamicMemberLookup(lens: Lens) { + _ = lens.#^LENS_DOT^# +// LENS_DOT: Begin completions, 4 items +// LENS_DOT-DAG: Keyword[self]/CurrNominal: self[#Lens#]; +// LENS_DOT-DAG: Decl[InstanceVar]/CurrNominal: x[#Lens#]; +// LENS_DOT-DAG: Decl[InstanceVar]/CurrNominal: y[#Lens#]; +// LENS_DOT-DAG: Decl[InstanceVar]/CurrNominal: obj[#Point#]; +// LENS_DOT: End completions +} +func testRawRepresentable() { + MyEnum.#^MYENUM_DOT^# +// MYENUM_DOT: Begin completions, 7 items +// MYENUM_DOT-DAG: Keyword[self]/CurrNominal: self[#MyEnum.Type#]; +// MYENUM_DOT-DAG: Keyword/CurrNominal: Type[#MyEnum.Type#]; +// MYENUM_DOT-DAG: Decl[EnumElement]/CurrNominal: foo[#MyEnum#]; +// MYENUM_DOT-DAG: Decl[EnumElement]/CurrNominal: bar[#MyEnum#]; +// MYENUM_DOT-DAG: Decl[TypeAlias]/CurrNominal: RawValue[#String#]; +// MYENUM_DOT-DAG: Decl[Constructor]/CurrNominal: init({#rawValue: String#})[#MyEnum?#]; +// MYENUM_DOT-DAG: Decl[InstanceMethod]/Super: hash({#(self): MyEnum#})[#(into: inout Hasher) -> Void#]; +// MYENUM_DOT: End completions +} + +func testHasWrappedValue(value: HasWrapped) { + value.#^HASWRAPPED_DOT^# +// HASWRAPPED_DOT: Begin completions, 3 items +// HASWRAPPED_DOT: Keyword[self]/CurrNominal: self[#HasWrapped#]; +// HASWRAPPED_DOT: Decl[InstanceVar]/CurrNominal: wrapped[#Int#]; +// HASWRAPPED_DOT: Decl[InstanceVar]/CurrNominal: $wrapped[#Wrap#]; +// HASWRAPPED_DOT: End completions +} diff --git a/test/IDE/complete_override.swift b/test/IDE/complete_override.swift index 2970a0efc6980..27110af69ab8e 100644 --- a/test/IDE/complete_override.swift +++ b/test/IDE/complete_override.swift @@ -724,9 +724,10 @@ class Override26 : OverrideBase, OverrideP { // Same as MODIFIER24 } -// MODIFIER1: Begin completions, 9 items +// MODIFIER1: Begin completions, 10 items // MODIFIER1-DAG: Decl[Constructor]/Super: required init(p: Int) {|}; name=required init(p: Int) // MODIFIER1-DAG: Decl[StaticMethod]/Super: override class func classMethod() {|}; name=classMethod() +// MODIFIER1-DAG: Decl[StaticVar]/Super: override class var classVar: Int; name=classVar: Int // MODIFIER1-DAG: Decl[StaticVar]/Super: override class var classGetOnlyVar: Int; name=classGetOnlyVar: Int // MODIFIER1-DAG: Decl[InstanceMethod]/Super: override func defaultMethod() {|}; name=defaultMethod() // MODIFIER1-DAG: Decl[InstanceMethod]/Super: override func openMethod() {|}; name=openMethod() @@ -736,7 +737,8 @@ class Override26 : OverrideBase, OverrideP { // MODIFIER1-DAG: Decl[AssociatedType]/Super: typealias Assoc = {#(Type)#}; name=Assoc = Type // MODIFIER1: End completions -// MODIFIER2: Begin completions, 5 items +// MODIFIER2: Begin completions, 6 items +// MODIFIER2-DAG: Decl[StaticVar]/Super: override class var classVar: Int; name=classVar: Int // MODIFIER2-DAG: Decl[StaticVar]/Super: override class var classGetOnlyVar: Int; name=classGetOnlyVar: Int // MODIFIER2-DAG: Decl[StaticMethod]/Super: override class func classMethod() {|}; name=classMethod() // MODIFIER2-DAG: Decl[InstanceMethod]/Super: override func defaultMethod() {|}; name=defaultMethod() @@ -760,7 +762,8 @@ class Override26 : OverrideBase, OverrideP { // MODIFIER6-DAG: Decl[AssociatedType]/Super: Assoc = {#(Type)#}; name=Assoc = Type // MODIFIER6: End completions -// MODIFIER7: Begin completions, 7 items +// MODIFIER7: Begin completions, 8 items +// MODIFIER7-DAG: Decl[StaticVar]/Super: class var classVar: Int; name=classVar: Int // MODIFIER7-DAG: Decl[StaticVar]/Super: class var classGetOnlyVar: Int; name=classGetOnlyVar: Int // MODIFIER7-DAG: Decl[StaticMethod]/Super: class func classMethod() {|}; name=classMethod() // MODIFIER7-DAG: Decl[InstanceMethod]/Super: func defaultMethod() {|}; name=defaultMethod() @@ -785,11 +788,13 @@ class Override26 : OverrideBase, OverrideP { // MODIFIER13-NOT: Begin completions -// MODIFIER15: Begin completions, 1 items +// MODIFIER15: Begin completions, 2 items +// MODIFIER15-DAG: Decl[StaticVar]/Super/Erase[4]: override var classVar: Int; name=classVar: Int // MODIFIER15-DAG: Decl[StaticVar]/Super/Erase[4]: override var classGetOnlyVar: Int; name=classGetOnlyVar: Int // MODIFIER15: End completions -// MODIFIER17: Begin completions, 1 items +// MODIFIER17: Begin completions, 2 items +// MODIFIER17-DAG: Decl[StaticVar]/Super: classVar: Int; name=classVar: Int // MODIFIER17-DAG: Decl[StaticVar]/Super: classGetOnlyVar: Int; name=classGetOnlyVar: Int // MODIFIER17: End completions @@ -801,13 +806,15 @@ class Override26 : OverrideBase, OverrideP { // MODIFIER22: Decl[StaticMethod]/Super/Erase[5]: override func classMethod() {|}; name=classMethod() // MODIFIER22: End completions -// MODIFIER23: Begin completions, 2 items +// MODIFIER23: Begin completions, 3 items // MODIFIER23-DAG: Decl[StaticMethod]/Super: override func classMethod() {|}; name=classMethod() +// MODIFIER23-DAG: Decl[StaticVar]/Super: override var classVar: Int; name=classVar: Int // MODIFIER23-DAG: Decl[StaticVar]/Super: override var classGetOnlyVar: Int; name=classGetOnlyVar: Int // MODIFIER23: End completions -// MODIFIER24: Begin completions, 2 items +// MODIFIER24: Begin completions, 3 items // MODIFIER24-DAG: Decl[StaticMethod]/Super: func classMethod() {|}; name=classMethod() +// MODIFIER24-DAG: Decl[StaticVar]/Super: var classVar: Int; name=classVar: Int // MODIFIER24-DAG: Decl[StaticVar]/Super: var classGetOnlyVar: Int; name=classGetOnlyVar: Int // MODIFIER24: End completions diff --git a/test/IDE/print_type_interface.swift b/test/IDE/print_type_interface.swift index 5b2f976f2139b..7af1876b8af34 100644 --- a/test/IDE/print_type_interface.swift +++ b/test/IDE/print_type_interface.swift @@ -97,7 +97,7 @@ extension Array.Inner where Element: P2 { extension Int: P2 {} // Print interface for Array.Inner -// RUN: %target-swift-ide-test -print-type-interface -usr=\$sSa20print_type_interfaceE5InnerVySi_GD -module-name print_type_interface -source-filename %s | %FileCheck %s -check-prefix=TYPE6 +// RUN: %target-swift-ide-test -print-type-interface -usr='$sSa20print_type_interfaceE5InnerVySi_GD' -module-name print_type_interface -source-filename %s | %FileCheck %s -check-prefix=TYPE6 // TYPE6-LABEL: public struct Inner { // TYPE6: public func innerFoo() diff --git a/test/IRGen/address_sanitizer_recover.swift b/test/IRGen/address_sanitizer_recover.swift new file mode 100644 index 0000000000000..259fbbb5b5da8 --- /dev/null +++ b/test/IRGen/address_sanitizer_recover.swift @@ -0,0 +1,16 @@ +// RUN: %target-swift-frontend -emit-ir -sanitize=address -sanitize-recover=address %s | %FileCheck %s -check-prefix=ASAN_RECOVER +// RUN: %target-swift-frontend -emit-ir -sanitize=address %s | %FileCheck %s -check-prefix=ASAN_NO_RECOVER +// RUN: %target-swift-frontend -emit-ir -sanitize-recover=address %s | %FileCheck %s -check-prefix=NO_ASAN_RECOVER + +// ASAN_RECOVER: declare void @__asan_loadN_noabort( +// ASAN_NO_RECOVER: declare void @__asan_loadN( + +let size:Int = 128; +let x = UnsafeMutablePointer.allocate(capacity: size) +x.initialize(repeating: 0, count: size) +x.advanced(by: 0).pointee = 5; +print("Read first element:\(x.advanced(by: 0).pointee)") +x.deallocate(); + +// There should be no ASan instrumentation in this case. +// NO_ASAN_RECOVER-NOT: declare void @__asan_load diff --git a/test/IRGen/foreign_type_metadata.swift b/test/IRGen/foreign_type_metadata.swift new file mode 100644 index 0000000000000..19761bc2d107c --- /dev/null +++ b/test/IRGen/foreign_type_metadata.swift @@ -0,0 +1,22 @@ +// RUN: %target-swift-frontend %s -emit-ir | %FileCheck %s + +// REQUIRES: objc_interop + +import Foundation + +// Make sure we emit a metadata accessor for foreign types even if the type +// metadata is not required by this TU. Another TU could require it and the +// linker could choose the less defined one of the two. + +// CHECK: @"$sSo8_NSRangeVMn" = linkonce_odr hidden constant <{ {{.*}}sSo8_NSRangeVMa{{.*}} }>, section "__TEXT,__const" + +func use(_ closure: @escaping (Int) -> ()) {} + +public func captureRange(_ r: NSRange?) { + var l = r + use { + if $0 == 0 { + l = NSRange() + } + } +} diff --git a/test/IRGen/lazy_opaque_result_type.swift b/test/IRGen/lazy_opaque_result_type.swift index 382ad927ec039..d526623ebff0b 100644 --- a/test/IRGen/lazy_opaque_result_type.swift +++ b/test/IRGen/lazy_opaque_result_type.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -enable-implicit-dynamic -disable-availability-checking -Xllvm -sil-disable-pass=OpaqueArchetypeSpecializer -parse-as-library -module-name=test -O -primary-file %s -emit-ir > %t.ll +// RUN: %target-swift-frontend -enable-implicit-dynamic -disable-availability-checking -parse-as-library -module-name=test -O -primary-file %s -emit-ir > %t.ll // RUN: %FileCheck %s < %t.ll protocol P { } diff --git a/test/IRGen/multi_file_resilience.swift b/test/IRGen/multi_file_resilience.swift index 5487120c83bda..aaadb088feec4 100644 --- a/test/IRGen/multi_file_resilience.swift +++ b/test/IRGen/multi_file_resilience.swift @@ -28,13 +28,10 @@ // CHECK: [[DEST:%.*]] = bitcast [[FOO]]* [[COPY]] to %swift.opaque* // CHECK: [[SRC:%.*]] = bitcast [[FOO]]* %1 to %swift.opaque* // CHECK: call %swift.opaque* [[COPYFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]]) -// Perform 'initializeWithTake' via the VWT. -// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4 -// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]], -// CHECK: [[TAKEFN:%.*]] = bitcast i8* [[T1]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* +// Perform 'initializeWithCopy' via the VWT. // CHECK: [[DEST:%.*]] = bitcast [[FOO]]* %0 to %swift.opaque* // CHECK: [[SRC:%.*]] = bitcast [[FOO]]* [[COPY]] to %swift.opaque* -// CHECK: call %swift.opaque* [[TAKEFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]]) +// CHECK: call %swift.opaque* [[COPYFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]]) public func copyFoo(foo: Foo) -> Foo { let copy = foo return copy diff --git a/test/IRGen/multi_module_resilience.swift b/test/IRGen/multi_module_resilience.swift index 06a3896c448f7..b9fdfcf79a1af 100644 --- a/test/IRGen/multi_module_resilience.swift +++ b/test/IRGen/multi_module_resilience.swift @@ -32,13 +32,10 @@ import OtherModule // CHECK: [[DEST:%.*]] = bitcast [[FOO]]* [[COPY]] to %swift.opaque* // CHECK: [[SRC:%.*]] = bitcast [[FOO]]* %1 to %swift.opaque* // CHECK: call %swift.opaque* [[COPYFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]]) -// Perform 'initializeWithTake' via the VWT. -// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4 -// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]], -// CHECK: [[TAKEFN:%.*]] = bitcast i8* [[T1]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* +// Perform 'initializeWithCopy' via the VWT. // CHECK: [[DEST:%.*]] = bitcast [[FOO]]* %0 to %swift.opaque* // CHECK: [[SRC:%.*]] = bitcast [[FOO]]* [[COPY]] to %swift.opaque* -// CHECK: call %swift.opaque* [[TAKEFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]]) +// CHECK: call %swift.opaque* [[COPYFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]]) public func copyFoo(foo: Foo) -> Foo { let copy = foo return copy @@ -61,13 +58,10 @@ public func copyFoo(foo: Foo) -> Foo { // CHECK: [[DEST:%.*]] = bitcast [[BAR]]* [[COPY]] to %swift.opaque* // CHECK: [[SRC:%.*]] = bitcast [[BAR]]* %1 to %swift.opaque* // CHECK: call %swift.opaque* [[COPYFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]]) -// Perform 'initializeWithTake' via the VWT. -// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4 -// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]], -// CHECK: [[TAKEFN:%.*]] = bitcast i8* [[T1]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* +// Perform 'initializeWithCopy' via the VWT. // CHECK: [[DEST:%.*]] = bitcast [[BAR]]* %0 to %swift.opaque* // CHECK: [[SRC:%.*]] = bitcast [[BAR]]* [[COPY]] to %swift.opaque* -// CHECK: call %swift.opaque* [[TAKEFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]]) +// CHECK: call %swift.opaque* [[COPYFN]](%swift.opaque* noalias [[DEST]], %swift.opaque* noalias [[SRC]], %swift.type* [[METADATA]]) public func copyBar(bar: Bar) -> Bar { let copy = bar return copy diff --git a/test/IRGen/objc_enum_multi_file.swift b/test/IRGen/objc_enum_multi_file.swift index 2f70b371933c1..1ef5a4e160f6a 100644 --- a/test/IRGen/objc_enum_multi_file.swift +++ b/test/IRGen/objc_enum_multi_file.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -module-name main -primary-file %s %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir | %FileCheck %s +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -enable-objc-interop -module-name main -primary-file %s %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir | %FileCheck %s // RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -enable-objc-interop -emit-module %S/Inputs/objc_enum_multi_file_helper.swift -o %t // RUN: %target-swift-frontend -module-name main -primary-file %s -I %t -DIMPORT -emit-ir | %FileCheck %s diff --git a/test/IRGen/objc_protocol_multi_file.swift b/test/IRGen/objc_protocol_multi_file.swift index 03affcc33d975..21c739982baa7 100644 --- a/test/IRGen/objc_protocol_multi_file.swift +++ b/test/IRGen/objc_protocol_multi_file.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -primary-file %s %S/Inputs/objc_protocol_multi_file_helper.swift -g -emit-ir | %FileCheck %s +// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -enable-objc-interop -primary-file %s %S/Inputs/objc_protocol_multi_file_helper.swift -g -emit-ir | %FileCheck %s // This used to crash . // To tickle the crash, SubProto must not be used elsewhere in this file. diff --git a/test/IRGen/opaque_result_type_debug.swift b/test/IRGen/opaque_result_type_debug.swift index c4e26d4d201db..a5b0de69c28f4 100644 --- a/test/IRGen/opaque_result_type_debug.swift +++ b/test/IRGen/opaque_result_type_debug.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -disable-availability-checking -g -emit-ir -enable-anonymous-context-mangled-names %s | %FileCheck %s +// RUN: %target-swift-frontend -enable-library-evolution -disable-availability-checking -g -emit-ir -enable-anonymous-context-mangled-names %s | %FileCheck %s public protocol P {} extension Int: P {} @@ -24,6 +24,7 @@ public var prop: some P { // CHECK: @"$s24opaque_result_type_debug3FooVQrycipQOMQ" = {{.*}}constant{{.*}} @"$s24opaque_result_type_debug3FooVQrycipMXX" public struct Foo { + public init() {} public subscript() -> some P { return 0 } @@ -33,6 +34,7 @@ public struct Foo { @_silgen_name("use") public func use(_: T) +@inlinable public func bar(genericValue: T) { use(genericValue) diff --git a/test/IRGen/opaque_result_type_substitution.swift b/test/IRGen/opaque_result_type_substitution.swift index e5d80c020f113..5fbe15e35217e 100644 --- a/test/IRGen/opaque_result_type_substitution.swift +++ b/test/IRGen/opaque_result_type_substitution.swift @@ -1,21 +1,22 @@ -// RUN: %target-swift-frontend -disable-availability-checking -emit-ir -primary-file %s | %FileCheck %s +// RUN: %target-swift-frontend -enable-library-evolution -disable-availability-checking -emit-ir -primary-file %s | %FileCheck %s -protocol E {} +public protocol E {} -struct Pair : E { +public struct Pair : E { var fst : T var snd : V - init(_ f: T, _ s: V) { + public init(_ f: T, _ s: V) { self.fst = f self.snd = s } - func foobar() -> some E { + public func foobar() -> some E { return self } } +@inlinable public func usePair(_ t: T, _ v: V) { var x = Pair(t, v) let q = x.foobar() diff --git a/test/IRGen/partial_apply.sil b/test/IRGen/partial_apply.sil index 87974e3d3c67c..79c5d9d10e354 100644 --- a/test/IRGen/partial_apply.sil +++ b/test/IRGen/partial_apply.sil @@ -527,7 +527,14 @@ enum GenericEnum2 { sil public_external @generic_indirect_return2 : $@convention(thin) (Int) -> @owned GenericEnum2 // CHECK-LABEL: define{{.*}} @partial_apply_generic_indirect_return2 -// CHECK: insertvalue {{.*}}$s24generic_indirect_return2TA +// CHECK: [[CTX:%.]] = call noalias %swift.refcounted* @swift_allocObject +// CHECK: store {{.*}}$s24generic_indirect_return2TA +// CHECK: store %swift.refcounted* [[CTX]] +// CHECK: [[FN:%.*]] = load i8* +// CHECK: [[CTX2:%.*]] = load %swift.refcounted* +// CHECK: [[R1:%.]] = insertvalue { i8*, %swift.refcounted* } undef, i8* [[FN]], 0 +// CHECK: [[R2:%.*]] = insertvalue { i8*, %swift.refcounted* } [[R1]], %swift.refcounted* [[CTX2]], 1 +// CHECK: ret { i8*, %swift.refcounted* } [[R2]] // CHECK-LABEL: define internal swiftcc void @"$s24generic_indirect_return2TA"(%T13partial_apply12GenericEnum2OySiG* noalias nocapture sret, %swift.refcounted* swiftself) // CHECK: [[CASTED_ADDR:%.*]] = bitcast %T13partial_apply12GenericEnum2OySiG* %0 to %T13partial_apply12GenericEnum2O* diff --git a/test/Index/patterns.swift b/test/Index/patterns.swift index 20ccaf9bc6d52..1b210caddbe30 100644 --- a/test/Index/patterns.swift +++ b/test/Index/patterns.swift @@ -4,6 +4,8 @@ struct Foo { enum Inner { case bar } + + struct Bar {} } let a: Foo.Inner = .bar @@ -26,3 +28,19 @@ case Foo.Inner.bar: default: break } + +let prop1 = 1 + +if prop1 is Foo {} +// CHECK: [[@LINE-1]]:13 | struct/Swift | Foo | +if prop1 is Foo.Bar {} +// CHECK: [[@LINE-1]]:13 | struct/Swift | Foo | +// CHECK: [[@LINE-2]]:17 | struct/Swift | Bar | + +let prop2: Int? = 1 + +if prop2 is Foo {} +// CHECK: [[@LINE-1]]:13 | struct/Swift | Foo | +if prop2 is Foo.Bar {} +// CHECK: [[@LINE-1]]:13 | struct/Swift | Foo | +// CHECK: [[@LINE-2]]:17 | struct/Swift | Bar | diff --git a/test/Interpreter/ForeignMetadata.swift b/test/Interpreter/ForeignMetadata.swift new file mode 100644 index 0000000000000..e42eb59e6ed08 --- /dev/null +++ b/test/Interpreter/ForeignMetadata.swift @@ -0,0 +1,11 @@ +// RUN: %empty-directory(%t) +// RUN: cp %s %t/main.swift +// RUN: %target-build-swift -o %t/main %S/Inputs/ForeignTypeMetadata1.swift %S/Inputs/ForeignTypeMetadata2.swift %t/main.swift -swift-version 5 +// RUN: %target-codesign %t/main +// RUN: %target-run %t/main + + +// REQUIRES: executable_test +// REQUIRES: objc_interop + +useType() diff --git a/test/Interpreter/Inputs/ForeignTypeMetadata1.swift b/test/Interpreter/Inputs/ForeignTypeMetadata1.swift new file mode 100644 index 0000000000000..5bdd0f08b3dc5 --- /dev/null +++ b/test/Interpreter/Inputs/ForeignTypeMetadata1.swift @@ -0,0 +1,12 @@ +import Foundation + +func use(_ closure: @escaping (Int) -> ()) {} + +public func captureRange(_ r: NSRange?) { + var l = r + use { + if $0 == 0 { + l = NSRange() + } + } +} diff --git a/test/Interpreter/Inputs/ForeignTypeMetadata2.swift b/test/Interpreter/Inputs/ForeignTypeMetadata2.swift new file mode 100644 index 0000000000000..386639931ac45 --- /dev/null +++ b/test/Interpreter/Inputs/ForeignTypeMetadata2.swift @@ -0,0 +1,7 @@ +import Foundation + +public func useType() { + var x = [NSRange]() + x.append(NSRange()) + print(x) +} diff --git a/test/Interpreter/dynamic_replacement_dlclose.swift b/test/Interpreter/dynamic_replacement_dlclose.swift deleted file mode 100644 index 4c9339b9cb414..0000000000000 --- a/test/Interpreter/dynamic_replacement_dlclose.swift +++ /dev/null @@ -1,72 +0,0 @@ -// RUN: %empty-directory(%t) -// RUN: %target-build-swift-dylib(%t/%target-library-name(Module1)) -DMODULE -module-name Module1 -emit-module -emit-module-path %t/Module1.swiftmodule -swift-version 5 %S/Inputs/dynamic_replacement_dlclose.swift -Xfrontend -enable-private-imports -// RUN: %target-build-swift-dylib(%t/%target-library-name(Module2)) -I%t -L%t -lModule1 %target-rpath(%t) -DMODULE2 -module-name Module2 -emit-module -emit-module-path %t/Module2.swiftmodule -swift-version 5 %S/Inputs/dynamic_replacement_dlclose2.swift -// RUN: %target-build-swift -I%t -L%t -lModule1 -DMAIN -o %t/main %target-rpath(%t) %s -swift-version 5 -// RUN: %target-codesign %t/main %t/%target-library-name(Module1) %t/%target-library-name(Module2) -// RUN: %target-run %t/main %t/%target-library-name(Module1) %t/%target-library-name(Module2) - -// REQUIRES: executable_test - -import Module1 - -import StdlibUnittest - -#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) - import Darwin -#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) - import Glibc -#elseif os(Windows) - import MSVCRT - import WinSDK -#else -#error("Unsupported platform") -#endif - -var DynamicallyReplaceable = TestSuite("DynamicallyReplaceable") - - - -private func target_library_name(_ name: String) -> String { -#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) - return "lib\(name).dylib" -#elseif os(Windows) - return "\(name).dll" -#else - return "lib\(name).so" -#endif -} - - -DynamicallyReplaceable.test("DynamicallyReplaceable") { - var executablePath = CommandLine.arguments[0] - executablePath.removeLast(4) - expectEqual(1, test()) - // Now, test with the module containing the replacements. - -#if os(Linux) - let h = dlopen(target_library_name("Module2"), RTLD_NOW) -#elseif os(Windows) - let h = LoadLibraryA(target_library_name("Module2")) -#else - let h = dlopen(executablePath+target_library_name("Module2"), RTLD_NOW) -#endif - - expectEqual(2, test()) - -#if os(Linux) -#elseif os(Windows) -#else - dlclose(h) -#endif - -#if os(Linux) - _ = dlopen(target_library_name("Module2"), RTLD_NOW) -#elseif os(Windows) -#else - _ = dlopen(executablePath+target_library_name("Module2"), RTLD_NOW) -#endif - expectEqual(2, test()) - -} - -runAllTests() diff --git a/test/Misc/Inputs/empty.swiftinterface b/test/Misc/Inputs/empty.swiftinterface new file mode 100644 index 0000000000000..0b76e7dd9f37a --- /dev/null +++ b/test/Misc/Inputs/empty.swiftinterface @@ -0,0 +1,2 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -swift-version 5 diff --git a/test/Misc/stats_dir_module_interface.swift b/test/Misc/stats_dir_module_interface.swift new file mode 100644 index 0000000000000..254d1aaf8fd78 --- /dev/null +++ b/test/Misc/stats_dir_module_interface.swift @@ -0,0 +1,6 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir %t/stats +// RUN: mkdir %t/cache +// RUN: %target-swift-frontend -typecheck %s -I %S/Inputs -stats-output-dir %t/stats -module-cache-path %t/cache + +import empty diff --git a/test/ModuleInterface/ModuleCache/SerializedSIL.swiftinterface b/test/ModuleInterface/ModuleCache/SerializedSIL.swiftinterface index fd934c5879cb2..d7dd3611b3282 100644 --- a/test/ModuleInterface/ModuleCache/SerializedSIL.swiftinterface +++ b/test/ModuleInterface/ModuleCache/SerializedSIL.swiftinterface @@ -46,7 +46,7 @@ public var readOnlyVar: Int { get } public var readWriteVar: Int { get set } public func verySimpleFunction() -// CHECK: sil [serialized] [exact_self_class] [canonical] @$s13SerializedSIL9TestClassCACycfC : $@convention(method) (@thick TestClass.Type) -> @owned TestClass { +// CHECK: sil [serialized] [exact_self_class] [canonical] [ossa] @$s13SerializedSIL9TestClassCACycfC : $@convention(method) (@thick TestClass.Type) -> @owned TestClass { // NEGATIVE-NOT: {{sil .*@.+storedProp}} diff --git a/test/ModuleInterface/static-initialize-objc-metadata-attr.swift b/test/ModuleInterface/static-initialize-objc-metadata-attr.swift new file mode 100644 index 0000000000000..f2ed55450f8e2 --- /dev/null +++ b/test/ModuleInterface/static-initialize-objc-metadata-attr.swift @@ -0,0 +1,22 @@ +// RUN: %target-swift-frontend -typecheck -emit-module-interface-path - %s -enable-library-evolution -target %target-pre-stable-abi-triple -module-name Module | %FileCheck %s +// REQUIRES: objc_interop + +import Foundation + +// To infer @_staticInitializeObjCMetadata, the following needs to be true +// Our class needs to be: +// - A subclass of a generic Objective-C class +// - That inherits a conformance to a protocol +// - Declared in a module with a deployment target before the stable ABI + +public class Super: NSObject, NSCoding { + required public init(coder: NSCoder) {} + public func encode(with: NSCoder) {} +} + +// CHECK-NOT: @_staticInitializeObjCMetadata +// CHECK: public class Sub : Module.Super +public class Sub: Super { + required public init(coder: NSCoder) {} + override public func encode(with: NSCoder) {} +} diff --git a/test/SIL/Serialization/deserialize_generic.sil b/test/SIL/Serialization/deserialize_generic.sil index 68d402784fcac..1fd291035a78f 100644 --- a/test/SIL/Serialization/deserialize_generic.sil +++ b/test/SIL/Serialization/deserialize_generic.sil @@ -22,5 +22,5 @@ bb0: } // Make sure the function body is deserialized. -// CHECK-LABEL: sil public_external [serialized] [canonical] @$s11def_generic1AC23convertFromArrayLiteralyACyxGxd_tF : $@convention(method) (@guaranteed Array, @guaranteed A) -> @owned A { +// CHECK-LABEL: sil public_external [serialized] [canonical] [ossa] @$s11def_generic1AC23convertFromArrayLiteralyACyxGxd_tF : $@convention(method) (@guaranteed Array, @guaranteed A) -> @owned A { sil @$s11def_generic1AC23convertFromArrayLiteralyACyxGxd_tF : $@convention(method) (@guaranteed Array, @guaranteed A) -> @owned A diff --git a/test/SIL/Serialization/opaque_return_type_serialize.sil b/test/SIL/Serialization/opaque_return_type_serialize.sil index 2a42e8740a058..37c589eebe77e 100644 --- a/test/SIL/Serialization/opaque_return_type_serialize.sil +++ b/test/SIL/Serialization/opaque_return_type_serialize.sil @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -disable-availability-checking -emit-module -emit-module-path %t/OpaqueReturnTypeExporter.swiftmodule -module-name OpaqueReturnTypeExporter %S/Inputs/OpaqueReturnTypeExporter.swift +// RUN: %target-swift-frontend -disable-availability-checking -enable-library-evolution -emit-module -emit-module-path %t/OpaqueReturnTypeExporter.swiftmodule -module-name OpaqueReturnTypeExporter %S/Inputs/OpaqueReturnTypeExporter.swift // RUN: %target-sil-opt -I %t %s -emit-sib -module-name test -o %t/test.sib // RUN: %target-swift-frontend -disable-availability-checking -I %t -emit-ir %t/test.sib @@ -12,7 +12,7 @@ typealias SomeButt2 = @_opaqueReturnTypeOf("$sSi24OpaqueReturnTypeExporterE8some sil @$s24OpaqueReturnTypeExporter07exportsaB0QryF : $@convention(thin) () -> @out SomeButt sil @$sSi24OpaqueReturnTypeExporterE8someButtQryF : $@convention(thin) (Int) -> @out SomeButt2 -sil @use_opaque_type : $@convention(thin) (Int) -> () { +sil [serialized] @use_opaque_type : $@convention(thin) (Int) -> () { entry(%a : $Int): %f = function_ref @$s24OpaqueReturnTypeExporter07exportsaB0QryF : $@convention(thin) () -> @out SomeButt %x = alloc_stack $SomeButt diff --git a/test/SILGen/Inputs/default_arg_other.swift b/test/SILGen/Inputs/default_arg_other.swift new file mode 100644 index 0000000000000..d45733916862c --- /dev/null +++ b/test/SILGen/Inputs/default_arg_other.swift @@ -0,0 +1,12 @@ + +public func foo(x: Int = 0) -> Int { x } + +public struct Subscript1 { + public init() { } + public subscript(x: Int = 0) -> Int { x } +} + +public struct Subscript2 { + public init() { } + public subscript(x: String = #function) -> String { x } +} diff --git a/test/SILGen/default_arg_multiple_modules.swift b/test/SILGen/default_arg_multiple_modules.swift new file mode 100644 index 0000000000000..2deff092a9457 --- /dev/null +++ b/test/SILGen/default_arg_multiple_modules.swift @@ -0,0 +1,53 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -emit-module-path=%t/default_arg_other.swiftmodule -module-name=default_arg_other %S/Inputs/default_arg_other.swift +// RUN: %target-swift-emit-silgen -module-name default_arg_multiple_modules -I %t %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime + +import default_arg_other + +// CHECK-LABEL: sil hidden [ossa] @${{.*}}test1{{.*}} +func test1() -> Int { + // CHECK: [[DEF_ARG_FN:%[0-9]+]] = function_ref @$s17default_arg_other3foo1xS2i_tFfA_ : $@convention(thin) () -> Int + // CHECK: [[DEF_ARG:%[0-9]+]] = apply [[DEF_ARG_FN]]() {{.*}} + // CHECK: [[FN:%[0-9]+]] = function_ref @$s17default_arg_other3foo1xS2i_tF : $@convention(thin) (Int) -> Int + // CHECK: [[CALL:%[0-9]+]] = apply [[FN]]([[DEF_ARG]]) {{.*}} + // CHECK: return [[CALL]] : $Int + return foo() +} + +// CHECK-LABEL: sil hidden [ossa] @${{.*}}test2{{.*}} +func test2() -> Int { + // CHECK: [[DEF_ARG_FN:%[0-9]+]] = function_ref @$s17default_arg_other10Subscript1VyS2icipfA_ : $@convention(thin) () -> Int + // CHECK: [[DEF_ARG:%[0-9]+]] = apply [[DEF_ARG_FN]]() {{.*}} + // CHECK: [[FN:%[0-9]+]] = function_ref @$s17default_arg_other10Subscript1VyS2icig : $@convention(method) (Int, Subscript1) -> Int + // CHECK: [[CALL:%[0-9]+]] = apply [[FN]]([[DEF_ARG]], {{.*}} + // CHECK: return [[CALL]] : $Int + return Subscript1()[] +} + +// CHECK-LABEL: sil hidden [ossa] @${{.*}}test3{{.*}} +func test3() -> String { + // This should not call default arg constructor + // CHECK: [[STR_LIT:%[0-9]+]] = string_literal utf8 "test3()" + // CHECK: [[DEF_ARG:%[0-9]+]] = apply %{{[0-9]+}}([[STR_LIT]], {{.*}} + // CHECK: [[FN:%[0-9]+]] = function_ref @$s17default_arg_other10Subscript2VyS2Scig : $@convention(method) (@guaranteed String, Subscript2) -> @owned String + // CHECK: [[CALL:%[0-9]+]] = apply [[FN]]([[DEF_ARG]], {{.*}} + // CHECK: return [[CALL]] : $String + return Subscript2()[] +} + +// CHECK-LABEL: sil hidden [ossa] @${{.*}}test4{{.*}} +func test4() { + // CHECK: [[DEF_ARG_FN:%[0-9]+]] = function_ref @$s17default_arg_other10Subscript1VyS2icipfA_ : $@convention(thin) () -> Int + // CHECK: [[DEF_ARG:%[0-9]+]] = apply [[DEF_ARG_FN]]() {{.*}} + // CHECK: keypath $KeyPath, (root $Subscript1; gettable_property $Int, id @$s17default_arg_other10Subscript1VyS2icig : $@convention(method) (Int, Subscript1) -> Int, getter @$s17default_arg_other10Subscript1VyS2icipACTK : $@convention(thin) (@in_guaranteed Subscript1, UnsafeRawPointer) -> @out Int, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sSiTh : $@convention(thin) (UnsafeRawPointer) -> Int, external #Subscript1.subscript) ([[DEF_ARG]]) + _ = \Subscript1.[] +} + +// CHECK-LABEL: sil hidden [ossa] @${{.*}}test5{{.*}} +func test5() { + // This should not call default arg constructor + // CHECK: [[STR_LIT:%[0-9]+]] = string_literal utf8 "test5()" + // CHECK: [[DEF_ARG:%[0-9]+]] = apply %{{[0-9]+}}([[STR_LIT]], {{.*}} + // CHECK: keypath $KeyPath, (root $Subscript2; gettable_property $String, id @$s17default_arg_other10Subscript2VyS2Scig : $@convention(method) (@guaranteed String, Subscript2) -> @owned String, getter @$s17default_arg_other10Subscript2VyS2ScipACTK : $@convention(thin) (@in_guaranteed Subscript2, UnsafeRawPointer) -> @out String, indices [%$0 : $String : $String], indices_equals @$sSSTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sSSTh : $@convention(thin) (UnsafeRawPointer) -> Int, external #Subscript2.subscript) ([[DEF_ARG]]) + _ = \Subscript2.[] +} diff --git a/test/SILGen/keypaths.swift b/test/SILGen/keypaths.swift index cfd9b5257bff7..38ea8c64e6c39 100644 --- a/test/SILGen/keypaths.swift +++ b/test/SILGen/keypaths.swift @@ -322,7 +322,54 @@ struct Subscripts { } } -// CHECK-LABEL: sil hidden [ossa] @{{.*}}10subscripts +struct SubscriptDefaults1 { + subscript(x: Int = 0) -> Int { + get { fatalError() } + set { fatalError() } + } + subscript(x: Int, y: Int, z: Int = 0) -> Int { + get { fatalError() } + set { fatalError() } + } + subscript(x: Bool, bool y: Bool = false) -> Bool { + get { fatalError() } + set { fatalError() } + } + subscript(bool x: Bool, y: Int, z: Int = 0) -> Int { + get { fatalError() } + set { fatalError() } + } +} + +struct SubscriptDefaults2 { + subscript(x: Int? = nil) -> Int { + get { fatalError() } + set { fatalError() } + } +} + +struct SubscriptDefaults3 { + subscript(x: Int = #line) -> Int { + get { fatalError() } + set { fatalError() } + } +} + +struct SubscriptDefaults4 { + subscript(x x: T, y y: T = 0) -> T { + get { fatalError() } + set { fatalError() } + } +} + +struct SubscriptDefaults5 { + subscript(x x: T, y y: T = #function) -> T { + get { fatalError() } + set { fatalError() } + } +} + +// CHECK-LABEL: sil hidden [ossa] @{{.*}}10subscripts1x1y1syx_q_SStSHRzSHR_r0_lF func subscripts(x: T, y: U, s: String) { _ = \Subscripts.[] _ = \Subscripts.[generic: x] @@ -352,6 +399,57 @@ func subscripts(x: T, y: U, s: String) { _ = \Subscripts.[Bass()] _ = \Subscripts.[Treble()] + + _ = \SubscriptDefaults1.[] + _ = \SubscriptDefaults1.[0] + _ = \SubscriptDefaults1.[0, 0] + _ = \SubscriptDefaults1.[0, 0, 0] + _ = \SubscriptDefaults1.[false] + _ = \SubscriptDefaults1.[false, bool: false] + _ = \SubscriptDefaults1.[bool: false, 0] + _ = \SubscriptDefaults1.[bool: false, 0, 0] + + _ = \SubscriptDefaults2.[] + _ = \SubscriptDefaults2.[0] + _ = \SubscriptDefaults3.[] + _ = \SubscriptDefaults3.[0] + _ = \SubscriptDefaults4.[x: 0] + _ = \SubscriptDefaults4.[x: 0, y: 0] + _ = \SubscriptDefaults5.[x: ""] + _ = \SubscriptDefaults5.[x: "", y: ""] +} + +// CHECK-LABEL: sil hidden [ossa] @{{.*}}check_default_subscripts +func check_default_subscripts() { + // CHECK: [[INTX:%[0-9]+]] = integer_literal $Builtin.IntLiteral, 0 + // CHECK: [[IX:%[0-9]+]] = apply %{{[0-9]+}}([[INTX]], {{.*}} + // CHECK: [[INTY:%[0-9]+]] = integer_literal $Builtin.IntLiteral, 0 + // CHECK: [[IY:%[0-9]+]] = apply %{{[0-9]+}}([[INTY]], {{.*}} + // CHECK: [[KEYPATH:%[0-9]+]] = keypath $WritableKeyPath, (root $SubscriptDefaults4; settable_property $Int, id @$s8keypaths18SubscriptDefaults4V1x1yxx_xtcSjRzluig : $@convention(method) <τ_0_0 where τ_0_0 : Numeric> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0, SubscriptDefaults4) -> @out τ_0_0, getter @$s8keypaths18SubscriptDefaults4V1x1yxx_xtcSjRzluipACSiTK : $@convention(thin) (@in_guaranteed SubscriptDefaults4, UnsafeRawPointer) -> @out Int, setter @$s8keypaths18SubscriptDefaults4V1x1yxx_xtcSjRzluipACSiTk : $@convention(thin) (@in_guaranteed Int, @inout SubscriptDefaults4, UnsafeRawPointer) -> (), indices [%$0 : $Int : $Int, %$1 : $Int : $Int], indices_equals @$sS2iTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sS2iTh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[IX]], [[IY]]) + _ = \SubscriptDefaults4.[x: 0, y: 0] + + // CHECK: [[INTINIT:%[0-9]+]] = integer_literal $Builtin.IntLiteral, 0 + // CHECK: [[I:%[0-9]+]] = apply %{{[0-9]+}}([[INTINIT]], {{.*}} + // CHECK: [[DFN:%[0-9]+]] = function_ref @$s8keypaths18SubscriptDefaults4V1x1yxx_xtcSjRzluipfA0_ : $@convention(thin) <τ_0_0 where τ_0_0 : Numeric> () -> @out τ_0_0 + // CHECK: [[ALLOC:%[0-9]+]] = alloc_stack $Int + // CHECK: apply [[DFN]]([[ALLOC]]) : $@convention(thin) <τ_0_0 where τ_0_0 : Numeric> () -> @out τ_0_0 + // CHECK: [[LOAD:%[0-9]+]] = load [trivial] [[ALLOC]] : $*Int + // CHECK: [[KEYPATH:%[0-9]+]] = keypath $WritableKeyPath, (root $SubscriptDefaults4; settable_property $Int, id @$s8keypaths18SubscriptDefaults4V1x1yxx_xtcSjRzluig : $@convention(method) <τ_0_0 where τ_0_0 : Numeric> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0, SubscriptDefaults4) -> @out τ_0_0, getter @$s8keypaths18SubscriptDefaults4V1x1yxx_xtcSjRzluipACSiTK : $@convention(thin) (@in_guaranteed SubscriptDefaults4, UnsafeRawPointer) -> @out Int, setter @$s8keypaths18SubscriptDefaults4V1x1yxx_xtcSjRzluipACSiTk : $@convention(thin) (@in_guaranteed Int, @inout SubscriptDefaults4, UnsafeRawPointer) -> (), indices [%$0 : $Int : $Int, %$1 : $Int : $Int], indices_equals @$sS2iTH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sS2iTh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[I]], [[LOAD]]) + _ = \SubscriptDefaults4.[x: 0] + + // CHECK: [[STRX_LIT:%[0-9]+]] = string_literal utf8 "" + // CHECK: [[STRX:%[0-9]+]] = apply %{{[0-9]+}}([[STRX_LIT]], {{.*}} + // CHECK: [[STRY_LIT:%[0-9]+]] = string_literal utf8 "check_default_subscripts()" + // CHECK: [[DEF_ARG:%[0-9]+]] = apply %{{[0-9]+}}([[STRY_LIT]], {{.*}} + // CHECK: keypath $WritableKeyPath, (root $SubscriptDefaults5; settable_property $String, id @$s8keypaths18SubscriptDefaults5V1x1yxx_xtcs26ExpressibleByStringLiteralRzluig : $@convention(method) <τ_0_0 where τ_0_0 : ExpressibleByStringLiteral> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0, SubscriptDefaults5) -> @out τ_0_0, getter @$s8keypaths18SubscriptDefaults5V1x1yxx_xtcs26ExpressibleByStringLiteralRzluipACSSTK : $@convention(thin) (@in_guaranteed SubscriptDefaults5, UnsafeRawPointer) -> @out String, setter @$s8keypaths18SubscriptDefaults5V1x1yxx_xtcs26ExpressibleByStringLiteralRzluipACSSTk : $@convention(thin) (@in_guaranteed String, @inout SubscriptDefaults5, UnsafeRawPointer) -> (), indices [%$0 : $String : $String, %$1 : $String : $String], indices_equals @$sS2STH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sS2STh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[STRX]], [[DEF_ARG]]) + _ = \SubscriptDefaults5.[x: ""] + + // CHECK: [[STRX_LIT:%[0-9]+]] = string_literal utf8 "" + // CHECK: [[STRX:%[0-9]+]] = apply %{{[0-9]+}}([[STRX_LIT]], {{.*}} + // CHECK: [[STRY_LIT:%[0-9]+]] = string_literal utf8 "" + // CHECK: [[STRY:%[0-9]+]] = apply %{{[0-9]+}}([[STRY_LIT]], {{.*}} + // CHECK: keypath $WritableKeyPath, (root $SubscriptDefaults5; settable_property $String, id @$s8keypaths18SubscriptDefaults5V1x1yxx_xtcs26ExpressibleByStringLiteralRzluig : $@convention(method) <τ_0_0 where τ_0_0 : ExpressibleByStringLiteral> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0, SubscriptDefaults5) -> @out τ_0_0, getter @$s8keypaths18SubscriptDefaults5V1x1yxx_xtcs26ExpressibleByStringLiteralRzluipACSSTK : $@convention(thin) (@in_guaranteed SubscriptDefaults5, UnsafeRawPointer) -> @out String, setter @$s8keypaths18SubscriptDefaults5V1x1yxx_xtcs26ExpressibleByStringLiteralRzluipACSSTk : $@convention(thin) (@in_guaranteed String, @inout SubscriptDefaults5, UnsafeRawPointer) -> (), indices [%$0 : $String : $String, %$1 : $String : $String], indices_equals @$sS2STH : $@convention(thin) (UnsafeRawPointer, UnsafeRawPointer) -> Bool, indices_hash @$sS2STh : $@convention(thin) (UnsafeRawPointer) -> Int) ([[STRX]], [[STRY]]) + _ = \SubscriptDefaults5.[x: "", y: ""] } // CHECK-LABEL: sil hidden [ossa] @{{.*}}subclass_generics diff --git a/test/SILGen/opaque_result_type.swift b/test/SILGen/opaque_result_type.swift index 50ae18fc37105..eacbd6204ab5f 100644 --- a/test/SILGen/opaque_result_type.swift +++ b/test/SILGen/opaque_result_type.swift @@ -1,4 +1,8 @@ -// RUN: %target-swift-frontend -disable-availability-checking -emit-silgen %s | %FileCheck %s +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift +// RUN: %target-swift-frontend -I %t -disable-availability-checking -emit-silgen %s | %FileCheck %s + +import resilient_struct protocol P {} protocol Q: AnyObject {} @@ -10,39 +14,138 @@ class C: Q {} // CHECK-LABEL: sil hidden {{.*}}11valueToAddr1xQr func valueToAddr(x: String) -> some P { - // CHECK: [[UNDERLYING:%.*]] = unchecked_addr_cast %0 - // CHECK: [[VALUE_COPY:%.*]] = copy_value %1 - // CHECK: store [[VALUE_COPY]] to [init] [[UNDERLYING]] + // CHECK: bb0([[ARG0:%.*]] : $*String, [[ARG1:%.*]] : @guaranteed $String): + // CHECK: [[VALUE_COPY:%.*]] = copy_value [[ARG1]] + // CHECK: store [[VALUE_COPY]] to [init] [[ARG0]] return x } // CHECK-LABEL: sil hidden {{.*}}10addrToAddr1xQr func addrToAddr(x: AddrOnly) -> some P { - // CHECK: [[UNDERLYING:%.*]] = unchecked_addr_cast %0 - // CHECK: copy_addr %1 to [initialization] [[UNDERLYING]] + // CHECK: bb0([[ARG0:%.*]] : $*AddrOnly, [[ARG1:%.*]] : $*AddrOnly): + // CHECK: copy_addr [[ARG1]] to [initialization] [[ARG0]] return x } // CHECK-LABEL: sil hidden {{.*}}13genericAddrToE01xQr func genericAddrToAddr(x: T) -> some P { - // CHECK: [[UNDERLYING:%.*]] = unchecked_addr_cast %0 - // CHECK: copy_addr %1 to [initialization] [[UNDERLYING]] + // CHECK: bb0([[ARG0:%.*]] : $*T, [[ARG1:%.*]] : $*T): + // CHECK: copy_addr [[ARG1]] to [initialization] [[ARG0]] return x } // CHECK-LABEL: sil hidden {{.*}}12valueToValue1xQr func valueToValue(x: C) -> some Q { - // CHECK: [[VALUE_COPY:%.*]] = copy_value %0 - // CHECK: [[CAST_TO_OPAQUE:%.*]] = unchecked_ref_cast [[VALUE_COPY]] - // CHECK: return [[CAST_TO_OPAQUE]] + // CHECK: bb0([[ARG:%.*]] : @guaranteed $C): + // CHECK: [[VALUE_COPY:%.*]] = copy_value [[ARG]] + // CHECK: return [[VALUE_COPY]] return x } // CHECK-LABEL: sil hidden {{.*}}13reabstraction1xQr func reabstraction(x: @escaping () -> ()) -> some Any { - // CHECK: [[UNDERLYING:%.*]] = unchecked_addr_cast %0 : ${{.*}} to $*@callee_guaranteed () -> @out () - // CHECK: [[VALUE_COPY:%.*]] = copy_value %1 - // CHECK: [[VALUE_REABSTRACT:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[VALUE_COPY]]) - // CHECK: store [[VALUE_REABSTRACT]] to [init] [[UNDERLYING]] + // CHECK: bb0([[ARG0:%.*]] : $*@callee_guaranteed () -> @out (), [[ARG1:%.*]] : @guaranteed $@callee_guaranteed () -> ()): + // CHECK: [[VALUE_COPY:%.*]] = copy_value [[ARG1]] + // CHECK: [[REABSTRACT:%.*]] = function_ref @$sIeg_ytIegr_TR + // CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACT]]([[VALUE_COPY]]) + // CHECK: store [[THUNK]] to [init] [[ARG0]] return x } + +protocol X { + associatedtype A + func foo() -> A +} + +extension Int : P {} + +extension ResilientInt : P {} + +class K : P {} + +func useClosure2(_ cl: () -> ()) {} + +func useClosure(_ cl: @escaping () -> ()) { + cl() +} + +struct S : X { + + func foo() -> some P { + return returnTrivial() + } + + func returnTrivial() -> some P { + return 1 + } + + func returnClass() -> some P { + return K() + } + + func returnResilient() -> some P { + return ResilientInt(i: 1) + } + + func testCapture() { + var someP = returnTrivial() + var someK = returnClass() + var someR = returnResilient() + useClosure { + someP = self.returnTrivial() + someK = self.returnClass() + someR = self.returnResilient() + } + print(someP) + print(someK) + print(someR) + } + + func testCapture2() { + var someP = returnTrivial() + var someK = returnClass() + var someR = returnResilient() + useClosure2 { + someP = self.returnTrivial() + someK = self.returnClass() + someR = self.returnResilient() + } + print(someP) + print(someK) + print(someR) + } + + func testCapture3() { + let someP = returnTrivial() + let someK = returnClass() + let someR = returnResilient() + useClosure { + print(someP) + print(someK) + print(someR) + } + } + + func testCapture4() { + let someP = returnTrivial() + let someK = returnClass() + let someR = returnResilient() + useClosure { + print(someP) + print(someK) + print(someR) + } + } +} + +extension Optional : P { } + +struct S2 : X { + func foo() -> some P { + let x : Optional = 1 + return x + } + func returnFunctionType() -> () -> A { + return foo + } +} diff --git a/test/SILOptimizer/OSLogPrototypeCompileTest.sil b/test/SILOptimizer/OSLogPrototypeCompileTest.sil index cce273c92e101..3193ce9c5cd8c 100644 --- a/test/SILOptimizer/OSLogPrototypeCompileTest.sil +++ b/test/SILOptimizer/OSLogPrototypeCompileTest.sil @@ -59,7 +59,8 @@ bb0: return %13 : $() // CHECK-NOT: {{%.*}} = struct_extract {{%.*}} : $OSLogInterpolationStub, #OSLogInterpolationStub.formatString // CHECK-DAG: [[STRINGUSE:%[0-9]+]] = function_ref @useFormatString - // CHECK-DAG: {{%.*}} = apply [[STRINGUSE]]([[STRINGCONST:%[0-9]+]]) + // CHECK-DAG: {{%.*}} = apply [[STRINGUSE]]([[BORROW:%[0-9]+]]) + // CHECK-DAG: [[BORROW]] = begin_borrow [[STRINGCONST:%[0-9]+]] // CHECK-DAG: [[STRINGCONST]] = apply [[STRINGINIT:%[0-9]+]]([[LIT:%[0-9]+]], {{%.*}}, {{%.*}}, {{%.*}}) // CHECK-DAG: [[STRINGINIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC // CHECK-DAG: [[LIT]] = string_literal utf8 "test message: %lld" @@ -175,7 +176,8 @@ bb0: // CHECK-DAG: [[STRINGUSE:%[0-9]+]] = function_ref @useFormatString // CHECK-DAG: {{%.*}} = apply [[STRINGUSE]]([[BORROW:%[0-9]+]]) // CHECK-DAG: [[BORROW]] = begin_borrow [[COPYVAL:%[0-9]+]] - // CHECK-DAG: [[COPYVAL]] = copy_value [[STRINGCONST:%[0-9]+]] + // CHECK-DAG: [[COPYVAL]] = copy_value [[BORROW2:%[0-9]+]] + // CHECK-DAG: [[BORROW2]] = begin_borrow [[STRINGCONST:%[0-9]+]] // CHECK-DAG: [[STRINGCONST]] = apply [[STRINGINIT:%[0-9]+]]([[LIT:%[0-9]+]], {{%.*}}, {{%.*}}, {{%.*}}) // CHECK-DAG: [[STRINGINIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC // CHECK-DAG: [[LIT]] = string_literal utf8 "test message: %lld" @@ -278,7 +280,7 @@ bb1: cond_br %2, bb2, bb3 // Check release of the folded value of %15. // CHECK-LABEL: bb1: - // CHECK-NEXT: destroy_value [[STRINGCONST1:%[0-9]+]] : $String + // CHECK: destroy_value [[STRINGCONST1:%[0-9]+]] : $String bb2: %12 = apply %9(%11) : $@convention(thin) (@guaranteed String) -> () @@ -396,10 +398,590 @@ bb0: return %17 : $() // CHECK-DAG: [[STRINGUSE:%[0-9]+]] = function_ref @useFormatString // CHECK-DAG: {{%.*}} = apply [[STRINGUSE]]([[CONSTCOPY:%[0-9]+]]) - // CHECK-DAG: [[CONSTCOPY]] = copy_value [[STRINGCONST:%[0-9]+]] + // CHECK-DAG: [[CONSTCOPY]] = copy_value [[BORROW:%[0-9]+]] + // CHECK-DAG: [[BORROW]] = begin_borrow [[STRINGCONST:%[0-9]+]] // CHECK-DAG: [[STRINGCONST]] = apply [[STRINGINIT:%[0-9]+]]([[LIT:%[0-9]+]], {{%.*}}, {{%.*}}, {{%.*}}) // CHECK-DAG: [[STRINGINIT]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC // CHECK-DAG: [[LIT]] = string_literal utf8 "test message: %lld" // CHECK-DAG: destroy_value [[STRINGCONST]] : $String } +// Check folding of arrays by the OSLogOptimization pass. + +/// A simplified stub for OSLogInterpolation type for testing array folding. +struct OSLogInterpolationArrayStub { + var arguments: [Int64] +} + +/// A simplified stub for OSLogMessage for testing array folding. +struct OSLogMessageArrayStub { + var interpolation: OSLogInterpolationArrayStub +} + +/// A stub for OSLogMessage.init. The optimization is driven by this function. +/// This function must take at least one argument which is required by the pass. +sil [Onone] [_semantics "constant_evaluable"] [_semantics "oslog.message.init_stub"] @oslogMessageArrayStubInit : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageArrayStub { +bb0(%0 : $Builtin.Int1): + // Create an array with elements 99, 98 and 90 + %1 = integer_literal $Builtin.Word, 3 + // function_ref _allocateUninitializedArray(_:) + %2 = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) + %3 = apply %2(%1) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) + %4 = tuple_extract %3 : $(Array, Builtin.RawPointer), 0 + %5 = tuple_extract %3 : $(Array, Builtin.RawPointer), 1 + %6 = pointer_to_address %5 : $Builtin.RawPointer to [strict] $*Int64 + %7 = integer_literal $Builtin.Int64, 99 + %8 = struct $Int64 (%7 : $Builtin.Int64) + store %8 to %6 : $*Int64 + %10 = integer_literal $Builtin.Word, 1 + %11 = index_addr %6 : $*Int64, %10 : $Builtin.Word + %12 = integer_literal $Builtin.Int64, 98 + %13 = struct $Int64 (%12 : $Builtin.Int64) + store %13 to %11 : $*Int64 + %15 = integer_literal $Builtin.Word, 2 + %16 = index_addr %6 : $*Int64, %15 : $Builtin.Word + %17 = integer_literal $Builtin.Int64, 90 + %18 = struct $Int64 (%17 : $Builtin.Int64) + store %18 to %16 : $*Int64 + + // Create an instance of OSLogMessageArrayStub using the above array. + %20 = struct $OSLogInterpolationArrayStub(%4 : $Array) + %21 = struct $OSLogMessageArrayStub(%20 : $OSLogInterpolationArrayStub) + return %21 : $OSLogMessageArrayStub +} + +// _allocateUninitializedArray(_:) +sil [serialized] [always_inline] [_semantics "array.uninitialized_intrinsic"] @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) + +/// A function that models the use of an array. +sil @useArray: $@convention(thin) (@guaranteed Array) -> () + +// CHECK-LABEL: @testConstantFoldingOfArray +sil [ossa] @testConstantFoldingOfArray : $@convention(thin) () -> () { +bb0: + // Construct an OSLogMessageArrayStub instance. + %0 = integer_literal $Builtin.Int1, 1 + %1 = function_ref @oslogMessageArrayStubInit : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageArrayStub + %2 = apply %1(%0) : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageArrayStub + + // Use the arguments property of OSLogMessageArrayStub which will be constant + // folded by the OSLogOptimization pass, as checked below. + %3 = begin_borrow %2 : $OSLogMessageArrayStub + %4 = struct_extract %3 : $OSLogMessageArrayStub, #OSLogMessageArrayStub.interpolation + %5 = struct_extract %4 : $OSLogInterpolationArrayStub, #OSLogInterpolationArrayStub.arguments + %6 = function_ref @useArray : $@convention(thin) (@guaranteed Array) -> () + %7 = apply %6(%5) : $@convention(thin) (@guaranteed Array) -> () + end_borrow %3 : $OSLogMessageArrayStub + destroy_value %2 : $OSLogMessageArrayStub + %8 = tuple () + return %8 : $() + // CHECK: [[ELEM1:%[0-9]+]] = integer_literal $Builtin.Int64, 99 + // CHECK: [[ELEM1INT:%[0-9]+]] = struct $Int64 ([[ELEM1]] : $Builtin.Int64) + // CHECK: [[ELEM2:%[0-9]+]] = integer_literal $Builtin.Int64, 98 + // CHECK: [[ELEM2INT:%[0-9]+]] = struct $Int64 ([[ELEM2]] : $Builtin.Int64) + // CHECK: [[ELEM3:%[0-9]+]] = integer_literal $Builtin.Int64, 90 + // CHECK: [[ELEM3INT:%[0-9]+]] = struct $Int64 ([[ELEM3]] : $Builtin.Int64) + // CHECK: [[NUMELEMS:%[0-9]+]] = integer_literal $Builtin.Word, 3 + // CHECK: [[ALLOCATORREF:%[0-9]+]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK: [[TUPLE:%[0-9]+]] = apply [[ALLOCATORREF]]([[NUMELEMS]]) + // CHECK: ([[ARRAY:%[0-9]+]], [[STORAGEPTR:%[0-9]+]]) = destructure_tuple [[TUPLE]] + // CHECK: [[BORROW:%[0-9]+]] = begin_borrow [[ARRAY]] + // CHECK: [[STORAGEADDR:%[0-9]+]] = pointer_to_address [[STORAGEPTR]] : $Builtin.RawPointer to [strict] $*Int64 + // CHECK: store [[ELEM1INT]] to [trivial] [[STORAGEADDR]] : $*Int64 + // CHECK: [[INDEX1:%[0-9]+]] = integer_literal $Builtin.Word, 1 + // CHECK: [[INDEXADDR1:%[0-9]+]] = index_addr [[STORAGEADDR]] : $*Int64, [[INDEX1]] : $Builtin.Word + // CHECK: store [[ELEM2INT]] to [trivial] [[INDEXADDR1]] : $*Int64 + // CHECK: [[INDEX2:%[0-9]+]] = integer_literal $Builtin.Word, 2 + // CHECK: [[INDEXADDR2:%[0-9]+]] = index_addr [[STORAGEADDR]] : $*Int64, [[INDEX2]] : $Builtin.Word + // CHECK: store [[ELEM3INT]] to [trivial] [[INDEXADDR2]] : $*Int64 + // CHECK: [[USEREF:%[0-9]+]] = function_ref @useArray + // CHECK: apply [[USEREF]]([[BORROW]]) + // CHECK: end_borrow [[BORROW]] + // CHECK: destroy_value [[ARRAY]] : $Array +} + +// CHECK-LABEL: @testConstantFoldingOfArrayNonOSSA +sil @testConstantFoldingOfArrayNonOSSA : $@convention(thin) () -> () { +bb0: + // Construct an OSLogMessageArrayStub instance. + %0 = integer_literal $Builtin.Int1, 1 + %1 = function_ref @oslogMessageArrayStubInit : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageArrayStub + %2 = apply %1(%0) : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageArrayStub + + // Use the arguments property of OSLogMessageArrayStub which will be constant + // folded by the OSLogOptimization pass, as checked below. + %4 = struct_extract %2 : $OSLogMessageArrayStub, #OSLogMessageArrayStub.interpolation + %5 = struct_extract %4 : $OSLogInterpolationArrayStub, #OSLogInterpolationArrayStub.arguments + %6 = function_ref @useArray : $@convention(thin) (@guaranteed Array) -> () + %7 = apply %6(%5) : $@convention(thin) (@guaranteed Array) -> () + release_value %2 : $OSLogMessageArrayStub + %8 = tuple () + return %8 : $() + // CHECK: [[ELEM1:%[0-9]+]] = integer_literal $Builtin.Int64, 99 + // CHECK: [[ELEM1INT:%[0-9]+]] = struct $Int64 ([[ELEM1]] : $Builtin.Int64) + // CHECK: [[ELEM2:%[0-9]+]] = integer_literal $Builtin.Int64, 98 + // CHECK: [[ELEM2INT:%[0-9]+]] = struct $Int64 ([[ELEM2]] : $Builtin.Int64) + // CHECK: [[ELEM3:%[0-9]+]] = integer_literal $Builtin.Int64, 90 + // CHECK: [[ELEM3INT:%[0-9]+]] = struct $Int64 ([[ELEM3]] : $Builtin.Int64) + // CHECK: [[NUMELEMS:%[0-9]+]] = integer_literal $Builtin.Word, 3 + // CHECK: [[ALLOCATORREF:%[0-9]+]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK: [[TUPLE:%[0-9]+]] = apply [[ALLOCATORREF]]([[NUMELEMS]]) + // CHECK: [[ARRAY:%[0-9]+]] = tuple_extract [[TUPLE]] : $(Array, Builtin.RawPointer), 0 + // CHECK: [[STORAGEPTR:%[0-9]+]] = tuple_extract [[TUPLE]] : $(Array, Builtin.RawPointer), 1 + // CHECK: [[STORAGEADDR:%[0-9]+]] = pointer_to_address [[STORAGEPTR]] : $Builtin.RawPointer to [strict] $*Int64 + // CHECK: store [[ELEM1INT]] to [[STORAGEADDR]] : $*Int64 + // CHECK: [[INDEX1:%[0-9]+]] = integer_literal $Builtin.Word, 1 + // CHECK: [[INDEXADDR1:%[0-9]+]] = index_addr [[STORAGEADDR]] : $*Int64, [[INDEX1]] : $Builtin.Word + // CHECK: store [[ELEM2INT]] to [[INDEXADDR1]] : $*Int64 + // CHECK: [[INDEX2:%[0-9]+]] = integer_literal $Builtin.Word, 2 + // CHECK: [[INDEXADDR2:%[0-9]+]] = index_addr [[STORAGEADDR]] : $*Int64, [[INDEX2]] : $Builtin.Word + // CHECK: store [[ELEM3INT]] to [[INDEXADDR2]] : $*Int64 + // CHECK: [[USEREF:%[0-9]+]] = function_ref @useArray + // CHECK: apply [[USEREF]]([[ARRAY]]) + // CHECK: release_value [[ARRAY]] : $Array +} + +/// A stub for OSLogMessage.init. The optimization is driven by this function. +/// This function must take at least one argument which is required by the pass. +sil [Onone] [_semantics "constant_evaluable"] [_semantics "oslog.message.init_stub"] @oslogMessageStubEmptyArrayInit : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageArrayStub { +bb0(%0 : $Builtin.Int1): + // Create an empty array + %1 = integer_literal $Builtin.Word, 0 + // function_ref _allocateUninitializedArray(_:) + %2 = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) + %3 = apply %2(%1) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) + %4 = tuple_extract %3 : $(Array, Builtin.RawPointer), 0 + + // Create an instance of OSLogMessageArrayStub using the above array. + %20 = struct $OSLogInterpolationArrayStub(%4 : $Array) + %21 = struct $OSLogMessageArrayStub(%20 : $OSLogInterpolationArrayStub) + return %21 : $OSLogMessageArrayStub +} + +// CHECK-LABEL: @testConstantFoldingOfEmptyArray +sil [ossa] @testConstantFoldingOfEmptyArray : $@convention(thin) () -> () { +bb0: + // Construct an OSLogMessageArrayStub instance. + %0 = integer_literal $Builtin.Int1, 1 + %1 = function_ref @oslogMessageStubEmptyArrayInit : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageArrayStub + %2 = apply %1(%0) : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageArrayStub + + // Use the arguments property of OSLogMessageArrayStub which will be constant + // folded by the OSLogOptimization pass, as checked below. + %3 = begin_borrow %2 : $OSLogMessageArrayStub + %4 = struct_extract %3 : $OSLogMessageArrayStub, #OSLogMessageArrayStub.interpolation + %5 = struct_extract %4 : $OSLogInterpolationArrayStub, #OSLogInterpolationArrayStub.arguments + %6 = function_ref @useArray : $@convention(thin) (@guaranteed Array) -> () + %7 = apply %6(%5) : $@convention(thin) (@guaranteed Array) -> () + end_borrow %3 : $OSLogMessageArrayStub + destroy_value %2 : $OSLogMessageArrayStub + %8 = tuple () + return %8 : $() + // CHECK: [[NUMELEMS:%[0-9]+]] = integer_literal $Builtin.Word, 0 + // CHECK: [[ALLOCATORREF:%[0-9]+]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK: [[TUPLE:%[0-9]+]] = apply [[ALLOCATORREF]]([[NUMELEMS]]) + // CHECK: ([[ARRAY:%[0-9]+]], [[STORAGEPTR:%[0-9]+]]) = destructure_tuple [[TUPLE]] + // CHECK: [[BORROW:%[0-9]+]] = begin_borrow [[ARRAY]] + // CHECK: [[USEREF:%[0-9]+]] = function_ref @useArray + // CHECK: apply [[USEREF]]([[BORROW]]) + // CHECK: end_borrow [[BORROW]] + // CHECK: destroy_value [[ARRAY]] : $Array +} + +/// A simplified stub for OSLogInterpolation type for testing folding of array +/// of strings. +struct OSLogInterpolationStringArrayStub { + var arguments: [String] +} + +/// A simplified stub for OSLogMessage for testing folding of array of strings. +struct OSLogMessageStringArrayStub { + var interpolation: OSLogInterpolationStringArrayStub +} + +/// A stub for OSLogMessage.init. The os_log optimization is driven by this +/// function. This function must take at least one argument which is required +/// by the pass. +sil [Onone] [_semantics "constant_evaluable"] [_semantics "oslog.message.init_stub"] @oslogMessageStringArrayStubInit : $@convention(thin) (@owned String) -> @owned OSLogMessageStringArrayStub { +bb0(%0 : $String): + // Create an array with one element "a" + %1 = integer_literal $Builtin.Word, 1 + // function_ref _allocateUninitializedArray(_:) + %2 = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) + %3 = apply %2(%1) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) + %4 = tuple_extract %3 : $(Array, Builtin.RawPointer), 0 + %5 = tuple_extract %3 : $(Array, Builtin.RawPointer), 1 + %6 = pointer_to_address %5 : $Builtin.RawPointer to [strict] $*String + store %0 to %6 : $*String + + // Create an instance of OSLogMessageArrayStub using the above array. + %20 = struct $OSLogInterpolationStringArrayStub(%4 : $Array) + %21 = struct $OSLogMessageStringArrayStub(%20 : $OSLogInterpolationStringArrayStub) + return %21 : $OSLogMessageStringArrayStub +} + +/// A function that models the use of an array. +sil @useArrayString: $@convention(thin) (@guaranteed Array) -> () + +// CHECK-LABEL: @testConstantFoldingOfStringArray +sil [ossa] @testConstantFoldingOfStringArray : $@convention(thin) () -> () { +bb0: + // Construct an OSLogMessageStringArrayStub instance. + %10 = string_literal utf8 "ab" + %11 = integer_literal $Builtin.Word, 2 + %12 = integer_literal $Builtin.Int1, -1 + %13 = metatype $@thin String.Type + // function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:) + %14 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String + %15 = apply %14(%10, %11, %12, %13) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String + %1 = function_ref @oslogMessageStringArrayStubInit : $@convention(thin) (@owned String) -> @owned OSLogMessageStringArrayStub + %2 = apply %1(%15) : $@convention(thin) (@owned String) -> @owned OSLogMessageStringArrayStub + + // Use the arguments property of OSLogMessageStringArrayStub which will be constant + // folded by the OSLogOptimization pass, as checked below. + %3 = begin_borrow %2 : $OSLogMessageStringArrayStub + %4 = struct_extract %3 : $OSLogMessageStringArrayStub, #OSLogMessageStringArrayStub.interpolation + %5 = struct_extract %4 : $OSLogInterpolationStringArrayStub, #OSLogInterpolationStringArrayStub.arguments + %6 = function_ref @useArrayString : $@convention(thin) (@guaranteed Array) -> () + %7 = apply %6(%5) : $@convention(thin) (@guaranteed Array) -> () + end_borrow %3 : $OSLogMessageStringArrayStub + destroy_value %2 : $OSLogMessageStringArrayStub + %8 = tuple () + return %8 : $() + // Skip the first instance of "ab". + // CHECK: [[LIT:%[0-9]+]] = string_literal utf8 "ab" + // CHECK: [[LIT:%[0-9]+]] = string_literal utf8 "ab" + // CHECK: [[STRINGINIT:%[0-9]+]] = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC + // CHECK: [[STRINGCONST:%[0-9]+]] = apply [[STRINGINIT]]([[LIT]], {{%.*}}, {{%.*}}, {{%.*}}) + // CHECK: [[NUMELEMS:%[0-9]+]] = integer_literal $Builtin.Word, 1 + // CHECK: [[ALLOCATORREF:%[0-9]+]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK: [[TUPLE:%[0-9]+]] = apply [[ALLOCATORREF]]([[NUMELEMS]]) + // CHECK: ([[ARRAY:%[0-9]+]], [[STORAGEPTR:%[0-9]+]]) = destructure_tuple [[TUPLE]] + // CHECK: [[BORROW:%[0-9]+]] = begin_borrow [[ARRAY]] + // CHECK: [[STORAGEADDR:%[0-9]+]] = pointer_to_address [[STORAGEPTR]] : $Builtin.RawPointer to [strict] $*String + // CHECK: store [[STRINGCONST]] to [init] [[STORAGEADDR]] : $*String + // CHECK: [[USEREF:%[0-9]+]] = function_ref @useArrayString + // CHECK: apply [[USEREF]]([[BORROW]]) + // CHECK: end_borrow [[BORROW]] + // CHECK: destroy_value [[ARRAY]] : $Array +} + +sil [ossa] [Onone] [_semantics "constant_evaluable"] [_semantics "oslog.message.init_stub"] @oslogMessageArrayInterpolationInit : $@convention(thin) (@owned OSLogInterpolationArrayStub) + -> @owned OSLogMessageArrayStub { +bb0(%0 : @owned $OSLogInterpolationArrayStub): + %1 = struct $OSLogMessageArrayStub(%0 : $OSLogInterpolationArrayStub) + return %1 : $OSLogMessageArrayStub +} + +// CHECK-LABEL: @testNoFoldingOfArrayLiterals +sil [ossa] @testNoFoldingOfArrayLiterals : $@convention(thin) () -> () { +bb0: + // Create an empty array + %1 = integer_literal $Builtin.Word, 0 + // function_ref _allocateUninitializedArray(_:) + %2 = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) + %3 = apply %2(%1) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) + (%4, %ignore) = destructure_tuple %3 : $(Array, Builtin.RawPointer) + %5 = copy_value %4 : $Array + %6 = struct $OSLogInterpolationArrayStub(%4 : $Array) + %7 = function_ref @oslogMessageArrayInterpolationInit : $@convention(thin) (@owned OSLogInterpolationArrayStub) -> @owned OSLogMessageArrayStub + %8 = apply %7(%6) : $@convention(thin) (@owned OSLogInterpolationArrayStub) -> @owned OSLogMessageArrayStub + // Use the array literal. + %9 = function_ref @useArray : $@convention(thin) (@guaranteed Array) -> () + %10 = apply %9(%5) : $@convention(thin) (@guaranteed Array) -> () + destroy_value %5 : $Array + destroy_value %8 : $OSLogMessageArrayStub + %11 = tuple () + return %11 : $() + // There should be only one instance of _allocateUninitializedArray + // CHECK-LABEL: function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-NOT: function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF +} + +// Check folding of closures by the OSLogOptimization pass. + +/// A simplified stub for OSLogInterpolation type for testing closure folding. +struct OSLogInterpolationClosureStub { + var closure: () -> Int32 +} + +/// A simplified stub for OSLogMessage for testing closure folding. +struct OSLogMessageClosureStub { + var interpolation: OSLogInterpolationClosureStub +} + +sil private @idFunction : $@convention(thin) (Int32) -> Int32 { +bb0(%0 : $Int32): + return %0 : $Int32 +} + +/// A stub for OSLogMessage.init. The optimization is driven by this function. +/// This function must take at least one argument which is required by the pass. +sil [Onone] [_semantics "constant_evaluable"] [_semantics "oslog.message.init_stub"] @oslogMessageClosureStubInit : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageClosureStub { +bb0(%0 : $Builtin.Int1): + %7 = integer_literal $Builtin.Int32, 81 + %8 = struct $Int32 (%7 : $Builtin.Int32) + %9 = function_ref @idFunction : $@convention(thin) (Int32) -> Int32 + %10 = partial_apply [callee_guaranteed] %9(%8) : $@convention(thin) (Int32) -> Int32 + + // Create an instance of OSLogMessageClosureStub using the above closure. + %20 = struct $OSLogInterpolationClosureStub(%10 : $@callee_guaranteed () -> Int32) + %21 = struct $OSLogMessageClosureStub(%20 : $OSLogInterpolationClosureStub) + return %21 : $OSLogMessageClosureStub +} + +/// A function that models the use of a closure. +sil @useClosure: $@convention(thin) (@callee_guaranteed () -> Int32) -> () + +// CHECK-LABEL: @testConstantFoldingOfClosure +sil [ossa] @testConstantFoldingOfClosure : $@convention(thin) () -> () { +bb0: + // Construct an OSLogMessageClosureStub instance. + %0 = integer_literal $Builtin.Int1, 1 + %1 = function_ref @oslogMessageClosureStubInit : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageClosureStub + %2 = apply %1(%0) : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageClosureStub + + // Use the closure property of OSLogMessageClosureStub which will be constant + // folded by the OSLogOptimization pass, as checked below. + %3 = begin_borrow %2 : $OSLogMessageClosureStub + %4 = struct_extract %3 : $OSLogMessageClosureStub, #OSLogMessageClosureStub.interpolation + %5 = struct_extract %4 : $OSLogInterpolationClosureStub, #OSLogInterpolationClosureStub.closure + %6 = function_ref @useClosure : $@convention(thin) (@callee_guaranteed () -> Int32) -> () + %7 = apply %6(%5) : $@convention(thin) (@callee_guaranteed () -> Int32) -> () + end_borrow %3 : $OSLogMessageClosureStub + destroy_value %2 : $OSLogMessageClosureStub + %8 = tuple () + return %8 : $() + // CHECK: [[LIT:%[0-9]+]] = integer_literal $Builtin.Int32, 81 + // CHECK: [[INT:%[0-9]+]] = struct $Int32 ([[LIT]] : $Builtin.Int32) + // CHECK: [[FUNREF:%[0-9]+]] = function_ref @idFunction + // CHECK: [[CLOSURE:%[0-9]+]] = partial_apply [callee_guaranteed] [[FUNREF]]([[INT]]) + // CHECK: [[BORROW:%[0-9]+]] = begin_borrow [[CLOSURE]] : $@callee_guaranteed () -> Int32 + // CHECK: [[USE:%[0-9]+]] = function_ref @useClosure + // CHECK: apply [[USE]]([[BORROW]]) + // CHECK: end_borrow [[BORROW]] + // CHECK: destroy_value [[CLOSURE]] +} + +sil private @constantFunction : $@convention(thin) () -> Int32 { +bb0: + %0 = integer_literal $Builtin.Int32, 91 + %1 = struct $Int32 (%0 : $Builtin.Int32) + return %1 : $Int32 +} + +sil [Onone] [_semantics "constant_evaluable"] [_semantics "oslog.message.init_stub"] @oslogMessageThinClosureStubInit : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageClosureStub { +bb0(%0 : $Builtin.Int1): + %7 = integer_literal $Builtin.Int32, 81 + %8 = struct $Int32 (%7 : $Builtin.Int32) + %9 = function_ref @constantFunction : $@convention(thin) () -> Int32 + %10 = thin_to_thick_function %9 : $@convention(thin) () -> Int32 to $@callee_guaranteed () -> Int32 + // Create an instance of OSLogMessageClosureStub using the above closure. + %20 = struct $OSLogInterpolationClosureStub(%10 : $@callee_guaranteed () -> Int32) + %21 = struct $OSLogMessageClosureStub(%20 : $OSLogInterpolationClosureStub) + return %21 : $OSLogMessageClosureStub +} + +// CHECK-LABEL: @testConstantFoldingOfThinClosure +sil [ossa] @testConstantFoldingOfThinClosure : $@convention(thin) () -> () { +bb0: + // Construct an OSLogMessageClosureStub instance. + %0 = integer_literal $Builtin.Int1, 1 + %1 = function_ref @oslogMessageThinClosureStubInit : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageClosureStub + %2 = apply %1(%0) : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageClosureStub + + %3 = begin_borrow %2 : $OSLogMessageClosureStub + %4 = struct_extract %3 : $OSLogMessageClosureStub, #OSLogMessageClosureStub.interpolation + %5 = struct_extract %4 : $OSLogInterpolationClosureStub, #OSLogInterpolationClosureStub.closure + %6 = function_ref @useClosure : $@convention(thin) (@callee_guaranteed () -> Int32) -> () + %7 = apply %6(%5) : $@convention(thin) (@callee_guaranteed () -> Int32) -> () + end_borrow %3 : $OSLogMessageClosureStub + destroy_value %2 : $OSLogMessageClosureStub + %8 = tuple () + return %8 : $() + // CHECK: [[FUNREF:%[0-9]+]] = function_ref @constantFunction + // CHECK: [[CLOSURE:%[0-9]+]] = partial_apply [callee_guaranteed] [[FUNREF]]() + // CHECK: [[BORROW:%[0-9]+]] = begin_borrow [[CLOSURE]] : $@callee_guaranteed () -> Int32 + // CHECK: [[USE:%[0-9]+]] = function_ref @useClosure + // CHECK: apply [[USE]]([[BORROW]]) + // CHECK: end_borrow [[BORROW]] + // CHECK: destroy_value [[CLOSURE]] +} + +/// A simplified stub for OSLogInterpolation type for testing folding of +/// closures with non-trivial captures. +struct OSLogInterpolationStringCapture { + var closure: () -> String +} + +/// A simplified stub for OSLogMessage for testing folding of closures with +/// non-trivial captures. +struct OSLogMessageStringCapture { + var interpolation: OSLogInterpolationStringCapture +} + +sil [ossa] @idString : $@convention(thin) (@guaranteed String) -> @owned String { +bb0(%0 : @guaranteed $String): + %1 = copy_value %0 : $String + return %1 : $String +} + +sil [ossa] [Onone] [_semantics "constant_evaluable"] [_semantics "oslog.message.init_stub"] @oslogMessageStringCaptureInit : $@convention(thin) (@owned OSLogInterpolationStringCapture) + -> @owned OSLogMessageStringCapture { +bb0(%0 : @owned $OSLogInterpolationStringCapture): + %5 = struct $OSLogMessageStringCapture(%0 : $OSLogInterpolationStringCapture) + return %5 : $OSLogMessageStringCapture +} + +sil @useStringCapture: $@convention(thin) (@callee_guaranteed () -> @owned String) -> () + +// CHECK-LABEL: @testConstantFoldingOfStringCapture +sil [ossa] @testConstantFoldingOfStringCapture : $@convention(thin) (@guaranteed String) -> () { +bb0(%0 : @guaranteed $String): + %1 = function_ref @idString : $@convention(thin) (@guaranteed String) -> @owned String + %2 = copy_value %0 : $String + %3 = partial_apply [callee_guaranteed] %1(%2) : $@convention(thin) (@guaranteed String) -> @owned String + %4 = struct $OSLogInterpolationStringCapture(%3 : $@callee_guaranteed () -> @owned String) + %5 = function_ref @oslogMessageStringCaptureInit : $@convention(thin) (@owned OSLogInterpolationStringCapture) -> @owned OSLogMessageStringCapture + %6 = apply %5(%4) : $@convention(thin) (@owned OSLogInterpolationStringCapture) -> @owned OSLogMessageStringCapture + + %13 = begin_borrow %6 : $OSLogMessageStringCapture + %14 = struct_extract %13 : $OSLogMessageStringCapture, #OSLogMessageStringCapture.interpolation + %15 = struct_extract %14 : $OSLogInterpolationStringCapture, #OSLogInterpolationStringCapture.closure + %16 = function_ref @useStringCapture : $@convention(thin) (@callee_guaranteed () -> @owned String) -> () + %17 = apply %16(%15) : $@convention(thin) (@callee_guaranteed () -> @owned String) -> () + end_borrow %13 : $OSLogMessageStringCapture + destroy_value %6 : $OSLogMessageStringCapture + %18 = tuple () + return %18 : $() + // CHECK: [[FUNREFORIG:%[0-9]+]] = function_ref @idString + // CHECK: [[ORIGCAPTURE:%[0-9]+]] = copy_value %0 : $String + // CHECK: [[NEWCAPTURE:%[0-9]+]] = copy_value [[ORIGCAPTURE]] : $String + // CHECK: [[FUNREF:%[0-9]+]] = function_ref @idString + // CHECK: [[CLOSURE:%[0-9]+]] = partial_apply [callee_guaranteed] [[FUNREF]]([[NEWCAPTURE]]) + // CHECK: [[BORROW:%[0-9]+]] = begin_borrow [[CLOSURE]] : $@callee_guaranteed () -> @owned String + // CHECK: [[USE:%[0-9]+]] = function_ref @useStringCapture + // CHECK: apply [[USE]]([[BORROW]]) + // CHECK: end_borrow [[BORROW]] + // CHECK: destroy_value [[CLOSURE]] +} + +sil [ossa] @genericFunction : $@convention(thin) (@in_guaranteed U, @in_guaranteed V) -> Int32 { +bb0(%0 : $*U, %1 : $*V): + %2 = integer_literal $Builtin.Int32, 99 + %3 = struct $Int32 (%2 : $Builtin.Int32) + return %3 : $Int32 +} + +sil [ossa] [Onone] [_semantics "constant_evaluable"] [_semantics "oslog.message.init_stub"] @oslogMessageGenericClosureInit : $@convention(thin) (@owned OSLogInterpolationClosureStub) -> @owned OSLogMessageClosureStub { +bb0(%0 : @owned $OSLogInterpolationClosureStub): + %5 = struct $OSLogMessageClosureStub(%0 : $OSLogInterpolationClosureStub) + return %5 : $OSLogMessageClosureStub +} + +// CHECK-LABEL: @testConstantFoldingOfGenericClosure +sil [ossa] @testConstantFoldingOfGenericClosure : $@convention(thin) () -> () { +bb0: + %0 = integer_literal $Builtin.Int1, 1 + %1 = alloc_stack $Int64 + %2 = alloc_stack $Bool + %3 = struct $Bool (%0 : $Builtin.Int1) + store %3 to [trivial] %2 : $*Bool + %4 = integer_literal $Builtin.Int64, 81 + %5 = struct $Int64 (%4 : $Builtin.Int64) + store %5 to [trivial] %1 : $*Int64 + + %6 = function_ref @genericFunction : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> Int32 + %7 = partial_apply [callee_guaranteed] %6(%1, %2) : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> Int32 + %8 = struct $OSLogInterpolationClosureStub(%7 : $@callee_guaranteed () -> Int32) + %11 = function_ref @oslogMessageGenericClosureInit : $@convention(thin) (@owned OSLogInterpolationClosureStub) -> @owned OSLogMessageClosureStub + %12 = apply %11(%8) : $@convention(thin) (@owned OSLogInterpolationClosureStub) -> @owned OSLogMessageClosureStub + + %13 = begin_borrow %12 : $OSLogMessageClosureStub + %14 = struct_extract %13 : $OSLogMessageClosureStub, #OSLogMessageClosureStub.interpolation + %15 = struct_extract %14 : $OSLogInterpolationClosureStub, #OSLogInterpolationClosureStub.closure + %16 = function_ref @useClosure : $@convention(thin) (@callee_guaranteed () -> Int32) -> () + %17 = apply %16(%15) : $@convention(thin) (@callee_guaranteed () -> Int32) -> () + end_borrow %13 : $OSLogMessageClosureStub + destroy_value %12 : $OSLogMessageClosureStub + dealloc_stack %2 : $*Bool + dealloc_stack %1 : $*Int64 + %18 = tuple () + return %18 : $() + // CHECK: [[FUNREFORIG:%[0-9]+]] = function_ref @genericFunction + // CHECK: [[CLOSUREORIG:%[0-9]+]] = partial_apply [callee_guaranteed] [[FUNREFORIG]]([[CAPTURE1:%[0-9]+]], [[CAPTURE2:%[0-9]+]]) + // CHECK: [[FUNREF:%[0-9]+]] = function_ref @genericFunction + // CHECK: [[CLOSURE:%[0-9]+]] = partial_apply [callee_guaranteed] [[FUNREF]]([[CAPTURE1]], [[CAPTURE2]]) + // CHECK: [[BORROW:%[0-9]+]] = begin_borrow [[CLOSURE]] : $@callee_guaranteed () -> Int32 + // CHECK: [[USE:%[0-9]+]] = function_ref @useClosure + // CHECK: apply [[USE]]([[BORROW]]) + // CHECK: end_borrow [[BORROW]] + // CHECK: destroy_value [[CLOSURE]] +} + +// Check folding of array of closures. This is essentially the feature needed +// by the OSLog overlay. + +/// A simplified stub for OSLogInterpolation type for testing folding of array +/// of closures. +struct OSLogInterpolationClosureArrayStub { + var closure: [() -> Int32] +} + +/// A simplified stub for OSLogMessage for testing folding of array of closures. +struct OSLogMessageClosureArrayStub { + var interpolation: OSLogInterpolationClosureArrayStub +} + +sil private @closure1 : $@convention(thin) (Int32) -> Int32 { +bb0(%0 : $Int32): + return %0 : $Int32 +} + +/// A stub for OSLogMessage.init. The optimization is driven by this function. +/// This function must take at least one argument which is required by the pass. +sil [Onone] [_semantics "constant_evaluable"] [_semantics "oslog.message.init_stub"] @oslogMessageClosureArrayStubInit : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageClosureArrayStub { +bb0(%0 : $Builtin.Int1): + %1 = integer_literal $Builtin.Word, 1 + // function_ref _allocateUninitializedArray(_:) + %2 = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) + %3 = apply %2<() -> Int32>(%1) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) + %4 = tuple_extract %3 : $(Array<() -> Int32>, Builtin.RawPointer), 0 + %5 = tuple_extract %3 : $(Array<() -> Int32>, Builtin.RawPointer), 1 + %6 = pointer_to_address %5 : $Builtin.RawPointer to [strict] $*@callee_guaranteed () -> Int32 + %7 = integer_literal $Builtin.Int32, 81 + %8 = struct $Int32 (%7 : $Builtin.Int32) + %9 = function_ref @closure1 : $@convention(thin) (Int32) -> Int32 + %10 = partial_apply [callee_guaranteed] %9(%8) : $@convention(thin) (Int32) -> Int32 + store %10 to %6 : $*@callee_guaranteed () -> Int32 + + // Create an instance of OSLogMessageClosureArrayStub using the above array + // of closures. + %20 = struct $OSLogInterpolationClosureArrayStub(%4 : $Array<() -> Int32>) + %21 = struct $OSLogMessageClosureArrayStub(%20 : $OSLogInterpolationClosureArrayStub) + return %21 : $OSLogMessageClosureArrayStub +} + +/// A function that models the use of an array of closures. +sil @useClosureArray: $@convention(thin) (@guaranteed Array<() -> Int32>) -> () + +// CHECK-LABEL: @testConstantFoldingOfClosureArray +sil [ossa] @testConstantFoldingOfClosureArray : $@convention(thin) () -> () { +bb0: + // Construct an OSLogMessageClosureArrayStub instance. + %0 = integer_literal $Builtin.Int1, 1 + %1 = function_ref @oslogMessageClosureArrayStubInit : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageClosureArrayStub + %2 = apply %1(%0) : $@convention(thin) (Builtin.Int1) -> @owned OSLogMessageClosureArrayStub + + // Use the arguments property of OSLogMessageClosureArrayStub which will be constant + // folded by the OSLogOptimization pass, as checked below. + %3 = begin_borrow %2 : $OSLogMessageClosureArrayStub + %4 = struct_extract %3 : $OSLogMessageClosureArrayStub, #OSLogMessageClosureArrayStub.interpolation + %5 = struct_extract %4 : $OSLogInterpolationClosureArrayStub, #OSLogInterpolationClosureArrayStub.closure + %6 = function_ref @useClosureArray : $@convention(thin) (@guaranteed Array<() -> Int32>) -> () + %7 = apply %6(%5) : $@convention(thin) (@guaranteed Array<() -> Int32>) -> () + end_borrow %3 : $OSLogMessageClosureArrayStub + destroy_value %2 : $OSLogMessageClosureArrayStub + %8 = tuple () + return %8 : $() +} diff --git a/test/SILOptimizer/OSLogPrototypeCompileTest.swift b/test/SILOptimizer/OSLogPrototypeCompileTest.swift index c5c0b2e428e81..d0678c8af61c2 100644 --- a/test/SILOptimizer/OSLogPrototypeCompileTest.swift +++ b/test/SILOptimizer/OSLogPrototypeCompileTest.swift @@ -7,10 +7,6 @@ // whether specific compile-time constants such as the format string, // the size of the byte buffer etc. are literals after the mandatory pipeline. -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - import OSLogPrototype if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { @@ -48,6 +44,17 @@ if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 + + // Check whether argument array is folded. We need not check the contents of + // the array which is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store [[ARGSARRAY:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY]] = tuple_extract [[ARRAYINITRES:%[0-9]+]] : $(Array<(inout UnsafeMutablePointer, inout Array) -> ()>, Builtin.RawPointer), 0 + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 } // CHECK-LABEL: @$s25OSLogPrototypeCompileTest34testInterpolationWithFormatOptionsL_1hy0aB06LoggerV_tF @@ -81,6 +88,17 @@ if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 + + // Check whether argument array is folded. We need not check the contents of + // the array which is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store [[ARGSARRAY:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY]] = tuple_extract [[ARRAYINITRES:%[0-9]+]] : $(Array<(inout UnsafeMutablePointer, inout Array) -> ()>, Builtin.RawPointer), 0 + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 } // CHECK-LABEL: @$s25OSLogPrototypeCompileTest44testInterpolationWithFormatOptionsAndPrivacyL_1hy0aB06LoggerV_tF @@ -117,6 +135,17 @@ if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 1 + + // Check whether argument array is folded. We need not check the contents of + // the array which is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store [[ARGSARRAY:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY]] = tuple_extract [[ARRAYINITRES:%[0-9]+]] : $(Array<(inout UnsafeMutablePointer, inout Array) -> ()>, Builtin.RawPointer), 0 + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 3 } // CHECK-LABEL: @$s25OSLogPrototypeCompileTest38testInterpolationWithMultipleArgumentsL_1hy0aB06LoggerV_tF @@ -159,6 +188,17 @@ if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 3 + + // Check whether argument array is folded. We need not check the contents of + // the array which is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store [[ARGSARRAY:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY]] = tuple_extract [[ARRAYINITRES:%[0-9]+]] : $(Array<(inout UnsafeMutablePointer, inout Array) -> ()>, Builtin.RawPointer), 0 + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 9 } // CHECK-LABEL: @$s25OSLogPrototypeCompileTest25testLogMessageWithoutDataL_1hy0aB06LoggerV_tF @@ -196,6 +236,16 @@ if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 0 + + // Check whether argument array is folded. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store [[ARGSARRAY:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY]] = tuple_extract [[ARRAYINITRES:%[0-9]+]] : $(Array<(inout UnsafeMutablePointer, inout Array) -> ()>, Builtin.RawPointer), 0 + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 0 } // CHECK-LABEL: @$s25OSLogPrototypeCompileTest22testEscapingOfPercentsL_1hy0aB06LoggerV_tF @@ -266,6 +316,16 @@ if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 48 + + // Check whether argument array is folded. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store [[ARGSARRAY:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY]] = tuple_extract [[ARRAYINITRES:%[0-9]+]] : $(Array<(inout UnsafeMutablePointer, inout Array) -> ()>, Builtin.RawPointer), 0 + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 144 } // CHECK-LABEL: @$s25OSLogPrototypeCompileTest22testInt32InterpolationL_1hy0aB06LoggerV_tF @@ -338,6 +398,17 @@ if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { // CHECK-DAG: apply [[SERIALIZE]]([[ARGCOUNT:%[0-9]+]], {{%.*}}) // CHECK-DAG: [[ARGCOUNT]] = struct $UInt8 ([[ARGCOUNTLIT:%[0-9]+]] : $Builtin.Int8) // CHECK-DAG: [[ARGCOUNTLIT]] = integer_literal $Builtin.Int8, 2 + + // Check whether argument array is folded. We need not check the contents of + // the array which is checked by a different test suite. + + // CHECK-DAG: [[FOREACH:%[0-9]+]] = function_ref @$sSTsE7forEachyyy7ElementQzKXEKF + // CHECK-DAG: try_apply [[FOREACH]], inout Array) -> ()>>({{%.*}}, [[ARGSARRAYADDR:%[0-9]+]]) + // CHECK-DAG: store [[ARGSARRAY:%[0-9]+]] to [[ARGSARRAYADDR]] + // CHECK-DAG: [[ARGSARRAY]] = tuple_extract [[ARRAYINITRES:%[0-9]+]] : $(Array<(inout UnsafeMutablePointer, inout Array) -> ()>, Builtin.RawPointer), 0 + // CHECK-DAG: [[ARRAYINITRES]] = apply [[ARRAYINIT:%[0-9]+]]<(inout UnsafeMutablePointer, inout Array) -> ()>([[ARRAYSIZE:%[0-9]+]]) + // CHECK-DAG: [[ARRAYINIT]] = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF + // CHECK-DAG: [[ARRAYSIZE]] = integer_literal $Builtin.Word, 6 } } diff --git a/test/SILOptimizer/cast_folding.swift b/test/SILOptimizer/cast_folding.swift index 156b6a2d54780..1394bbc7b10d0 100644 --- a/test/SILOptimizer/cast_folding.swift +++ b/test/SILOptimizer/cast_folding.swift @@ -1072,7 +1072,7 @@ public func testCastToPForOptionalFailure() -> Bool { struct Underlying : P { } -func returnOpaque() -> some P { +public func returnOpaque() -> some P { return Underlying() } @@ -1083,6 +1083,7 @@ func returnOpaque() -> some P { // MANDATORY: [[U:%.*]] = alloc_stack $Underlying // MANDATORY: unconditional_checked_cast_addr @_opaqueReturnTypeOf{{.*}}in [[O]] : $*@_opaqueReturnTypeOf{{.*}}to Underlying in [[U]] : $*Underlying // MANDATORY: load [[U]] : $*Underlying +@inlinable public func testCastOpaqueArchetype() { let o = returnOpaque() as! Underlying } diff --git a/test/SILOptimizer/constant_evaluable_subset_test.swift b/test/SILOptimizer/constant_evaluable_subset_test.swift index 12132fef53743..8e1b6fa33b592 100644 --- a/test/SILOptimizer/constant_evaluable_subset_test.swift +++ b/test/SILOptimizer/constant_evaluable_subset_test.swift @@ -18,10 +18,6 @@ // // RUN: %FileCheck %s < %t/error-output-mandatory -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - // Test Swift code snippets that are expected to be constant evaluable and those // that are not. If any of the test here fails, it indicates a change in the // output of SILGen or the mandatory passes that affects the constant diff --git a/test/SILOptimizer/constant_propagation_diagnostics.swift b/test/SILOptimizer/constant_propagation_diagnostics.swift index e62498a46f860..de433d7a5a44c 100644 --- a/test/SILOptimizer/constant_propagation_diagnostics.swift +++ b/test/SILOptimizer/constant_propagation_diagnostics.swift @@ -1,10 +1,6 @@ // RUN: %target-swift-frontend -emit-sil -sdk %S/../SILGen/Inputs %s -o /dev/null -verify // RUN: %target-swift-frontend -enable-ownership-stripping-after-serialization -emit-sil -sdk %S/../SILGen/Inputs %s -o /dev/null -verify -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - // enum with raw values that are too big are not diagnosed enum EnumWithTooLargeElements : UInt8 { case negativeOne = -1 // expected-error 2 {{negative integer '-1' overflows when stored into unsigned type 'UInt8'}} diff --git a/test/SILOptimizer/constantprop-wrongscope.swift b/test/SILOptimizer/constantprop-wrongscope.swift index 12f9d62ba7709..92961fc96625e 100644 --- a/test/SILOptimizer/constantprop-wrongscope.swift +++ b/test/SILOptimizer/constantprop-wrongscope.swift @@ -13,7 +13,7 @@ // instructions surrounding it. // CHECK: destroy_addr %7 : $*Any, loc {{.*}}:22:19, scope 2 -// CHECK: dealloc_stack %12 : $*Optional, loc {{.*}}:22:23, scope 2 +// CHECK: dealloc_stack %13 : $*Optional, loc {{.*}}:22:23, scope 2 // CHECK: dealloc_stack %7 : $*Any, loc {{.*}}:22:23, scope 2 // CHECK: dealloc_stack %6 : $*A, loc {{.*}}:22:7, scope 2 diff --git a/test/SILOptimizer/definite_init_diagnostics.swift b/test/SILOptimizer/definite_init_diagnostics.swift index 8db86c0d440ba..a563afdd18a74 100644 --- a/test/SILOptimizer/definite_init_diagnostics.swift +++ b/test/SILOptimizer/definite_init_diagnostics.swift @@ -1,10 +1,6 @@ // RUN: %target-swift-frontend -emit-sil -primary-file %s -o /dev/null -verify // RUN: %target-swift-frontend -emit-sil -enable-ownership-stripping-after-serialization -primary-file %s -o /dev/null -verify -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - import Swift func markUsed(_ t: T) {} diff --git a/test/SILOptimizer/definite_init_diagnostics_objc.swift b/test/SILOptimizer/definite_init_diagnostics_objc.swift index 02c53017b956d..b1ecf92999b6e 100644 --- a/test/SILOptimizer/definite_init_diagnostics_objc.swift +++ b/test/SILOptimizer/definite_init_diagnostics_objc.swift @@ -2,10 +2,6 @@ // RUN: %target-swift-frontend -emit-sil -sdk %S/../SILGen/Inputs %s -I %S/../SILGen/Inputs -enable-source-import -parse-stdlib -o /dev/null -verify -enable-ownership-stripping-after-serialization // REQUIRES: objc_interop -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - import Swift import gizmo diff --git a/test/SILOptimizer/definite_init_failable_initializers.swift b/test/SILOptimizer/definite_init_failable_initializers.swift index 96bf16b5ba44f..c444af21b5469 100644 --- a/test/SILOptimizer/definite_init_failable_initializers.swift +++ b/test/SILOptimizer/definite_init_failable_initializers.swift @@ -133,8 +133,8 @@ struct FailableStruct { // // CHECK: [[SUCC_BB]]: // CHECK-NEXT: [[SELF_VALUE:%.*]] = unchecked_enum_data [[SELF_OPTIONAL]] -// CHECK-NEXT: store [[SELF_VALUE]] to [[SELF_BOX]] // CHECK-NEXT: retain_value [[SELF_VALUE]] +// CHECK-NEXT: store [[SELF_VALUE]] to [[SELF_BOX]] // CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional, #Optional.some!enumelt.1, [[SELF_VALUE]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] @@ -311,8 +311,8 @@ struct ThrowStruct { // CHECK: bb1([[RESULT:%.*]] : $Int): // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers11ThrowStructV6noFailACyt_tcfC // CHECK-NEXT: [[NEW_SELF:%.*]] = apply [[INIT_FN]](%1) -// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: retain_value [[NEW_SELF]] +// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] @@ -333,8 +333,8 @@ struct ThrowStruct { // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers11ThrowStructV4failACyt_tKcfC // CHECK-NEXT: try_apply [[INIT_FN]](%1) // CHECK: bb2([[NEW_SELF:%.*]] : $ThrowStruct): -// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: retain_value [[NEW_SELF]] +// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] @@ -359,8 +359,10 @@ struct ThrowStruct { // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers11ThrowStructV20failBeforeDelegationACSi_tKcfC // CHECK-NEXT: try_apply [[INIT_FN]]([[RESULT]], %1) // CHECK: bb2([[NEW_SELF:%.*]] : $ThrowStruct): +// CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] -// CHECK: dealloc_stack [[SELF_BOX]] +// CHECK-NEXT: destroy_addr [[SELF_BOX]] +// CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] // CHECK: bb3([[ERROR:%.*]] : $Error): // CHECK-NEXT: br bb5([[ERROR]] : $Error) @@ -379,8 +381,8 @@ struct ThrowStruct { // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers11ThrowStructV4failACyt_tKcfC // CHECK-NEXT: try_apply [[INIT_FN]](%1) // CHECK: bb1([[NEW_SELF:%.*]] : $ThrowStruct): -// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: retain_value [[NEW_SELF]] +// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] @@ -396,11 +398,12 @@ struct ThrowStruct { // CHECK: [[SELF_BOX:%.*]] = alloc_stack $ThrowStruct // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers11ThrowStructV6noFailACyt_tcfC // CHECK-NEXT: [[NEW_SELF:%.*]] = apply [[INIT_FN]](%1) +// CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] -// CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF +// CHECK-NEXT: // function_ref +// CHECK-NEXT: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb1([[RESULT:%.*]] : $Int): -// CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] @@ -424,11 +427,12 @@ struct ThrowStruct { // CHECK: bb1([[NEW_SELF:.*]] : $ThrowStruct): // CHECK-NEXT: [[BIT:%.*]] = integer_literal $Builtin.Int1, -1 // CHECK-NEXT: store [[BIT]] to [[BITMAP_BOX]] +// CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] -// CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF +// CHECK-NEXT: // function_ref +// CHECK-NEXT: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb2([[RESULT:%.*]] : $Int): -// CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[BITMAP_BOX]] @@ -436,6 +440,7 @@ struct ThrowStruct { // CHECK: bb3([[ERROR:%.*]] : $Error): // CHECK-NEXT: br bb5([[ERROR]] : $Error) // CHECK: bb4([[ERROR:%.*]] : $Error): +// CHECK-NEXT: release_value [[NEW_SELF]] // CHECK-NEXT: br bb5([[ERROR]] : $Error) // CHECK: bb5([[ERROR:%.*]] : $Error): // CHECK-NEXT: [[COND:%.*]] = load [[BITMAP_BOX]] @@ -467,11 +472,12 @@ struct ThrowStruct { // CHECK-NEXT: [[NEW_SELF:%.*]] = apply [[INIT_FN]](%1) // CHECK-NEXT: [[BIT:%.*]] = integer_literal $Builtin.Int1, -1 // CHECK-NEXT: store [[BIT]] to [[BITMAP_BOX]] +// CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] -// CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF +// CHECK-NEXT: // function_ref +// CHECK-NEXT: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb2([[RESULT:%.*]] : $Int): -// CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[BITMAP_BOX]] @@ -479,6 +485,7 @@ struct ThrowStruct { // CHECK: bb3([[ERROR:%.*]] : $Error): // CHECK-NEXT: br bb5([[ERROR]] : $Error) // CHECK: bb4([[ERROR:%.*]] : $Error): +// CHECK-NEXT: release_value [[NEW_SELF]] // CHECK-NEXT: br bb5([[ERROR]] : $Error) // CHECK: bb5([[ERROR:%.*]] : $Error): // CHECK-NEXT: [[COND:%.*]] = load [[BITMAP_BOX]] @@ -520,8 +527,8 @@ struct ThrowStruct { // // CHECK: [[SUCC_BB]]: // CHECK-NEXT: [[SELF_VALUE:%.*]] = unchecked_enum_data [[SELF_OPTIONAL]] -// CHECK-NEXT: store [[SELF_VALUE]] to [[SELF_BOX]] // CHECK-NEXT: retain_value [[SELF_VALUE]] +// CHECK-NEXT: store [[SELF_VALUE]] to [[SELF_BOX]] // CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional, #Optional.some!enumelt.1, [[SELF_VALUE]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] @@ -530,8 +537,8 @@ struct ThrowStruct { // CHECK: [[EPILOG_BB]]([[NEW_SELF:%.*]] : $Optional): // CHECK-NEXT: return [[NEW_SELF]] : $Optional // -// CHECK: [[TRY_APPLY_FAIL_BB]]([[ERROR]] : $Error): -// CHECK-NEXT: strong_release [[ERROR:%.*]] : $Error +// CHECK: [[TRY_APPLY_FAIL_BB]]([[ERROR:%.*]] : $Error): +// CHECK-NEXT: strong_release [[ERROR]] : $Error // CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK-NEXT: br [[TRY_APPLY_CONT]]([[NEW_SELF]] : $Optional) init?(throwsToOptional: Int) { @@ -567,9 +574,9 @@ struct ThrowStruct { // CHECK-NEXT: try_apply [[INIT_FN]]([[SELF_TYPE]]) // CHECK: bb1([[NEW_SELF:%.*]] : $ThrowStruct): // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [static] [[SELF_BOX]] : $*ThrowStruct +// CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: store [[NEW_SELF]] to [[WRITE]] // CHECK-NEXT: end_access [[WRITE]] : $*ThrowStruct -// CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] @@ -587,16 +594,17 @@ struct ThrowStruct { // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers11ThrowStructV6noFailACyt_tcfC // CHECK-NEXT: [[NEW_SELF:%.*]] = apply [[INIT_FN]]([[SELF_TYPE]]) // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [static] [[SELF_BOX]] : $*ThrowStruct +// CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: store [[NEW_SELF]] to [[WRITE]] // CHECK-NEXT: end_access [[WRITE]] : $*ThrowStruct // CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb1([[RESULT:%.*]] : $Int): -// CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] // CHECK: bb2([[ERROR:%.*]] : $Error): +// CHECK-NEXT: release_value [[NEW_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: throw [[ERROR]] @@ -773,8 +781,8 @@ class FailableBaseClass { // // CHECK: [[SUCC_BB]]: // CHECK-NEXT: [[SELF_VALUE:%.*]] = unchecked_enum_data [[SELF_OPTIONAL]] -// CHECK-NEXT: store [[SELF_VALUE]] to [[SELF_BOX]] // CHECK-NEXT: strong_retain [[SELF_VALUE]] +// CHECK-NEXT: store [[SELF_VALUE]] to [[SELF_BOX]] // CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional, #Optional.some!enumelt.1, [[SELF_VALUE]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] @@ -822,25 +830,30 @@ class FailableDerivedClass : FailableBaseClass { // CHECK: bb0(%0 : $FailableDerivedClass): // CHECK: [[SELF_BOX:%.*]] = alloc_stack $FailableDerivedClass // CHECK: store %0 to [[SELF_BOX]] +// CHECK-NEXT: [[RELOAD_FROM_SELF_BOX:%.*]] = load [[SELF_BOX]] // CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thick FailableDerivedClass.Type -// CHECK-NEXT: dealloc_partial_ref %0 : $FailableDerivedClass, [[METATYPE]] : $@thick FailableDerivedClass.Type +// CHECK-NEXT: dealloc_partial_ref [[RELOAD_FROM_SELF_BOX]] : $FailableDerivedClass, [[METATYPE]] : $@thick FailableDerivedClass.Type // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: [[RESULT:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK-NEXT: return [[RESULT]] +// CHECK: } // end sil function '$s35definite_init_failable_initializers20FailableDerivedClassC27derivedFailBeforeDelegationACSgyt_tcfc' init?(derivedFailBeforeDelegation: ()) { return nil } // CHECK-LABEL: sil hidden @$s35definite_init_failable_initializers20FailableDerivedClassC27derivedFailDuringDelegationACSgyt_tcfc -// CHECK: bb0(%0 : $FailableDerivedClass): +// CHECK: bb0([[SELF:%.*]] : $FailableDerivedClass): // CHECK-NEXT: [[SELF_BOX:%.*]] = alloc_stack $FailableDerivedClass -// CHECK: store %0 to [[SELF_BOX]] -// CHECK: [[CANARY:%.*]] = apply -// CHECK-NEXT: [[MEMBER_ADDR:%.*]] = ref_element_addr %0 +// CHECK: store [[SELF]] to [[SELF_BOX]] +// CHECK: [[CANARY_FUN:%.*]] = function_ref @$s35definite_init_failable_initializers6CanaryCACycfC : +// CHECK: [[CANARY:%.*]] = apply [[CANARY_FUN]]( +// CHECK-NEXT: [[MEMBER_ADDR:%.*]] = ref_element_addr [[SELF]] // CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[MEMBER_ADDR]] : $*Canary // CHECK-NEXT: store [[CANARY]] to [[WRITE]] // CHECK-NEXT: end_access [[WRITE]] : $*Canary -// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast %0 +// CHECK-NEXT: strong_release [[SELF]] +// CHECK-NEXT: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] +// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast [[RELOAD_SELF]] // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers17FailableBaseClassC28failBeforeFullInitializationACSgyt_tcfc // CHECK-NEXT: [[SELF_OPTIONAL:%.*]] = apply [[INIT_FN]]([[BASE_SELF]]) // CHECK: [[COND:%.*]] = select_enum [[SELF_OPTIONAL]] @@ -855,8 +868,8 @@ class FailableDerivedClass : FailableBaseClass { // CHECK: [[SUCC_BB]]: // CHECK-NEXT: [[BASE_SELF_VALUE:%.*]] = unchecked_enum_data [[SELF_OPTIONAL]] // CHECK-NEXT: [[SELF_VALUE:%.*]] = unchecked_ref_cast [[BASE_SELF_VALUE]] -// CHECK-NEXT: store [[SELF_VALUE]] to [[SELF_BOX]] // CHECK-NEXT: strong_retain [[SELF_VALUE]] +// CHECK-NEXT: store [[SELF_VALUE]] to [[SELF_BOX]] // CHECK-NEXT: [[NEW_SELF:%.*]] = enum $Optional, #Optional.some!enumelt.1, [[SELF_VALUE]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] @@ -864,6 +877,7 @@ class FailableDerivedClass : FailableBaseClass { // // CHECK: [[EPILOG_BB]]([[NEW_SELF:%.*]] : $Optional): // CHECK-NEXT: return [[NEW_SELF]] : $Optional +// CHECK: } // end sil function '$s35definite_init_failable_initializers20FailableDerivedClassC27derivedFailDuringDelegationACSgyt_tcfc' init?(derivedFailDuringDelegation: ()) { self.otherMember = Canary() super.init(failBeforeFullInitialization: ()) @@ -905,16 +919,17 @@ class ThrowBaseClass { class ThrowDerivedClass : ThrowBaseClass { // CHECK-LABEL: sil hidden @$s35definite_init_failable_initializers17ThrowDerivedClassCACyKcfc -// CHECK: bb0(%0 : $ThrowDerivedClass): +// CHECK: bb0([[SELF:%.*]] : $ThrowDerivedClass): // CHECK-NEXT: [[SELF_BOX:%.*]] = alloc_stack $ThrowDerivedClass -// CHECK: store %0 to [[SELF_BOX]] -// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast %0 +// CHECK: store [[SELF]] to [[SELF_BOX]] +// CHECK-NEXT: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] +// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast [[RELOAD_SELF]] // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers14ThrowBaseClassCACyKcfc // CHECK-NEXT: try_apply [[INIT_FN]]([[BASE_SELF]]) // CHECK: bb1([[NEW_SELF:%.*]] : $ThrowBaseClass): // CHECK-NEXT: [[DERIVED_SELF:%.*]] = unchecked_ref_cast [[NEW_SELF]] -// CHECK-NEXT: store [[DERIVED_SELF]] to [[SELF_BOX]] // CHECK-NEXT: strong_retain [[DERIVED_SELF]] +// CHECK-NEXT: store [[DERIVED_SELF]] to [[SELF_BOX]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[DERIVED_SELF]] @@ -930,24 +945,26 @@ class ThrowDerivedClass : ThrowBaseClass { } // CHECK-LABEL: sil hidden @$s35definite_init_failable_initializers17ThrowDerivedClassC28failBeforeFullInitializationACSi_tKcfc -// CHECK: bb0(%0 : $Int, %1 : $ThrowDerivedClass): +// CHECK: bb0(%0 : $Int, [[SELF:%.*]] : $ThrowDerivedClass): // CHECK-NEXT: [[SELF_BOX:%.*]] = alloc_stack $ThrowDerivedClass -// CHECK: store %1 to [[SELF_BOX]] +// CHECK: store [[SELF]] to [[SELF_BOX]] // CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb1([[RESULT:%.*]] : $Int): -// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast %1 +// CHECK-NEXT: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] +// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast [[RELOAD_SELF]] // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers14ThrowBaseClassC6noFailACyt_tcfc // CHECK-NEXT: [[NEW_SELF:%.*]] = apply [[INIT_FN]]([[BASE_SELF]]) // CHECK-NEXT: [[DERIVED_SELF:%.*]] = unchecked_ref_cast [[NEW_SELF]] -// CHECK-NEXT: store [[DERIVED_SELF]] to [[SELF_BOX]] // CHECK-NEXT: strong_retain [[DERIVED_SELF]] +// CHECK-NEXT: store [[DERIVED_SELF]] to [[SELF_BOX]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[DERIVED_SELF]] : $ThrowDerivedClass // CHECK: bb2([[ERROR:%.*]] : $Error): +// CHECK-NEXT: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] // CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thick ThrowDerivedClass.Type -// CHECK-NEXT: dealloc_partial_ref %1 : $ThrowDerivedClass, [[METATYPE]] : $@thick ThrowDerivedClass.Type +// CHECK-NEXT: dealloc_partial_ref [[RELOAD_SELF]] : $ThrowDerivedClass, [[METATYPE]] : $@thick ThrowDerivedClass.Type // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: throw [[ERROR]] init(failBeforeFullInitialization: Int) throws { @@ -965,15 +982,16 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb1([[RESULT:%.*]] : $Int) -// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast %2 +// CHECK-NEXT: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] +// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast [[RELOAD_SELF]] // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers14ThrowBaseClassCACyKcfc // CHECK-NEXT: [[BIT:%.*]] = integer_literal $Builtin.Int1, -1 // CHECK-NEXT: store [[BIT]] to [[BITMAP_BOX]] // CHECK: try_apply [[INIT_FN]]([[BASE_SELF]]) // CHECK: bb2([[NEW_SELF:%.*]] : $ThrowBaseClass): // CHECK-NEXT: [[DERIVED_SELF:%.*]] = unchecked_ref_cast [[NEW_SELF]] -// CHECK-NEXT: store [[DERIVED_SELF]] to [[SELF_BOX]] // CHECK-NEXT: strong_retain [[DERIVED_SELF]] +// CHECK-NEXT: store [[DERIVED_SELF]] to [[SELF_BOX]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[BITMAP_BOX]] @@ -988,8 +1006,9 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: bb6: // CHECK-NEXT: br bb8 // CHECK: bb7: +// CHECK-NEXT: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] // CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thick ThrowDerivedClass.Type -// CHECK-NEXT: dealloc_partial_ref %2 : $ThrowDerivedClass, [[METATYPE]] : $@thick ThrowDerivedClass.Type +// CHECK-NEXT: dealloc_partial_ref [[RELOAD_SELF]] : $ThrowDerivedClass, [[METATYPE]] : $@thick ThrowDerivedClass.Type // CHECK-NEXT: br bb8 // CHECK: bb8: // CHECK-NEXT: dealloc_stack [[SELF_BOX]] @@ -1004,19 +1023,21 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: bb0(%0 : $Int, %1 : $ThrowDerivedClass): // CHECK-NEXT: [[SELF_BOX:%.*]] = alloc_stack $ThrowDerivedClass // CHECK: store %1 to [[SELF_BOX]] -// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast %1 +// CHECK-NEXT: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] +// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast [[RELOAD_SELF]] // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers14ThrowBaseClassC6noFailACyt_tcfc // CHECK-NEXT: [[NEW_SELF:%.*]] = apply [[INIT_FN]]([[BASE_SELF]]) // CHECK-NEXT: [[DERIVED_SELF:%.*]] = unchecked_ref_cast [[NEW_SELF]] +// CHECK-NEXT: strong_retain [[DERIVED_SELF]] // CHECK-NEXT: store [[DERIVED_SELF]] to [[SELF_BOX]] // CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb1([[RESULT:%.*]] : $Int): -// CHECK-NEXT: strong_retain [[DERIVED_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[DERIVED_SELF]] // CHECK: bb2([[ERROR:%.*]] : $Error): +// CHECK-NEXT: strong_release [[DERIVED_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: throw [[ERROR]] @@ -1032,18 +1053,19 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int2, 0 // CHECK-NEXT: store [[ZERO]] to [[BITMAP_BOX]] // CHECK: store %2 to [[SELF_BOX]] -// CHECK-NEXT: [[DERIVED_SELF:%.*]] = upcast %2 +// CHECK-NEXT: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] +// CHECK-NEXT: [[DERIVED_SELF:%.*]] = upcast [[RELOAD_SELF]] // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers14ThrowBaseClassCACyKcfc // CHECK: try_apply [[INIT_FN]]([[DERIVED_SELF]]) // CHECK: bb1([[NEW_SELF:%.*]] : $ThrowBaseClass): // CHECK-NEXT: [[BIT:%.*]] = integer_literal $Builtin.Int2, -1 // CHECK-NEXT: store [[BIT]] to [[BITMAP_BOX]] // CHECK-NEXT: [[DERIVED_SELF:%.*]] = unchecked_ref_cast [[NEW_SELF]] +// CHECK-NEXT: strong_retain [[DERIVED_SELF]] // CHECK-NEXT: store [[DERIVED_SELF]] to [[SELF_BOX]] // CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb2([[RESULT:%.*]] : $Int): -// CHECK-NEXT: strong_retain [[DERIVED_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[BITMAP_BOX]] @@ -1051,6 +1073,7 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: bb3([[ERROR:%.*]] : $Error): // CHECK-NEXT: br bb5([[ERROR]] : $Error) // CHECK: bb4([[ERROR:%.*]] : $Error): +// CHECK-NEXT: strong_release [[DERIVED_SELF]] // CHECK-NEXT: br bb5([[ERROR]] : $Error) // CHECK: bb5([[ERROR:%.*]] : $Error): // CHECK-NEXT: [[BITMAP:%.*]] = load [[BITMAP_BOX]] @@ -1084,17 +1107,18 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: bb1([[RESULT:%.*]] : $Int): // CHECK-NEXT: [[TWO:%.*]] = integer_literal $Builtin.Int2, -2 // CHECK-NEXT: store [[TWO]] to [[BITMAP_BOX]] -// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast %2 +// CHECK-NEXT: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] +// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast [[RELOAD_SELF]] // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers14ThrowBaseClassC6noFailACyt_tcfc // CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Int2, -1 // CHECK-NEXT: store [[ONE]] to [[BITMAP_BOX]] // CHECK: [[NEW_SELF:%.*]] = apply [[INIT_FN]]([[BASE_SELF]]) // CHECK-NEXT: [[DERIVED_SELF:%.*]] = unchecked_ref_cast [[NEW_SELF]] +// CHECK-NEXT: strong_retain [[DERIVED_SELF]] // CHECK-NEXT: store [[DERIVED_SELF]] to [[SELF_BOX]] // CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%1) // CHECK: bb2([[RESULT:%.*]] : $Int): -// CHECK-NEXT: strong_retain [[DERIVED_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[BITMAP_BOX]] @@ -1102,6 +1126,7 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: bb3([[ERROR:%.*]] : $Error): // CHECK-NEXT: br bb5([[ERROR]] : $Error) // CHECK: bb4([[ERROR:%.*]] : $Error): +// CHECK-NEXT: strong_release [[DERIVED_SELF]] // CHECK-NEXT: br bb5([[ERROR]] : $Error) // CHECK: bb5([[ERROR:%.*]] : $Error): // CHECK-NEXT: [[BITMAP:%.*]] = load [[BITMAP_BOX]] @@ -1145,7 +1170,8 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb1([[RESULT:%.*]] : $Int): -// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast %3 +// CHECK-NEXT: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] +// CHECK-NEXT: [[BASE_SELF:%.*]] = upcast [[RELOAD_SELF]] // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers14ThrowBaseClassCACyKcfc // CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Int2, 1 // CHECK-NEXT: store [[ONE]] to [[BITMAP_BOX]] @@ -1154,11 +1180,11 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK-NEXT: [[NEG_ONE:%.*]] = integer_literal $Builtin.Int2, -1 // CHECK-NEXT: store [[NEG_ONE]] to [[BITMAP_BOX]] // CHECK-NEXT: [[DERIVED_SELF:%.*]] = unchecked_ref_cast [[NEW_SELF]] +// CHECK-NEXT: strong_retain [[DERIVED_SELF]] // CHECK-NEXT: store [[DERIVED_SELF]] to [[SELF_BOX]] // CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%2) // CHECK: bb3([[RESULT:%.*]] : $Int): -// CHECK-NEXT: strong_retain [[DERIVED_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[BITMAP_BOX]] @@ -1168,6 +1194,7 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: bb5([[ERROR:%.*]] : $Error): // CHECK-NEXT: br bb7([[ERROR]] : $Error) // CHECK: bb6([[ERROR:%.*]] : $Error): +// CHECK-NEXT: strong_release [[DERIVED_SELF]] // CHECK-NEXT: br bb7([[ERROR]] : $Error) // CHECK: bb7([[ERROR:%.*]] : $Error): // CHECK-NEXT: [[BITMAP:%.*]] = load [[BITMAP_BOX]] @@ -1213,8 +1240,8 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: bb1([[ARG:%.*]] : $Int): // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers17ThrowDerivedClassC6noFailACyt_tcfC // CHECK-NEXT: [[NEW_SELF:%.*]] = apply [[INIT_FN]](%1) -// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: strong_retain [[NEW_SELF]] +// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] @@ -1232,8 +1259,8 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers17ThrowDerivedClassCACyKcfC // CHECK-NEXT: try_apply [[INIT_FN]](%1) // CHECK: bb1([[NEW_SELF:%.*]] : $ThrowDerivedClass): -// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: strong_retain [[NEW_SELF]] +// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] @@ -1253,8 +1280,8 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers17ThrowDerivedClassCACyKcfC // CHECK-NEXT: try_apply [[INIT_FN]](%1) // CHECK: bb2([[NEW_SELF:%.*]] : $ThrowDerivedClass): -// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: strong_retain [[NEW_SELF]] +// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] @@ -1279,8 +1306,8 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers17ThrowDerivedClassC20failBeforeDelegationACSi_tKcfC // CHECK-NEXT: try_apply [[INIT_FN]]([[ARG]], %1) // CHECK: bb2([[NEW_SELF:%.*]] : $ThrowDerivedClass): -// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: strong_retain [[NEW_SELF]] +// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] @@ -1300,15 +1327,16 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK-NEXT: [[SELF_BOX:%.*]] = alloc_stack $ThrowDerivedClass // CHECK: [[INIT_FN:%.*]] = function_ref @$s35definite_init_failable_initializers17ThrowDerivedClassC6noFailACyt_tcfC // CHECK-NEXT: [[NEW_SELF:%.*]] = apply [[INIT_FN]](%1) +// CHECK-NEXT: strong_retain [[NEW_SELF]] // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb1([[RESULT:%.*]] : $Int): -// CHECK-NEXT: strong_retain [[NEW_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] // CHECK: bb2([[ERROR:%.*]] : $Error): +// CHECK-NEXT: strong_release [[NEW_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: throw [[ERROR]] @@ -1328,11 +1356,11 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: bb1([[NEW_SELF:%.*]] : $ThrowDerivedClass): // CHECK-NEXT: [[BIT:%.*]] = integer_literal $Builtin.Int1, -1 // CHECK-NEXT: store [[BIT]] to [[BITMAP_BOX]] +// CHECK-NEXT: strong_retain [[NEW_SELF]] // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb2([[RESULT:%.*]] : $Int): -// CHECK-NEXT: strong_retain [[NEW_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[BITMAP_BOX]] @@ -1340,6 +1368,7 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: bb3([[ERROR1:%.*]] : $Error): // CHECK-NEXT: br bb5([[ERROR1]] : $Error) // CHECK: bb4([[ERROR2:%.*]] : $Error): +// CHECK-NEXT: strong_release [[NEW_SELF]] // CHECK-NEXT: br bb5([[ERROR2]] : $Error) // CHECK: bb5([[ERROR3:%.*]] : $Error): // CHECK-NEXT: [[BITMAP:%.*]] = load [[BITMAP_BOX]] @@ -1371,11 +1400,11 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK-NEXT: [[NEW_SELF:%.*]] = apply [[INIT_FN]](%1) // CHECK-NEXT: [[BIT:%.*]] = integer_literal $Builtin.Int1, -1 // CHECK-NEXT: store [[BIT]] to [[BITMAP_BOX]] +// CHECK-NEXT: strong_retain [[NEW_SELF]] // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] // CHECK: [[UNWRAP_FN:%.*]] = function_ref @$s35definite_init_failable_initializers6unwrapyS2iKF // CHECK-NEXT: try_apply [[UNWRAP_FN]](%0) // CHECK: bb2([[RESULT:%.*]] : $Int): -// CHECK-NEXT: strong_retain [[NEW_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[BITMAP_BOX]] @@ -1383,6 +1412,7 @@ class ThrowDerivedClass : ThrowBaseClass { // CHECK: bb3([[ERROR:%.*]] : $Error): // CHECK-NEXT: br bb5([[ERROR]] : $Error) // CHECK: bb4([[ERROR:%.*]] : $Error): +// CHECK-NEXT: strong_release [[NEW_SELF]] // CHECK-NEXT: br bb5([[ERROR]] : $Error) // CHECK: bb5([[ERROR:%.*]] : $Error): // CHECK-NEXT: [[BITMAP:%.*]] = load [[BITMAP_BOX]] diff --git a/test/SILOptimizer/definite_init_failable_initializers_diagnostics.swift b/test/SILOptimizer/definite_init_failable_initializers_diagnostics.swift index 573b9c57e391b..125458ed212f6 100644 --- a/test/SILOptimizer/definite_init_failable_initializers_diagnostics.swift +++ b/test/SILOptimizer/definite_init_failable_initializers_diagnostics.swift @@ -1,10 +1,6 @@ // RUN: %target-swift-frontend -emit-sil -disable-objc-attr-requires-foundation-module -verify %s // RUN: %target-swift-frontend -emit-sil -disable-objc-attr-requires-foundation-module -verify %s -enable-ownership-stripping-after-serialization -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - // High-level tests that DI rejects certain invalid idioms for early // return from initializers. diff --git a/test/SILOptimizer/definite_init_failable_initializers_objc.swift b/test/SILOptimizer/definite_init_failable_initializers_objc.swift index a1e387452e236..f6b40025e5cb9 100644 --- a/test/SILOptimizer/definite_init_failable_initializers_objc.swift +++ b/test/SILOptimizer/definite_init_failable_initializers_objc.swift @@ -38,32 +38,37 @@ class Cat : FakeNSObject { // CHECK: end sil function '$s40definite_init_failable_initializers_objc3CatC1n5afterACSgSi_SbtcfC' // CHECK-LABEL: sil hidden @$s40definite_init_failable_initializers_objc3CatC1n5afterACSgSi_Sbtcfc : $@convention(method) (Int, Bool, @owned Cat) -> @owned Optional - // CHECK: bb0(%0 : $Int, %1 : $Bool, %2 : $Cat): + // CHECK: bb0([[ARG0:%.*]] : $Int, [[ARG1:%.*]] : $Bool, [[ARG2:%.*]] : $Cat): // CHECK-NEXT: [[SELF_BOX:%.*]] = alloc_stack $Cat - // CHECK: store %2 to [[SELF_BOX]] : $*Cat - // CHECK: [[FIELD_ADDR:%.*]] = ref_element_addr %2 : $Cat, #Cat.x + // CHECK: store [[ARG2]] to [[SELF_BOX]] : $*Cat + // CHECK: [[FIELD_ADDR:%.*]] = ref_element_addr [[ARG2]] : $Cat, #Cat.x // CHECK-NEXT: store {{%.*}} to [[FIELD_ADDR]] : $*LifetimeTracked + // CHECK-NEXT: strong_release [[ARG2]] // CHECK-NEXT: [[COND:%.*]] = struct_extract %1 : $Bool, #Bool._value // CHECK-NEXT: cond_br [[COND]], bb1, bb2 // CHECK: bb1: - // CHECK-NEXT: [[FIELD_ADDR:%.*]] = ref_element_addr %2 : $Cat, #Cat.x + // CHECK-NEXT: [[FIELD_ADDR:%.*]] = ref_element_addr [[ARG2]] : $Cat, #Cat.x // CHECK-NEXT: destroy_addr [[FIELD_ADDR]] : $*LifetimeTracked + // CHECK-NEXT: strong_release [[ARG2]] + // CHECK-NEXT: [[RELOAD_FROM_BOX:%.*]] = load [[SELF_BOX]] // CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thick Cat.Type - // CHECK-NEXT: dealloc_partial_ref %2 : $Cat, [[METATYPE]] : $@thick Cat.Type + // CHECK-NEXT: dealloc_partial_ref [[RELOAD_FROM_BOX]] : $Cat, [[METATYPE]] : $@thick Cat.Type // CHECK-NEXT: dealloc_stack [[SELF_BOX]] : $*Cat // CHECK-NEXT: [[RESULT:%.*]] = enum $Optional, #Optional.none!enumelt // CHECK-NEXT: br bb3([[RESULT]] : $Optional) // CHECK: bb2: - // CHECK-NEXT: [[SUPER:%.*]] = upcast %2 : $Cat to $FakeNSObject + // CHECK-NEXT: strong_release [[ARG2]] + // CHECK-NEXT: [[RELOAD_ARG2:%.*]] = load [[SELF_BOX]] + // CHECK-NEXT: [[SUPER:%.*]] = upcast [[RELOAD_ARG2]] : $Cat to $FakeNSObject // CHECK-NEXT: [[SUB:%.*]] = unchecked_ref_cast [[SUPER]] : $FakeNSObject to $Cat // CHECK-NEXT: [[SUPER_FN:%.*]] = objc_super_method [[SUB]] : $Cat, #FakeNSObject.init!initializer.1.foreign : (FakeNSObject.Type) -> () -> FakeNSObject, $@convention(objc_method) (@owned FakeNSObject) -> @owned FakeNSObject // CHECK-NEXT: [[NEW_SUPER_SELF:%.*]] = apply [[SUPER_FN]]([[SUPER]]) : $@convention(objc_method) (@owned FakeNSObject) -> @owned FakeNSObject // CHECK-NEXT: [[NEW_SELF:%.*]] = unchecked_ref_cast [[NEW_SUPER_SELF]] : $FakeNSObject to $Cat - // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] : $*Cat // TODO: Once we re-enable arbitrary take promotion, this retain and the associated destroy_addr will go away. // CHECK-NEXT: strong_retain [[NEW_SELF]] + // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] : $*Cat // CHECK-NEXT: [[RESULT:%.*]] = enum $Optional, #Optional.some!enumelt.1, [[NEW_SELF]] : $Cat // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] : $*Cat @@ -89,18 +94,19 @@ class Cat : FakeNSObject { // CHECK: end sil function '$s40definite_init_failable_initializers_objc3CatC4fail5afterACSgSb_SbtcfC' // CHECK-LABEL: sil hidden @$s40definite_init_failable_initializers_objc3CatC4fail5afterACSgSb_Sbtcfc : $@convention(method) (Bool, Bool, @owned Cat) -> @owned Optional - // CHECK: bb0(%0 : $Bool, %1 : $Bool, %2 : $Cat): + // CHECK: bb0([[ARG0:%.*]] : $Bool, [[ARG1:%.*]] : $Bool, [[ARG2:%.*]] : $Cat): // CHECK-NEXT: [[HAS_RUN_INIT_BOX:%.+]] = alloc_stack $Builtin.Int1 // CHECK-NEXT: [[SELF_BOX:%.+]] = alloc_stack [dynamic_lifetime] $Cat - // CHECK: store %2 to [[SELF_BOX]] : $*Cat - // CHECK-NEXT: [[COND:%.+]] = struct_extract %0 : $Bool, #Bool._value + // CHECK: store [[ARG2]] to [[SELF_BOX]] : $*Cat + // CHECK-NEXT: [[COND:%.+]] = struct_extract [[ARG0]] : $Bool, #Bool._value // CHECK-NEXT: cond_br [[COND]], bb1, bb2 // CHECK: bb1: // CHECK-NEXT: br [[ERROR_BRANCH:bb[0-9]+]] // CHECK: bb{{[0-9]+}}: - // CHECK: [[SELF_INIT:%.+]] = objc_method %2 : $Cat, #Cat.init!initializer.1.foreign : (Cat.Type) -> (Int, Bool) -> Cat? + // CHECK: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] + // CHECK: [[SELF_INIT:%.+]] = objc_method [[RELOAD_SELF]] : $Cat, #Cat.init!initializer.1.foreign : (Cat.Type) -> (Int, Bool) -> Cat? // CHECK: [[NEW_OPT_SELF:%.+]] = apply [[SELF_INIT]]({{%.+}}, {{%.+}}, {{%.+}}) : $@convention(objc_method) (Int, ObjCBool, @owned Cat) -> @owned Optional // CHECK: [[COND:%.+]] = select_enum [[NEW_OPT_SELF]] : $Optional // CHECK-NEXT: cond_br [[COND]], [[SUCCESS_BRANCH:bb[0-9]+]], [[RELEASE_THEN_ERROR_BRANCH:bb[0-9]+]] @@ -111,9 +117,9 @@ class Cat : FakeNSObject { // CHECK: [[SUCCESS_BRANCH]]: // CHECK-NEXT: [[NEW_SELF:%.+]] = unchecked_enum_data [[NEW_OPT_SELF]] : $Optional, #Optional.some!enumelt.1 - // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] : $*Cat // TODO: Once we re-enable arbitrary take promotion, this retain and the associated destroy_addr will go away. // CHECK-NEXT: strong_retain [[NEW_SELF]] + // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] : $*Cat // CHECK-NEXT: [[RESULT:%.+]] = enum $Optional, #Optional.some!enumelt.1, [[NEW_SELF]] : $Cat // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] : $*Cat @@ -127,8 +133,9 @@ class Cat : FakeNSObject { // CHECK-NEXT: br [[ERROR_CLEANUP_BRANCH:bb[0-9]+]] // CHECK: [[ERROR_WITH_DESTROY_BRANCH]]: - // CHECK-NEXT: [[MOST_DERIVED_TYPE:%.+]] = value_metatype $@thick Cat.Type, %2 : $Cat - // CHECK-NEXT: dealloc_partial_ref %2 : $Cat, [[MOST_DERIVED_TYPE]] : $@thick Cat.Type + // CHECK: [[RELOAD_SELF:%.*]] = load [[SELF_BOX]] + // CHECK-NEXT: [[MOST_DERIVED_TYPE:%.+]] = value_metatype $@thick Cat.Type, [[RELOAD_SELF]] : $Cat + // CHECK-NEXT: dealloc_partial_ref [[RELOAD_SELF]] : $Cat, [[MOST_DERIVED_TYPE]] : $@thick Cat.Type // CHECK-NEXT: br [[ERROR_CLEANUP_BRANCH]] // CHECK: [[ERROR_CLEANUP_BRANCH]]: diff --git a/test/SILOptimizer/definite_init_protocol_init.swift b/test/SILOptimizer/definite_init_protocol_init.swift index 182affb558f6c..fca217255fabd 100644 --- a/test/SILOptimizer/definite_init_protocol_init.swift +++ b/test/SILOptimizer/definite_init_protocol_init.swift @@ -35,10 +35,10 @@ class TrivialClass : TriviallyConstructible { // CHECK-NEXT: [[FN:%.*]] = function_ref @$s023definite_init_protocol_B022TriviallyConstructiblePAAE6middlexSi_tcfC // CHECK-NEXT: apply [[FN]]<@dynamic_self TrivialClass>([[RESULT]], %0, [[METATYPE]]) // CHECK-NEXT: [[NEW_SELF:%.*]] = load [[RESULT]] - // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] - // CHECK-NEXT: dealloc_stack [[RESULT]] // TODO: Once we restore arbitrary takes, the strong_retain/destroy_addr pair below will go away. // CHECK-NEXT: strong_retain [[NEW_SELF]] + // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_BOX]] + // CHECK-NEXT: dealloc_stack [[RESULT]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: return [[NEW_SELF]] diff --git a/test/SILOptimizer/definite_init_value_types.swift b/test/SILOptimizer/definite_init_value_types.swift index aa23047d53533..dc5538d43930f 100644 --- a/test/SILOptimizer/definite_init_value_types.swift +++ b/test/SILOptimizer/definite_init_value_types.swift @@ -59,9 +59,9 @@ enum ValueEnum { // CHECK: bb6: // CHECK-NEXT: [[NEW_STATE:%.*]] = integer_literal $Builtin.Int1, -1 // CHECK-NEXT: store [[NEW_STATE]] to [[STATE]] + // CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: store [[NEW_SELF]] to [[SELF_ACCESS]] // CHECK-NEXT: end_access [[SELF_ACCESS]] - // CHECK-NEXT: retain_value [[NEW_SELF]] // CHECK-NEXT: destroy_addr [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[SELF_BOX]] // CHECK-NEXT: dealloc_stack [[STATE]] diff --git a/test/SILOptimizer/diagnostic_constant_propagation.swift b/test/SILOptimizer/diagnostic_constant_propagation.swift index 4e556f4f3b5b2..a0fd24cc56eee 100644 --- a/test/SILOptimizer/diagnostic_constant_propagation.swift +++ b/test/SILOptimizer/diagnostic_constant_propagation.swift @@ -9,10 +9,6 @@ // References: , // -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable RUN lines after SR-11336 is fixed. -// XFAIL: * - import StdlibUnittest func testArithmeticOverflow() { diff --git a/test/SILOptimizer/diagnostic_constant_propagation_int_arch64.swift b/test/SILOptimizer/diagnostic_constant_propagation_int_arch64.swift index c55e1058508a2..38104f2455167 100644 --- a/test/SILOptimizer/diagnostic_constant_propagation_int_arch64.swift +++ b/test/SILOptimizer/diagnostic_constant_propagation_int_arch64.swift @@ -13,10 +13,6 @@ // // FIXME: A false negative that happens only in REPL -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - import StdlibUnittest func testArithmeticOverflow_Int_64bit() { diff --git a/test/SILOptimizer/escape_analysis.sil b/test/SILOptimizer/escape_analysis.sil index 53759dbb463dd..3868f44f1ec7f 100644 --- a/test/SILOptimizer/escape_analysis.sil +++ b/test/SILOptimizer/escape_analysis.sil @@ -99,8 +99,8 @@ bb0(%0 : $Int): // CHECK-NEXT: Con %0.1 Esc: A, Succ: %2 // CHECK-NEXT: Arg %1 Esc: G, Succ: // CHECK-NEXT: Val %2 Esc: A, Succ: (%2.1) -// CHECK-NEXT: Con %2.1 Esc: A, Succ: (%2.2) -// CHECK-NEXT: Con %2.2 Esc: G, Succ: %1 +// CHECK-NEXT: Con %2.1 Esc: A, Succ: (%3) +// CHECK-NEXT: Con %3 Esc: G, Succ: %1 // CHECK-NEXT: End sil @test_simple : $@convention(thin) (@inout Y, @owned X) -> () { bb0(%0 : $*Y, %1 : $X): @@ -120,8 +120,8 @@ bb0(%0 : $*Y, %1 : $X): // CHECK-NEXT: Arg %0 Esc: A, Succ: (%3.1) // CHECK-NEXT: Arg %1 Esc: A, Succ: // CHECK-NEXT: Val %3 Esc: %3, Succ: (%3.1), %0 -// CHECK-NEXT: Con %3.1 Esc: A, Succ: (%3.2) -// CHECK-NEXT: Con %3.2 Esc: A, Succ: %1 +// CHECK-NEXT: Con %3.1 Esc: A, Succ: (%4) +// CHECK-NEXT: Con %4 Esc: A, Succ: %1 // CHECK-NEXT: Ret Esc: R, Succ: %0 // CHECK-NEXT: End sil @deferringEdge : $@convention(thin) (@owned LinkedNode, @owned LinkedNode) -> @owned LinkedNode { @@ -151,12 +151,12 @@ bb0: // CHECK-LABEL: CG of test_linked_list // CHECK-NEXT: Arg %0 Esc: A, Succ: (%1.1) // CHECK-NEXT: Val %1 Esc: A, Succ: (%1.1) -// CHECK-NEXT: Con %1.1 Esc: A, Succ: (%11.1) +// CHECK-NEXT: Con %1.1 Esc: A, Succ: (%2) +// CHECK-NEXT: Con %2 Esc: A, Succ: %0, %1, %4 // CHECK-NEXT: Val %4 Esc: A, Succ: (%1.1) // CHECK-NEXT: Val %7 Esc: %11, Succ: (%1.1) -// CHECK-NEXT: Val %11 Esc: %11, Succ: (%1.1), %7, %11.1 -// CHECK-NEXT: Con %11.1 Esc: A, Succ: (%1.1), %0, %1, %4 -// CHECK-NEXT: Ret Esc: R, Succ: %11.1 +// CHECK-NEXT: Val %11 Esc: %11, Succ: (%1.1), %2, %7 +// CHECK-NEXT: Ret Esc: R, Succ: %2 // CHECK-NEXT: End sil @test_linked_list : $@convention(thin) (@owned LinkedNode) -> @owned LinkedNode { bb0(%0 : $LinkedNode): @@ -186,11 +186,11 @@ bb2: // CHECK-LABEL: CG of create_chain // CHECK-NEXT: Arg %0 Esc: A, Succ: (%7.1) // CHECK-NEXT: Val %1 Esc: A, Succ: (%7.1) -// CHECK-NEXT: Con %1.1 Esc: A, Succ: %0, %1, %4 // CHECK-NEXT: Val %4 Esc: A, Succ: (%7.1) // CHECK-NEXT: Val %7 Esc: %11, Succ: (%7.1) -// CHECK-NEXT: Con %7.1 Esc: A, Succ: (%1.1) -// CHECK-NEXT: Val %11 Esc: R, Succ: (%7.1), %1.1 +// CHECK-NEXT: Con %7.1 Esc: A, Succ: (%8) +// CHECK-NEXT: Con %8 Esc: A, Succ: %0, %1, %4 +// CHECK-NEXT: Val %11 Esc: R, Succ: (%7.1), %8 // CHECK-NEXT: Ret Esc: R, Succ: %11 // CHECK-NEXT: End sil @create_chain : $@convention(thin) (@owned LinkedNode) -> @owned LinkedNode { @@ -212,10 +212,10 @@ bb0(%0 : $LinkedNode): // CHECK-LABEL: CG of loadNext // CHECK-NEXT: Arg %0 Esc: A, Succ: (%2.1) -// CHECK-NEXT: Val %2 Esc: %2, Succ: (%2.1), %0, %2.2 -// CHECK-NEXT: Con %2.1 Esc: A, Succ: (%2.2) -// CHECK-NEXT: Con %2.2 Esc: A, Succ: (%2.1) -// CHECK-NEXT: Ret Esc: R, Succ: %2.2 +// CHECK-NEXT: Val %2 Esc: %2, Succ: (%2.1), %0, %3 +// CHECK-NEXT: Con %2.1 Esc: A, Succ: (%3) +// CHECK-NEXT: Con %3 Esc: A, Succ: (%2.1) +// CHECK-NEXT: Ret Esc: R, Succ: %3 // CHECK-NEXT: End sil @loadNext : $@convention(thin) (@owned LinkedNode) -> @owned LinkedNode { bb0(%0 : $LinkedNode): @@ -252,13 +252,13 @@ bb0(%0 : $LinkedNode): // CHECK-LABEL: CG of load_next3 // CHECK-NEXT: Arg %0 Esc: A, Succ: (%0.1) -// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%0.2) -// CHECK-NEXT: Con %0.2 Esc: A, Succ: (%0.3) -// CHECK-NEXT: Con %0.3 Esc: A, Succ: (%0.4) -// CHECK-NEXT: Con %0.4 Esc: A, Succ: (%0.5) -// CHECK-NEXT: Con %0.5 Esc: A, Succ: (%0.6) -// CHECK-NEXT: Con %0.6 Esc: A, Succ: -// CHECK-NEXT: Ret Esc: R, Succ: %0.6 +// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%1) +// CHECK-NEXT: Con %1 Esc: A, Succ: (%2) +// CHECK-NEXT: Con %2 Esc: A, Succ: (%3) +// CHECK-NEXT: Con %3 Esc: A, Succ: (%4) +// CHECK-NEXT: Con %4 Esc: A, Succ: (%5) +// CHECK-NEXT: Con %5 Esc: A, Succ: +// CHECK-NEXT: Ret Esc: R, Succ: %5 // CHECK-NEXT: End sil @load_next3 : $@convention(thin) (@owned LinkedNode) -> @owned LinkedNode { bb0(%0 : $LinkedNode): @@ -278,9 +278,9 @@ sil_global @global_x : $X // CHECK-LABEL: CG of call_store_pointer // CHECK-NEXT: Arg %0 Esc: G, Succ: (%0.1) -// CHECK-NEXT: Con %0.1 Esc: G, Succ: (%0.2) -// CHECK-NEXT: Con %0.2 Esc: G, Succ: -// CHECK-NEXT: Ret Esc: R, Succ: %0.2 +// CHECK-NEXT: Con %0.1 Esc: G, Succ: (%5) +// CHECK-NEXT: Con %5 Esc: G, Succ: +// CHECK-NEXT: Ret Esc: R, Succ: %5 // CHECK-NEXT: End sil @call_store_pointer : $@convention(thin) (@owned Pointer) -> @owned X { bb0(%0 : $Pointer): @@ -311,10 +311,10 @@ bb0(%0 : $Pointer): // CHECK-LABEL: CG of store_content // CHECK-NEXT: Arg %0 Esc: A, Succ: (%0.1) -// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%0.2) -// CHECK-NEXT: Con %0.2 Esc: G, Succ: +// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%3) // CHECK-NEXT: Val %1 Esc: G, Succ: (%1.1) -// CHECK-NEXT: Con %1.1 Esc: G, Succ: %0.2 +// CHECK-NEXT: Con %1.1 Esc: G, Succ: %3 +// CHECK-NEXT: Con %3 Esc: G, Succ: // CHECK-NEXT: End sil @store_content : $@convention(thin) (@owned Pointer) -> () { bb0(%0 : $Pointer): @@ -329,9 +329,9 @@ bb0(%0 : $Pointer): // CHECK-LABEL: CG of call_store_content // CHECK-NEXT: Arg %0 Esc: A, Succ: (%0.1) -// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%0.2) -// CHECK-NEXT: Con %0.2 Esc: G, Succ: -// CHECK-NEXT: Ret Esc: R, Succ: %0.2 +// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%4) +// CHECK-NEXT: Con %4 Esc: G, Succ: +// CHECK-NEXT: Ret Esc: R, Succ: %4 // CHECK-NEXT: End sil @call_store_content : $@convention(thin) (@owned Pointer) -> @owned X { bb0(%0 : $Pointer): @@ -405,12 +405,12 @@ sil @call_copy_addr_content : $@convention(thin) () -> () { // CHECK-LABEL: CG of test_partial_apply // CHECK-NEXT: Arg %1 Esc: G, Succ: -// CHECK-NEXT: Arg %2 Esc: A, Succ: (%6.3) +// CHECK-NEXT: Arg %2 Esc: A, Succ: (%7.1) // CHECK-NEXT: Val %3 Esc: %14,%15,%17, Succ: (%6.1) // CHECK-NEXT: Val %6 Esc: %14,%15,%16, Succ: (%6.1) -// CHECK-NEXT: Con %6.1 Esc: %14,%15,%16,%17, Succ: (%6.2) -// CHECK-NEXT: Con %6.2 Esc: %14,%15,%16,%17, Succ: %2 -// CHECK-NEXT: Con %6.3 Esc: G, Succ: +// CHECK-NEXT: Con %6.1 Esc: %14,%15,%16,%17, Succ: (%7) +// CHECK-NEXT: Con %7 Esc: %14,%15,%16,%17, Succ: %2 +// CHECK-NEXT: Con %7.1 Esc: G, Succ: // CHECK-NEXT: Val %12 Esc: %14,%15, Succ: %3, %6 // CHECK-NEXT: End sil @test_partial_apply : $@convention(thin) (Int64, @owned X, @owned Y) -> Int64 { @@ -460,10 +460,10 @@ bb0(%0 : $X, %1 : $<τ_0_0> { var τ_0_0 } , %2 : $<τ_0_0> { var τ_0_0 // CHECK-LABEL: CG of closure2 // CHECK-NEXT: Arg %0 Esc: G, Succ: // CHECK-NEXT: Arg %1 Esc: A, Succ: (%1.1) -// CHECK-NEXT: Con %1.1 Esc: A, Succ: (%1.2) -// CHECK-NEXT: Con %1.2 Esc: A, Succ: (%1.3) -// CHECK-NEXT: Con %1.3 Esc: G, Succ: (%1.4) -// CHECK-NEXT: Con %1.4 Esc: G, Succ: %0 +// CHECK-NEXT: Con %1.1 Esc: A, Succ: (%2) +// CHECK-NEXT: Con %2 Esc: A, Succ: (%3) +// CHECK-NEXT: Con %3 Esc: G, Succ: (%4) +// CHECK-NEXT: Con %4 Esc: G, Succ: %0 // CHECK-NEXT: End sil @closure2 : $@convention(thin) (@owned X, @owned <τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $X, %1 : $<τ_0_0> { var τ_0_0 } ): @@ -565,9 +565,9 @@ sil_global @global_ln : $LinkedNode // CHECK-LABEL: CG of load_next_recursive // CHECK-NEXT: Arg %0 Esc: A, Succ: (%0.1) -// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%0.2) -// CHECK-NEXT: Con %0.2 Esc: G, Succ: -// CHECK-NEXT: Val %4 Esc: G, Succ: %0.2 +// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%1) +// CHECK-NEXT: Con %1 Esc: G, Succ: +// CHECK-NEXT: Val %4 Esc: G, Succ: %1 // CHECK-NEXT: Ret Esc: R, Succ: %4 // CHECK-NEXT: End sil @load_next_recursive : $@convention(thin) (@owned LinkedNode) -> @owned LinkedNode { @@ -580,8 +580,8 @@ bb0(%0 : $LinkedNode): } // CHECK-LABEL: CG of let_escape -// CHECK-NEXT: Arg %0 Esc: G, Succ: (%0.1) -// CHECK-NEXT: Con %0.1 Esc: G, Succ: +// CHECK-NEXT: Arg %0 Esc: G, Succ: +// CHECK-NEXT: Con %0.1 Esc: G, Succ: // CHECK-NEXT: Val %1 Esc: G, Succ: (%1.1) // CHECK-NEXT: Con %1.1 Esc: G, Succ: %0 // CHECK-NEXT: Val %4 Esc: G, Succ: %0 @@ -621,11 +621,11 @@ bb2(%5 : $LinkedNode): // CHECK-LABEL: CG of loadNext2 // CHECK-NEXT: Arg %0 Esc: A, Succ: (%0.1) -// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%0.2) -// CHECK-NEXT: Con %0.2 Esc: A, Succ: (%0.3) -// CHECK-NEXT: Con %0.3 Esc: A, Succ: (%0.4) -// CHECK-NEXT: Con %0.4 Esc: A, Succ: (%4.1) -// CHECK-NEXT: Val %4 Esc: R, Succ: %0.4 +// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%1) +// CHECK-NEXT: Con %1 Esc: A, Succ: (%1.1) +// CHECK-NEXT: Con %1.1 Esc: A, Succ: (%1.2) +// CHECK-NEXT: Con %1.2 Esc: A, Succ: (%4.1) +// CHECK-NEXT: Val %4 Esc: R, Succ: %1.2, %4.2 // CHECK-NEXT: Con %4.1 Esc: A, Succ: (%4.2) // CHECK-NEXT: Con %4.2 Esc: A, Succ: (%4.1) // CHECK-NEXT: Ret Esc: R, Succ: %4 @@ -641,12 +641,12 @@ bb0(%0 : $LinkedNode): // CHECK-LABEL: CG of returnNext2 // CHECK-NEXT: Arg %0 Esc: A, Succ: (%0.1) -// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%0.2) -// CHECK-NEXT: Con %0.2 Esc: A, Succ: (%0.3) -// CHECK-NEXT: Con %0.3 Esc: A, Succ: (%0.4) -// CHECK-NEXT: Con %0.4 Esc: A, Succ: (%0.3) -// CHECK-NEXT: Val %3 Esc: R, Succ: (%0.3), %0.4 -// CHECK-NEXT: Val %8 Esc: R, Succ: %0.2, %3 +// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%5) +// CHECK-NEXT: Val %3 Esc: R, Succ: (%5.1), %5.2 +// CHECK-NEXT: Con %5 Esc: A, Succ: (%5.1) +// CHECK-NEXT: Con %5.1 Esc: A, Succ: (%5.2) +// CHECK-NEXT: Con %5.2 Esc: A, Succ: (%5.1) +// CHECK-NEXT: Val %8 Esc: R, Succ: %3, %5 // CHECK-NEXT: Ret Esc: R, Succ: %8 // CHECK-NEXT: End sil @returnNext2 : $@convention(thin) (@owned LinkedNode) -> @owned LinkedNode { @@ -670,10 +670,10 @@ bb3(%8 : $LinkedNode): // A single-cycle recursion test. // CHECK-LABEL: CG of single_cycle_recursion -// CHECK-NEXT: Arg %0 Esc: A, Succ: (%0.2) -// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%0.2) -// CHECK-NEXT: Con %0.2 Esc: A, Succ: (%0.1) -// CHECK-NEXT: Val %5 Esc: R, Succ: (%0.2), %0.1 +// CHECK-NEXT: Arg %0 Esc: A, Succ: (%2.1) +// CHECK-NEXT: Con %2 Esc: A, Succ: (%2.1) +// CHECK-NEXT: Con %2.1 Esc: A, Succ: (%2) +// CHECK-NEXT: Val %5 Esc: R, Succ: (%2.1), %2 // CHECK-NEXT: Val %7 Esc: R, Succ: %0, %5 // CHECK-NEXT: Ret Esc: R, Succ: %7 // CHECK-NEXT: End @@ -758,11 +758,11 @@ sil @unknown_throwing_func : $@convention(thin) (@owned X) -> (@owned X, @error // Test that the deinit of a box itself does not capture anything. // CHECK-LABEL: CG of test_release_of_partial_apply_with_box -// CHECK-NEXT: Arg %0 Esc: A, Succ: (%1.3) +// CHECK-NEXT: Arg %0 Esc: A, Succ: (%2.1) // CHECK-NEXT: Val %1 Esc: %6, Succ: (%1.1) -// CHECK-NEXT: Con %1.1 Esc: %6, Succ: (%1.2) -// CHECK-NEXT: Con %1.2 Esc: %6, Succ: %0 -// CHECK-NEXT: Con %1.3 Esc: G, Succ: +// CHECK-NEXT: Con %1.1 Esc: %6, Succ: (%2) +// CHECK-NEXT: Con %2 Esc: %6, Succ: %0 +// CHECK-NEXT: Con %2.1 Esc: G, Succ: // CHECK-NEXT: Val %5 Esc: %6, Succ: %1 // CHECK-NEXT: End sil @test_release_of_partial_apply_with_box : $@convention(thin) (@owned Y) -> () { @@ -784,8 +784,8 @@ sil @take_y_box : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } ) -> () // CHECK-LABEL: CG of store_to_unknown_reference // CHECK-NEXT: Arg %0 Esc: G, Succ: // CHECK-NEXT: Val %2 Esc: G, Succ: (%2.1) -// CHECK-NEXT: Con %2.1 Esc: G, Succ: (%2.2) -// CHECK-NEXT: Con %2.2 Esc: G, Succ: %0 +// CHECK-NEXT: Con %2.1 Esc: G, Succ: (%3) +// CHECK-NEXT: Con %3 Esc: G, Succ: %0 // CHECK-NEXT: End sil @store_to_unknown_reference : $@convention(thin) (@owned X) -> () { bb0(%0 : $X): @@ -833,8 +833,8 @@ bb0: // CHECK-LABEL: CG of create_and_store_x // CHECK-NEXT: Val %0 Esc: G, Succ: // CHECK-NEXT: Val %2 Esc: G, Succ: (%2.1) -// CHECK-NEXT: Con %2.1 Esc: G, Succ: (%2.2) -// CHECK-NEXT: Con %2.2 Esc: G, Succ: %0 +// CHECK-NEXT: Con %2.1 Esc: G, Succ: (%3) +// CHECK-NEXT: Con %3 Esc: G, Succ: %0 // CHECK-NEXT: End sil @create_and_store_x : $@convention(thin) () -> () { bb0: @@ -850,9 +850,10 @@ bb0: // Test types which are considered as pointers. // CHECK-LABEL: CG of pointer_types -// CHECK-NEXT: Arg %0 Esc: A, Succ: %1 +// CHECK-NEXT: Arg %0 Esc: A, Succ: // CHECK-NEXT: Arg %1 Esc: A, Succ: -// CHECK-NEXT: Val %7 Esc: R, Succ: %0 +// CHECK-NEXT: Val %4 Esc: R, Succ: %0, %1 +// CHECK-NEXT: Val %7 Esc: R, Succ: %4 // CHECK-NEXT: Ret Esc: R, Succ: %7 // CHECK-NEXT: End sil @pointer_types : $@convention(thin) (@owned Y, @owned Y) -> @owned Y { @@ -871,11 +872,11 @@ bb1(%7 : $(Pointer, Pointer)): // CHECK-LABEL: CG of defer_edge_cycle // CHECK-NEXT: Arg %0 Esc: A, Succ: (%0.1) -// CHECK-NEXT: Con %0.1 Esc: A, Succ: %1.1 -// CHECK-NEXT: Con %0.2 Esc: A, Succ: (%0.3) -// CHECK-NEXT: Con %0.3 Esc: A, Succ: +// CHECK-NEXT: Con %0.1 Esc: A, Succ: (%2), %1.1 // CHECK-NEXT: Arg %1 Esc: A, Succ: (%1.1) -// CHECK-NEXT: Con %1.1 Esc: A, Succ: (%0.2), %0.1 +// CHECK-NEXT: Con %1.1 Esc: A, Succ: %0.1 +// CHECK-NEXT: Con %2 Esc: A, Succ: (%6) +// CHECK-NEXT: Con %6 Esc: A, Succ: // CHECK-NEXT: End sil @defer_edge_cycle : $@convention(thin) (@inout Y, @inout Y) -> () { entry(%0 : $*Y, %1 : $*Y): @@ -968,8 +969,8 @@ bb0(%0 : $Builtin.Int64, %1 : $X, %2 : $X, %3 : $X): // CHECK-LABEL: CG of test_existential_addr // CHECK-NEXT: Arg %0 Esc: A, Succ: // CHECK-NEXT: Val %1 Esc: , Succ: (%1.1) -// CHECK-NEXT: Con %1.1 Esc: , Succ: (%1.2) -// CHECK-NEXT: Con %1.2 Esc: , Succ: %0 +// CHECK-NEXT: Con %1.1 Esc: , Succ: (%2) +// CHECK-NEXT: Con %2 Esc: , Succ: %0 // CHECK-NEXT: End sil @test_existential_addr : $@convention(thin) (@owned Pointer) -> () { bb0(%0 : $Pointer): @@ -1073,10 +1074,11 @@ bb0(%0 : $*U, %1 : $*T, %2 : $@thick U.Type): sil_global @global_y : $SomeData // CHECK-LABEL: CG of test_node_merge_during_struct_inst -// CHECK-NEXT: Arg %0 Esc: G, Succ: (%4.1) +// CHECK-NEXT: Arg %0 Esc: A, Succ: (%4.1) // CHECK-NEXT: Val %1 Esc: G, Succ: (%4.1) -// CHECK-NEXT: Val %4 Esc: G, Succ: (%4.1) -// CHECK-NEXT: Con %4.1 Esc: G, Succ: (%4.1), %0, %1, %4 +// CHECK-NEXT: Val %4 Esc: , Succ: (%4.1) +// CHECK-NEXT: Con %4.1 Esc: G, Succ: (%4.1), %1 +// CHECK-NEXT: Val %10 Esc: , Succ: %0, %4, %4.1 // CHECK-NEXT: End sil @test_node_merge_during_struct_inst : $@convention(thin) (Y) -> () { bb0(%0 : $Y): @@ -1244,10 +1246,10 @@ bb(%0 : $*Array, %1 : $@callee_owned (@inout X) -> (@out (), @error Error)): // CHECK-LABEL: CG of arraysemantics_createUninitialized // CHECK-NEXT: Arg %0 Esc: A, Succ: -// CHECK-NEXT: Val %2 Esc: R, Succ: (%4.2) +// CHECK-NEXT: Val %2 Esc: R, Succ: (%6) // CHECK-NEXT: Val %4 Esc: R, Succ: (%4.1) // CHECK-NEXT: Con %4.1 Esc: R, Succ: %2 -// CHECK-NEXT: Con %4.2 Esc: R, Succ: %0 +// CHECK-NEXT: Con %6 Esc: R, Succ: %0 // CHECK-NEXT: Ret Esc: R, Succ: %4 // CHECK-NEXT: End sil @arraysemantics_createUninitialized : $@convention(thin) (@owned X) -> @owned Array { @@ -1451,10 +1453,10 @@ bb0(%0 : $X): // Z.deinit // CHECK-LABEL: CG of $s4main1ZCfD // CHECK: Arg %0 Esc: A, Succ: (%0.1) -// CHECK: Con %0.1 Esc: A, Succ: (%0.2) -// CHECK: Con %0.2 Esc: G, Succ: +// CHECK: Con %0.1 Esc: A, Succ: (%1) +// CHECK: Con %1 Esc: G, Succ: // CHECK: Val %3 Esc: G, Succ: (%3.1) -// CHECK: Con %3.1 Esc: G, Succ: %0.2 +// CHECK: Con %3.1 Esc: G, Succ: %1 // CHECK: End sil @$s4main1ZCfD: $@convention(method) (@owned Z) -> () { bb0(%0 : $Z): @@ -1533,3 +1535,123 @@ bb0: return %7 : $() } +// Test the absence of redundant pointsTo edges +// CHECK-LABEL: CG of testInitializePointsToLeaf +// CHECK: Arg %0 Esc: A, Succ: (%0.1) +// CHECK: Con %0.1 Esc: A, Succ: (%0.2) [rc] +// CHECK: Con %0.2 Esc: A, Succ: (%12.1) +// CHECK: Val %2 Esc: %4, Succ: %0.2 +// CHECK: Val %4 Esc: %4, Succ: %2 +// CHECK: Val %7 Esc: %12, Succ: (%12.1), %0.2 +// CHECK: Val %12 Esc: %12, Succ: (%12.1), %7 +// CHECK: Con %12.1 Esc: A, Succ: (%13) [rc] +// CHECK: Con %13 Esc: A, Succ: +// CHECK-LABEL: End +class C { + var c: C +} + +sil @testInitializePointsToWrapOptional : $@convention(method) (@guaranteed LinkedNode) -> Optional { +bb0(%0: $LinkedNode): + %adr = ref_element_addr %0 : $LinkedNode, #LinkedNode.next + %val = load %adr : $*LinkedNode + %optional = enum $Optional, #Optional.some!enumelt.1, %val : $LinkedNode + return %optional : $Optional +} + +sil @testInitializePointsToLeaf : $@convention(method) (@guaranteed LinkedNode) -> () { +bb0(%0 : $LinkedNode): + %f1 = function_ref @testInitializePointsToWrapOptional : $@convention(method) (@guaranteed LinkedNode) -> Optional + %call1 = apply %f1(%0) : $@convention(method) (@guaranteed LinkedNode) -> Optional + switch_enum %call1 : $Optional, case #Optional.some!enumelt.1: bb2, case #Optional.none!enumelt: bb3 + +bb2(%arg1 : $LinkedNode): + br bb4 + +bb3: + br bb4 + +bb4: + %call2 = apply %f1(%0) : $@convention(method) (@guaranteed LinkedNode) -> Optional + switch_enum %call2 : $Optional, case #Optional.some!enumelt.1: bb10, case #Optional.none!enumelt: bb9 + +bb9: + %37 = integer_literal $Builtin.Int1, -1 + cond_fail %37 : $Builtin.Int1, "Unexpectedly found nil while unwrapping an Optional value" + unreachable + +// %40 +bb10(%arg2 : $LinkedNode): + %adr = ref_element_addr %arg2 : $LinkedNode, #LinkedNode.next + %val = load %adr : $*LinkedNode + %66 = tuple () + return %66 : $() +} + +// Another test for redundant pointsTo edges. In the original +// implementation, redundant points edges were created whenever adding +// a defer edge from a node with uninitialized pointsTo to a node with +// already-initialized pointsTo. +// CHECK-LABEL: CG of testInitializePointsToRedundant +// CHECK: Arg %0 Esc: A, Succ: (%0.1) +// CHECK: Con %0.1 Esc: A, Succ: (%2) [rc] +// CHECK: Arg %1 Esc: A, Succ: (%0.1) +// CHECK: Con %2 Esc: A, Succ: +// CHECK: Val %7 Esc: %7,%18, Succ: %0 +// CHECK: Val %12 Esc: %12,%14,%18, Succ: %1 +// CHECK: Val %14 Esc: %18, Succ: (%0.1), %1, %12 +// CHECK: Val %18 Esc: %18, Succ: %7, %14 +// CHECK-LABEL: End +sil @testInitializePointsToMerge : $@convention(method) (@guaranteed C, @guaranteed C) -> C { +bb0(%0: $C, %1 : $C): + cond_br undef, bb1, bb2 + +bb1: + br bb3(%0 : $C) + +bb2: + br bb3(%1 : $C) + +bb3(%arg : $C): + return %arg : $C +} + +sil @testInitializePointsToRedundant : $@convention(method) (@guaranteed C, @guaranteed C) -> () { +bb0(%0 : $C, %1 : $C): + %adr0 = ref_element_addr %0 : $C, #C.c + %val0 = load %adr0 : $*C + cond_br undef, bb1, bb2 + +bb1: + br bb3(%0 : $C) + +bb2: + br bb3(%0 : $C) + +bb3(%arg1 : $C): + br bb4 + +bb4: + cond_br undef, bb5, bb6 + +bb5: + br bb7(%1 : $C) + +bb6: + br bb7(%1 : $C) + +bb7(%arg2 : $C): + %f1 = function_ref @testInitializePointsToMerge : $@convention(method) (@guaranteed C, @guaranteed C) -> C + %call1 = apply %f1(%arg2, %1) : $@convention(method) (@guaranteed C, @guaranteed C) -> C + cond_br undef, bb8, bb9 + +bb8: + br bb10(%call1 : $C) + +bb9: + br bb10(%arg1 : $C) + +bb10(%arg3 : $C): + %66 = tuple () + return %66 : $() +} diff --git a/test/SILOptimizer/exclusivity_static_diagnostics.swift b/test/SILOptimizer/exclusivity_static_diagnostics.swift index 0a2b177b7b1d9..96afff273e1a5 100644 --- a/test/SILOptimizer/exclusivity_static_diagnostics.swift +++ b/test/SILOptimizer/exclusivity_static_diagnostics.swift @@ -1,10 +1,6 @@ // RUN: %target-swift-frontend -enforce-exclusivity=checked -swift-version 4 -emit-sil -primary-file %s -o /dev/null -verify // RUN: %target-swift-frontend -enforce-exclusivity=checked -swift-version 4 -emit-sil -primary-file %s -o /dev/null -verify -enable-ownership-stripping-after-serialization -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - import Swift func takesTwoInouts(_ p1: inout T, _ p2: inout T) { } diff --git a/test/SILOptimizer/exclusivity_static_diagnostics_objc.swift b/test/SILOptimizer/exclusivity_static_diagnostics_objc.swift index a896756bb3c0d..a2403ab2d67c9 100644 --- a/test/SILOptimizer/exclusivity_static_diagnostics_objc.swift +++ b/test/SILOptimizer/exclusivity_static_diagnostics_objc.swift @@ -2,10 +2,6 @@ // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -import-objc-header %S/Inputs/optional_closure_bridging.h -enforce-exclusivity=checked -swift-version 4 -emit-sil -primary-file %s -o /dev/null -verify -enable-ownership-stripping-after-serialization // REQUIRES: objc_interop -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - import Foundation class SomeClass { diff --git a/test/SILOptimizer/generalized_accessors.swift b/test/SILOptimizer/generalized_accessors.swift index 36c7715bf61a0..a0faa6159d7a8 100644 --- a/test/SILOptimizer/generalized_accessors.swift +++ b/test/SILOptimizer/generalized_accessors.swift @@ -3,10 +3,6 @@ // // Tests for yield-once diagnostics emitted for generalized accessors. -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - struct TestNoYield { var computed: Int { _read { diff --git a/test/SILOptimizer/infinite_recursion.swift b/test/SILOptimizer/infinite_recursion.swift index cf07919694c3f..00c1bd94b0178 100644 --- a/test/SILOptimizer/infinite_recursion.swift +++ b/test/SILOptimizer/infinite_recursion.swift @@ -1,10 +1,6 @@ // RUN: %target-swift-frontend -emit-sil -primary-file %s -o /dev/null -verify // RUN: %target-swift-frontend -emit-sil -primary-file %s -o /dev/null -verify -enable-ownership-stripping-after-serialization -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - func a() { // expected-warning {{all paths through this function will call itself}} a() } diff --git a/test/SILOptimizer/invalid_escaping_captures.swift b/test/SILOptimizer/invalid_escaping_captures.swift index 96883ea5e4cda..ae9ceb780ce3b 100644 --- a/test/SILOptimizer/invalid_escaping_captures.swift +++ b/test/SILOptimizer/invalid_escaping_captures.swift @@ -1,10 +1,6 @@ // RUN: %target-swift-frontend -emit-sil %s -verify // RUN: %target-swift-frontend -emit-sil %s -verify -enable-ownership-stripping-after-serialization -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - func takesEscaping(_: @escaping () -> ()) {} func takesNonEscaping(_ fn: () -> ()) { fn() } diff --git a/test/SILOptimizer/mandatory_inlining.swift b/test/SILOptimizer/mandatory_inlining.swift index 3409e42aad096..7867ce7baee4f 100644 --- a/test/SILOptimizer/mandatory_inlining.swift +++ b/test/SILOptimizer/mandatory_inlining.swift @@ -1,10 +1,6 @@ // RUN: %target-swift-frontend -sil-verify-all -primary-file %s -emit-sil -o - -verify | %FileCheck %s // RUN: %target-swift-frontend -sil-verify-all -primary-file %s -emit-sil -o - -verify -enable-ownership-stripping-after-serialization -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - // These tests are deliberately shallow, because I do not want to depend on the // specifics of SIL generation, which might change for reasons unrelated to this // pass diff --git a/test/SILOptimizer/noescape_param_exclusivity.swift b/test/SILOptimizer/noescape_param_exclusivity.swift index 9357626c9d540..ad7833937f279 100644 --- a/test/SILOptimizer/noescape_param_exclusivity.swift +++ b/test/SILOptimizer/noescape_param_exclusivity.swift @@ -1,10 +1,6 @@ // RUN: %target-swift-frontend -emit-sil %s -verify // RUN: %target-swift-frontend -emit-sil %s -verify -enable-ownership-stripping-after-serialization -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable test after SR-11336 is fixed. -// XFAIL: * - func test0(a: (() -> ()) -> (), b: () -> ()) { a(b) // expected-error {{passing a non-escaping function parameter 'b' to a call to a non-escaping function parameter can allow re-entrant modification of a variable}} } diff --git a/test/SILOptimizer/optionset.swift b/test/SILOptimizer/optionset.swift index 3be6ff165e7df..ba74ab1f561e9 100644 --- a/test/SILOptimizer/optionset.swift +++ b/test/SILOptimizer/optionset.swift @@ -16,7 +16,6 @@ public struct TestOptions: OptionSet { // CHECK-NEXT: bb0: // CHECK-NEXT: integer_literal {{.*}}, 15 // CHECK-NEXT: struct $Int -// CHECK-NEXT: debug_value // CHECK-NEXT: struct $TestOptions // CHECK-NEXT: return public func returnTestOptions() -> TestOptions { @@ -27,7 +26,6 @@ public func returnTestOptions() -> TestOptions { // CHECK-NEXT: global_addr // CHECK-NEXT: integer_literal {{.*}}, 15 // CHECK-NEXT: struct $Int -// CHECK-NEXT: debug_value // CHECK-NEXT: struct $TestOptions // CHECK-NEXT: store // CHECK-NEXT: tuple diff --git a/test/SILOptimizer/pound_assert.swift b/test/SILOptimizer/pound_assert.swift index a8ea5137bdfd2..acccdaf0e32b5 100644 --- a/test/SILOptimizer/pound_assert.swift +++ b/test/SILOptimizer/pound_assert.swift @@ -2,10 +2,6 @@ // RUN: %target-swift-frontend -enable-experimental-static-assert -enable-ownership-stripping-after-serialization -emit-sil %s -verify // REQUIRES: asserts -// SWIFT_ENABLE_TENSORFLOW -// TODO(TF-799): Re-enable RUN line after SR-11336 is fixed. -// XFAIL: * - //===----------------------------------------------------------------------===// // Basic function calls and control flow //===----------------------------------------------------------------------===// diff --git a/test/SILOptimizer/predictable_memaccess_opts.sil b/test/SILOptimizer/predictable_memaccess_opts.sil index f261e4a12b4ad..8fa9df6db1b1e 100644 --- a/test/SILOptimizer/predictable_memaccess_opts.sil +++ b/test/SILOptimizer/predictable_memaccess_opts.sil @@ -16,7 +16,17 @@ struct NativeObjectPair { var y: Builtin.NativeObject } -sil @guaranteed_object_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () +struct IntPair { + var x: Builtin.Int32 + var y: Builtin.Int32 +} + +sil @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () +sil @intpair_user : $@convention(thin) (IntPair) -> () +sil @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> () +sil @inout_int32_user : $@convention(thin) (@inout Builtin.Int32) -> () +sil @get_object : $@convention(thin) () -> @owned Builtin.NativeObject +sil @nativeobject_tuple_user : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> () /// Needed to avoid tuple scalarization code in the use gatherer. struct NativeObjectAndTuple { @@ -50,9 +60,11 @@ bb0(%0 : $Builtin.Int32): // CHECK: [[STACK:%.*]] = alloc_stack $Builtin.NativeObject // CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]] // CHECK: store [[ARG]] to [init] [[STACK]] +// CHECK: [[ARG_COPY_2:%.*]] = copy_value [[ARG_COPY]] +// CHECK: destroy_value [[ARG_COPY]] // CHECK: destroy_addr [[STACK]] // CHECK: dealloc_stack [[STACK]] -// CHECK: return [[ARG_COPY]] +// CHECK: return [[ARG_COPY_2]] // CHECK: } // end sil function 'simple_nontrivial_load_promotion' sil [ossa] @simple_nontrivial_load_promotion : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject { bb0(%0 : @owned $Builtin.NativeObject): @@ -73,10 +85,14 @@ bb0(%0 : @owned $Builtin.NativeObject): // CHECK: store [[ARG1]] to [init] [[FIRST_ADDR]] // CHECK: [[ARG2_COPY:%.*]] = copy_value [[ARG2]] // CHECK: store [[ARG2]] to [init] [[SECOND_ADDR]] -// CHECK: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY:%.*]] : $Builtin.NativeObject, [[ARG2_COPY:%.*]] : $Builtin.NativeObject) +// CHECK: [[ARG1_COPY_BORROW:%.*]] = begin_borrow [[ARG1_COPY]] +// CHECK: [[ARG2_COPY_BORROW:%.*]] = begin_borrow [[ARG2_COPY]] +// CHECK: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY_BORROW:%.*]] : $Builtin.NativeObject, [[ARG2_COPY_BORROW:%.*]] : $Builtin.NativeObject) +// CHECK: [[RESULT_COPY_1:%.*]] = copy_value [[RESULT]] +// CHECK: [[RESULT_COPY_2:%.*]] = copy_value [[RESULT_COPY_1]] // CHECK: destroy_addr [[STACK]] // CHECK: dealloc_stack [[STACK]] -// CHECK: return [[RESULT]] +// CHECK: return [[RESULT_COPY_2]] // CHECK: } // end sil function 'struct_nontrivial_load_promotion' sil [ossa] @struct_nontrivial_load_promotion : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned NativeObjectPair { bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject): @@ -134,9 +150,11 @@ bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject): // CHECK: br bb3([[ARG_COPY]] : // // CHECK: bb3([[RESULT:%.*]] : @owned $Builtin.NativeObject): +// CHECK: [[RESULT_COPY_1:%.*]] = copy_value [[RESULT]] +// CHECK: [[RESULT_COPY_2:%.*]] = copy_value [[RESULT_COPY_1]] // CHECK: destroy_addr [[STACK]] // CHECK: dealloc_stack [[STACK]] -// CHECK: return [[RESULT]] +// CHECK: return [[RESULT_COPY_2]] // CHECK: } // end sil function 'simple_nontrivial_load_promotion_multi_insertpt' sil [ossa] @simple_nontrivial_load_promotion_multi_insertpt : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject { bb0(%0 : @owned $Builtin.NativeObject): @@ -182,10 +200,16 @@ bb3: // CHECK: br bb3([[ARG1_COPY]] : $Builtin.NativeObject, [[ARG2_COPY]] : $Builtin.NativeObject) // // CHECK: bb3([[ARG1_COPY:%.*]] : @owned $Builtin.NativeObject, [[ARG2_COPY:%.*]] : @owned $Builtin.NativeObject): -// CHECK: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY:%.*]] : $Builtin.NativeObject, [[ARG2_COPY:%.*]] : $Builtin.NativeObject) +// CHECK: [[ARG1_COPY_COPY:%.*]] = copy_value [[ARG1_COPY]] +// CHECK: [[ARG2_COPY_COPY:%.*]] = copy_value [[ARG2_COPY]] +// CHECK: [[ARG1_COPY_COPY_BORROW:%.*]] = begin_borrow [[ARG1_COPY_COPY]] +// CHECK: [[ARG2_COPY_COPY_BORROW:%.*]] = begin_borrow [[ARG2_COPY_COPY]] +// CHECK: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY_COPY_BORROW:%.*]] : $Builtin.NativeObject, [[ARG2_COPY_COPY_BORROW:%.*]] : $Builtin.NativeObject) +// CHECK: [[RESULT_COPY:%.*]] = copy_value [[RESULT]] +// CHECK: [[RESULT_COPY_2:%.*]] = copy_value [[RESULT_COPY]] // CHECK: destroy_addr [[STACK]] // CHECK: dealloc_stack [[STACK]] -// CHECK: return [[RESULT]] +// CHECK: return [[RESULT_COPY_2]] // CHECK: } // end sil function 'struct_nontrivial_load_promotion_multi_insertpt' sil [ossa] @struct_nontrivial_load_promotion_multi_insertpt : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned NativeObjectPair { bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject): @@ -296,12 +320,17 @@ bb3: // CHECK: br bb3([[ARG1_COPY]] : $Builtin.NativeObject) // // CHECK: bb3([[ARG1_COPY:%.*]] : @owned $Builtin.NativeObject): +// CHECK: [[ARG1_COPY_COPY:%.*]] = copy_value [[ARG1_COPY]] // CHECK: [[SECOND_ADDR:%.*]] = struct_element_addr [[STACK]] // CHECK: [[SECOND_VAL_COPY:%.*]] = load [copy] [[SECOND_ADDR]] -// CHECK: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY:%.*]] : $Builtin.NativeObject, [[SECOND_VAL_COPY]] : $Builtin.NativeObject) +// CHECK: [[ARG1_COPY_COPY_BORROW:%.*]] = begin_borrow [[ARG1_COPY_COPY]] +// CHECK: [[SECOND_VAL_COPY_BORROW:%.*]] = begin_borrow [[SECOND_VAL_COPY]] +// CHECK: [[RESULT:%.*]] = struct $NativeObjectPair ([[ARG1_COPY_COPY_BORROW:%.*]] : $Builtin.NativeObject, [[SECOND_VAL_COPY_BORROW]] : $Builtin.NativeObject) +// CHECK: [[RESULT_COPY_1:%.*]] = copy_value [[RESULT]] +// CHECK: [[RESULT_COPY_2:%.*]] = copy_value [[RESULT_COPY_1]] // CHECK: destroy_addr [[STACK]] // CHECK: dealloc_stack [[STACK]] -// CHECK: return [[RESULT]] +// CHECK: return [[RESULT_COPY_2]] // CHECK: } // end sil function 'struct_nontrivial_load_promotion_multi_insertpt_value_not_fully_available' sil [ossa] @struct_nontrivial_load_promotion_multi_insertpt_value_not_fully_available : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned NativeObjectPair { bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject, %arg2 : @owned $Builtin.NativeObject): @@ -403,9 +432,11 @@ bb3: // CHECK: [[COPIED_ARG_FIELD:%.*]] = copy_value [[BORROWED_ARG_FIELD]] // CHECK: end_borrow [[BORROWED_ARG]] // CHECK: store [[ARG]] to [init] [[STACK]] +// CHECK: [[COPIED_ARG_FIELD_COPY_1:%.*]] = copy_value [[COPIED_ARG_FIELD]] +// CHECK: [[COPIED_ARG_FIELD_COPY_2:%.*]] = copy_value [[COPIED_ARG_FIELD_COPY_1]] // CHECK: destroy_addr [[STACK]] // CHECK: dealloc_stack [[STACK]] -// CHECK: return [[COPIED_ARG_FIELD]] +// CHECK: return [[COPIED_ARG_FIELD_COPY_2]] // CHECK: } // end sil function 'simple_partialstructuse_load_promotion' sil [ossa] @simple_partialstructuse_load_promotion : $@convention(thin) (@owned NativeObjectPair) -> (@owned Builtin.NativeObject) { bb0(%0 : @owned $NativeObjectPair): @@ -427,9 +458,11 @@ bb0(%0 : @owned $NativeObjectPair): // CHECK: [[COPIED_ARG_FIELD:%.*]] = copy_value [[BORROWED_ARG_FIELD_2]] // CHECK: end_borrow [[BORROWED_ARG]] // CHECK: store [[ARG]] to [init] [[STACK]] +// CHECK: [[COPIED_ARG_FIELD_COPY_1:%.*]] = copy_value [[COPIED_ARG_FIELD]] +// CHECK: [[COPIED_ARG_FIELD_COPY_2:%.*]] = copy_value [[COPIED_ARG_FIELD_COPY_1]] // CHECK: destroy_addr [[STACK]] // CHECK: dealloc_stack [[STACK]] -// CHECK: return [[COPIED_ARG_FIELD]] +// CHECK: return [[COPIED_ARG_FIELD_COPY_2]] // CHECK: } // end sil function 'simple_partialtupleuse_load_promotion' sil [ossa] @simple_partialtupleuse_load_promotion : $@convention(thin) (@owned NativeObjectAndTuple) -> (@owned Builtin.NativeObject) { bb0(%0 : @owned $NativeObjectAndTuple): @@ -449,9 +482,10 @@ bb0(%0 : @owned $NativeObjectAndTuple): // CHECK: store [[ARG0]] to [init] [[STACK]] // CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]] // CHECK: store [[ARG1]] to [assign] [[STACK]] +// CHECK: [[ARG1_COPY_1:%.*]] = copy_value [[ARG1_COPY]] // CHECK: destroy_addr [[STACK]] // CHECK: dealloc_stack [[STACK]] -// CHECK: return [[ARG1_COPY]] +// CHECK: return [[ARG1_COPY_1]] // CHECK: } // end sil function 'simple_assignstore' sil [ossa] @simple_assignstore : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> @owned Builtin.NativeObject { bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject): @@ -478,11 +512,15 @@ bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject): // // CHECK: bb1: // CHECK: destroy_value [[LHS1_COPY]] -// CHECK: br bb3([[LHS2_COPY]] : +// CHECK: [[LHS2_COPY_1:%.*]] = copy_value [[LHS2_COPY]] +// CHECK: [[LHS2_COPY_2:%.*]] = copy_value [[LHS2_COPY_1]] +// CHECK: br bb3([[LHS2_COPY_2]] : // // CHECK: bb2: // CHECK: destroy_value [[LHS2_COPY]] -// CHECK: br bb3([[LHS1_COPY]] : +// CHECK: [[LHS1_COPY_1:%.*]] = copy_value [[LHS1_COPY]] +// CHECK: [[LHS1_COPY_2:%.*]] = copy_value [[LHS1_COPY_1]] +// CHECK: br bb3([[LHS1_COPY_2]] : // // CHECK: bb3([[PHI:%.*]] : // CHECK: destroy_addr [[STACK]] @@ -538,13 +576,36 @@ bb0(%0 : @owned $Builtin.NativeObject): // CHECK-LABEL: sil [ossa] @load_borrow_promotion : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject { // CHECK: bb0([[ARG:%.*]] : +// Block where we have our store and do our lifetime extending copy_value. // CHECK: [[STACK:%.*]] = alloc_stack $Builtin.NativeObject // CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]] // CHECK: store [[ARG]] to [init] [[STACK]] -// CHECK: [[BORROWED_ARG_COPY:%.*]] = begin_borrow [[ARG_COPY]] +// CHECK: br bb1 +// +// Our load block. Here, we insert our copy_value + begin_borrow that is +// associated with the load_borrow. We can not use the original copy since even +// though in this situation we know that our copy/borrow would be strongly +// control equivalent, this is not always true. To simplify the algorithm, we +// always insert the copy here. We insert a destroy_value to end the lifetime of +// ARG_COPY since we do not have a loop here. +// +// CHECK: bb1: +// CHECK: [[CONTROL_EQUIVALENT_ARG_COPY:%.*]] = copy_value [[ARG_COPY]] +// CHECK: [[BORROWED_ARG_COPY:%.*]] = begin_borrow [[CONTROL_EQUIVALENT_ARG_COPY]] +// CHECK: destroy_value [[ARG_COPY]] +// CHECK: br bb2 +// +// The block where the load_borrow is actually used. We destroy the control +// equivalent arg copy here after the end_borrow. +// +// CHECK: bb2: // CHECK: [[RESULT:%.*]] = copy_value [[BORROWED_ARG_COPY]] // CHECK: end_borrow [[BORROWED_ARG_COPY]] -// CHECK: destroy_value [[ARG_COPY]] +// CHECK: destroy_value [[CONTROL_EQUIVALENT_ARG_COPY]] +// CHECK: br bb3 +// +// The block after the load_borrow is ever used. +// CHECK: bb3: // CHECK: destroy_addr [[STACK]] // CHECK: return [[RESULT]] // CHECK: } // end sil function 'load_borrow_promotion' @@ -552,9 +613,18 @@ sil [ossa] @load_borrow_promotion : $@convention(thin) (@owned Builtin.NativeObj bb0(%0 : @owned $Builtin.NativeObject): %1 = alloc_stack $Builtin.NativeObject store %0 to [init] %1 : $*Builtin.NativeObject + br bb1 + +bb1: %2 = load_borrow %1 : $*Builtin.NativeObject + br bb2 + +bb2: %3 = copy_value %2 : $Builtin.NativeObject end_borrow %2 : $Builtin.NativeObject + br bb3 + +bb3: destroy_addr %1 : $*Builtin.NativeObject dealloc_stack %1 : $*Builtin.NativeObject return %3 : $Builtin.NativeObject @@ -572,7 +642,7 @@ bb0(%0 : @owned $NativeObjectPair): bb2: %3 = load_borrow %2 : $*Builtin.NativeObject - %4 = function_ref @guaranteed_object_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + %4 = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () end_borrow %3 : $Builtin.NativeObject br bb2 @@ -590,7 +660,7 @@ bb0(%0 : @owned $NativeObjectPair): bb2: %3 = load_borrow %2 : $*Builtin.NativeObject - %4 = function_ref @guaranteed_object_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + %4 = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () end_borrow %3 : $Builtin.NativeObject cond_br undef, bb3, bb4 @@ -655,17 +725,21 @@ bb9: // CHECK: ([[TUP_0:%.*]], [[TUP_1:%.*]]) = destructure_tuple [[TUP]] // CHECK: [[TUP_0_COPY:%.*]] = copy_value [[TUP_0]] // CHECK: [[TUP_1_COPY:%.*]] = copy_value [[TUP_1]] -// CHECK: [[BORROWED_TUP_0_COPY:%.*]] = begin_borrow [[TUP_0_COPY]] -// CHECK: [[BORROWED_TUP_1_COPY:%.*]] = begin_borrow [[TUP_1_COPY]] +// CHECK: [[CONTROL_EQUIVALENT_TUP_0_COPY:%.*]] = copy_value [[TUP_0_COPY]] +// CHECK: [[BORROWED_TUP_0_COPY:%.*]] = begin_borrow [[CONTROL_EQUIVALENT_TUP_0_COPY]] +// CHECK: destroy_value [[TUP_0_COPY]] +// CHECK: [[CONTROL_EQUIVALENT_TUP_1_COPY:%.*]] = copy_value [[TUP_1_COPY]] +// CHECK: [[BORROWED_TUP_1_COPY:%.*]] = begin_borrow [[CONTROL_EQUIVALENT_TUP_1_COPY]] +// CHECK: destroy_value [[TUP_1_COPY]] // CHECK: [[BORROWED_TUP:%.*]] = tuple ([[BORROWED_TUP_0_COPY]] : ${{.*}}, [[BORROWED_TUP_1_COPY]] : // CHECK: [[TUP_EXT_1:%.*]] = tuple_extract [[BORROWED_TUP]] : // CHECK: [[TUP_EXT_2:%.*]] = tuple_extract [[BORROWED_TUP]] : // CHECK: apply {{%.*}}([[TUP_EXT_1]]) // CHECK: apply {{%.*}}([[TUP_EXT_2]]) // CHECK: end_borrow [[BORROWED_TUP_0_COPY]] -// CHECK: destroy_value [[TUP_0_COPY]] +// CHECK: destroy_value [[CONTROL_EQUIVALENT_TUP_0_COPY]] // CHECK: end_borrow [[BORROWED_TUP_1_COPY]] -// CHECK: destroy_value [[TUP_1_COPY]] +// CHECK: destroy_value [[CONTROL_EQUIVALENT_TUP_1_COPY]] // CHECK: } // end sil function 'load_borrow_tuple_scalarize' sil [canonical] [ossa] @load_borrow_tuple_scalarize : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject): @@ -676,7 +750,7 @@ bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject): %4 = load_borrow %2 : $*(Builtin.NativeObject, Builtin.NativeObject) %5 = tuple_extract %4 : $(Builtin.NativeObject, Builtin.NativeObject), 0 %6 = tuple_extract %4 : $(Builtin.NativeObject, Builtin.NativeObject), 1 - %7 = function_ref @guaranteed_object_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + %7 = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () apply %7(%5) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () apply %7(%6) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () end_borrow %4 : $(Builtin.NativeObject, Builtin.NativeObject) @@ -686,3 +760,1178 @@ bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject): %9999 = tuple() return %9999 : $() } + +// CHECK-LABEL: sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> () { +// CHECK: bb0( +// CHECK-NOT: load [trivial] %{{[0-9][0-9]*}} : $*IntPair +// CHECK-NOT: bb{{[0-9][0-9]*}}( +// CHECK: } // end sil function 'trivial_multiple_available_values_diamond_followed_by_loop_trivial' +sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> () { +bb0(%0a : $Builtin.Int32, %0b : $Builtin.Int32): + %func = function_ref @intpair_user : $@convention(thin) (IntPair) -> () + %1 = alloc_stack $IntPair + %1a = struct_element_addr %1 : $*IntPair, #IntPair.x + %1b = struct_element_addr %1 : $*IntPair, #IntPair.y + cond_br undef, bb1, bb2 + +bb1: + store %0a to [trivial] %1a : $*Builtin.Int32 + store %0b to [trivial] %1b : $*Builtin.Int32 + br bb3 + +bb2: + store %0a to [trivial] %1a : $*Builtin.Int32 + store %0b to [trivial] %1b : $*Builtin.Int32 + br bb3 + +bb3: + br bb4 + +bb4: + br bb5 + +bb5: + %2 = load [trivial] %1 : $*IntPair + cond_br undef, bb6, bb7 + +bb6: + apply %func(%2) : $@convention(thin) (IntPair) -> () + br bb5 + +bb7: + apply %func(%2) : $@convention(thin) (IntPair) -> () + dealloc_stack %1 : $*IntPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial_reload : $@convention(thin) (Builtin.Int32, Builtin.Int32, Builtin.Int32) -> () { +// CHECK: bb0( +// CHECK-NOT: load [trivial] %{{[0-9][0-9]*}} : $*IntPair +// CHECK-NOT: bb{{[0-9][0-9]*}}( +// CHECK: } // end sil function 'trivial_multiple_available_values_diamond_followed_by_loop_trivial_reload' +sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial_reload : $@convention(thin) (Builtin.Int32, Builtin.Int32, Builtin.Int32) -> () { +bb0(%0a : $Builtin.Int32, %0b : $Builtin.Int32, %0c : $Builtin.Int32): + %func = function_ref @intpair_user : $@convention(thin) (IntPair) -> () + %1 = alloc_stack $IntPair + %1a = struct_element_addr %1 : $*IntPair, #IntPair.x + %1b = struct_element_addr %1 : $*IntPair, #IntPair.y + cond_br undef, bb1, bb2 + +bb1: + store %0a to [trivial] %1a : $*Builtin.Int32 + store %0c to [trivial] %1b : $*Builtin.Int32 + br bb3 + +bb2: + store %0a to [trivial] %1a : $*Builtin.Int32 + store %0b to [trivial] %1b : $*Builtin.Int32 + br bb3 + +bb3: + br bb4 + +bb4: + br bb5 + +bb5: + %2 = load [trivial] %1 : $*IntPair + cond_br undef, bb6, bb7 + +bb6: + apply %func(%2) : $@convention(thin) (IntPair) -> () + br bb5 + +bb7: + apply %func(%2) : $@convention(thin) (IntPair) -> () + dealloc_stack %1 : $*IntPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial_store_in_loop : $@convention(thin) (Builtin.Int32, Builtin.Int32, Builtin.Int32) -> () { +// CHECK-NOT: load +// CHECK: } // end sil function 'trivial_multiple_available_values_diamond_followed_by_loop_trivial_store_in_loop' +sil [ossa] @trivial_multiple_available_values_diamond_followed_by_loop_trivial_store_in_loop : $@convention(thin) (Builtin.Int32, Builtin.Int32, Builtin.Int32) -> () { +bb0(%0a : $Builtin.Int32, %0b : $Builtin.Int32, %0c : $Builtin.Int32): + %func = function_ref @intpair_user : $@convention(thin) (IntPair) -> () + %1 = alloc_stack $IntPair + %1a = struct_element_addr %1 : $*IntPair, #IntPair.x + %1b = struct_element_addr %1 : $*IntPair, #IntPair.y + cond_br undef, bb1, bb2 + +bb1: + store %0a to [trivial] %1a : $*Builtin.Int32 + store %0b to [trivial] %1b : $*Builtin.Int32 + br bb3 + +bb2: + store %0a to [trivial] %1a : $*Builtin.Int32 + store %0b to [trivial] %1b : $*Builtin.Int32 + br bb3 + +bb3: + br bb4 + +bb4: + br bb5 + +bb5: + %2 = load [trivial] %1 : $*IntPair + cond_br undef, bb6, bb7 + +bb6: + apply %func(%2) : $@convention(thin) (IntPair) -> () + store %0b to [trivial] %1b : $*Builtin.Int32 + br bb5 + +bb7: + apply %func(%2) : $@convention(thin) (IntPair) -> () + dealloc_stack %1 : $*IntPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @multiple_available_values_diamond_followed_by_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { +// CHECK: bb0( +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'multiple_available_values_diamond_followed_by_loop' +sil [ossa] @multiple_available_values_diamond_followed_by_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { +bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject): + %func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> () + %1 = alloc_stack $NativeObjectPair + %1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x + %1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y + cond_br undef, bb1, bb2 + +bb1: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + br bb3 + +bb2: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + br bb3 + +bb3: + br bb4 + +bb4: + br bb5 + +bb5: + %2 = load_borrow %1 : $*NativeObjectPair + cond_br undef, bb6, bb7 + +bb6: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + end_borrow %2 : $NativeObjectPair + br bb5 + +bb7: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + end_borrow %2 : $NativeObjectPair + destroy_addr %1 : $*NativeObjectPair + dealloc_stack %1 : $*NativeObjectPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @multiple_available_values_diamond_followed_by_loop_reload : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'multiple_available_values_diamond_followed_by_loop_reload' +sil [ossa] @multiple_available_values_diamond_followed_by_loop_reload : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { +bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @owned $Builtin.NativeObject): + %func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> () + %1 = alloc_stack $NativeObjectPair + %1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x + %1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y + cond_br undef, bb1, bb2 + +bb1: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0c to [init] %1b : $*Builtin.NativeObject + destroy_value %0b : $Builtin.NativeObject + br bb3 + +bb2: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + destroy_value %0c : $Builtin.NativeObject + br bb3 + +bb3: + br bb4 + +bb4: + br bb5 + +bb5: + %2 = load_borrow %1 : $*NativeObjectPair + cond_br undef, bb6, bb7 + +bb6: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + end_borrow %2 : $NativeObjectPair + br bb5 + +bb7: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + end_borrow %2 : $NativeObjectPair + destroy_addr %1 : $*NativeObjectPair + dealloc_stack %1 : $*NativeObjectPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @multiple_available_values_diamond_followed_by_loop_store_in_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'multiple_available_values_diamond_followed_by_loop_store_in_loop' +sil [ossa] @multiple_available_values_diamond_followed_by_loop_store_in_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject): + %func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> () + %1 = alloc_stack $NativeObjectPair + %1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x + %1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y + %0bhat = copy_value %0b : $Builtin.NativeObject + cond_br undef, bb1, bb2 + +bb1: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + br bb3 + +bb2: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + br bb3 + +bb3: + br bb4 + +bb4: + br bb5 + +bb5: + %2 = load_borrow %1 : $*NativeObjectPair + cond_br undef, bb6, bb7 + +bb6: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + end_borrow %2 : $NativeObjectPair + destroy_addr %1b : $*Builtin.NativeObject + %0bhat2 = copy_value %0bhat : $Builtin.NativeObject + store %0bhat2 to [init] %1b : $*Builtin.NativeObject + br bb5 + +bb7: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + end_borrow %2 : $NativeObjectPair + destroy_value %0bhat : $Builtin.NativeObject + destroy_addr %1 : $*NativeObjectPair + dealloc_stack %1 : $*NativeObjectPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadborrow : $@convention(thin) (@owned Builtin.NativeObject) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'loop_carry_loadborrow' +sil [canonical] [ossa] @loop_carry_loadborrow : $@convention(thin) (@owned Builtin.NativeObject) -> () { +bb0(%0 : @owned $Builtin.NativeObject): + %func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + %1 = alloc_stack $Builtin.NativeObject + store %0 to [init] %1 : $*Builtin.NativeObject + cond_br undef, bb1, bb7 + +bb1: + br bb2 + +bb2: + br bb3 + +bb3: + %2 = load_borrow %1 : $*Builtin.NativeObject + cond_br undef, bb4, bb5 + +bb4: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + end_borrow %2 : $Builtin.NativeObject + br bb2 + +bb5: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + end_borrow %2 : $Builtin.NativeObject + br bb6 + +bb6: + br bb8 + +bb7: + br bb8 + +bb8: + destroy_addr %1 : $*Builtin.NativeObject + dealloc_stack %1 : $*Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadborrow_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'loop_carry_loadborrow_2' +sil [canonical] [ossa] @loop_carry_loadborrow_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () { +bb0(%0 : @owned $Builtin.NativeObject): + %func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + %1 = alloc_stack $Builtin.NativeObject + store %0 to [init] %1 : $*Builtin.NativeObject + cond_br undef, bb1, bb7 + +bb1: + br bb2 + +bb2: + br bb3 + +bb3: + %2 = load_borrow %1 : $*Builtin.NativeObject + cond_br undef, bb4, bb5 + +bb4: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + end_borrow %2 : $Builtin.NativeObject + br bb2 + +bb5: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + end_borrow %2 : $Builtin.NativeObject + br bb6 + +bb6: + br bb8 + +bb7: + br bb8 + +bb8: + destroy_addr %1 : $*Builtin.NativeObject + dealloc_stack %1 : $*Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadborrow_3 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'loop_carry_loadborrow_3' +sil [canonical] [ossa] @loop_carry_loadborrow_3 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject): + %func = function_ref @nativeobject_tuple_user : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> () + %1 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject) + %1a = tuple_element_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject), 0 + %1b = tuple_element_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject), 1 + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + cond_br undef, bb1, bb7 + +bb1: + br bb2 + +bb2: + br bb3 + +bb3: + %0ccopy = copy_value %0c : $Builtin.NativeObject + destroy_addr %1a : $*Builtin.NativeObject + store %0ccopy to [init] %1a : $*Builtin.NativeObject + %2 = load_borrow %1 : $*(Builtin.NativeObject, Builtin.NativeObject) + cond_br undef, bb4, bb5 + +bb4: + apply %func(%2) : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> () + end_borrow %2 : $(Builtin.NativeObject, Builtin.NativeObject) + br bb2 + +bb5: + apply %func(%2) : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> () + end_borrow %2 : $(Builtin.NativeObject, Builtin.NativeObject) + br bb6 + +bb6: + br bb8 + +bb7: + br bb8 + +bb8: + destroy_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject) + dealloc_stack %1 : $*(Builtin.NativeObject, Builtin.NativeObject) + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadborrow_4 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'loop_carry_loadborrow_4' +sil [canonical] [ossa] @loop_carry_loadborrow_4 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject): + %func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> () + %1 = alloc_stack $NativeObjectPair + %1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x + %1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + cond_br undef, bb1, bb7 + +bb1: + br bb2 + +bb2: + br bb3 + +bb3: + %0ccopy = copy_value %0c : $Builtin.NativeObject + destroy_addr %1a : $*Builtin.NativeObject + store %0ccopy to [init] %1a : $*Builtin.NativeObject + %2 = load_borrow %1 : $*NativeObjectPair + cond_br undef, bb4, bb5 + +bb4: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + end_borrow %2 : $NativeObjectPair + br bb2 + +bb5: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + end_borrow %2 : $NativeObjectPair + br bb6 + +bb6: + br bb8 + +bb7: + br bb8 + +bb8: + destroy_addr %1 : $*NativeObjectPair + dealloc_stack %1 : $*NativeObjectPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @loop_carry_load_borrow_phi_not_control_equivalent : $@convention(thin) (@owned Builtin.NativeObject) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'loop_carry_load_borrow_phi_not_control_equivalent' +sil [ossa] @loop_carry_load_borrow_phi_not_control_equivalent : $@convention(thin) (@owned Builtin.NativeObject) -> () { +bb0(%arg : @owned $Builtin.NativeObject): + %func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + %0 = alloc_stack $Builtin.NativeObject + cond_br undef, bb1, bb2 + +bb1: + cond_br undef, bb3, bb4 + +bb2: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb5 + +bb3: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb6 + +bb4: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb7 + +bb5: + br bb8 + +bb6: + br bb8 + +bb7: + br bbPreLoopHeader + +bb8: + br bbPreLoopHeader + +bbPreLoopHeader: + br bbLoop + +bbLoop: + br bbLoop1 + +bbLoop1: + br bbLoop2 + +bbLoop2: + %2 = load_borrow %0 : $*Builtin.NativeObject + cond_br undef, bbLoop3, bbLoop4 + +bbLoop3: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + end_borrow %2 : $Builtin.NativeObject + br bbLoop2 + +bbLoop4: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + end_borrow %2 : $Builtin.NativeObject + br bbEnd + +bbEnd: + destroy_addr %0 : $*Builtin.NativeObject + dealloc_stack %0 : $*Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// In this case, we will have that we need to separately lifetime extend our phi +// node's copy to prevent leaks along the edge skipping the loop. +// CHECK-LABEL: sil [ossa] @loop_carry_load_borrow_phi_not_control_equivalent_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'loop_carry_load_borrow_phi_not_control_equivalent_2' +sil [ossa] @loop_carry_load_borrow_phi_not_control_equivalent_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () { +bb0(%arg : @owned $Builtin.NativeObject): + %func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + %0 = alloc_stack $Builtin.NativeObject + cond_br undef, bb1, bb2 + +bb1: + cond_br undef, bb3, bb4 + +bb2: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb5 + +bb3: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb6 + +bb4: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb7 + +bb5: + br bb8a + +bb6: + br bb8a + +bb7: + br bbPreLoopHeader + +bb8a: + br bb8 + +bb8: + cond_br undef, bbPreLoopHeader1, bbSkipLoop + +bbPreLoopHeader: + br bbLoop + +bbPreLoopHeader1: + br bbLoop + +bbLoop: + br bbLoop1 + +bbLoop1: + br bbLoop2 + +bbLoop2: + %2 = load_borrow %0 : $*Builtin.NativeObject + br bbLoop6 + +bbLoop6: + cond_br undef, bbLoop3, bbLoop4 + +bbLoop3: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + end_borrow %2 : $Builtin.NativeObject + br bbLoop5 + +bbLoop5: + br bbLoop2 + +bbLoop4: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + end_borrow %2 : $Builtin.NativeObject + br bbEnd + +bbSkipLoop: + br bbEnd + +bbEnd: + destroy_addr %0 : $*Builtin.NativeObject + dealloc_stack %0 : $*Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +//--- + +// CHECK-LABEL: sil [ossa] @load_copy_promote_with_loop_1 : $@convention(thin) (@owned NativeObjectPair) -> () { +// CHECK-NOT: load_borrow +// CHECK: } // end sil function 'load_copy_promote_with_loop_1' +sil [ossa] @load_copy_promote_with_loop_1 : $@convention(thin) (@owned NativeObjectPair) -> () { +bb0(%0 : @owned $NativeObjectPair): + %1 = alloc_stack $NativeObjectPair + store %0 to [init] %1 : $*NativeObjectPair + %2 = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x + br bb2 + +bb2: + %3 = load [copy] %2 : $*Builtin.NativeObject + %4 = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + destroy_value %3 : $Builtin.NativeObject + br bb2 +} + +// CHECK-LABEL: sil [ossa] @load_copy_loop_promote_with_loop_2 : $@convention(thin) (@owned NativeObjectPair) -> () { +// CHECK-NOT: load [copy] +// CHECK: } // end sil function 'load_copy_loop_promote_with_loop_2' +sil [ossa] @load_copy_loop_promote_with_loop_2 : $@convention(thin) (@owned NativeObjectPair) -> () { +bb0(%0 : @owned $NativeObjectPair): + %1 = alloc_stack $NativeObjectPair + store %0 to [init] %1 : $*NativeObjectPair + %2 = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x + br bb2 + +bb2: + %3 = load [copy] %2 : $*Builtin.NativeObject + %4 = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + destroy_value %3 : $Builtin.NativeObject + cond_br undef, bb3, bb4 + +bb3: + br bb2 + +bb4: + destroy_addr %1 : $*NativeObjectPair + dealloc_stack %1 : $*NativeObjectPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @load_copy_promote_two_backedge_loop : $@convention(thin) (@owned Builtin.NativeObject) -> () { +// CHECK-NOT: load [copy] +// CHECK: } // end sil function 'load_copy_promote_two_backedge_loop' +sil [ossa] @load_copy_promote_two_backedge_loop : $@convention(thin) (@owned Builtin.NativeObject) -> () { +bb0(%0 : @owned $Builtin.NativeObject): + %1 = alloc_stack $Builtin.NativeObject + store %0 to [init] %1 : $*Builtin.NativeObject + br bb1 + +bb1: + br bb2 + +bb2: + cond_br undef, bb3, bb4 + +bb3: + %2 = load [copy] %1 : $*Builtin.NativeObject + destroy_value %2 : $Builtin.NativeObject + cond_br undef, bb5, bb6 + +bb4: + %3 = load [copy] %1 : $*Builtin.NativeObject + destroy_value %3 : $Builtin.NativeObject + cond_br undef, bb7, bb8 + +bb5: + br bb2 + +bb6: + br bb9 + +bb7: + br bb2 + +bb8: + br bb9 + +bb9: + destroy_addr %1 : $*Builtin.NativeObject + dealloc_stack %1 : $*Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { +// CHECK: bb0( +// CHECK-NOT: load [copy] +// CHECK: } // end sil function 'load_copy_multiple_available_values_diamond_followed_by_loop' +sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { +bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject): + %func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> () + %1 = alloc_stack $NativeObjectPair + %1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x + %1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y + cond_br undef, bb1, bb2 + +bb1: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + br bb3 + +bb2: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + br bb3 + +bb3: + br bb4 + +bb4: + br bb5 + +bb5: + %2 = load [copy] %1 : $*NativeObjectPair + cond_br undef, bb6, bb7 + +bb6: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + destroy_value %2 : $NativeObjectPair + br bb5 + +bb7: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + destroy_value %2 : $NativeObjectPair + destroy_addr %1 : $*NativeObjectPair + dealloc_stack %1 : $*NativeObjectPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop_reload : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { +// CHECK-NOT: load [copy] {{%.*}} : $*NativeObjectPair +// CHECK: } // end sil function 'load_copy_multiple_available_values_diamond_followed_by_loop_reload' +sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop_reload : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { +bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @owned $Builtin.NativeObject): + %func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> () + %1 = alloc_stack $NativeObjectPair + %1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x + %1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y + cond_br undef, bb1, bb2 + +bb1: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0c to [init] %1b : $*Builtin.NativeObject + destroy_value %0b : $Builtin.NativeObject + br bb3 + +bb2: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + destroy_value %0c : $Builtin.NativeObject + br bb3 + +bb3: + br bb4 + +bb4: + br bb5 + +bb5: + %2 = load [copy] %1 : $*NativeObjectPair + cond_br undef, bb6, bb7 + +bb6: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + destroy_value %2 : $NativeObjectPair + br bb5 + +bb7: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + destroy_value %2 : $NativeObjectPair + destroy_addr %1 : $*NativeObjectPair + dealloc_stack %1 : $*NativeObjectPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop_store_in_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +// CHECK-NOT: load [copy] {{%.*}} : $*NativeObjectPair +// CHECK: } // end sil function 'load_copy_multiple_available_values_diamond_followed_by_loop_store_in_loop' +sil [ossa] @load_copy_multiple_available_values_diamond_followed_by_loop_store_in_loop : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject): + %func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> () + %1 = alloc_stack $NativeObjectPair + %1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x + %1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y + %0bhat = copy_value %0b : $Builtin.NativeObject + cond_br undef, bb1, bb2 + +bb1: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + br bb3 + +bb2: + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + br bb3 + +bb3: + br bb4 + +bb4: + br bb5 + +bb5: + %2 = load [copy] %1 : $*NativeObjectPair + cond_br undef, bb6, bb7 + +bb6: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + destroy_value %2 : $NativeObjectPair + destroy_addr %1b : $*Builtin.NativeObject + %0bhat2 = copy_value %0bhat : $Builtin.NativeObject + store %0bhat2 to [init] %1b : $*Builtin.NativeObject + br bb5 + +bb7: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + destroy_value %2 : $NativeObjectPair + destroy_value %0bhat : $Builtin.NativeObject + destroy_addr %1 : $*NativeObjectPair + dealloc_stack %1 : $*NativeObjectPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadcopy : $@convention(thin) (@owned Builtin.NativeObject) -> () { +// CHECK-NOT: load [copy] +// CHECK: } // end sil function 'loop_carry_loadcopy' +sil [canonical] [ossa] @loop_carry_loadcopy : $@convention(thin) (@owned Builtin.NativeObject) -> () { +bb0(%0 : @owned $Builtin.NativeObject): + %func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + %1 = alloc_stack $Builtin.NativeObject + store %0 to [init] %1 : $*Builtin.NativeObject + cond_br undef, bb1, bb7 + +bb1: + br bb2 + +bb2: + br bb3 + +bb3: + %2 = load [copy] %1 : $*Builtin.NativeObject + cond_br undef, bb4, bb5 + +bb4: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + destroy_value %2 : $Builtin.NativeObject + br bb2 + +bb5: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + destroy_value %2 : $Builtin.NativeObject + br bb6 + +bb6: + br bb8 + +bb7: + br bb8 + +bb8: + destroy_addr %1 : $*Builtin.NativeObject + dealloc_stack %1 : $*Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadcopy_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () { +// CHECK-NOT: load [copy] +// CHECK: } // end sil function 'loop_carry_loadcopy_2' +sil [canonical] [ossa] @loop_carry_loadcopy_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () { +bb0(%0 : @owned $Builtin.NativeObject): + %func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + %1 = alloc_stack $Builtin.NativeObject + store %0 to [init] %1 : $*Builtin.NativeObject + cond_br undef, bb1, bb7 + +bb1: + br bb2 + +bb2: + br bb3 + +bb3: + %2 = load [copy] %1 : $*Builtin.NativeObject + cond_br undef, bb4, bb5 + +bb4: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + destroy_value %2 : $Builtin.NativeObject + br bb2 + +bb5: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + destroy_value %2 : $Builtin.NativeObject + br bb6 + +bb6: + br bb8 + +bb7: + br bb8 + +bb8: + destroy_addr %1 : $*Builtin.NativeObject + dealloc_stack %1 : $*Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadcopy_3 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +// CHECK-NOT: load [copy] +// CHECK: } // end sil function 'loop_carry_loadcopy_3' +sil [canonical] [ossa] @loop_carry_loadcopy_3 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject): + %func = function_ref @nativeobject_tuple_user : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> () + %1 = alloc_stack $(Builtin.NativeObject, Builtin.NativeObject) + %1a = tuple_element_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject), 0 + %1b = tuple_element_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject), 1 + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + cond_br undef, bb1, bb7 + +bb1: + br bb2 + +bb2: + br bb3 + +bb3: + %0ccopy = copy_value %0c : $Builtin.NativeObject + destroy_addr %1a : $*Builtin.NativeObject + store %0ccopy to [init] %1a : $*Builtin.NativeObject + %2 = load [copy] %1 : $*(Builtin.NativeObject, Builtin.NativeObject) + cond_br undef, bb4, bb5 + +bb4: + apply %func(%2) : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> () + destroy_value %2 : $(Builtin.NativeObject, Builtin.NativeObject) + br bb2 + +bb5: + apply %func(%2) : $@convention(thin) (@guaranteed (Builtin.NativeObject, Builtin.NativeObject)) -> () + destroy_value %2 : $(Builtin.NativeObject, Builtin.NativeObject) + br bb6 + +bb6: + br bb8 + +bb7: + br bb8 + +bb8: + destroy_addr %1 : $*(Builtin.NativeObject, Builtin.NativeObject) + dealloc_stack %1 : $*(Builtin.NativeObject, Builtin.NativeObject) + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [canonical] [ossa] @loop_carry_loadcopy_4 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +// CHECK-NOT: load [copy] +// CHECK: } // end sil function 'loop_carry_loadcopy_4' +sil [canonical] [ossa] @loop_carry_loadcopy_4 : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { +bb0(%0a : @owned $Builtin.NativeObject, %0b : @owned $Builtin.NativeObject, %0c : @guaranteed $Builtin.NativeObject): + %func = function_ref @nativeobjectpair_user : $@convention(thin) (@guaranteed NativeObjectPair) -> () + %1 = alloc_stack $NativeObjectPair + %1a = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.x + %1b = struct_element_addr %1 : $*NativeObjectPair, #NativeObjectPair.y + store %0a to [init] %1a : $*Builtin.NativeObject + store %0b to [init] %1b : $*Builtin.NativeObject + cond_br undef, bb1, bb7 + +bb1: + br bb2 + +bb2: + br bb3 + +bb3: + %0ccopy = copy_value %0c : $Builtin.NativeObject + destroy_addr %1a : $*Builtin.NativeObject + store %0ccopy to [init] %1a : $*Builtin.NativeObject + %2 = load [copy] %1 : $*NativeObjectPair + cond_br undef, bb4, bb5 + +bb4: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + destroy_value %2 : $NativeObjectPair + br bb2 + +bb5: + apply %func(%2) : $@convention(thin) (@guaranteed NativeObjectPair) -> () + destroy_value %2 : $NativeObjectPair + br bb6 + +bb6: + br bb8 + +bb7: + br bb8 + +bb8: + destroy_addr %1 : $*NativeObjectPair + dealloc_stack %1 : $*NativeObjectPair + %9999 = tuple() + return %9999 : $() +} + +// CHECK-LABEL: sil [ossa] @load_copy_loop_carry_load_copy_phi_not_control_equivalent : $@convention(thin) (@owned Builtin.NativeObject) -> () { +// CHECK-NOT: load [copy] +// CHECK: } // end sil function 'load_copy_loop_carry_load_copy_phi_not_control_equivalent' +sil [ossa] @load_copy_loop_carry_load_copy_phi_not_control_equivalent : $@convention(thin) (@owned Builtin.NativeObject) -> () { +bb0(%arg : @owned $Builtin.NativeObject): + %func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + %0 = alloc_stack $Builtin.NativeObject + cond_br undef, bb1, bb2 + +bb1: + cond_br undef, bb3, bb4 + +bb2: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb5 + +bb3: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb6 + +bb4: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb7 + +bb5: + br bb8 + +bb6: + br bb8 + +bb7: + br bbPreLoopHeader + +bb8: + br bbPreLoopHeader + +bbPreLoopHeader: + br bbLoop + +bbLoop: + br bbLoop1 + +bbLoop1: + br bbLoop2 + +bbLoop2: + %2 = load [copy] %0 : $*Builtin.NativeObject + cond_br undef, bbLoop3, bbLoop4 + +bbLoop3: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + destroy_value %2 : $Builtin.NativeObject + br bbLoop2 + +bbLoop4: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + destroy_value %2 : $Builtin.NativeObject + br bbEnd + +bbEnd: + destroy_addr %0 : $*Builtin.NativeObject + dealloc_stack %0 : $*Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + +// In this case, we will have that we need to separately lifetime extend our phi +// node's copy to prevent leaks along the edge skipping the loop. +// CHECK-LABEL: sil [ossa] @load_copy_loop_carry_load_copy_phi_not_control_equivalent_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () { +// CHECK-NOT: load [copy] +// CHECK: } // end sil function 'load_copy_loop_carry_load_copy_phi_not_control_equivalent_2' +sil [ossa] @load_copy_loop_carry_load_copy_phi_not_control_equivalent_2 : $@convention(thin) (@owned Builtin.NativeObject) -> () { +bb0(%arg : @owned $Builtin.NativeObject): + %func = function_ref @nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + %0 = alloc_stack $Builtin.NativeObject + cond_br undef, bb1, bb2 + +bb1: + cond_br undef, bb3, bb4 + +bb2: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb5 + +bb3: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb6 + +bb4: + store %arg to [init] %0 : $*Builtin.NativeObject + br bb7 + +bb5: + br bb8a + +bb6: + br bb8a + +bb7: + br bbPreLoopHeader + +bb8a: + br bb8 + +bb8: + cond_br undef, bbPreLoopHeader1, bbSkipLoop + +bbPreLoopHeader: + br bbLoop + +bbPreLoopHeader1: + br bbLoop + +bbLoop: + br bbLoop1 + +bbLoop1: + br bbLoop2 + +bbLoop2: + %2 = load [copy] %0 : $*Builtin.NativeObject + br bbLoop6 + +bbLoop6: + cond_br undef, bbLoop3, bbLoop4 + +bbLoop3: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + destroy_value %2 : $Builtin.NativeObject + br bbLoop5 + +bbLoop5: + br bbLoop2 + +bbLoop4: + apply %func(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () + destroy_value %2 : $Builtin.NativeObject + br bbEnd + +bbSkipLoop: + br bbEnd + +bbEnd: + destroy_addr %0 : $*Builtin.NativeObject + dealloc_stack %0 : $*Builtin.NativeObject + %9999 = tuple() + return %9999 : $() +} + diff --git a/test/SILOptimizer/predictable_memopt_ownership.sil b/test/SILOptimizer/predictable_memopt_ownership.sil index ebb893ac4b803..e18ace13123ac 100644 --- a/test/SILOptimizer/predictable_memopt_ownership.sil +++ b/test/SILOptimizer/predictable_memopt_ownership.sil @@ -211,8 +211,12 @@ bb0(%0 : @owned $ContainsNativeObject): // CHECK: [[f3:%.*]] = struct_extract [[BORROWED_ARG]] : $ComplexStruct, #ComplexStruct.f1 // CHECK: [[f3_copy:%.*]] = copy_value [[f3]] // CHECK: end_borrow [[BORROWED_ARG]] +// CHECK: [[f3_copy_1:%.*]] = copy_value [[f3_copy]] +// CHECK: [[f3_copy_2:%.*]] = copy_value [[f3_copy_1]] +// CHECK: [[f2_x_copy_1:%.*]] = copy_value [[f2_x_copy]] +// CHECK: [[f2_x_copy_2:%.*]] = copy_value [[f2_x_copy_1]] // CHECK: destroy_value [[ARG]] -// CHECK: [[RESULT:%.*]] = tuple ([[f3_copy]] : $Builtin.NativeObject, [[f2_x_copy]] : $Builtin.NativeObject, [[f1]] : $Builtin.Int32) +// CHECK: [[RESULT:%.*]] = tuple ([[f3_copy_2]] : $Builtin.NativeObject, [[f2_x_copy_2]] : $Builtin.NativeObject, [[f1]] : $Builtin.Int32) // CHECK: return [[RESULT]] // CHECK: } // end sil function 'multiple_level_extract_2' sil [ossa] @multiple_level_extract_2 : $@convention(thin) (@owned ComplexStruct) -> (@owned Builtin.NativeObject, @owned Builtin.NativeObject, Builtin.Int32) { @@ -559,11 +563,15 @@ bb3: // // CHECK: bb1: // CHECK: destroy_value [[LHS1_COPY]] -// CHECK: br bb3([[LHS2_COPY]] : +// CHECK: [[LHS2_COPY_1:%.*]] = copy_value [[LHS2_COPY]] +// CHECK: [[LHS2_COPY_2:%.*]] = copy_value [[LHS2_COPY_1]] +// CHECK: br bb3([[LHS2_COPY_2]] : // // CHECK: bb2: // CHECK: destroy_value [[LHS2_COPY]] : $Builtin.NativeObject -// CHECK: br bb3([[LHS1_COPY]] : +// CHECK: [[LHS1_COPY_1:%.*]] = copy_value [[LHS1_COPY]] +// CHECK: [[LHS1_COPY_2:%.*]] = copy_value [[LHS1_COPY_1]] +// CHECK: br bb3([[LHS1_COPY_2]] : // // CHECK: bb3([[PHI:%.*]] : // CHECK: destroy_value [[ARG]] @@ -649,9 +657,11 @@ struct NativeObjectTriple { // CHECK-NEXT: br bb3([[PAIR_LHS_COPY]] : // // CHECK: bb3([[PHI:%.*]] : @owned $Builtin.NativeObject): -// CHECK-NEXT: [[REFORMED:%.*]] = struct $NativeObjectTriple ([[ARG0]] : {{.*}}, [[ARG1]] : {{.*}}) -// CHECK-NEXT: destroy_value [[REFORMED]] -// CHECK-NEXT: return [[PHI]] +// CHECK: [[PHI_COPY_1:%.*]] = copy_value [[PHI]] +// CHECK: [[PHI_COPY_2:%.*]] = copy_value [[PHI_COPY_1]] +// CHECK: [[REFORMED:%.*]] = struct $NativeObjectTriple ([[ARG0]] : {{.*}}, [[ARG1]] : {{.*}}) +// CHECK: destroy_value [[REFORMED]] +// CHECK: return [[PHI_COPY_2]] // CHECK: } // end sil function 'diamond_test_4' sil [ossa] @diamond_test_4 : $@convention(thin) (@owned Builtin.NativeObject, @owned NativeObjectPair) -> @owned Builtin.NativeObject { bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $NativeObjectPair): @@ -710,9 +720,14 @@ bb3: // CHECK: bb4: // CHECK: [[TRIPLE_RHS_LHS:%.*]] = struct_element_addr [[TRIPLE_RHS]] : $*NativeObjectPair, #NativeObjectPair.x // CHECK: [[TRIPLE_RHS_LHS_VAL:%.*]] = load [copy] [[TRIPLE_RHS_LHS]] : $*Builtin.NativeObject -// CHECK: [[STRUCT:%.*]] = struct $NativeObjectPair ([[TRIPLE_RHS_LHS_VAL]] : {{.*}}, [[TRIPLE_RHS_RHS_VAL]] : {{.*}}) +// CHECK: [[TRIPLE_RHS_RHS_VAL_COPY:%.*]] = copy_value [[TRIPLE_RHS_RHS_VAL]] +// CHECK: [[TRIPLE_RHS_LHS_VAL_BORROW:%.*]] = begin_borrow [[TRIPLE_RHS_LHS_VAL]] +// CHECK: [[TRIPLE_RHS_RHS_VAL_COPY_BORROW:%.*]] = begin_borrow [[TRIPLE_RHS_RHS_VAL_COPY]] +// CHECK: [[STRUCT:%.*]] = struct $NativeObjectPair ([[TRIPLE_RHS_LHS_VAL_BORROW]] : {{.*}}, [[TRIPLE_RHS_RHS_VAL_COPY_BORROW]] : {{.*}}) +// CHECK: [[STRUCT_COPY:%.*]] = copy_value [[STRUCT]] +// CHECK: [[STRUCT_COPY_2:%.*]] = copy_value [[STRUCT_COPY]] // CHECK: destroy_addr [[BOX]] -// CHECK: return [[STRUCT]] +// CHECK: return [[STRUCT_COPY_2]] // CHECK: } // end sil function 'diamond_test_5' sil [ossa] @diamond_test_5 : $@convention(thin) (@owned Builtin.NativeObject, @owned NativeObjectPair, @owned Builtin.NativeObject) -> @owned NativeObjectPair { bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $NativeObjectPair, %arg2 : @owned $Builtin.NativeObject): @@ -758,10 +773,14 @@ bb4: // CHECK: cond_br undef, [[CRITEDGE_BREAK_BB_1:bb[0-9]+]], [[CRITEDGE_BREAK_BB_2:bb[0-9]+]] // // CHECK: [[CRITEDGE_BREAK_BB_1]]: -// CHECK-NEXT: br [[SUCC_2:bb[0-9]+]]([[TRIPLE_RHS_RHS_VAL]] : +// CHECK-NEXT: [[TRIPLE_RHS_RHS_VAL_COPY:%.*]] = copy_value [[TRIPLE_RHS_RHS_VAL]] +// CHECK-NEXT: destroy_value [[TRIPLE_RHS_RHS_VAL]] +// CHECK-NEXT: br [[SUCC_2:bb[0-9]+]]([[TRIPLE_RHS_RHS_VAL_COPY]] : // // CHECK: [[CRITEDGE_BREAK_BB_2]]: -// CHECK-NEXT: br [[SUCC_1:bb[0-9]+]]([[TRIPLE_RHS_RHS_VAL]] : +// CHECK-NEXT: [[TRIPLE_RHS_RHS_VAL_COPY:%.*]] = copy_value [[TRIPLE_RHS_RHS_VAL]] +// CHECK-NEXT: destroy_value [[TRIPLE_RHS_RHS_VAL]] +// CHECK-NEXT: br [[SUCC_1:bb[0-9]+]]([[TRIPLE_RHS_RHS_VAL_COPY]] : // // CHECK: [[FALSE_BB]]: // CHECK: [[TRIPLE_LHS:%.*]] = struct_element_addr [[BOX]] : $*NativeObjectTriple, #NativeObjectTriple.f1 @@ -774,10 +793,14 @@ bb4: // CHECK: cond_br undef, [[CRITEDGE_BREAK_BB_1:bb[0-9]+]], [[CRITEDGE_BREAK_BB_2:bb[0-9]+]] // // CHECK: [[CRITEDGE_BREAK_BB_1]]: -// CHECK-NEXT: br [[SUCC_2]]([[TRIPLE_RHS_RHS_VAL]] : +// CHECK-NEXT: [[TRIPLE_RHS_RHS_VAL_COPY:%.*]] = copy_value [[TRIPLE_RHS_RHS_VAL]] +// CHECK-NEXT: destroy_value [[TRIPLE_RHS_RHS_VAL]] +// CHECK-NEXT: br [[SUCC_2]]([[TRIPLE_RHS_RHS_VAL_COPY]] : // // CHECK: [[CRITEDGE_BREAK_BB_2]]: -// CHECK-NEXT: br [[SUCC_1]]([[TRIPLE_RHS_RHS_VAL]] : +// CHECK-NEXT: [[TRIPLE_RHS_RHS_VAL_COPY:%.*]] = copy_value [[TRIPLE_RHS_RHS_VAL]] +// CHECK-NEXT: destroy_value [[TRIPLE_RHS_RHS_VAL]] +// CHECK-NEXT: br [[SUCC_1]]([[TRIPLE_RHS_RHS_VAL_COPY]] : // // CHECK: [[SUCC_2]]([[PHI1:%.*]] : @owned $Builtin.NativeObject): // CHECK: [[TRIPLE_RHS:%.*]] = struct_element_addr [[BOX]] : $*NativeObjectTriple, #NativeObjectTriple.f2 @@ -786,15 +809,21 @@ bb4: // CHECK: br [[EXIT_BB:bb[0-9]+]]([[PHI1:%.*]] : $Builtin.NativeObject) // // CHECK: [[SUCC_1]]([[PHI:%.*]] : @owned $Builtin.NativeObject): -// CHECK: br [[EXIT_BB]]([[PHI]] : {{.*}}) +// CHECK: [[PHI_COPY:%.*]] = copy_value [[PHI]] +// CHECK: br [[EXIT_BB]]([[PHI_COPY]] : {{.*}}) // // CHECK: [[EXIT_BB]]([[PHI:%.*]] : @owned $Builtin.NativeObject): // CHECK: [[TRIPLE_RHS:%.*]] = struct_element_addr [[BOX]] : $*NativeObjectTriple, #NativeObjectTriple.f2 // CHECK: [[TRIPLE_RHS_LHS:%.*]] = struct_element_addr [[TRIPLE_RHS]] : $*NativeObjectPair, #NativeObjectPair.x // CHECK: [[TRIPLE_RHS_LHS_VAL:%.*]] = load [copy] [[TRIPLE_RHS_LHS]] : $*Builtin.NativeObject -// CHECK: [[STRUCT:%.*]] = struct $NativeObjectPair ([[TRIPLE_RHS_LHS_VAL]] : {{.*}}, [[PHI]] : {{.*}}) +// CHECK: [[PHI_COPY:%.*]] = copy_value [[PHI]] +// CHECK: [[TRIPLE_RHS_LHS_VAL_BORROW:%.*]] = begin_borrow [[TRIPLE_RHS_LHS_VAL]] +// CHECK: [[PHI_COPY_BORROW:%.*]] = begin_borrow [[PHI_COPY]] +// CHECK: [[STRUCT:%.*]] = struct $NativeObjectPair ([[TRIPLE_RHS_LHS_VAL_BORROW]] : {{.*}}, [[PHI_COPY_BORROW]] : {{.*}}) +// CHECK: [[STRUCT_COPY_1:%.*]] = copy_value [[STRUCT]] +// CHECK: [[STRUCT_COPY_2:%.*]] = copy_value [[STRUCT_COPY_1]] // CHECK: destroy_addr [[BOX]] -// CHECK: return [[STRUCT]] +// CHECK: return [[STRUCT_COPY_2]] // CHECK: } // end sil function 'diamond_test_6' sil [ossa] @diamond_test_6 : $@convention(thin) (@owned Builtin.NativeObject, @owned NativeObjectPair, @owned Builtin.NativeObject) -> @owned NativeObjectPair { bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $NativeObjectPair, %arg2 : @owned $Builtin.NativeObject): diff --git a/test/SILOptimizer/semantic-arc-opts.sil b/test/SILOptimizer/semantic-arc-opts.sil index e05cb475e7966..9842a6c65d9a3 100644 --- a/test/SILOptimizer/semantic-arc-opts.sil +++ b/test/SILOptimizer/semantic-arc-opts.sil @@ -824,8 +824,8 @@ bb0: unreachable } -// Make sure we do perform the optimization if our borrowed value is an -// argument. +// Make sure that since we have a guaranteed argument and do not need to reason +// about end_borrows, we handle this. // // CHECK-LABEL: sil [ossa] @guaranteed_arg_used_by_postdominating_no_return_function : $@convention(thin) (@guaranteed NativeObjectPair) -> MyNever { // CHECK-NOT: copy_value @@ -839,6 +839,23 @@ bb0(%0 : @guaranteed $NativeObjectPair): unreachable } + +// Make sure that since our borrow introducer is a begin_borrow, we do not +// eliminate the copy. +// +// CHECK-LABEL: sil [ossa] @borrowed_val_used_by_postdominating_no_return_function : $@convention(thin) (@owned NativeObjectPair) -> MyNever { +// CHECK: copy_value +// CHECK: } // end sil function 'borrowed_val_used_by_postdominating_no_return_function' +sil [ossa] @borrowed_val_used_by_postdominating_no_return_function : $@convention(thin) (@owned NativeObjectPair) -> MyNever { +bb0(%0 : @owned $NativeObjectPair): + %1 = begin_borrow %0 : $NativeObjectPair + %2 = struct_extract %1 : $NativeObjectPair, #NativeObjectPair.obj1 + %3 = copy_value %2 : $Builtin.NativeObject + %func = function_ref @unreachable_guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever + apply %func(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever + unreachable +} + // Just make sure that we do not crash on this. We should be able to eliminate // everything here. // @@ -855,4 +872,31 @@ bb0(%0 : @guaranteed $NativeObjectPair): destroy_value %2 : $Builtin.NativeObject %9999 = tuple() return %9999 : $() -} \ No newline at end of file +} + +// Just make sure we do not crash here. +// +// CHECK-LABEL: sil [ossa] @do_not_insert_end_borrow_given_deadend : $@convention(thin) (@guaranteed ClassLet) -> () { +// CHECK: copy_value +// CHECK: } // end sil function 'do_not_insert_end_borrow_given_deadend' +sil [ossa] @do_not_insert_end_borrow_given_deadend : $@convention(thin) (@guaranteed ClassLet) -> () { +bb0(%x : @guaranteed $ClassLet): + %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () + %p = ref_element_addr %x : $ClassLet, #ClassLet.aLet + %v = load_borrow %p : $*Klass + %c = copy_value %v : $Klass + end_borrow %v : $Klass + apply %f(%c) : $@convention(thin) (@guaranteed Klass) -> () + cond_br undef, bb1, bb2 + +bb1: + destroy_value %c : $Klass + br bb3 + +bb2: + destroy_value %c : $Klass + br bb3 + +bb3: + unreachable +} diff --git a/test/SILOptimizer/simplify_cfg_address_phi.sil b/test/SILOptimizer/simplify_cfg_address_phi.sil index 438ee2cbdf246..923ff8ba4a6cb 100644 --- a/test/SILOptimizer/simplify_cfg_address_phi.sil +++ b/test/SILOptimizer/simplify_cfg_address_phi.sil @@ -134,3 +134,118 @@ bb4: bb5: return %val : $Builtin.Int32 } + +// Test that debug_value_addr is not unnecessarilly lost during address projection sinking. +public class CC { + let r : R + init(_ _r: R) { r = _r } +} + +sil @useAny : $@convention(thin) (@in_guaranteed V) -> () + +// CHECK-LABEL: sil @testDebugValue : $@convention(method) (@in_guaranteed S, @guaranteed CC, Bool) -> () { +// CHECK: debug_value_addr %0 : $*S, let, name "u" +// CHECK: apply %{{.*}}(%0) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () +// CHECK: [[FIELD:%.*]] = ref_element_addr %1 : $CC, #CC.r +// CHECK: debug_value_addr [[FIELD]] : $*R, let, name "u" +// CHECK: apply %10([[FIELD]]) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () +// CHECK-LABEL: } // end sil function 'testDebugValue' +sil @testDebugValue : $@convention(method) (@in_guaranteed S, @guaranteed CC, Bool) -> () { +bb0(%0 : $*S, %1 : $CC, %2 : $Bool): + %bool = struct_extract %2 : $Bool, #Bool._value + cond_br %bool, bb1, bb2 + +bb1: + debug_value_addr %0 : $*S, let, name "u" + %f1 = function_ref @useAny : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () + %call1 = apply %f1(%0) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () + br bb2 + +bb2: + %field = ref_element_addr %1 : $CC, #CC.r + debug_value_addr %field : $*R, let, name "t" + cond_br %bool, bb3, bb4 + +bb3: + debug_value_addr %field : $*R, let, name "u" + %f2 = function_ref @useAny : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () + %call2 = apply %f2(%field) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () + br bb4 + +bb4: + %z = tuple () + return %z : $() +} + +// Test multiple uses and cloned allocation. +// +// project_box and struct_extract_addr will be sunk into three +// different blocks, but only once per block. +struct S { + @_hasStorage @_hasInitialValue var x: Int { get set } + init(x: Int = 0) + init() +} +sil @doNothing : $@convention(thin) (@inout Int) -> () + +// CHECK-LABEL: sil @testMultiUse : $@convention(method) (Bool, @inout Int) -> () { +// CHECK: bb0(%0 : $Bool, %1 : $*Int): +// CHECK: cond_br %{{.*}}, bb2, bb1 +// CHECK: bb1: +// CHECK: [[ALLOC1:%.*]] = alloc_box ${ var S }, var, name "s" +// CHECK: [[PROJ1:%.*]] = project_box [[ALLOC1]] : ${ var S }, 0 +// CHECK: [[ADR1:%.*]] = struct_element_addr [[PROJ1]] : $*S, #S.x +// CHECK: store %{{.*}} to [[ADR1]] : $*Int +// CHECK: br bb3([[ALLOC1]] : ${ var S }) +// CHECK: bb2: +// CHECK: apply %{{.*}}(%1) : $@convention(thin) (@inout Int) -> () +// CHECK: [[ALLOC2:%.*]] = alloc_box ${ var S }, var, name "s" +// CHECK: [[PROJ2:%.*]] = project_box [[ALLOC2]] : ${ var S }, 0 +// CHECK: [[ADR2:%.*]] = struct_element_addr [[PROJ2]] : $*S, #S.x +// CHECK: store %{{.*}} to [[ADR2]] : $*Int +// CHECK: apply %{{.*}}([[ADR2]]) : $@convention(thin) (@inout Int) -> () +// CHECK: br bb3([[ALLOC2]] : ${ var S }) +// CHECK: bb3([[BOXARG:%.*]] : ${ var S }): +// CHECK: [[PROJ3:%.*]] = project_box [[BOXARG]] : ${ var S }, 0 +// CHECK: [[ADR3:%.*]] = struct_element_addr [[PROJ3]] : $*S, #S.x +// CHECK: apply %{{.*}}([[ADR3]]) : $@convention(thin) (@inout Int) -> () +// CHECK: release_value [[BOXARG]] : ${ var S } +// CHECK-LABEL: } // end sil function 'testMultiUse' +sil @testMultiUse : $@convention(method) (Bool, @inout Int) -> () { +bb0(%0 : $Bool, %1 : $*Int): + %bool = struct_extract %0 : $Bool, #Bool._value + cond_br %bool, bb1, bb2 + +bb1: + %f1 = function_ref @doNothing : $@convention(thin) (@inout Int) -> () + %call1 = apply %f1(%1) : $@convention(thin) (@inout Int) -> () + br bb3 + +bb2: + br bb3 + +bb3: + %box3 = alloc_box ${ var S }, var, name "s" + %proj3 = project_box %box3 : ${ var S }, 0 + %adr3 = struct_element_addr %proj3 : $*S, #S.x + cond_br %bool, bb4, bb5 + +bb4: + %i4 = load %1 : $*Int + store %i4 to %adr3 : $*Int + %f2 = function_ref @doNothing : $@convention(thin) (@inout Int) -> () + %call2 = apply %f2(%adr3) : $@convention(thin) (@inout Int) -> () + br bb6 + +bb5: + %i5 = load %1 : $*Int + store %i5 to %adr3 : $*Int + br bb6 + +bb6: + %f6 = function_ref @doNothing : $@convention(thin) (@inout Int) -> () + %call6 = apply %f6(%adr3) : $@convention(thin) (@inout Int) -> () + release_value %box3 : ${ var S } + %z = tuple () + return %z : $() +} diff --git a/test/SILOptimizer/specialize_opaque_type_archetypes.swift b/test/SILOptimizer/specialize_opaque_type_archetypes.swift index 50dee3429f0c3..48cf8c8799248 100644 --- a/test/SILOptimizer/specialize_opaque_type_archetypes.swift +++ b/test/SILOptimizer/specialize_opaque_type_archetypes.swift @@ -49,12 +49,12 @@ func identity(_ t: T) -> T { // CHECK-LABEL: sil @$s1A10testFooBaryyxAA1PRzlF : $@convention(thin) (@in_guaranteed T) -> () { // CHECK: bb3([[FOOS_INT:%.*]] : $Builtin.Int64): -// CHECK: [[ID:%.*]] = function_ref @$s1A8identityyxxlFs5Int64V_Tg5 : $@convention(thin) (Int64) -> Int64 // CHECK: [[FOO_RES:%.*]] = struct $Int64 ([[FOOS_INT]] : $Builtin.Int64) +// CHECK: [[ID:%.*]] = function_ref @$s1A8identityyxxlFs5Int64V_Tg5 : $@convention(thin) (Int64) -> Int64 // CHECK: [[ID_RES:%.*]] = apply [[ID]]([[FOO_RES]]) : $@convention(thin) (Int64) -> Int64 // CHECK: [[USEP:%.*]] = function_ref @$s1A4usePyyxAA1PRzlFs5Int64V_Tg5 : $@convention(thin) (Int64) -> () -// CHECK: %27 = apply [[USEP]]([[ID_RES]]) : $@convention(thin) (Int64) -> () -// CHECK: %29 = apply [[USEP]]([[FOO_RES]]) : $@convention(thin) (Int64) -> () +// CHECK: apply [[USEP]]([[ID_RES]]) : $@convention(thin) (Int64) -> () +// CHECK: apply [[USEP]]([[FOO_RES]]) : $@convention(thin) (Int64) -> () public func testFooBar(_ t : T) { let x = foo(getInt()) @@ -99,9 +99,8 @@ public func returnC() -> some CP { } // CHECK-LABEL: sil @$s1A4useCyyF -// CHECK: [[INT:%.*]] = struct $Int64 ( -// CHECK: // function_ref specialized useP(_:) // CHECK: [[FUN:%.*]] = function_ref @$s1A4usePyyxAA1PRzlFs5Int64V_Tg5 +// CHECK: [[INT:%.*]] = struct $Int64 ( // CHECK: = apply [[FUN]]([[INT]]) public func useC() { let c = returnC() @@ -166,6 +165,7 @@ struct Container2 { } class Container3 { + @inline(__always) init(member : S.T) { self.member = member } @@ -229,8 +229,8 @@ func nonResilient() -> some ExternalP2 { // CHECK-LABEL: sil @$s1A019usePairResilientNonC0yyF : $@convention(thin) () -> () // CHECK: alloc_stack $Pair: P3 { // Don't assert. // CHECK-LABEL: sil {{.*}} @$s1A7AdapterVyxGAA2P3A2aEP3foo2ATQzyFTW // CHECK: [[F:%.*]] = function_ref @$s1A7AdapterV3fooQryF -// CHECK: apply [[F]]<τ_0_0>(%0, %1) : $@convention(method) <τ_0_0 where τ_0_0 : P3> (@in_guaranteed Adapter<τ_0_0>) -> @out @_opaqueReturnTypeOf("$s1A7AdapterV3fooQryF", 0) +// CHECK: apply [[F]]<τ_0_0>(%0, %1) : $@convention(method) <τ_0_0 where τ_0_0 : P3> (@in_guaranteed Adapter<τ_0_0>) -> extension P3 { public func foo() -> some P3 { return Adapter(inner: self) @@ -270,9 +270,8 @@ extension P3 { // CHECK-LABEL: sil @$s1A21useExternalResilient2yyF : $@convention(thin) () -> () // CHECK: [[RES:%.*]] = alloc_stack $Int64 -// CHECK: [[FUN:%.*]] = function_ref @$s9External226inlinableExternalResilientQryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s9External226inlinableExternalResilientQryF", 0) -// CHECK: [[RES2:%.*]] = unchecked_addr_cast [[RES]] : $*Int64 to $*@_opaqueReturnTypeOf("$s9External226inlinableExternalResilientQryF", 0) -// CHECK: apply [[FUN]]([[RES2]]) +// CHECK: [[FUN:%.*]] = function_ref @$s9External226inlinableExternalResilientQryF : $@convention(thin) () -> @out Int64 +// CHECK: apply [[FUN]]([[RES]]) // CHECK: return public func useExternalResilient2() { let e = inlinableExternalResilient() @@ -282,9 +281,8 @@ public func useExternalResilient2() { // In this case we should only 'peel' one layer of opaque archetypes. // CHECK-LABEL: sil @$s1A21useExternalResilient3yyF // CHECK: [[RES:%.*]] = alloc_stack $@_opaqueReturnTypeOf("$s9External217externalResilientQryF", 0) -// CHECK: [[FUN:%.*]] = function_ref @$s9External3031inlinableExternalResilientCallsD0QryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s9External3031inlinableExternalResilientCallsD0QryF", 0) -// CHECK: [[RES2:%.*]] = unchecked_addr_cast [[RES]] : $*@_opaqueReturnTypeOf("$s9External217externalResilientQryF", 0){{.*}}to $*@_opaqueReturnTypeOf("$s9External3031inlinableExternalResilientCallsD0QryF", 0) -// CHECK: apply [[FUN]]([[RES2]]) +// CHECK: [[FUN:%.*]] = function_ref @$s9External3031inlinableExternalResilientCallsD0QryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s9External217externalResilientQryF", 0) +// CHECK: apply [[FUN]]([[RES]]) public func useExternalResilient3() { let e = inlinableExternalResilientCallsResilient() useP(e.myValue3()) @@ -293,9 +291,8 @@ public func useExternalResilient3() { // Check that we can look throught two layers of inlinable resilient functions. // CHECK-LABEL: sil @$s1A21useExternalResilient4yyF // CHECK: [[RES:%.*]] = alloc_stack $Int64 -// CHECK: [[FUN:%.*]] = function_ref @$s9External3040inlinableExternalResilientCallsInlinablecD0QryF : $@convention(thin) () -> @out @_opaqueReturnTypeOf("$s9External3040inlinableExternalResilientCallsInlinablecD0QryF", 0) -// CHECK: [[RES2:%.*]] = unchecked_addr_cast [[RES]] : $*Int64 to $*@_opaqueReturnTypeOf("$s9External3040inlinableExternalResilientCallsInlinablecD0QryF", 0) -// CHECK: apply [[FUN]]([[RES2]]) +// CHECK: [[FUN:%.*]] = function_ref @$s9External3040inlinableExternalResilientCallsInlinablecD0QryF : $@convention(thin) () -> @out Int64 +// CHECK: apply [[FUN]]([[RES]]) public func useExternalResilient4() { let e = inlinableExternalResilientCallsInlinableExternalResilient() useP(e.myValue3()) @@ -306,8 +303,7 @@ public func useExternalResilient4() { // CHECK: [[CONTAINER:%.*]] = apply [[CONTAINER_INIT_FUN]] // CHECK: [[RES:%.*]] = alloc_stack $Int64 // CHECK: [[COMPUTED_PROP:%.*]] = function_ref @$s8External0A9ContainerV16computedPropertyQrvg -// CHECK: [[RES2:%.*]] = unchecked_addr_cast [[RES]] : $*Int64 to $*@_opaqueReturnTypeOf("$s8External0A9ContainerV16computedPropertyQrvp", 0) -// CHECK: apply [[COMPUTED_PROP]]([[RES2]], [[CONTAINER]]) +// CHECK: apply [[COMPUTED_PROP]]([[RES]], [[CONTAINER]]) // CHECK: [[MYVALUE:%.*]] = function_ref @$ss5Int64V8ExternalE8myValue2AByF : $@convention(method) (Int64) -> Int64 // CHECK: apply [[MYVALUE]] public func testStoredProperty() { @@ -329,8 +325,7 @@ public func testResilientProperty() { // CHECK: [[CONTAINER:%.*]] = alloc_stack $ResilientContainer // CHECK: [[RES:%.*]] = alloc_stack $Int64 // CHECK: [[FUN:%.*]] = function_ref @$s9External218ResilientContainerV18inlineablePropertyQrvg -// CHECK: [[RES2:%.*]] = unchecked_addr_cast [[RES]] : $*Int64 to $*@_opaqueReturnTypeOf("$s9External218ResilientContainerV18inlineablePropertyQrvp", 0) -// CHECK: apply [[FUN]]([[RES2]], [[CONTAINER]]) +// CHECK: apply [[FUN]]([[RES]], [[CONTAINER]]) public func testResilientInlinableProperty() { let r = ResilientContainer() useP(r.inlineableProperty.myValue3()) @@ -340,8 +335,7 @@ public func testResilientInlinableProperty() { // CHECK: [[CONTAINER:%.*]] = alloc_stack $ResilientContainer // CHECK: [[RES:%.*]] = alloc_stack $Int64 // CHECK: [[FUN:%.*]] = function_ref @$s9External218ResilientContainerV19inlineableProperty2Qrvg -// CHECK: [[RES2:%.*]] = unchecked_addr_cast [[RES]] : $*Int64 to $*@_opaqueReturnTypeOf("$s9External218ResilientContainerV19inlineableProperty2Qrvp", 0) -// CHECK: apply [[FUN]]([[RES2]], [[CONTAINER]]) +// CHECK: apply [[FUN]]([[RES]], [[CONTAINER]]) public func testResilientInlinableProperty3() { let r = ResilientContainer() useP(r.inlineableProperty2.myValue3()) @@ -362,8 +356,7 @@ public func testResilientProperty2() { // CHECK: [[CONTAINER:%.*]] = alloc_stack $ResilientContainer2 // CHECK: [[RES:%.*]] = alloc_stack $@_opaqueReturnTypeOf("$s9External218ResilientContainerV16computedPropertyQrvp", 0) // CHECK: [[FUN:%.*]] = function_ref @$s9External319ResilientContainer2V18inlineablePropertyQrvg -// CHECK: [[RES2:%.*]] = unchecked_addr_cast [[RES]] : $*@_opaqueReturnTypeOf("$s9External218ResilientContainerV16computedPropertyQrvp", 0){{.*}}to $*@_opaqueReturnTypeOf("$s9External319ResilientContainer2V18inlineablePropertyQrvp", 0) -// CHECK: apply [[FUN]]([[RES2]], [[CONTAINER]]) +// CHECK: apply [[FUN]]([[RES]], [[CONTAINER]]) public func testResilientInlinableProperty2() { let r = ResilientContainer2() useP(r.inlineableProperty.myValue3()) @@ -373,8 +366,7 @@ public func testResilientInlinableProperty2() { // CHECK: [[CONTAINTER:%.*]] = alloc_stack $ResilientContainer2 // CHECK: [[RES:%.*]] = alloc_stack $Int64 // CHECK: [[FUN:%.*]] = function_ref @$s9External319ResilientContainer2V023inlineablePropertyCallsB10InlineableQrvg -// CHECK: [[RES2:%.*]] = unchecked_addr_cast [[RES]] : $*Int64 to $*@_opaqueReturnTypeOf("$s9External319ResilientContainer2V023inlineablePropertyCallsB10InlineableQrvp", 0) -// CHECK: apply [[FUN]]([[RES2]], [[CONTAINTER]]) +// CHECK: apply [[FUN]]([[RES]], [[CONTAINTER]]) public func testResilientInlinablePropertyCallsResilientInlinable() { let r = ResilientContainer2() useP(r.inlineablePropertyCallsResilientInlineable.myValue3()) @@ -420,9 +412,9 @@ func testIt(cl: (Int64) throws -> T) { // CHECK-LABEL: sil shared [noinline] @$s1A16testPartialApplyyyxAA2P4RzlFAA2PAV_Tg5 // CHECK: [[PA:%.*]] = alloc_stack $PA // CHECK: store %0 to [[PA]] : $*PA -// CHECK: [[F:%.*]] = function_ref @$s1A2PAVAA2P4A2aDP3fooy2ATQzs5Int64VFTW : $@convention(witness_method: P4) (Int64, @in_guaranteed PA) -> @out @_opaqueReturnTypeOf("$s1A2PAV3fooyQrs5Int64VF", 0) -// CHECK: [[C:%.*]] = partial_apply [callee_guaranteed] [[F]]([[PA]]) : $@convention(witness_method: P4) (Int64, @in_guaranteed PA) -> @out @_opaqueReturnTypeOf("$s1A2PAV3fooyQrs5Int64VF", 0) -// CHECK: convert_function [[C]] : $@callee_guaranteed (Int64) -> @out @_opaqueReturnTypeOf("$s1A2PAV3fooyQrs5Int64VF", {{.*}} to $@callee_guaranteed (Int64) -> (@out Int64, @error Error) +// CHECK: [[F:%.*]] = function_ref @$s1A2PAVAA2P4A2aDP3fooy2ATQzs5Int64VFTW : $@convention(witness_method: P4) (Int64, @in_guaranteed PA) -> @out Int64 +// CHECK: [[C:%.*]] = partial_apply [callee_guaranteed] [[F]]([[PA]]) : $@convention(witness_method: P4) (Int64, @in_guaranteed PA) -> @out Int64 +// CHECK: convert_function [[C]] : $@callee_guaranteed (Int64) -> @out Int64 to $@callee_guaranteed (Int64) -> (@out Int64, @error Error) @inline(never) func testPartialApply(_ t: T) { let fun = t.foo @@ -563,7 +555,7 @@ public func rdar56410009_inlinedInner() { // CHECK-LABEL: sil @$s1A25rdar56410009_inlinedOuteryyF public func rdar56410009_inlinedOuter() { // CHECK: [[INLINABLE_EXTERNAL_RESILIENT_WRAPPER:%.+]] = function_ref @$s9External233inlinableExternalResilientWrapperyQrxAA0C2P2RzlFAA08externalD0QryFQOyQo__Tg5 - // CHECK: = apply [[INLINABLE_EXTERNAL_RESILIENT_WRAPPER]]({{%.+}}, {{%.+}}) : $@convention(thin) (@in_guaranteed @_opaqueReturnTypeOf("$s9External217externalResilientQryF", 0) 🦸) -> @out @_opaqueReturnTypeOf("$s9External233inlinableExternalResilientWrapperyQrxAA0C2P2RzlF", 0) 🦸<@_opaqueReturnTypeOf("$s9External217externalResilientQryF", 0) 🦸> + // CHECK: = apply [[INLINABLE_EXTERNAL_RESILIENT_WRAPPER]]({{%.+}}, {{%.+}}) : $@convention(thin) (@in_guaranteed @_opaqueReturnTypeOf("$s9External217externalResilientQryF", 0) 🦸) -> @out WrapperP2<@_opaqueReturnTypeOf("$s9External217externalResilientQryF" _ = inlinableExternalResilientWrapper(externalResilient()) } // CHECK: end sil function '$s1A25rdar56410009_inlinedOuteryyF' @@ -582,6 +574,6 @@ public func rdar56410009_inlinedOuter() { // CHECK-LABEL: sil @$s1A24rdar56410009_inlinedBothyyF public func rdar56410009_inlinedBoth() { // CHECK: [[INLINABLE_EXTERNAL_RESILIENT_WRAPPER:%.+]] = function_ref @$s9External233inlinableExternalResilientWrapperyQrxAA0C2P2RzlFs5Int64V_Tg5 - // CHECK: = apply [[INLINABLE_EXTERNAL_RESILIENT_WRAPPER]]({{%.+}}, {{%.+}}) : $@convention(thin) (Int64) -> @out @_opaqueReturnTypeOf("$s9External233inlinableExternalResilientWrapperyQrxAA0C2P2RzlF", 0) 🦸 + // CHECK: = apply [[INLINABLE_EXTERNAL_RESILIENT_WRAPPER]]({{%.+}}, {{%.+}}) : $@convention(thin) (Int64) -> @out WrapperP2 _ = inlinableExternalResilientWrapper(inlinableExternalResilient()) } // CHECK: end sil function '$s1A24rdar56410009_inlinedBothyyF' diff --git a/test/SILOptimizer/specialize_opaque_type_archetypes_multifile.swift b/test/SILOptimizer/specialize_opaque_type_archetypes_multifile.swift index 9e70b35bb6466..f858632090311 100644 --- a/test/SILOptimizer/specialize_opaque_type_archetypes_multifile.swift +++ b/test/SILOptimizer/specialize_opaque_type_archetypes_multifile.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -O -Xllvm -enable-opaque-archetype-specializer -disable-availability-checking -primary-file %s %S/Inputs/specialize_opaque_type_archetypes_multifile_A.swift -emit-sil | %FileCheck %s +// RUN: %target-swift-frontend -O -disable-availability-checking -primary-file %s %S/Inputs/specialize_opaque_type_archetypes_multifile_A.swift -emit-sil | %FileCheck %s protocol P {} diff --git a/test/Sanitizers/asan_interface.h b/test/Sanitizers/asan_interface.h new file mode 100644 index 0000000000000..8eaf265b74e61 --- /dev/null +++ b/test/Sanitizers/asan_interface.h @@ -0,0 +1,4 @@ +// This file is a swift bridging header to ASan's interface. It exists so +// we don't need to worry about where the header lives and instead let Clang +// figure out where the header lives. +#include "sanitizer/asan_interface.h" diff --git a/test/Sanitizers/asan_recover.swift b/test/Sanitizers/asan_recover.swift new file mode 100644 index 0000000000000..dbb8bd7662b68 --- /dev/null +++ b/test/Sanitizers/asan_recover.swift @@ -0,0 +1,103 @@ +// REQUIRES: executable_test +// REQUIRES: asan_runtime +// UNSUPPORTED: windows + +// Check with recovery instrumentation and runtime option to continue execution. +// RUN: %target-swiftc_driver %s -target %sanitizers-target-triple -g -sanitize=address -sanitize-recover=address -import-objc-header %S/asan_interface.h -emit-ir -o %t.asan_recover.ll +// RUN: %FileCheck -check-prefix=CHECK-IR -input-file=%t.asan_recover.ll %s +// RUN: %target-swiftc_driver %s -target %sanitizers-target-triple -g -sanitize=address -sanitize-recover=address -import-objc-header %S/asan_interface.h -o %t_asan_recover +// RUN: %target-codesign %t_asan_recover +// RUN: env %env-ASAN_OPTIONS=halt_on_error=0 %target-run %t_asan_recover > %t_asan_recover.stdout 2> %t_asan_recover.stderr +// RUN: %FileCheck --check-prefixes=CHECK-COMMON-STDERR,CHECK-RECOVER-STDERR -input-file=%t_asan_recover.stderr %s +// RUN: %FileCheck --check-prefixes=CHECK-COMMON-STDOUT,CHECK-RECOVER-STDOUT -input-file=%t_asan_recover.stdout %s + +// Check with recovery instrumentation but without runtime option to continue execution. +// RUN: not env %env-ASAN_OPTIONS=abort_on_error=0,halt_on_error=1 %target-run %t_asan_recover > %t_asan_no_runtime_recover.stdout 2> %t_asan_no_runtime_recover.stderr +// RUN: %FileCheck --check-prefixes=CHECK-COMMON-STDERR -input-file=%t_asan_no_runtime_recover.stderr %s +// RUN: %FileCheck --check-prefixes=CHECK-COMMON-STDOUT,CHECK-NO-RECOVER-STDOUT -input-file=%t_asan_no_runtime_recover.stdout %s + +// Check that without recovery instrumentation and runtime option to continue execution that error recovery does not happen. +// RUN: %target-swiftc_driver %s -target %sanitizers-target-triple -g -sanitize=address -import-objc-header %S/asan_interface.h -o %t_asan_no_recover +// RUN: %target-codesign %t_asan_no_recover +// RUN: not env %env-ASAN_OPTIONS=abort_on_error=0,halt_on_error=0 %target-run %t_asan_no_recover > %t_asan_no_recover.stdout 2> %t_asan_no_recover.stderr +// RUN: %FileCheck --check-prefixes=CHECK-COMMON-STDERR -input-file=%t_asan_no_recover.stderr %s +// RUN: %FileCheck --check-prefixes=CHECK-COMMON-STDOUT,CHECK-NO-RECOVER-STDOUT -input-file=%t_asan_no_recover.stdout %s + +// We need to test reads via instrumentation not via runtime so try to check +// for calls to unwanted interceptor/runtime functions. +// CHECK-IR-NOT: call {{.+}} @__asan_memcpy +// CHECK-IR-NOT: call {{.+}} @memcpy + +// FIXME: We need this so we can flush stdout but this won't +// work on other Platforms (e.g. Windows). +#if os(Linux) + import Glibc +#else + import Darwin.C +#endif + +// CHECK-COMMON-STDOUT: START +print("START") +fflush(stdout) + +let size:Int = 128; + +func foo(_ rawptr:UnsafeMutablePointer) { + print("Read second element:\(rawptr.advanced(by: 1).pointee)") + fflush(stdout) +} + +// In this test we need multiple issues to occur that ASan can detect. +// Allocating a buffer and artificially poisoning it seems like the best way to +// test this because there's no undefined behavior happening. Hopefully this +// means that the program behaviour after ASan catches an issue should be +// consistent. If we did something different like two use-after-free issues the +// behaviour could be very unpredicatable resulting in a flakey test. +var x = UnsafeMutablePointer.allocate(capacity: size) +x.initialize(repeating: 0, count: size) +__asan_poison_memory_region(UnsafeMutableRawPointer(x), size) + +// Perform accesses that ASan will catch. Note it is important here that +// the reads are performed **in** the instrumented code so that the +// instrumentation catches the access to poisoned memory. I tried doing: +// +// ``` +// var x = x.advanced(by: 0).pointee +// print(x) +// ``` +// +// However, this generated code that called into memcpy rather than performing +// a direct read which meant that ASan caught an issue via its interceptors +// rather than from instrumentation, which does not test the right thing here. +// +// Doing: +// +// ``` +// print("Read first element:\(x.advanced(by: 0).pointee)") +// ``` +// +// seems to do the right thing right now but this seems really fragile. + +// First error +// NOTE: Testing for stackframe `#0` should ensure that the poison read +// happened in instrumentation and not in an interceptor. +// CHECK-COMMON-STDERR: AddressSanitizer: use-after-poison +// CHECK-COMMON-STDERR: #0 0x{{.+}} in main{{.*}} +print("Read first element:\(x.advanced(by: 0).pointee)") +fflush(stdout) +// CHECK-RECOVER-STDOUT: Read first element:0 + +// Second error +// NOTE: Very loose regex is to accomodate if name demangling +// fails. rdar://problem/57235673 +// CHECK-RECOVER-STDERR: AddressSanitizer: use-after-poison +// CHECK-RECOVER-STDERR: #0 0x{{.+}} in {{.*}}foo{{.*}} +// CHECK-RECOVER-STDOUT: Read second element:0 +foo(x) +__asan_unpoison_memory_region(UnsafeMutableRawPointer(x), size) + +x.deallocate(); +// CHECK-NO-RECOVER-STDOUT-NOT: DONE +// CHECK-RECOVER-STDOUT: DONE +print("DONE") +fflush(stdout) diff --git a/test/Sema/enum_conformance_synthesis.swift b/test/Sema/enum_conformance_synthesis.swift index 94dd3577dcba2..8ae6a440aff5f 100644 --- a/test/Sema/enum_conformance_synthesis.swift +++ b/test/Sema/enum_conformance_synthesis.swift @@ -61,7 +61,7 @@ func customHashable() { enum InvalidCustomHashable { case A, B - var hashValue: String { return "" } // expected-note{{previously declared here}} + var hashValue: String { return "" } // expected-note 2 {{previously declared here}} } func ==(x: InvalidCustomHashable, y: InvalidCustomHashable) -> String { return "" @@ -72,7 +72,7 @@ func invalidCustomHashable() { s = InvalidCustomHashable.A.hashValue _ = s var _: Int = InvalidCustomHashable.A.hashValue - InvalidCustomHashable.A.hash(into: &hasher) + InvalidCustomHashable.A.hash(into: &hasher) // expected-error {{value of type 'InvalidCustomHashable' has no member 'hash'}} } // Check use of an enum's synthesized members before the enum is actually declared. diff --git a/test/Sema/immutability.swift b/test/Sema/immutability.swift index ec930f573911b..af74e64f54a88 100644 --- a/test/Sema/immutability.swift +++ b/test/Sema/immutability.swift @@ -656,8 +656,8 @@ func sr4214() { let closure = { val in val.x = 7 } as (inout MutableSubscripts) -> () // Ok var v = MutableSubscripts() closure(&v) - // FIXME: This diagnostic isn't really all that much better - // expected-error@+1 {{cannot convert value of type '(inout MutableSubscripts) -> ()' to expected argument type '(_) -> _'}} + // expected-error@+2 {{declared closure result '()' is incompatible with contextual type 'MutableSubscripts'}} + // expected-error@+1 {{cannot convert value of type '(inout MutableSubscripts) -> ()' to expected argument type '(MutableSubscripts) -> MutableSubscripts'}} sequence(v) { (state : inout MutableSubscripts) -> () in _ = MutableSubscripts.initialize(from: &state) return () @@ -701,3 +701,43 @@ extension JustAProtocol { name = "World" // expected-error {{cannot assign to property: 'self' is immutable}} } } + +struct S { + var x = 0 + static var y = 0 + + struct Nested { + func foo() { + // SR-11786: Make sure we don't offer the 'self.' fix-it here. + let x = 0 // expected-note {{change 'let' to 'var' to make it mutable}} + x += 1 // expected-error {{left side of mutating operator isn't mutable: 'x' is a 'let' constant}} + } + } + + func bar() { + // SR-11787: Make sure we insert "self." in the right location. + let x = 0 // expected-note 3{{change 'let' to 'var' to make it mutable}} + x += 1 // expected-error {{left side of mutating operator isn't mutable: 'x' is a 'let' constant}} + // expected-note@-1 {{add explicit 'self.' to refer to mutable property of 'S'}} {{5-5=self.}} + + (try x) += 1 // expected-error {{left side of mutating operator isn't mutable: 'x' is a 'let' constant}} + // expected-note@-1 {{add explicit 'self.' to refer to mutable property of 'S'}} {{10-10=self.}} + + x = 1 // expected-error {{cannot assign to value: 'x' is a 'let' constant}} + // expected-note@-1 {{add explicit 'self.' to refer to mutable property of 'S'}} {{5-5=self.}} + + // SR-11788: Insert "Type." for a static property. + let y = 0 // expected-note {{change 'let' to 'var' to make it mutable}} + y += 1 // expected-error {{left side of mutating operator isn't mutable: 'y' is a 'let' constant}} + // expected-note@-1 {{add explicit 'S.' to refer to mutable static property of 'S'}} {{5-5=S.}} + } +} + +struct S2 { + static var y: Int { get { 0 } set {} } + func foo() { + let y = 0 // expected-note {{change 'let' to 'var' to make it mutable}} + y += 1 // expected-error {{left side of mutating operator isn't mutable: 'y' is a 'let' constant}} + // expected-note@-1 {{add explicit 'S2.' to refer to mutable static property of 'S2'}} {{5-5=S2.}} + } +} diff --git a/test/Sema/substring_to_string_conversion_swift4.swift b/test/Sema/substring_to_string_conversion_swift4.swift index 10ab545feeacb..291f48d2c4161 100644 --- a/test/Sema/substring_to_string_conversion_swift4.swift +++ b/test/Sema/substring_to_string_conversion_swift4.swift @@ -45,7 +45,7 @@ do { // CTP_ClosureResult do { - [ss].map { (x: Substring) -> String in x } // expected-error {{cannot convert value of type 'Substring' to closure result type 'String'}} {{42-42=String(}} {{43-43=)}} + [ss].map { (x: Substring) -> String in x } // expected-error {{declared closure result 'Substring' is incompatible with contextual type 'String'}} } // CTP_ArrayElement diff --git a/test/Serialization/always_inline.swift b/test/Serialization/always_inline.swift index 178b529aeca55..8c6dfc584d790 100644 --- a/test/Serialization/always_inline.swift +++ b/test/Serialization/always_inline.swift @@ -8,9 +8,9 @@ import def_always_inline -// SIL-LABEL: sil public_external [serialized] [always_inline] [canonical] @$s17def_always_inline16testAlwaysInline1xS2b_tF : $@convention(thin) (Bool) -> Bool { +// SIL-LABEL: sil public_external [serialized] [always_inline] [canonical] [ossa] @$s17def_always_inline16testAlwaysInline1xS2b_tF : $@convention(thin) (Bool) -> Bool { -// SIL-LABEL: sil public_external [serialized] [always_inline] [canonical] @$s17def_always_inline22AlwaysInlineInitStructV1xACSb_tcfC : $@convention(method) (Bool, @thin AlwaysInlineInitStruct.Type) -> AlwaysInlineInitStruct { +// SIL-LABEL: sil public_external [serialized] [always_inline] [canonical] [ossa] @$s17def_always_inline22AlwaysInlineInitStructV1xACSb_tcfC : $@convention(method) (Bool, @thin AlwaysInlineInitStruct.Type) -> AlwaysInlineInitStruct { // SIL-LABEL: sil @main // SIL: [[RAW:%.+]] = global_addr @$s13always_inline3rawSbvp : $*Bool diff --git a/test/Serialization/attr-invalid.swift b/test/Serialization/attr-invalid.swift index 623ee022bf45d..5c32dd9974f49 100644 --- a/test/Serialization/attr-invalid.swift +++ b/test/Serialization/attr-invalid.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -emit-module -o %t/attr.swiftmodule %s -verify +// RUN: %target-swift-frontend -emit-module -o %t/attr.swiftmodule %s -verify -warnings-as-errors // RUN: llvm-bcanalyzer -dump %t/attr.swiftmodule | %FileCheck -check-prefix=CHECK-NON-RESILIENT %s // RUN: %target-swift-frontend -emit-module -o %t/attr_resilient.swiftmodule -enable-library-evolution -warnings-as-errors %s // RUN: llvm-bcanalyzer -dump %t/attr_resilient.swiftmodule | %FileCheck -check-prefix=CHECK-RESILIENT %s @@ -8,7 +8,7 @@ // CHECK-RESILIENT: Frozen_DECL_ATTR // CHECK-NON-RESILIENT-NOT: Frozen_DECL_ATTR -@frozen // expected-warning {{@frozen has no effect without -enable-library-evolution}} +@frozen // expected-no-warning public enum SomeEnum { case x } diff --git a/test/Serialization/noinline.swift b/test/Serialization/noinline.swift index 4a775d2e0cc45..a57ac201dcef6 100644 --- a/test/Serialization/noinline.swift +++ b/test/Serialization/noinline.swift @@ -8,9 +8,9 @@ import def_noinline -// SIL-LABEL: sil public_external [serialized] [noinline] [canonical] @$s12def_noinline12testNoinline1xS2b_tF : $@convention(thin) (Bool) -> Bool { +// SIL-LABEL: sil public_external [serialized] [noinline] [canonical] [ossa] @$s12def_noinline12testNoinline1xS2b_tF : $@convention(thin) (Bool) -> Bool { -// SIL-LABEL: sil public_external [serialized] [noinline] [canonical] @$s12def_noinline18NoInlineInitStructV1xACSb_tcfC : $@convention(method) (Bool, @thin NoInlineInitStruct.Type) -> NoInlineInitStruct { +// SIL-LABEL: sil public_external [serialized] [noinline] [canonical] [ossa] @$s12def_noinline18NoInlineInitStructV1xACSb_tcfC : $@convention(method) (Bool, @thin NoInlineInitStruct.Type) -> NoInlineInitStruct { // SIL-LABEL: sil @main // SIL: [[RAW:%.+]] = global_addr @$s8noinline3rawSbvp : $*Bool diff --git a/test/Serialization/serialize_attr.swift b/test/Serialization/serialize_attr.swift index ceeddbbabe606..c5b48d90b497a 100644 --- a/test/Serialization/serialize_attr.swift +++ b/test/Serialization/serialize_attr.swift @@ -79,6 +79,6 @@ public class CC { } } -// CHECK-DAG: sil [serialized] [_specialize exported: false, kind: full, where T == Int, U == Float] [canonical] @$s14serialize_attr14specializeThis_1uyx_q_tr0_lF : $@convention(thin) (@in_guaranteed T, @in_guaranteed U) -> () { +// CHECK-DAG: sil [serialized] [_specialize exported: false, kind: full, where T == Int, U == Float] [canonical] [ossa] @$s14serialize_attr14specializeThis_1uyx_q_tr0_lF : $@convention(thin) (@in_guaranteed T, @in_guaranteed U) -> () { -// CHECK-DAG: sil [serialized] [noinline] [_specialize exported: false, kind: full, where T == RR, U == SS] [canonical] @$s14serialize_attr2CCC3foo_1gqd___AA2GGVyxGtqd___AHtAA2QQRd__lF : $@convention(method) (@in_guaranteed U, GG, @guaranteed CC) -> (@out U, GG) { +// CHECK-DAG: sil [serialized] [noinline] [_specialize exported: false, kind: full, where T == RR, U == SS] [canonical] [ossa] @$s14serialize_attr2CCC3foo_1gqd___AA2GGVyxGtqd___AHtAA2QQRd__lF : $@convention(method) (@in_guaranteed U, GG, @guaranteed CC) -> (@out U, GG) { diff --git a/test/SourceKit/CodeComplete/complete_member.swift b/test/SourceKit/CodeComplete/complete_member.swift index 1851daee22ee6..3816b82331f44 100644 --- a/test/SourceKit/CodeComplete/complete_member.swift +++ b/test/SourceKit/CodeComplete/complete_member.swift @@ -32,7 +32,7 @@ class Base { } class Derived: Base { - func foo() {} + override func foo() {} } func testOverrideUSR() { diff --git a/test/SourceKit/CodeComplete/injected_vfs.swift b/test/SourceKit/CodeComplete/injected_vfs.swift index e4b5f71ff45ed..b6eb657337790 100644 --- a/test/SourceKit/CodeComplete/injected_vfs.swift +++ b/test/SourceKit/CodeComplete/injected_vfs.swift @@ -19,9 +19,9 @@ func foo( // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -o %t/SwiftModule.swiftmodule -module-name SwiftModule %S/../Inputs/vfs/SwiftModule/SwiftModule.swift -// RUN: %sourcekitd-test -req=complete -pos=9:27 -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s -// RUN: %sourcekitd-test -req=complete -pos=10:31 -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SWIFTMODULE %s -// RUN: %sourcekitd-test -req=complete -pos=11:30 -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SAMETARGET %s +// RUN: %sourcekitd-test -req=complete -pos=9:27 -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s +// RUN: %sourcekitd-test -req=complete -pos=10:31 -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SWIFTMODULE %s +// RUN: %sourcekitd-test -req=complete -pos=11:30 -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SAMETARGET %s // RUN: not %sourcekitd-test -req=complete -vfs-name nope %s -pass-as-sourcetext -dont-print-request -pos=9:27 2>&1 | %FileCheck %s -check-prefix=NONEXISTENT_VFS_ERROR // NONEXISTENT_VFS_ERROR: error response (Request Failed): unknown virtual filesystem 'nope' diff --git a/test/SourceKit/CodeComplete/injected_vfs_complete_open.swift b/test/SourceKit/CodeComplete/injected_vfs_complete_open.swift index 9f6df7bd69ffa..167fea6c7855e 100644 --- a/test/SourceKit/CodeComplete/injected_vfs_complete_open.swift +++ b/test/SourceKit/CodeComplete/injected_vfs_complete_open.swift @@ -19,32 +19,32 @@ func foo( // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -o %t/SwiftModule.swiftmodule -module-name SwiftModule %S/../Inputs/vfs/SwiftModule/SwiftModule.swift -// RUN: %sourcekitd-test -req=complete.open -pos=9:28 -vfs-files=/target_file1.swift=@%s,/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s -// RUN: %sourcekitd-test -req=complete.open -pos=10:32 -vfs-files=/target_file1.swift=@%s,/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SWIFTMODULE %s -// RUN: %sourcekitd-test -req=complete.open -pos=11:31 -vfs-files=/target_file1.swift=@%s,/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SAMETARGET %s +// RUN: %sourcekitd-test -req=complete.open -pos=9:28 -vfs-files=%t/VFS/target_file1.swift=@%s,%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s +// RUN: %sourcekitd-test -req=complete.open -pos=10:32 -vfs-files=%t/VFS/target_file1.swift=@%s,%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SWIFTMODULE %s +// RUN: %sourcekitd-test -req=complete.open -pos=11:31 -vfs-files=%t/VFS/target_file1.swift=@%s,%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SAMETARGET %s // RUN: not %sourcekitd-test -req=complete.open -vfs-name nope %s -pass-as-sourcetext -dont-print-request -pos=9:27 2>&1 | %FileCheck %s -check-prefix=NONEXISTENT_VFS_ERROR // NONEXISTENT_VFS_ERROR: error response (Request Failed): unknown virtual filesystem 'nope' -// RUN: not %sourcekitd-test -req=complete.open -pos=11:31 -vfs-files=/target_file1.swift=@%s,/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple \ -// RUN: == -req=complete.update -pos=11:31 -vfs-files=/target_file1.swift=@%s,/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift 2>&1 | %FileCheck --check-prefix=UNSUPPORTED_REQ %s +// RUN: not %sourcekitd-test -req=complete.open -pos=11:31 -vfs-files=%t/VFS/target_file1.swift=@%s,%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple \ +// RUN: == -req=complete.update -pos=11:31 -vfs-files=%t/VFS/target_file1.swift=@%s,%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift 2>&1 | %FileCheck --check-prefix=UNSUPPORTED_REQ %s // UNSUPPORTED_REQ: error response (Request Invalid): This request does not support custom filesystems -// RUN: %sourcekitd-test -req=complete.open -pos=11:31 -dont-print-response -vfs-files=/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple \ +// RUN: %sourcekitd-test -req=complete.open -pos=11:31 -dont-print-response -vfs-files=%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple \ // RUN: == -req=complete.update -pos=11:31 %s | %FileCheck --check-prefix=CHECK-SAMETARGET %s -// RUN: %sourcekitd-test -req=complete.open -pos=11:31 -dont-print-response -vfs-files=/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple \ +// RUN: %sourcekitd-test -req=complete.open -pos=11:31 -dont-print-response -vfs-files=%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple \ // RUN: == -req=complete.update -pos=11:31 -req-opts=filtertext=method %s | %FileCheck --check-prefix=CHECK-SAMETARGET %s // Inner completion. -// RUN: %sourcekitd-test -req=complete.open -pos=9:1 -req-opts=filtertext=StructDefinedInSameTarget -vfs-files=/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=INNER_SAMETARGET %s -// RUN: %sourcekitd-test -req=complete.open -pos=9:1 -dont-print-response -vfs-files=/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple \ +// RUN: %sourcekitd-test -req=complete.open -pos=9:1 -req-opts=filtertext=StructDefinedInSameTarget -vfs-files=%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=INNER_SAMETARGET %s +// RUN: %sourcekitd-test -req=complete.open -pos=9:1 -dont-print-response -vfs-files=%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple \ // RUN: == -req=complete.update -pos=9:1 -req-opts=filtertext=StructDefinedInSameTarget %s | %FileCheck --check-prefix=INNER_SAMETARGET %s // INNER_SAMETARGET: key.name: "StructDefinedInSameTarget" // INNER_SAMETARGET: key.name: "StructDefinedInSameTarget." -// RUN: %sourcekitd-test -req=complete.open -pos=9:1 -req-opts=filtertext=StructDefinedInCModule -vfs-files=/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=INNER_CMODULE %s -// RUN: %sourcekitd-test -req=complete.open -pos=9:1 -dont-print-response -vfs-files=/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple \ +// RUN: %sourcekitd-test -req=complete.open -pos=9:1 -req-opts=filtertext=StructDefinedInCModule -vfs-files=%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=INNER_CMODULE %s +// RUN: %sourcekitd-test -req=complete.open -pos=9:1 -dont-print-response -vfs-files=%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple \ // RUN: == -req=complete.update -pos=9:1 -req-opts=filtertext=StructDefinedInCModule %s | %FileCheck --check-prefix=INNER_CMODULE %s // INNER_CMODULE: key.name: "StructDefinedInCModule" // INNER_CMODULE: key.name: "StructDefinedInCModule." diff --git a/test/SourceKit/CodeComplete/injected_vfs_swiftinterface.swift b/test/SourceKit/CodeComplete/injected_vfs_swiftinterface.swift index 572de65437b03..1088f98e3a45d 100644 --- a/test/SourceKit/CodeComplete/injected_vfs_swiftinterface.swift +++ b/test/SourceKit/CodeComplete/injected_vfs_swiftinterface.swift @@ -10,4 +10,4 @@ func foo( // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module-interface-path %t/SwiftModule.swiftinterface -module-name SwiftModule -emit-module -o /dev/null %S/../Inputs/vfs/SwiftModule/SwiftModule.swift -// RUN: %sourcekitd-test -req=complete -pos=6:31 -vfs-files=/target_file1.swift=%s,/SwiftModule/SwiftModule.swiftinterface=%t/SwiftModule.swiftinterface /target_file1.swift -pass-as-sourcetext -- /target_file1.swift -I /SwiftModule -target %target-triple | %FileCheck %s +// RUN: %sourcekitd-test -req=complete -pos=6:31 -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/SwiftModule/SwiftModule.swiftinterface=%t/SwiftModule.swiftinterface %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift -I %t/VFS/SwiftModule -target %target-triple | %FileCheck %s diff --git a/test/SourceKit/CompileNotifications/diagnostics.swift b/test/SourceKit/CompileNotifications/diagnostics.swift index 4a6d0894e5956..e2a2f6a09649d 100644 --- a/test/SourceKit/CompileNotifications/diagnostics.swift +++ b/test/SourceKit/CompileNotifications/diagnostics.swift @@ -63,7 +63,7 @@ // Note: we're missing the "compiler is in code completion mode" diagnostic, // which is probably just as well. // RUN: %sourcekitd-test -req=track-compiles == -req=complete -offset=0 %s -- %s | %FileCheck %s -check-prefix=NODIAGS -// RUN: %sourcekitd-test -req=track-compiles == -req=complete -pos=2:1 %S/Inputs/sema-error.swift -- %S/Inputs/sema-error.swift | %FileCheck %s -check-prefix=SEMA +// RUN: %sourcekitd-test -req=track-compiles == -req=complete -pos=2:1 %S/Inputs/sema-error.swift -- %S/Inputs/sema-error.swift | %FileCheck %s -check-prefix=NODIAGS // FIXME: invalid arguments cause us to early-exit and not send the notifications // RUN_DISABLED: %sourcekitd-test -req=track-compiles == -req=sema %s -- %s -invalid-arg | %FileCheck %s -check-prefix=INVALID_ARG diff --git a/test/SourceKit/CursorInfo/injected_vfs.swift b/test/SourceKit/CursorInfo/injected_vfs.swift index fd9348ee46082..44e3a461c9c50 100644 --- a/test/SourceKit/CursorInfo/injected_vfs.swift +++ b/test/SourceKit/CursorInfo/injected_vfs.swift @@ -10,7 +10,7 @@ func foo( // CHECK-CMODULE: key.kind: source.lang.swift.ref.struct // CHECK-CMODULE: key.name: "StructDefinedInCModule" -// CHECK-CMODULE: key.filepath: "/CModule/CModule.h" +// CHECK-CMODULE: key.filepath: "{{.*}}/CModule{{/|\\\\}}CModule.h" // CHECK-SWIFTMODULE-REF: key.kind: source.lang.swift.ref.struct // CHECK-SWIFTMODULE-REF: key.name: "StructDefinedInSwiftModule" @@ -32,28 +32,28 @@ func foo( // RUN: %target-swift-frontend -emit-module -o %t/SwiftModule.swiftmodule -module-name SwiftModule %S/../Inputs/vfs/SwiftModule/SwiftModule.swift // == CursorInfo works for struct defined in CModule == -// RUN: %sourcekitd-test -req=cursor -pos=5:43 -print-raw-response -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s +// RUN: %sourcekitd-test -req=cursor -pos=5:43 -print-raw-response -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s // USR test intentionally omitted for CModule, because SourceKit does not support clang USRs. // == CursorInfo works for struct defined in SwiftModule == -// RUN: %sourcekitd-test -req=cursor -pos=6:43 -print-raw-response -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SWIFTMODULE-REF %s -// RUN: %sourcekitd-test -req=cursor -usr "s:11SwiftModule015StructDefinedInaB0V" -print-raw-response -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SWIFTMODULE-DECL %s +// RUN: %sourcekitd-test -req=cursor -pos=6:43 -print-raw-response -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SWIFTMODULE-REF %s +// RUN: %sourcekitd-test -req=cursor -usr "s:11SwiftModule015StructDefinedInaB0V" -print-raw-response -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SWIFTMODULE-DECL %s // == CursorInfo works for struct defined in same target as primary file == -// RUN: %sourcekitd-test -req=cursor -pos=7:43 -print-raw-response -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SAMETARGET-REF %s -// RUN: %sourcekitd-test -req=cursor -usr "s:4main25StructDefinedInSameTargetV" -print-raw-response -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SAMETARGET-DECL %s +// RUN: %sourcekitd-test -req=cursor -pos=7:43 -print-raw-response -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SAMETARGET-REF %s +// RUN: %sourcekitd-test -req=cursor -usr "s:4main25StructDefinedInSameTargetV" -print-raw-response -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-SAMETARGET-DECL %s // == Using an open document == // RUN: %sourcekitd-test \ -// RUN: -req=open -vfs-files=/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple == \ -// RUN: -req=cursor -pos=5:43 %s -print-raw-response -- %s /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s +// RUN: -req=open -vfs-files=%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext -- %s %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple == \ +// RUN: -req=cursor -pos=5:43 %s -print-raw-response -- %s %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s // == Using an open document without semantic info == // RUN: %sourcekitd-test \ -// RUN: -req=syntax-map -vfs-files=/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext == \ -// RUN: -req=cursor -pos=5:43 %s -print-raw-response -- %s /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s +// RUN: -req=syntax-map -vfs-files=%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %s -pass-as-sourcetext == \ +// RUN: -req=cursor -pos=5:43 %s -print-raw-response -- %s %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s // == Overriding an open document == // RUN: %sourcekitd-test \ // RUN: -req=syntax-map %s -pass-as-sourcetext == \ -// RUN: -req=cursor -pos=5:43 %s -print-raw-response -vfs-files=/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule -- %s /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s +// RUN: -req=cursor -pos=5:43 %s -print-raw-response -vfs-files=%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule -- %s %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple | %FileCheck --check-prefix=CHECK-CMODULE %s diff --git a/test/SourceKit/DocumentStructure/Inputs/main.swift b/test/SourceKit/DocumentStructure/Inputs/main.swift index 1825f3a070c83..2901836ce4691 100644 --- a/test/SourceKit/DocumentStructure/Inputs/main.swift +++ b/test/SourceKit/DocumentStructure/Inputs/main.swift @@ -135,3 +135,33 @@ class OneMore { fatalError() } } + +class Chain { + func + (lhs: Chain, rhs: Chain) -> Chain { fatalError() } +} + +public init() { + fatalError() +} + +deinit { + fatalError() +} + +#if false +extension Result { + func foo() {} +} + +extension Outer { + class Inner { + deinit {} + } +} + +public extension Outer2 { + class Inner2 { + deinit {} + } +} +#endif diff --git a/test/SourceKit/DocumentStructure/access_parse.swift.response b/test/SourceKit/DocumentStructure/access_parse.swift.response index 7ca60e870922f..0e8c673b3761f 100644 --- a/test/SourceKit/DocumentStructure/access_parse.swift.response +++ b/test/SourceKit/DocumentStructure/access_parse.swift.response @@ -777,7 +777,6 @@ }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "DefAccess", key.offset: 1399, key.length: 43, @@ -788,7 +787,6 @@ key.substructure: [ { key.kind: source.lang.swift.decl.function.method.instance, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "defFunc()", key.offset: 1423, key.length: 17, @@ -801,7 +799,6 @@ }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "PubAccess", key.offset: 1443, key.length: 43, @@ -812,7 +809,6 @@ key.substructure: [ { key.kind: source.lang.swift.decl.function.method.instance, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "defFunc()", key.offset: 1467, key.length: 17, @@ -825,7 +821,6 @@ }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "IntAccess", key.offset: 1487, key.length: 43, @@ -836,7 +831,6 @@ key.substructure: [ { key.kind: source.lang.swift.decl.function.method.instance, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "defFunc()", key.offset: 1511, key.length: 17, @@ -849,7 +843,6 @@ }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "PrivAccess", key.offset: 1531, key.length: 44, @@ -860,7 +853,6 @@ key.substructure: [ { key.kind: source.lang.swift.decl.function.method.instance, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "defFunc()", key.offset: 1556, key.length: 17, diff --git a/test/SourceKit/DocumentStructure/structure.swift.empty.response b/test/SourceKit/DocumentStructure/structure.swift.empty.response index 43b0be09bfa2a..ce39fc3f36c5f 100644 --- a/test/SourceKit/DocumentStructure/structure.swift.empty.response +++ b/test/SourceKit/DocumentStructure/structure.swift.empty.response @@ -1,6 +1,6 @@ { key.offset: 0, - key.length: 2259, + key.length: 2587, key.diagnostic_stage: source.diagnostic.stage.swift.parse, key.substructure: [ { @@ -223,7 +223,6 @@ }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "OuterCls", key.offset: 377, key.length: 45, @@ -234,7 +233,6 @@ key.substructure: [ { key.kind: source.lang.swift.decl.class, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "InnerCls2", key.offset: 402, key.length: 18, @@ -558,7 +556,6 @@ }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "Foo", key.offset: 999, key.length: 58, @@ -569,7 +566,6 @@ key.substructure: [ { key.kind: source.lang.swift.decl.function.method.instance, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "anExtendedFooFunction()", key.offset: 1019, key.length: 36, @@ -1403,6 +1399,222 @@ ] } ] + }, + { + key.kind: source.lang.swift.decl.class, + key.accessibility: source.lang.swift.accessibility.internal, + key.name: "Chain", + key.offset: 2260, + key.length: 87, + key.nameoffset: 2266, + key.namelength: 5, + key.bodyoffset: 2276, + key.bodylength: 70, + key.substructure: [ + { + key.kind: source.lang.swift.decl.generic_type_param, + key.name: "A", + key.offset: 2272, + key.length: 1, + key.nameoffset: 2272, + key.namelength: 1 + }, + { + key.kind: source.lang.swift.decl.function.method.static, + key.accessibility: source.lang.swift.accessibility.internal, + key.name: "+(_:_:)", + key.offset: 2279, + key.length: 66, + key.typename: "Chain", + key.nameoffset: 2284, + key.namelength: 32, + key.bodyoffset: 2330, + key.bodylength: 14, + key.substructure: [ + { + key.kind: source.lang.swift.decl.var.parameter, + key.name: "lhs", + key.offset: 2287, + key.length: 13, + key.typename: "Chain", + key.nameoffset: 0, + key.namelength: 0 + }, + { + key.kind: source.lang.swift.decl.var.parameter, + key.name: "rhs", + key.offset: 2302, + key.length: 13, + key.typename: "Chain", + key.nameoffset: 0, + key.namelength: 0 + }, + { + key.kind: source.lang.swift.expr.call, + key.name: "fatalError", + key.offset: 2331, + key.length: 12, + key.nameoffset: 2331, + key.namelength: 10, + key.bodyoffset: 2342, + key.bodylength: 0 + } + ] + } + ] + }, + { + key.kind: source.lang.swift.decl.function.free, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "init()", + key.offset: 2356, + key.length: 27, + key.nameoffset: 2356, + key.namelength: 6, + key.bodyoffset: 2364, + key.bodylength: 18, + key.attributes: [ + { + key.offset: 2349, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ], + key.substructure: [ + { + key.kind: source.lang.swift.expr.call, + key.name: "fatalError", + key.offset: 2369, + key.length: 12, + key.nameoffset: 2369, + key.namelength: 10, + key.bodyoffset: 2380, + key.bodylength: 0 + } + ] + }, + { + key.kind: source.lang.swift.decl.function.free, + key.accessibility: source.lang.swift.accessibility.private, + key.name: "deinit", + key.offset: 2385, + key.length: 27, + key.nameoffset: 2385, + key.namelength: 6, + key.bodyoffset: 2393, + key.bodylength: 18, + key.substructure: [ + { + key.kind: source.lang.swift.expr.call, + key.name: "fatalError", + key.offset: 2398, + key.length: 12, + key.nameoffset: 2398, + key.namelength: 10, + key.bodyoffset: 2409, + key.bodylength: 0 + } + ] + }, + { + key.kind: source.lang.swift.decl.extension, + key.name: "Result", + key.offset: 2424, + key.length: 36, + key.nameoffset: 2434, + key.namelength: 6, + key.bodyoffset: 2442, + key.bodylength: 17, + key.substructure: [ + { + key.kind: source.lang.swift.decl.function.method.instance, + key.name: "foo()", + key.offset: 2445, + key.length: 13, + key.nameoffset: 2450, + key.namelength: 5, + key.bodyoffset: 2457, + key.bodylength: 0 + } + ] + }, + { + key.kind: source.lang.swift.decl.extension, + key.name: "Outer", + key.offset: 2462, + key.length: 53, + key.nameoffset: 2472, + key.namelength: 5, + key.bodyoffset: 2479, + key.bodylength: 35, + key.substructure: [ + { + key.kind: source.lang.swift.decl.class, + key.name: "Inner", + key.offset: 2482, + key.length: 31, + key.nameoffset: 2488, + key.namelength: 5, + key.bodyoffset: 2495, + key.bodylength: 17, + key.substructure: [ + { + key.kind: source.lang.swift.decl.function.method.instance, + key.name: "deinit", + key.offset: 2500, + key.length: 9, + key.nameoffset: 2500, + key.namelength: 6, + key.bodyoffset: 2508, + key.bodylength: 0 + } + ] + } + ] + }, + { + key.kind: source.lang.swift.decl.extension, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "Outer2", + key.offset: 2524, + key.length: 55, + key.nameoffset: 2534, + key.namelength: 6, + key.bodyoffset: 2542, + key.bodylength: 36, + key.attributes: [ + { + key.offset: 2517, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ], + key.substructure: [ + { + key.kind: source.lang.swift.decl.class, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "Inner2", + key.offset: 2545, + key.length: 32, + key.nameoffset: 2551, + key.namelength: 6, + key.bodyoffset: 2559, + key.bodylength: 17, + key.substructure: [ + { + key.kind: source.lang.swift.decl.function.method.instance, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "deinit", + key.offset: 2564, + key.length: 9, + key.nameoffset: 2564, + key.namelength: 6, + key.bodyoffset: 2572, + key.bodylength: 0 + } + ] + } + ] } ], key.diagnostics: [ @@ -1439,6 +1651,20 @@ key.sourcetext: "func " } ] + }, + { + key.line: 143, + key.column: 12, + key.severity: source.diagnostic.severity.error, + key.description: "initializers may only be declared within a type", + key.diagnostic_stage: source.diagnostic.stage.swift.parse + }, + { + key.line: 147, + key.column: 1, + key.severity: source.diagnostic.severity.error, + key.description: "deinitializers may only be declared within a class", + key.diagnostic_stage: source.diagnostic.stage.swift.parse } ] } diff --git a/test/SourceKit/DocumentStructure/structure.swift.foobar.response b/test/SourceKit/DocumentStructure/structure.swift.foobar.response index 3ecd5555db9e2..ebf0786fa318e 100644 --- a/test/SourceKit/DocumentStructure/structure.swift.foobar.response +++ b/test/SourceKit/DocumentStructure/structure.swift.foobar.response @@ -1,6 +1,6 @@ { key.offset: 0, - key.length: 2259, + key.length: 2587, key.diagnostic_stage: source.diagnostic.stage.swift.parse, key.substructure: [ { @@ -223,7 +223,6 @@ }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "OuterCls", key.offset: 377, key.length: 45, @@ -234,7 +233,6 @@ key.substructure: [ { key.kind: source.lang.swift.decl.class, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "InnerCls2", key.offset: 402, key.length: 18, @@ -558,7 +556,6 @@ }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "Foo", key.offset: 999, key.length: 58, @@ -569,7 +566,6 @@ key.substructure: [ { key.kind: source.lang.swift.decl.function.method.instance, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "anExtendedFooFunction()", key.offset: 1019, key.length: 36, @@ -1403,6 +1399,222 @@ ] } ] + }, + { + key.kind: source.lang.swift.decl.class, + key.accessibility: source.lang.swift.accessibility.internal, + key.name: "Chain", + key.offset: 2260, + key.length: 87, + key.nameoffset: 2266, + key.namelength: 5, + key.bodyoffset: 2276, + key.bodylength: 70, + key.substructure: [ + { + key.kind: source.lang.swift.decl.generic_type_param, + key.name: "A", + key.offset: 2272, + key.length: 1, + key.nameoffset: 2272, + key.namelength: 1 + }, + { + key.kind: source.lang.swift.decl.function.method.static, + key.accessibility: source.lang.swift.accessibility.internal, + key.name: "+(_:_:)", + key.offset: 2279, + key.length: 66, + key.typename: "Chain", + key.nameoffset: 2284, + key.namelength: 32, + key.bodyoffset: 2330, + key.bodylength: 14, + key.substructure: [ + { + key.kind: source.lang.swift.decl.var.parameter, + key.name: "lhs", + key.offset: 2287, + key.length: 13, + key.typename: "Chain", + key.nameoffset: 0, + key.namelength: 0 + }, + { + key.kind: source.lang.swift.decl.var.parameter, + key.name: "rhs", + key.offset: 2302, + key.length: 13, + key.typename: "Chain", + key.nameoffset: 0, + key.namelength: 0 + }, + { + key.kind: source.lang.swift.expr.call, + key.name: "fatalError", + key.offset: 2331, + key.length: 12, + key.nameoffset: 2331, + key.namelength: 10, + key.bodyoffset: 2342, + key.bodylength: 0 + } + ] + } + ] + }, + { + key.kind: source.lang.swift.decl.function.free, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "init()", + key.offset: 2356, + key.length: 27, + key.nameoffset: 2356, + key.namelength: 6, + key.bodyoffset: 2364, + key.bodylength: 18, + key.attributes: [ + { + key.offset: 2349, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ], + key.substructure: [ + { + key.kind: source.lang.swift.expr.call, + key.name: "fatalError", + key.offset: 2369, + key.length: 12, + key.nameoffset: 2369, + key.namelength: 10, + key.bodyoffset: 2380, + key.bodylength: 0 + } + ] + }, + { + key.kind: source.lang.swift.decl.function.free, + key.accessibility: source.lang.swift.accessibility.private, + key.name: "deinit", + key.offset: 2385, + key.length: 27, + key.nameoffset: 2385, + key.namelength: 6, + key.bodyoffset: 2393, + key.bodylength: 18, + key.substructure: [ + { + key.kind: source.lang.swift.expr.call, + key.name: "fatalError", + key.offset: 2398, + key.length: 12, + key.nameoffset: 2398, + key.namelength: 10, + key.bodyoffset: 2409, + key.bodylength: 0 + } + ] + }, + { + key.kind: source.lang.swift.decl.extension, + key.name: "Result", + key.offset: 2424, + key.length: 36, + key.nameoffset: 2434, + key.namelength: 6, + key.bodyoffset: 2442, + key.bodylength: 17, + key.substructure: [ + { + key.kind: source.lang.swift.decl.function.method.instance, + key.name: "foo()", + key.offset: 2445, + key.length: 13, + key.nameoffset: 2450, + key.namelength: 5, + key.bodyoffset: 2457, + key.bodylength: 0 + } + ] + }, + { + key.kind: source.lang.swift.decl.extension, + key.name: "Outer", + key.offset: 2462, + key.length: 53, + key.nameoffset: 2472, + key.namelength: 5, + key.bodyoffset: 2479, + key.bodylength: 35, + key.substructure: [ + { + key.kind: source.lang.swift.decl.class, + key.name: "Inner", + key.offset: 2482, + key.length: 31, + key.nameoffset: 2488, + key.namelength: 5, + key.bodyoffset: 2495, + key.bodylength: 17, + key.substructure: [ + { + key.kind: source.lang.swift.decl.function.method.instance, + key.name: "deinit", + key.offset: 2500, + key.length: 9, + key.nameoffset: 2500, + key.namelength: 6, + key.bodyoffset: 2508, + key.bodylength: 0 + } + ] + } + ] + }, + { + key.kind: source.lang.swift.decl.extension, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "Outer2", + key.offset: 2524, + key.length: 55, + key.nameoffset: 2534, + key.namelength: 6, + key.bodyoffset: 2542, + key.bodylength: 36, + key.attributes: [ + { + key.offset: 2517, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ], + key.substructure: [ + { + key.kind: source.lang.swift.decl.class, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "Inner2", + key.offset: 2545, + key.length: 32, + key.nameoffset: 2551, + key.namelength: 6, + key.bodyoffset: 2559, + key.bodylength: 17, + key.substructure: [ + { + key.kind: source.lang.swift.decl.function.method.instance, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "deinit", + key.offset: 2564, + key.length: 9, + key.nameoffset: 2564, + key.namelength: 6, + key.bodyoffset: 2572, + key.bodylength: 0 + } + ] + } + ] } ], key.diagnostics: [ @@ -1442,6 +1654,22 @@ key.sourcetext: "func " } ] + }, + { + key.line: 143, + key.column: 12, + key.filepath: "-foobar", + key.severity: source.diagnostic.severity.error, + key.description: "initializers may only be declared within a type", + key.diagnostic_stage: source.diagnostic.stage.swift.parse + }, + { + key.line: 147, + key.column: 1, + key.filepath: "-foobar", + key.severity: source.diagnostic.severity.error, + key.description: "deinitializers may only be declared within a class", + key.diagnostic_stage: source.diagnostic.stage.swift.parse } ] } diff --git a/test/SourceKit/DocumentStructure/structure.swift.invalid.response b/test/SourceKit/DocumentStructure/structure.swift.invalid.response index 9ee32104bfeb2..56ddd30872a9c 100644 --- a/test/SourceKit/DocumentStructure/structure.swift.invalid.response +++ b/test/SourceKit/DocumentStructure/structure.swift.invalid.response @@ -16,7 +16,6 @@ }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "OuterCls", key.offset: 12, key.length: 43, @@ -27,7 +26,6 @@ key.substructure: [ { key.kind: source.lang.swift.decl.class, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "InnerCls1", key.offset: 35, key.length: 18, diff --git a/test/SourceKit/DocumentStructure/structure.swift.response b/test/SourceKit/DocumentStructure/structure.swift.response index 83d66b8c72def..45fb37a2ba1a7 100644 --- a/test/SourceKit/DocumentStructure/structure.swift.response +++ b/test/SourceKit/DocumentStructure/structure.swift.response @@ -1,6 +1,6 @@ { key.offset: 0, - key.length: 2259, + key.length: 2587, key.diagnostic_stage: source.diagnostic.stage.swift.parse, key.substructure: [ { @@ -223,7 +223,6 @@ }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "OuterCls", key.offset: 377, key.length: 45, @@ -234,7 +233,6 @@ key.substructure: [ { key.kind: source.lang.swift.decl.class, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "InnerCls2", key.offset: 402, key.length: 18, @@ -558,7 +556,6 @@ }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "Foo", key.offset: 999, key.length: 58, @@ -569,7 +566,6 @@ key.substructure: [ { key.kind: source.lang.swift.decl.function.method.instance, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "anExtendedFooFunction()", key.offset: 1019, key.length: 36, @@ -1403,6 +1399,222 @@ ] } ] + }, + { + key.kind: source.lang.swift.decl.class, + key.accessibility: source.lang.swift.accessibility.internal, + key.name: "Chain", + key.offset: 2260, + key.length: 87, + key.nameoffset: 2266, + key.namelength: 5, + key.bodyoffset: 2276, + key.bodylength: 70, + key.substructure: [ + { + key.kind: source.lang.swift.decl.generic_type_param, + key.name: "A", + key.offset: 2272, + key.length: 1, + key.nameoffset: 2272, + key.namelength: 1 + }, + { + key.kind: source.lang.swift.decl.function.method.static, + key.accessibility: source.lang.swift.accessibility.internal, + key.name: "+(_:_:)", + key.offset: 2279, + key.length: 66, + key.typename: "Chain", + key.nameoffset: 2284, + key.namelength: 32, + key.bodyoffset: 2330, + key.bodylength: 14, + key.substructure: [ + { + key.kind: source.lang.swift.decl.var.parameter, + key.name: "lhs", + key.offset: 2287, + key.length: 13, + key.typename: "Chain", + key.nameoffset: 0, + key.namelength: 0 + }, + { + key.kind: source.lang.swift.decl.var.parameter, + key.name: "rhs", + key.offset: 2302, + key.length: 13, + key.typename: "Chain", + key.nameoffset: 0, + key.namelength: 0 + }, + { + key.kind: source.lang.swift.expr.call, + key.name: "fatalError", + key.offset: 2331, + key.length: 12, + key.nameoffset: 2331, + key.namelength: 10, + key.bodyoffset: 2342, + key.bodylength: 0 + } + ] + } + ] + }, + { + key.kind: source.lang.swift.decl.function.free, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "init()", + key.offset: 2356, + key.length: 27, + key.nameoffset: 2356, + key.namelength: 6, + key.bodyoffset: 2364, + key.bodylength: 18, + key.attributes: [ + { + key.offset: 2349, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ], + key.substructure: [ + { + key.kind: source.lang.swift.expr.call, + key.name: "fatalError", + key.offset: 2369, + key.length: 12, + key.nameoffset: 2369, + key.namelength: 10, + key.bodyoffset: 2380, + key.bodylength: 0 + } + ] + }, + { + key.kind: source.lang.swift.decl.function.free, + key.accessibility: source.lang.swift.accessibility.private, + key.name: "deinit", + key.offset: 2385, + key.length: 27, + key.nameoffset: 2385, + key.namelength: 6, + key.bodyoffset: 2393, + key.bodylength: 18, + key.substructure: [ + { + key.kind: source.lang.swift.expr.call, + key.name: "fatalError", + key.offset: 2398, + key.length: 12, + key.nameoffset: 2398, + key.namelength: 10, + key.bodyoffset: 2409, + key.bodylength: 0 + } + ] + }, + { + key.kind: source.lang.swift.decl.extension, + key.name: "Result", + key.offset: 2424, + key.length: 36, + key.nameoffset: 2434, + key.namelength: 6, + key.bodyoffset: 2442, + key.bodylength: 17, + key.substructure: [ + { + key.kind: source.lang.swift.decl.function.method.instance, + key.name: "foo()", + key.offset: 2445, + key.length: 13, + key.nameoffset: 2450, + key.namelength: 5, + key.bodyoffset: 2457, + key.bodylength: 0 + } + ] + }, + { + key.kind: source.lang.swift.decl.extension, + key.name: "Outer", + key.offset: 2462, + key.length: 53, + key.nameoffset: 2472, + key.namelength: 5, + key.bodyoffset: 2479, + key.bodylength: 35, + key.substructure: [ + { + key.kind: source.lang.swift.decl.class, + key.name: "Inner", + key.offset: 2482, + key.length: 31, + key.nameoffset: 2488, + key.namelength: 5, + key.bodyoffset: 2495, + key.bodylength: 17, + key.substructure: [ + { + key.kind: source.lang.swift.decl.function.method.instance, + key.name: "deinit", + key.offset: 2500, + key.length: 9, + key.nameoffset: 2500, + key.namelength: 6, + key.bodyoffset: 2508, + key.bodylength: 0 + } + ] + } + ] + }, + { + key.kind: source.lang.swift.decl.extension, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "Outer2", + key.offset: 2524, + key.length: 55, + key.nameoffset: 2534, + key.namelength: 6, + key.bodyoffset: 2542, + key.bodylength: 36, + key.attributes: [ + { + key.offset: 2517, + key.length: 6, + key.attribute: source.decl.attribute.public + } + ], + key.substructure: [ + { + key.kind: source.lang.swift.decl.class, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "Inner2", + key.offset: 2545, + key.length: 32, + key.nameoffset: 2551, + key.namelength: 6, + key.bodyoffset: 2559, + key.bodylength: 17, + key.substructure: [ + { + key.kind: source.lang.swift.decl.function.method.instance, + key.accessibility: source.lang.swift.accessibility.public, + key.name: "deinit", + key.offset: 2564, + key.length: 9, + key.nameoffset: 2564, + key.namelength: 6, + key.bodyoffset: 2572, + key.bodylength: 0 + } + ] + } + ] } ], key.diagnostics: [ @@ -1442,6 +1654,22 @@ key.sourcetext: "func " } ] + }, + { + key.line: 143, + key.column: 12, + key.filepath: main.swift, + key.severity: source.diagnostic.severity.error, + key.description: "initializers may only be declared within a type", + key.diagnostic_stage: source.diagnostic.stage.swift.parse + }, + { + key.line: 147, + key.column: 1, + key.filepath: main.swift, + key.severity: source.diagnostic.severity.error, + key.description: "deinitializers may only be declared within a class", + key.diagnostic_stage: source.diagnostic.stage.swift.parse } ] } diff --git a/test/SourceKit/InterfaceGen/gen_clang_module.swift.apinotes_swift3.response b/test/SourceKit/InterfaceGen/gen_clang_module.swift.apinotes_swift3.response index a904d1ab08d7f..190980edf2204 100644 --- a/test/SourceKit/InterfaceGen/gen_clang_module.swift.apinotes_swift3.response +++ b/test/SourceKit/InterfaceGen/gen_clang_module.swift.apinotes_swift3.response @@ -1554,7 +1554,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "GlobalToMember_Class_Container", key.offset: 410, key.length: 87, @@ -1659,7 +1658,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToGlobal_Class_Container", key.offset: 649, key.length: 105, @@ -1750,7 +1748,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_Class_Swift3", key.offset: 934, key.length: 117, @@ -1779,7 +1776,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_Class_Swift4", key.offset: 1052, key.length: 88, @@ -1853,7 +1849,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_SameContainer_Class_Container", key.offset: 1269, key.length: 198, @@ -1974,7 +1969,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_SameName_Class_Swift3", key.offset: 1657, key.length: 127, @@ -2003,7 +1997,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_SameName_Class_Swift4", key.offset: 1785, key.length: 93, @@ -2093,7 +2086,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "GlobalToMember_Typedef_Container", key.offset: 2250, key.length: 82, @@ -2169,7 +2161,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToGlobal_Typedef_Container", key.offset: 2485, key.length: 109, @@ -2260,7 +2251,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_Typedef_Swift3", key.offset: 2778, key.length: 121, @@ -2289,7 +2279,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_Typedef_Swift4", key.offset: 2900, key.length: 83, @@ -2349,7 +2338,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_SameContainer_Typedef_Container", key.offset: 3114, key.length: 195, @@ -2456,7 +2444,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_SameName_Typedef_Swift3", key.offset: 3503, key.length: 131, @@ -2485,7 +2472,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_SameName_Typedef_Swift4", key.offset: 3635, key.length: 88, diff --git a/test/SourceKit/InterfaceGen/gen_clang_module.swift.apinotes_swift4.response b/test/SourceKit/InterfaceGen/gen_clang_module.swift.apinotes_swift4.response index 942911aa898a2..9d8951bb7351b 100644 --- a/test/SourceKit/InterfaceGen/gen_clang_module.swift.apinotes_swift4.response +++ b/test/SourceKit/InterfaceGen/gen_clang_module.swift.apinotes_swift4.response @@ -1088,7 +1088,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "GlobalToMember_Class_Container", key.offset: 323, key.length: 87, @@ -1255,7 +1254,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_Class_Swift4", key.offset: 741, key.length: 88, @@ -1329,7 +1327,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_SameContainer_Class_Container", key.offset: 958, key.length: 105, @@ -1434,7 +1431,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_SameName_Class_Swift4", key.offset: 1253, key.length: 93, @@ -1508,7 +1504,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "GlobalToMember_Typedef_Container", key.offset: 1627, key.length: 82, @@ -1646,7 +1641,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_Typedef_Swift4", key.offset: 2045, key.length: 83, @@ -1706,7 +1700,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_SameContainer_Typedef_Container", key.offset: 2259, key.length: 100, @@ -1797,7 +1790,6 @@ extension MemberToMember_SameName_Typedef_Swift4 { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "MemberToMember_SameName_Typedef_Swift4", key.offset: 2553, key.length: 88, diff --git a/test/SourceKit/InterfaceGen/gen_clang_module.swift.response b/test/SourceKit/InterfaceGen/gen_clang_module.swift.response index 2fe21a6d289f5..429e2c8b7095a 100644 --- a/test/SourceKit/InterfaceGen/gen_clang_module.swift.response +++ b/test/SourceKit/InterfaceGen/gen_clang_module.swift.response @@ -6535,7 +6535,6 @@ public class FooOverlayClassDerived : Foo.FooOverlayClassBase { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "FooClassBase", key.offset: 5587, key.length: 66, @@ -6565,7 +6564,6 @@ public class FooOverlayClassDerived : Foo.FooOverlayClassBase { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "FooClassBase", key.offset: 5700, key.length: 107, @@ -6612,7 +6610,6 @@ public class FooOverlayClassDerived : Foo.FooOverlayClassBase { }, { key.kind: source.lang.swift.decl.extension, - key.accessibility: source.lang.swift.accessibility.internal, key.name: "FooClassBase", key.offset: 5809, key.length: 66, diff --git a/test/SourceKit/InterfaceGen/gen_stdlib.swift b/test/SourceKit/InterfaceGen/gen_stdlib.swift index e8adf40a43696..b4a8320608cce 100644 --- a/test/SourceKit/InterfaceGen/gen_stdlib.swift +++ b/test/SourceKit/InterfaceGen/gen_stdlib.swift @@ -36,7 +36,7 @@ var x: Int // CHECK1-NEXT: $s // CHECK1-NEXT: Swift{{$}} // CHECK1-NEXT: Math/Integers -// CHECK1-NEXT: /{{$}} +// CHECK1-NEXT: {{[A-Za-z]:\\|/}}{{$}} // CHECK1-NEXT: SYSTEM // CHECK1-NEXT: @frozen struct Int : FixedWidthInteger{{.*}}SignedInteger{{.*}} diff --git a/test/SourceKit/Sema/injected_vfs.swift b/test/SourceKit/Sema/injected_vfs.swift index af9d3cecd1970..b3254c41f0992 100644 --- a/test/SourceKit/Sema/injected_vfs.swift +++ b/test/SourceKit/Sema/injected_vfs.swift @@ -17,32 +17,32 @@ func foo( // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -o %t/SwiftModule.swiftmodule -module-name SwiftModule %S/../Inputs/vfs/SwiftModule/SwiftModule.swift -// RUN: %sourcekitd-test -req=open -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple == \ -// RUN: -req=print-diags -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift | %FileCheck %s +// RUN: %sourcekitd-test -req=open -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple == \ +// RUN: -req=print-diags -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift | %FileCheck %s -// RUN: not %sourcekitd-test -req=syntax-map -vfs-files=/target_file1.swift=%s /target_file1.swift -dont-print-request 2>&1 | %FileCheck %s -check-prefix=SOURCEFILE_ERROR +// RUN: not %sourcekitd-test -req=syntax-map -vfs-files=%t/VFS/target_file1.swift=%s %t/VFS/target_file1.swift -dont-print-request 2>&1 | %FileCheck %s -check-prefix=SOURCEFILE_ERROR // SOURCEFILE_ERROR: error response (Request Failed): using 'key.sourcefile' to read source text from the filesystem // RUN: not %sourcekitd-test -req=syntax-map -vfs-name nope %s -pass-as-sourcetext -dont-print-request 2>&1 | %FileCheck %s -check-prefix=NONEXISTENT_VFS_ERROR // NONEXISTENT_VFS_ERROR: error response (Request Failed): unknown virtual filesystem 'nope' // == Close the document and reopen with a new VFS (modules) == -// RUN: %sourcekitd-test -req=open -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple == \ -// RUN: -req=close -name /target_file1.swift == \ -// RUN: -req=open -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple == \ -// RUN: -req=print-diags -vfs-files=/target_file1.swift=%s /target_file1.swift /target_file1.swift | %FileCheck %s -check-prefix=NO_MODULES_VFS +// RUN: %sourcekitd-test -req=open -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple == \ +// RUN: -req=close -name %t/VFS/target_file1.swift == \ +// RUN: -req=open -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple == \ +// RUN: -req=print-diags -vfs-files=%t/VFS/target_file1.swift=%s %t/VFS/target_file1.swift %t/VFS/target_file1.swift | %FileCheck %s -check-prefix=NO_MODULES_VFS // NO_MODULES_VFS: no such module 'CModule' // == Close the document and reopen with a new VFS (inputs) == -// RUN: %sourcekitd-test -req=open -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple == \ -// RUN: -req=close -name /target_file1.swift == \ -// RUN: -req=open -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target_2.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple == \ -// RUN: -req=print-diags -vfs-files=/target_file1.swift=%s /target_file1.swift /target_file1.swift | %FileCheck %s -check-prefix=TARGET_FILE_2_MOD +// RUN: %sourcekitd-test -req=open -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple == \ +// RUN: -req=close -name %t/VFS/target_file1.swift == \ +// RUN: -req=open -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target_2.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple == \ +// RUN: -req=print-diags -vfs-files=%t/VFS/target_file1.swift=%s %t/VFS/target_file1.swift %t/VFS/target_file1.swift | %FileCheck %s -check-prefix=TARGET_FILE_2_MOD // TARGET_FILE_2_MOD: cannot convert value of type 'Void' to specified type 'String' // TARGET_FILE_2_MOD: cannot convert value of type '()' to specified type 'Float' // TARGET_FILE_2_MOD: cannot convert value of type 'Int' to specified type 'Double' // == Reopen with a new VFS without closing == -// RUN: %sourcekitd-test -req=open -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple == \ -// RUN: -req=open -vfs-files=/target_file1.swift=%s,/target_file2.swift=%S/../Inputs/vfs/other_file_in_target_2.swift,/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -I /CModule -I /SwiftModule -target %target-triple == \ -// RUN: -req=print-diags -vfs-files=/target_file1.swift=%s /target_file1.swift /target_file1.swift | %FileCheck %s -check-prefix=TARGET_FILE_2_MOD +// RUN: %sourcekitd-test -req=open -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple == \ +// RUN: -req=open -vfs-files=%t/VFS/target_file1.swift=%s,%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target_2.swift,%t/VFS/CModule/module.modulemap=%S/../Inputs/vfs/CModule/module.modulemap,%t/VFS/CModule/CModule.h=%S/../Inputs/vfs/CModule/CModule.h,%t/VFS/SwiftModule/SwiftModule.swiftmodule=%t/SwiftModule.swiftmodule %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -I %t/VFS/CModule -I %t/VFS/SwiftModule -target %target-triple == \ +// RUN: -req=print-diags -vfs-files=%t/VFS/target_file1.swift=%s %t/VFS/target_file1.swift %t/VFS/target_file1.swift | %FileCheck %s -check-prefix=TARGET_FILE_2_MOD diff --git a/test/SourceKit/Sema/injected_vfs_after_edit.swift b/test/SourceKit/Sema/injected_vfs_after_edit.swift index 2c004254f0921..a233e125091e4 100644 --- a/test/SourceKit/Sema/injected_vfs_after_edit.swift +++ b/test/SourceKit/Sema/injected_vfs_after_edit.swift @@ -4,7 +4,7 @@ func foo(_ structDefinedInSameTarget: StructDefinedInSameTarget) { // CHECK: cannot convert value of type '()' to specified type 'Int' } -// RUN: %sourcekitd-test -req=open -vfs-files=/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift %s -pass-as-sourcetext -- %s /target_file2.swift -target %target-triple == \ +// RUN: %sourcekitd-test -req=open -vfs-files=%t/VFS/target_file2.swift=%S/../Inputs/vfs/other_file_in_target.swift %s -pass-as-sourcetext -- %s %t/VFS/target_file2.swift -target %target-triple == \ // RUN: -req=print-diags %s == \ // RUN: -req=edit %s -pos=2:12 -length=6 -replace='Int' == \ // RUN: -req=print-diags %s | %FileCheck %s diff --git a/test/SourceKit/Sema/injected_vfs_sourcetext.swift b/test/SourceKit/Sema/injected_vfs_sourcetext.swift index 66161c8db5ba1..6ef1e46a82dfa 100644 --- a/test/SourceKit/Sema/injected_vfs_sourcetext.swift +++ b/test/SourceKit/Sema/injected_vfs_sourcetext.swift @@ -3,5 +3,5 @@ func foo(_ structDefinedInSameTarget: StructDefinedInSameTarget) { // CHECK: cannot convert value of type '()' to specified type 'Double' } -// RUN: %sourcekitd-test -req=open -vfs-files=/target_file1.swift=@%s,/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift /target_file1.swift -pass-as-sourcetext -- /target_file1.swift /target_file2.swift -target %target-triple == \ -// RUN: -req=print-diags -vfs-files=/target_file1.swift=@%s,/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift /target_file1.swift | %FileCheck %s +// RUN: %sourcekitd-test -req=open -vfs-files=%t/VFS/target_file1.swift=@%s,%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift %t/VFS/target_file1.swift -pass-as-sourcetext -- %t/VFS/target_file1.swift %t/VFS/target_file2.swift -target %target-triple == \ +// RUN: -req=print-diags -vfs-files=%t/VFS/target_file1.swift=@%s,%t/VFS/target_file2.swift=@%S/../Inputs/vfs/other_file_in_target.swift %t/VFS/target_file1.swift | %FileCheck %s diff --git a/test/TBD/dylib-version-truncation.swift b/test/TBD/dylib-version-truncation.swift new file mode 100644 index 0000000000000..bc9bb431f6892 --- /dev/null +++ b/test/TBD/dylib-version-truncation.swift @@ -0,0 +1,27 @@ +// REQUIRES: VENDOR=apple +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend -typecheck %s -emit-tbd-path - -tbd-current-version 2.0 | %FileCheck %s --check-prefix TWOPOINTZERO +// RUN: %target-swift-frontend -typecheck %s -emit-tbd-path - -tbd-current-version 2 | %FileCheck %s --check-prefix TWOPOINTZERO +// RUN: %target-swift-frontend -typecheck %s -emit-tbd-path - -tbd-current-version 20.10 | %FileCheck %s --check-prefix TWENTYPOINTTEN + +// RUN: %target-swift-frontend -typecheck %s -emit-tbd-path - -tbd-compatibility-version 2.0 | %FileCheck %s --check-prefix TWOPOINTZEROCOMPAT +// RUN: %target-swift-frontend -typecheck %s -emit-tbd-path - -tbd-compatibility-version 2 | %FileCheck %s --check-prefix TWOPOINTZEROCOMPAT +// RUN: %target-swift-frontend -typecheck %s -emit-tbd-path - -tbd-compatibility-version 20.10 | %FileCheck %s --check-prefix TWENTYPOINTTENCOMPAT + +// Make sure we correctly truncate a value over 255 + +// RUN: %target-swift-frontend -typecheck %s -emit-tbd-path - -tbd-current-version 20.300 2>&1 | %FileCheck %s --check-prefix TWENTYPOINTTHREEHUNDRED +// RUN: %target-swift-frontend -typecheck %s -emit-tbd-path - -tbd-compatibility-version 20.300 2>&1 | %FileCheck %s --check-prefix TWENTYPOINTTHREEHUNDREDCOMPAT + +// TWOPOINTZERO: current-version: 2 +// TWENTYPOINTTEN: current-version: 20.10 + +// TWOPOINTZEROCOMPAT: compatibility-version: 2 +// TWENTYPOINTTENCOMPAT: compatibility-version: 20.10 + +// TWENTYPOINTTHREEHUNDRED: warning: truncating current version '20.300' in TBD file to fit in 32-bit space used by old mach-o format +// TWENTYPOINTTHREEHUNDRED: current-version: 20.255 + +// TWENTYPOINTTHREEHUNDREDCOMPAT: warning: truncating compatibility version '20.300' in TBD file to fit in 32-bit space used by old mach-o format +// TWENTYPOINTTHREEHUNDREDCOMPAT: compatibility-version: 20.255 diff --git a/test/TBD/dylib-version.swift b/test/TBD/dylib-version.swift index 242cf2fc7322b..7edb907acdb85 100644 --- a/test/TBD/dylib-version.swift +++ b/test/TBD/dylib-version.swift @@ -14,4 +14,4 @@ // CURRENT: current-version: 2 // COMPAT: compatibility-version: 2 -// BOGUS: version component contains non-numeric characters +// BOGUS: invalid dynamic library compatibility version 'not_a_version_string' diff --git a/test/api-digester/Outputs/Cake-abi.txt b/test/api-digester/Outputs/Cake-abi.txt index fa5be10f2f79a..f19c8589fdd62 100644 --- a/test/api-digester/Outputs/Cake-abi.txt +++ b/test/api-digester/Outputs/Cake-abi.txt @@ -76,8 +76,6 @@ cake: Protocol P4 is a new API without @available attribute cake: Struct C6 is now with @frozen cake: Var C1.CIIns1 changes from weak to strong cake: Var C1.CIIns2 changes from strong to weak -cake: Var GlobalLetChangedToVar changes from let to var -cake: Var GlobalVarChangedToLet changes from var to let cake: Var RequiementChanges.addedVar is a new API without @available attribute cake: Var fixedLayoutStruct.$__lazy_storage_$_lazy_d is a new API without @available attribute cake: Var fixedLayoutStruct.c is a new API without @available attribute diff --git a/test/attr/attr_override.swift b/test/attr/attr_override.swift index bfe6f6df68e90..4c74cfed12d8d 100644 --- a/test/attr/attr_override.swift +++ b/test/attr/attr_override.swift @@ -626,3 +626,25 @@ class SR_10198_Derived_1: SR_10198_Base_1 { init(_ arg1: Int) { super.init(SR_10198_Base_S()) } // okay, doesn't crash } +// SR-11740 + +public class SR_11740_Base {} + +public class SR_11740_Derived + : SR_11740_Base, A>, + SR_11740_Q {} + +public protocol SR_11740_P {} + +public protocol SR_11740_Q: SR_11740_P { + associatedtype A +} + +public extension SR_11740_Base where F: SR_11740_Q { + static func foo(_: F.A) {} +} + +extension SR_11740_Derived where F: SR_11740_P { + public static func foo(_: A) {} +} + diff --git a/test/decl/class/circular_inheritance.swift b/test/decl/class/circular_inheritance.swift index f1ae0fd4a3f60..aa48b67490cc1 100644 --- a/test/decl/class/circular_inheritance.swift +++ b/test/decl/class/circular_inheritance.swift @@ -47,11 +47,12 @@ class Outer3 // expected-error {{circular reference}} } // CHECK: ===CYCLE DETECTED=== -// CHECK-NEXT: `--{{.*}}SuperclassDeclRequest({{.*Left}} -// CHECK: `--{{.*}}InheritedDeclsReferencedRequest(circular_inheritance.(file).Left@ -// CHECK: `--{{.*}}SuperclassDeclRequest -// CHECK: `--{{.*}}InheritedDeclsReferencedRequest(circular_inheritance.(file).Right@ -// CHECK: `--{{.*}}SuperclassDeclRequest{{.*(cyclic dependency)}} +// CHECK-NEXT: `--{{.*}}HasCircularInheritanceRequest(circular_inheritance.(file).Left@ +// CHECK-NEXT: `--{{.*}}SuperclassDeclRequest({{.*Left}} +// CHECK: `--{{.*}}InheritedDeclsReferencedRequest(circular_inheritance.(file).Left@ +// CHECK: `--{{.*}}SuperclassDeclRequest +// CHECK: `--{{.*}}InheritedDeclsReferencedRequest(circular_inheritance.(file).Right@ +// CHECK: `--{{.*}}SuperclassDeclRequest{{.*(cyclic dependency)}} // CHECK-DOT: digraph Dependencies // CHECK-DOT: label="InheritedTypeRequest diff --git a/test/decl/enum/bool_raw_value.swift b/test/decl/enum/bool_raw_value.swift new file mode 100644 index 0000000000000..88905f4f532ad --- /dev/null +++ b/test/decl/enum/bool_raw_value.swift @@ -0,0 +1,26 @@ +// RUN: %target-typecheck-verify-swift +extension Bool: ExpressibleByIntegerLiteral { + public init(integerLiteral value: Int) { + self = value != 0 + } +} + +enum IsDefinitelyRecursive : Bool, Equatable, Hashable { + case recursive=false +} + +// expected-error@+1{{'IsRecursive' declares raw type 'Bool', but does not conform to RawRepresentable and conformance could not be synthesized}} +enum IsRecursive : Bool, Equatable, Hashable { + case recursive=false + case nonrecursive // expected-error{{enum case must declare a raw value when the preceding raw value is not an integer}} +} + +enum IsRecursiveBad1Integral : Bool, Equatable, Hashable { + case recursive = 0 + case nonrecursive +} + +// expected-error @+1{{'IsRecursiveBad2' declares raw type 'Int', but does not conform to RawRepresentable and conformance could not be synthesized}} +enum IsRecursiveBad2 : Int, Equatable, Hashable { + case recursive = false // expected-error{{cannot convert value of type 'Bool' to raw type 'Int'}} +} diff --git a/test/decl/enum/frozen-nonresilient.swift b/test/decl/enum/frozen-nonresilient.swift index c7682ecb0e7ca..34312ec89b3c7 100644 --- a/test/decl/enum/frozen-nonresilient.swift +++ b/test/decl/enum/frozen-nonresilient.swift @@ -1,5 +1,5 @@ -// RUN: %target-typecheck-verify-swift +// RUN: %target-typecheck-verify-swift -warnings-as-errors -@frozen public enum Exhaustive {} // expected-warning {{@frozen has no effect without -enable-library-evolution}} {{1-9=}} +@frozen public enum Exhaustive {} // expected-no-warning -@frozen enum NotPublic {} // expected-warning {{@frozen has no effect without -enable-library-evolution}} {{1-9=}} +@frozen enum NotPublic {} // expected-no-warning diff --git a/test/decl/enum/objc_bool_raw_value.swift b/test/decl/enum/objc_bool_raw_value.swift new file mode 100644 index 0000000000000..5245ceac3e7f3 --- /dev/null +++ b/test/decl/enum/objc_bool_raw_value.swift @@ -0,0 +1,12 @@ +// RUN: %target-typecheck-verify-swift +// REQUIRES: objc_interop + +extension Bool: ExpressibleByIntegerLiteral { + public init(integerLiteral value: Int) { + self = value != 0 + } +} + +@objc enum IsDefinitelyRecursive : Bool, Equatable, Hashable { // expected-error{{'@objc' enum raw type 'Bool' is not an integer type}} + case recursive=false +} diff --git a/test/decl/enum/objc_enum_multi_file.swift b/test/decl/enum/objc_enum_multi_file.swift index 8cd12f876a8f1..6e4451ad7f560 100644 --- a/test/decl/enum/objc_enum_multi_file.swift +++ b/test/decl/enum/objc_enum_multi_file.swift @@ -1,9 +1,9 @@ -// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D NO_RAW_TYPE 2>&1 | %FileCheck -check-prefix=NO_RAW_TYPE %s -// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D BAD_RAW_TYPE 2>&1 | %FileCheck -check-prefix=BAD_RAW_TYPE %s -// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D NON_INT_RAW_TYPE 2>&1 | %FileCheck -check-prefix=NON_INT_RAW_TYPE %s -// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D NON_INT_RAW_VALUE 2>&1 | %FileCheck -check-prefix=NON_INT_RAW_VALUE %s -// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D NO_CASES 2>&1 | %FileCheck -check-prefix=NO_CASES %s -// RUN: not %target-swift-frontend -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D DUPLICATE_CASES 2>&1 | %FileCheck -check-prefix=DUPLICATE_CASES %s +// RUN: not %target-swift-frontend -disable-objc-attr-requires-foundation-module -enable-objc-interop -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D NO_RAW_TYPE 2>&1 | %FileCheck -check-prefix=NO_RAW_TYPE %s +// RUN: not %target-swift-frontend -disable-objc-attr-requires-foundation-module -enable-objc-interop -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D BAD_RAW_TYPE 2>&1 | %FileCheck -check-prefix=BAD_RAW_TYPE %s +// RUN: not %target-swift-frontend -disable-objc-attr-requires-foundation-module -enable-objc-interop -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D NON_INT_RAW_TYPE 2>&1 | %FileCheck -check-prefix=NON_INT_RAW_TYPE %s +// RUN: not %target-swift-frontend -disable-objc-attr-requires-foundation-module -enable-objc-interop -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D NON_INT_RAW_VALUE 2>&1 | %FileCheck -check-prefix=NON_INT_RAW_VALUE %s +// RUN: not %target-swift-frontend -disable-objc-attr-requires-foundation-module -enable-objc-interop -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D NO_CASES 2>&1 | %FileCheck -check-prefix=NO_CASES %s +// RUN: not %target-swift-frontend -disable-objc-attr-requires-foundation-module -enable-objc-interop -module-name main %s -primary-file %S/Inputs/objc_enum_multi_file_helper.swift -emit-ir -D DUPLICATE_CASES 2>&1 | %FileCheck -check-prefix=DUPLICATE_CASES %s // Note that the *other* file is the primary file in this test! #if NO_RAW_TYPE diff --git a/test/decl/ext/extensions.swift b/test/decl/ext/extensions.swift index c1cb32945f9e4..e62a20191479f 100644 --- a/test/decl/ext/extensions.swift +++ b/test/decl/ext/extensions.swift @@ -341,3 +341,11 @@ extension Tree.LimbContent.Contents { extension Tree.BoughPayload.Contents { // expected-error@-1 {{constrained extension must be declared on the unspecialized generic type 'Nest'}} } + +// SR-10466 Check 'where' clause when referencing type defined inside extension +struct SR_10466 { + var a : A // expected-error {{'SR_10466.A' (aka 'Int') requires the types 'T' and 'Never' be equivalent}} +} +extension SR_10466 where T == Never { // expected-note {{requirement specified as 'T' == 'Never' [with T = T]}} + typealias A = Int +} diff --git a/test/decl/func/operator.swift b/test/decl/func/operator.swift index 8cc6904ba3290..c9c2d5da25a37 100644 --- a/test/decl/func/operator.swift +++ b/test/decl/func/operator.swift @@ -243,7 +243,7 @@ struct S1 { } extension S1 { - func %%%%(lhs: S1, rhs: S1) -> S1 { return lhs } // expected-error{{operator '%%%%' declared in type 'S1' must be 'static'}}{{3-3=static }} + func %%%%(lhs: S1, rhs: S1) -> S1 { return lhs } // expected-error{{operator '%%%%' declared in extension of 'S1' must be 'static'}}{{3-3=static }} } class C0 { diff --git a/test/decl/init/nonnominal_init.swift b/test/decl/init/nonnominal_init.swift index 96a906f14e9be..44f22b7f141d8 100644 --- a/test/decl/init/nonnominal_init.swift +++ b/test/decl/init/nonnominal_init.swift @@ -8,9 +8,12 @@ indirect enum Or { } func deMorgan(_ ne: Not>) -> And, Not> { + // FIXME(diagnostics): The error message about initialization here is confusing return And, Not>( - Not { a in ne(.left(a)) }, // expected-error {{non-nominal type 'Not' (aka '(A) -> Never') does not support explicit initialization}} - Not { a in ne(.right(a)) } + Not { a in ne(.left(a)) }, // expected-error {{type 'Not' (aka '(A) -> Never') has no member 'init'}} + // expected-error@-1 {{type 'Or' has no member 'left'}} + Not { a in ne(.right(a)) } // expected-error {{type 'Not' (aka '(B) -> Never') has no member 'init'}} + // expected-error@-1 {{type 'Or' has no member 'right'}} ) } diff --git a/test/decl/nested/protocol.swift b/test/decl/nested/protocol.swift index 437a8d39432c6..ea5c973467b10 100644 --- a/test/decl/nested/protocol.swift +++ b/test/decl/nested/protocol.swift @@ -106,8 +106,7 @@ func testLookup(_ x: OuterForUFI.Inner) { x.extMethod() } -// N.B. Lookup fails here because OuterForUFI.Inner is marked invalid. func testLookup(_ x: T) { - x.req() // expected-error {{value of type 'T' has no member 'req'}} - x.extMethod() // expected-error {{value of type 'T' has no member 'extMethod'}} + x.req() + x.extMethod() } diff --git a/test/decl/protocol/conforms/circular_validation.swift b/test/decl/protocol/conforms/circular_validation.swift index 5d22466b7fa3b..b52a8b516f063 100644 --- a/test/decl/protocol/conforms/circular_validation.swift +++ b/test/decl/protocol/conforms/circular_validation.swift @@ -13,6 +13,6 @@ struct S : P { // expected-error {{type 'S' does not conform to protocol 'P'}} } // FIXME: Lousy diagnostics on this case. -protocol SR9224_Foo: SR9224_Foobar {} // expected-error 3 {{protocol 'SR9224_Foo' refines itself}} -protocol SR9224_Bar: SR9224_Foobar {} // expected-error {{protocol 'SR9224_Bar' refines itself}} expected-note 2 {{protocol 'SR9224_Bar' declared here}} +protocol SR9224_Foo: SR9224_Foobar {} // expected-error 2 {{protocol 'SR9224_Foo' refines itself}} +protocol SR9224_Bar: SR9224_Foobar {} // expected-note {{protocol 'SR9224_Bar' declared here}} typealias SR9224_Foobar = SR9224_Foo & SR9224_Bar diff --git a/test/decl/protocol/req/associated_type_inference_valid.swift b/test/decl/protocol/req/associated_type_inference_valid.swift new file mode 100644 index 0000000000000..af92793e5a535 --- /dev/null +++ b/test/decl/protocol/req/associated_type_inference_valid.swift @@ -0,0 +1,24 @@ +// RUN: %target-swift-frontend -emit-silgen %s + +// This is a SILGen test to ensure we can completely check these conformances +// and build valid AST. + +protocol P { + associatedtype T : Q = S + typealias Y = T.X + + func foo(_: T.X) +} + +protocol Q { + associatedtype X +} + +struct S : Q { + typealias X = () +} + +struct R : P { + let x: Y? = nil + func foo(_: Y) {} +} diff --git a/test/decl/protocol/sr8767.swift b/test/decl/protocol/sr8767.swift new file mode 100644 index 0000000000000..6b0cb653af89b --- /dev/null +++ b/test/decl/protocol/sr8767.swift @@ -0,0 +1,64 @@ +// RUN: %target-typecheck-verify-swift + +// SR-8767: a number of related problems with unqualified lookup of +// associated type names. + + +// #1 +public protocol PA { + associatedtype F +} + +public protocol PDA : PA { +} + +public protocol PrB { + associatedtype F +} + +extension PDA where Self : PrB { + public init(first: F?) { + fatalError() + } +} + +// #2 +public protocol S { associatedtype F } +public protocol AM : S {} +public protocol AL { associatedtype F } +extension AM where Self : AL { + public init(first: F?) { fatalError() } +} + +// #3 +public protocol S2 { associatedtype F } +public protocol A2 : S2 {} +public protocol Z2 { associatedtype F } +extension A2 where Self : Z2 { + public init(first: F?) { fatalError() } +} + +// #4 +public protocol BM { associatedtype F } +public protocol C : BM {} +public protocol BL { associatedtype F } +extension C where Self : BL { public init(first: F?) { fatalError() } } + +// #5 +public protocol AZ { associatedtype F } +public protocol ZA : AZ {} +public protocol AA { associatedtype F } +extension ZA where Self : AA { public init(first: F?) { fatalError() } } + +// #6 +public protocol AZ2 { associatedtype F } +public protocol ZA2 : AZ2 {} +public protocol ZZ2 { associatedtype F } +extension ZA2 where Self : ZZ2 { public init(first: F?) { fatalError() } } + +// #7 +public protocol ZA3 { associatedtype F } +public protocol AZ3 : ZA3 {} +public protocol ZZ3 { associatedtype F } +extension AZ3 where Self : ZZ3 { public init(first: F?) { fatalError() } } + diff --git a/test/decl/subscript/subscripting.swift b/test/decl/subscript/subscripting.swift index 1cd4fe9c6ff49..1cd03a75154cd 100644 --- a/test/decl/subscript/subscripting.swift +++ b/test/decl/subscript/subscripting.swift @@ -327,6 +327,7 @@ class ClassConformingToRefinedProtocol: RefinedProtocol {} struct GenSubscriptFixitTest { subscript(_ arg: T) -> Bool { return true } // expected-note 3 {{declared here}} + // expected-note@-1 2 {{in call to 'subscript(_:)'}} } func testGenSubscriptFixit(_ s0: GenSubscriptFixitTest) { @@ -339,9 +340,11 @@ func testUnresolvedMemberSubscriptFixit(_ s0: GenSubscriptFixitTest) { _ = s0.subscript // expected-error@-1 {{value of type 'GenSubscriptFixitTest' has no property or method named 'subscript'; did you mean to use the subscript operator?}} {{9-19=[<#index#>]}} + // expected-error@-2 {{generic parameter 'T' could not be inferred}} s0.subscript = true // expected-error@-1 {{value of type 'GenSubscriptFixitTest' has no property or method named 'subscript'; did you mean to use the subscript operator?}} {{5-15=[<#index#>]}} + // expected-error@-2 {{generic parameter 'T' could not be inferred}} } struct SubscriptTest1 { diff --git a/test/decl/var/property_wrappers.swift b/test/decl/var/property_wrappers.swift index 85438807c0422..bf788e570cf9e 100644 --- a/test/decl/var/property_wrappers.swift +++ b/test/decl/var/property_wrappers.swift @@ -245,7 +245,7 @@ struct Initialization { var y = true @WrapperWithInitialValue - var y2 = true // expected-error{{Bool' is not convertible to 'Int}} + var y2 = true // expected-error{{cannot convert value of type 'Bool' to specified type 'Int'}} mutating func checkTypes(s: String) { x2 = s // expected-error{{cannot assign value of type 'String' to type 'Double'}} @@ -1584,12 +1584,12 @@ struct SR_11288_S3: SR_11288_P3 { // typealias as propertyWrapper in a constrained protocol extension // protocol SR_11288_P4 {} -extension SR_11288_P4 where Self: AnyObject { // expected-note 2 {{where 'Self' = 'SR_11288_S4'}} +extension SR_11288_P4 where Self: AnyObject { // expected-note {{requirement specified as 'Self' : 'AnyObject' [with Self = SR_11288_S4]}} typealias SR_11288_Wrapper4 = SR_11288_S0 } struct SR_11288_S4: SR_11288_P4 { - @SR_11288_Wrapper4 var answer = 42 // expected-error 2 {{referencing type alias 'SR_11288_Wrapper4' on 'SR_11288_P4' requires that 'SR_11288_S4' be a class type}} + @SR_11288_Wrapper4 var answer = 42 // expected-error {{'SR_11288_S4.SR_11288_Wrapper4' (aka 'SR_11288_S0') requires that 'SR_11288_S4' be a class type}} } class SR_11288_C0: SR_11288_P4 { diff --git a/test/expr/delayed-ident/static_var.swift b/test/expr/delayed-ident/static_var.swift index 02267a4f5dbeb..e1f47308def64 100644 --- a/test/expr/delayed-ident/static_var.swift +++ b/test/expr/delayed-ident/static_var.swift @@ -50,4 +50,5 @@ var _: HasClosure = .factoryOpt(3) // expected-error@-1 {{value of optional type '((Int) -> HasClosure)?' must be unwrapped to a value of type '(Int) -> HasClosure'}} // expected-note@-2 {{coalesce}} // expected-note@-3 {{force-unwrap}} -var _: HasClosure = .factoryOpt!(4) // expected-error {{type '((Int) -> HasClosure)?' has no member 'factoryOpt'}} +// FIXME: we should accept this +var _: HasClosure = .factoryOpt!(4) // expected-error {{type 'Optional<_>' has no member 'factoryOpt'}} diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index 1f8cc1490751e..58c7d69669147 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -593,7 +593,8 @@ func conversionTest(_ a: inout Double, b: inout Int) { var e3 = Empty(Float(d)) // expected-warning {{variable 'e3' inferred to have type 'Empty', which is an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}} {{9-9=: Empty}} } -struct Rule { +// FIXME(diagnostics): This note is pointing to a synthesized init +struct Rule { // expected-note {{'init(target:dependencies:)' declared here}} var target: String var dependencies: String } @@ -603,7 +604,7 @@ var ruleVar: Rule // does argument belong to in this case. If the `target` was of a different type, we currently suggest to add an argument for `dependencies:` // which is incorrect. ruleVar = Rule("a") // expected-error {{missing argument label 'target:' in call}} - +// expected-error@-1 {{missing argument for parameter 'dependencies' in call}} class C { var x: C? diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index f49b4d9eb71a7..f6f94f1274d4e 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -36,7 +36,7 @@ struct A: Hashable { func hash(into hasher: inout Hasher) { fatalError() } } struct B {} -struct C { // expected-note 2 {{'T' declared as parameter to type 'C'}} +struct C { // expected-note 3 {{'T' declared as parameter to type 'C'}} var value: T subscript() -> T { get { return value } } subscript(sub: Sub) -> T { get { return value } set { } } @@ -230,9 +230,9 @@ func testDisembodiedStringInterpolation(x: Int) { func testNoComponents() { let _: KeyPath = \A // expected-error{{must have at least one component}} - // FIXME(diagnostics): This should be diagnosed as `missing generic parameter 'T'` instead of a contextual failure. let _: KeyPath = \C // expected-error{{must have at least one component}} expected-error{{}} - // expected-error@-1 {{cannot convert value of type 'KeyPath' to specified type 'KeyPath, A>'}} + // expected-error@-1 {{generic parameter 'T' could not be inferred}} + // expected-error@-2 {{cannot convert value of type 'KeyPath' to specified type 'KeyPath, A>'}} } struct TupleStruct { diff --git a/test/lit.cfg b/test/lit.cfg index 5f5c74913c28f..84eb51a553428 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -422,6 +422,7 @@ config.substitutions.append( ('%sil-passpipeline-dumper', "%r" % (config.sil_pas config.substitutions.append( ('%lldb-moduleimport-test', "%r %s" % (config.lldb_moduleimport_test, mcp_opt)) ) config.substitutions.append( ('%lldb-moduleimport-test-with-sdk', '%s -sdk %r' % (config.lldb_moduleimport_test, config.variant_sdk)) ) +config.substitutions.append( ('%swift-dump-pcm', "%r -dump-pcm" % config.swiftc) ) config.substitutions.append( ('%swift-ide-test_plain', config.swift_ide_test) ) config.substitutions.append( ('%swift-ide-test', "%r %s %s -swift-version %s" % (config.swift_ide_test, mcp_opt, ccp_opt, swift_version)) ) config.substitutions.append( ('%swift-syntax-test', config.swift_syntax_test) ) @@ -918,6 +919,9 @@ if run_vendor == 'apple': config.target_swift_modulewrap = ( '%s -modulewrap -target %s' % (config.swiftc, config.variant_triple)) + config.target_swift_emit_pcm = ( + '%s -emit-pcm -target %s' % + (config.swiftc, config.variant_triple)) subst_target_swift_frontend_mock_sdk_after = \ target_options_for_mock_sdk_after config.target_sil_opt = ( @@ -1007,6 +1011,8 @@ elif run_os in ['windows-msvc']: resource_dir_opt, mcp_opt)) config.target_swift_modulewrap = \ ('%r -modulewrap -target %s' % (config.swiftc, config.variant_triple)) + config.target_swift_emit_pcm = \ + ('%r -emit-pcm -target %s' % (config.swiftc, config.variant_triple)) elif (run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'windows-cygnus', 'windows-gnu'] or @@ -1047,16 +1053,16 @@ elif (run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'windows-cygnus', 'w config.target_runtime = "native" config.target_swift_autolink_extract = inferSwiftBinary("swift-autolink-extract") - libdispatch_artifact_dir = make_path(config.libdispatch_build_path, 'src') + libdispatch_artifact_dir = config.libdispatch_build_path + libdispatch_swift_module_dir = make_path(libdispatch_artifact_dir, 'src', 'swift', 'swift') libdispatch_artifacts = [ make_path(libdispatch_artifact_dir, 'libdispatch.so'), make_path(libdispatch_artifact_dir, 'libswiftDispatch.so'), - make_path(libdispatch_artifact_dir, 'swift', 'Dispatch.swiftmodule')] + make_path(libdispatch_swift_module_dir, 'Dispatch.swiftmodule')] if (all(os.path.exists(p) for p in libdispatch_artifacts)): config.available_features.add('libdispatch') config.libdispatch_artifact_dir = libdispatch_artifact_dir libdispatch_source_dir = make_path(config.swift_src_root, os.pardir, 'swift-corelibs-libdispatch') - libdispatch_swift_module_dir = make_path(libdispatch_artifact_dir, 'swift') config.import_libdispatch = ('-I %s -I %s -L %s' % (libdispatch_source_dir, libdispatch_swift_module_dir, libdispatch_artifact_dir)) @@ -1094,6 +1100,9 @@ elif (run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'windows-cygnus', 'w config.target_swift_modulewrap = ( '%s -modulewrap -target %s' % (config.swiftc, config.variant_triple)) + config.target_swift_emit_pcm = ( + '%s -emit-pcm -target %s' % + (config.swiftc, config.variant_triple)) config.target_clang = ( "clang++ -target %s %s -fobjc-runtime=ios-5.0" % (config.variant_triple, clang_mcp_opt)) @@ -1215,6 +1224,9 @@ elif run_os == 'linux-androideabi' or run_os == 'linux-android': config.target_swift_modulewrap = ' '.join([ config.swiftc, '-modulewrap', '-target', config.variant_triple]) + config.target_swift_emit_pcm = ' '.join([ + config.swiftc, '-emit-pcm', + '-target', config.variant_triple]) config.target_clang = ' '.join([ 'clang++', '-target', config.variant_triple, @@ -1651,6 +1663,8 @@ if hasattr(config, 'target_swift_autolink_extract'): config.substitutions.append(('%target-swift-modulewrap', config.target_swift_modulewrap)) +config.substitutions.append(('%target-swift-emit-pcm', + config.target_swift_emit_pcm)) config.substitutions.insert(0, ('%platform-module-dir', platform_module_dir)) config.substitutions.insert(0, ('%platform-sdk-overlay-dir', platform_sdk_overlay_dir)) diff --git a/test/stdlib/Accelerate.swift b/test/stdlib/Accelerate.swift index e1151026284d0..9f19817c9a7b7 100644 --- a/test/stdlib/Accelerate.swift +++ b/test/stdlib/Accelerate.swift @@ -77,8 +77,9 @@ if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 4.0, *) { if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { + let n = 1024 + AccelerateTests.test("vDSP/DiscreteCosineTransform") { - let n = 1024 let source = (0 ..< n).map{ i in return sin(Float(i) * 0.05) + sin(Float(i) * 0.025) @@ -110,18 +111,17 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { source, &legacyDestination) - expectTrue(destination.elementsEqual(legacyDestination)) - expectTrue(destination.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(destination, legacyDestination)) + expectTrue(elementsAlmostEqual(destination, returnedResult)) } } } - + //===----------------------------------------------------------------------===// // // Sliding window summation // //===----------------------------------------------------------------------===// - if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { AccelerateTests.test("vDSP/SinglePrecisionSlidingWindowSum") { @@ -135,7 +135,7 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { let returnedResult = vDSP.slidingWindowSum(source, usingWindowLength: 3) - expectTrue(destination.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(destination, returnedResult)) expectTrue(destination.map{ Int($0) }.elementsEqual([23, 31, 24, 19, 12, 15])) } @@ -150,8 +150,7 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { let returnedResult = vDSP.slidingWindowSum(source, usingWindowLength: 3) - expectTrue(destination.elementsEqual(returnedResult)) - + expectTrue(elementsAlmostEqual(destination, returnedResult)) expectTrue(destination.map{ Int($0) }.elementsEqual([23, 31, 24, 19, 12, 15])) } @@ -194,8 +193,8 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { let returnedResult = vDSP.linearInterpolate(a, b, using: interpolationConstant) - expectTrue(result.elementsEqual(legacyResult)) - expectTrue(result.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(result, legacyResult)) + expectTrue(elementsAlmostEqual(result, returnedResult)) } AccelerateTests.test("vDSP/SinglePrecisionInterpolateBetweenNeighbours") { @@ -230,8 +229,8 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { let returnedResult = vDSP.linearInterpolate(elementsOf: shortSignal, using: controlVector) - expectTrue(result.elementsEqual(legacyResult)) - expectTrue(result.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(result, legacyResult)) + expectTrue(elementsAlmostEqual(result, returnedResult)) } AccelerateTests.test("vDSP/DoublePrecisionInterpolateBetweenVectors") { @@ -261,8 +260,8 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { let returnedResult = vDSP.linearInterpolate(a, b, using: interpolationConstant) - expectTrue(result.elementsEqual(legacyResult)) - expectTrue(result.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(result, legacyResult)) + expectTrue(elementsAlmostEqual(result, returnedResult)) } AccelerateTests.test("vDSP/DoublePrecisionInterpolateBetweenNeighbours") { @@ -297,8 +296,8 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { let returnedResult = vDSP.linearInterpolate(elementsOf: shortSignal, using: controlVector) - expectTrue(result.elementsEqual(legacyResult)) - expectTrue(result.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(result, legacyResult)) + expectTrue(elementsAlmostEqual(result, returnedResult)) } } @@ -344,8 +343,8 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { coefficients[3], coefficients[4])) - expectTrue(result.elementsEqual(legacyResult)) - expectTrue(result.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(result, legacyResult)) + expectTrue(elementsAlmostEqual(result, returnedResult)) } AccelerateTests.test("vDSP/DifferenceEquationDoublePrecision") { @@ -382,8 +381,8 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { coefficients[3], coefficients[4])) - expectTrue(result.elementsEqual(legacyResult)) - expectTrue(result.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(result, legacyResult)) + expectTrue(elementsAlmostEqual(result, returnedResult)) } } @@ -430,8 +429,8 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { decimationFactor: decimationFactor, filter: filter) - expectTrue(result.elementsEqual(legacyResult)) - expectTrue(result.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(result, legacyResult)) + expectTrue(elementsAlmostEqual(result, returnedResult)) } AccelerateTests.test("vDSP/DownsampleDoublePrecision") { @@ -470,8 +469,8 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { decimationFactor: decimationFactor, filter: filter) - expectTrue(result.elementsEqual(legacyResult)) - expectTrue(result.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(result, legacyResult)) + expectTrue(elementsAlmostEqual(result, returnedResult)) } } @@ -503,8 +502,8 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { let returnedResult = vDSP.evaluatePolynomial(usingCoefficients: coefficients, withVariables: variables) - expectTrue(result.elementsEqual(legacyResult)) - expectTrue(result.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(result, legacyResult)) + expectTrue(elementsAlmostEqual(result, returnedResult)) } AccelerateTests.test("vDSP/PolynomialEvaluationDoublePrecision") { @@ -527,8 +526,53 @@ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { let returnedResult = vDSP.evaluatePolynomial(usingCoefficients: coefficients, withVariables: variables) - expectTrue(result.elementsEqual(legacyResult)) - expectTrue(result.elementsEqual(returnedResult)) + expectTrue(elementsAlmostEqual(result, legacyResult)) + expectTrue(elementsAlmostEqual(result, returnedResult)) + } + + //===----------------------------------------------------------------------===// + // + // Array almost equal. + // + //===----------------------------------------------------------------------===// + + func elementsAlmostEqual(_ lhs: [T], _ rhs: [T]) -> Bool { + var returnValue = true + zip(lhs, rhs).forEach { + if !isAlmostEqual($0.0, $0.1) { + returnValue = false + return + } + } + return returnValue + } + + func isAlmostEqual(_ lhs: T, + _ rhs: T, + tolerance: T = T.ulpOfOne.squareRoot()) -> Bool { + assert(tolerance >= .ulpOfOne && tolerance < 1, "tolerance should be in [.ulpOfOne, 1).") + guard lhs.isFinite && rhs.isFinite else { + return rescaledAlmostEqual(lhs, rhs, tolerance: tolerance) + } + let scale = max(abs(lhs), abs(rhs), .leastNormalMagnitude) + return abs(lhs - rhs) < scale*tolerance + } + + func rescaledAlmostEqual(_ lhs: T, + _ rhs: T, + tolerance: T) -> Bool { + if lhs.isNaN || rhs.isNaN { return false } + if lhs.isInfinite { + if rhs.isInfinite { return lhs == rhs } + let scaledLhs = T(sign: lhs.sign, + exponent: T.greatestFiniteMagnitude.exponent, + significand: 1) + let scaledRhs = T(sign: .plus, + exponent: -1, + significand: rhs) + return isAlmostEqual(scaledLhs, scaledRhs, tolerance: tolerance) + } + return rescaledAlmostEqual(rhs, lhs, tolerance: tolerance) } } diff --git a/test/stdlib/ErrorBridged.swift b/test/stdlib/ErrorBridged.swift index 958ed7c896cbc..b11d71bda1210 100644 --- a/test/stdlib/ErrorBridged.swift +++ b/test/stdlib/ErrorBridged.swift @@ -767,4 +767,29 @@ ErrorBridgingTests.test("@objc error domains for nested types") { String(reflecting: NonPrintAsObjCError.self)) } +@inline(never) +@_optimize(none) +func anyToAny(_ a: T, _ : U.Type) -> U { + return a as! U +} + +ErrorBridgingTests.test("error-to-NSObject casts") { + let error = MyCustomizedError(code: 12345) + + // Unconditional cast + let nsErrorAsObject1 = unconditionalCast(error, to: NSObject.self) + let nsError1 = unconditionalCast(nsErrorAsObject1, to: NSError.self) + expectEqual("custom", nsError1.domain) + expectEqual(12345, nsError1.code) + + // Conditional cast + let nsErrorAsObject2 = conditionalCast(error, to: NSObject.self)! + let nsError2 = unconditionalCast(nsErrorAsObject2, to: NSError.self) + expectEqual("custom", nsError2.domain) + expectEqual(12345, nsError2.code) + + // "is" check + expectTrue(error is NSObject) +} + runAllTests() diff --git a/test/stdlib/Inputs/SwiftObjectNSObject/SwiftObjectNSObject.m b/test/stdlib/Inputs/SwiftObjectNSObject/SwiftObjectNSObject.m index dc97c4221c718..700756926f15c 100644 --- a/test/stdlib/Inputs/SwiftObjectNSObject/SwiftObjectNSObject.m +++ b/test/stdlib/Inputs/SwiftObjectNSObject/SwiftObjectNSObject.m @@ -412,7 +412,6 @@ void TestSwiftObjectNSObject(id c, id d) expectTrue ([[c description] isEqual:@"SwiftObjectNSObject.C"]); expectTrue ([[D description] isEqual:@"SwiftObjectNSObject.D"]); expectTrue ([[C description] isEqual:@"SwiftObjectNSObject.C"]); - expectTrue ([[S description] isEqual:@(SwiftObjectDemangledName)]); expectTrue ([[D_meta description] isEqual:@"SwiftObjectNSObject.D"]); expectTrue ([[C_meta description] isEqual:@"SwiftObjectNSObject.C"]); expectTrue ([[S_meta description] isEqual:@(SwiftObjectDemangledName)]); @@ -430,7 +429,6 @@ void TestSwiftObjectNSObject(id c, id d) expectTrue ([[c debugDescription] isEqual:@"SwiftObjectNSObject.C"]); expectTrue ([[D debugDescription] isEqual:@"SwiftObjectNSObject.D"]); expectTrue ([[C debugDescription] isEqual:@"SwiftObjectNSObject.C"]); - expectTrue ([[S debugDescription] isEqual:@(SwiftObjectDemangledName)]); expectTrue ([[D_meta debugDescription] isEqual:@"SwiftObjectNSObject.D"]); expectTrue ([[C_meta debugDescription] isEqual:@"SwiftObjectNSObject.C"]); expectTrue ([[S_meta debugDescription] isEqual:@(SwiftObjectDemangledName)]); diff --git a/test/stdlib/OSLogPrototypeExecTest.swift b/test/stdlib/OSLogPrototypeExecTest.swift index 9e5de5ec665ca..19996a4795bfd 100644 --- a/test/stdlib/OSLogPrototypeExecTest.swift +++ b/test/stdlib/OSLogPrototypeExecTest.swift @@ -8,6 +8,8 @@ // interpolations. The new APIs are still prototypes and must be used only in // tests. +// REQUIRES: disabled_temporarily_for_ownership_transition + import OSLogPrototype import StdlibUnittest diff --git a/test/stdlib/SwiftObjectNSObject.swift b/test/stdlib/SwiftObjectNSObject.swift index c46b184c64dc6..695a357427a0d 100644 --- a/test/stdlib/SwiftObjectNSObject.swift +++ b/test/stdlib/SwiftObjectNSObject.swift @@ -45,7 +45,7 @@ func TestSwiftObjectNSObject(_ c: C, _ d: D) // This check is for NSLog() output from TestSwiftObjectNSObject(). // CHECK: c ##SwiftObjectNSObject.C## // CHECK-NEXT: d ##SwiftObjectNSObject.D## -// CHECK-NEXT: S ##{{(Swift._)?}}SwiftObject## +// CHECK-NEXT: S ##{{.*}}SwiftObject## // Temporarily disable this test on older OSes until we have time to // look into why it's failing there. rdar://problem/47870743 diff --git a/test/type/opaque.swift b/test/type/opaque.swift index 9d65b73b214a1..f17474e7d2e4a 100644 --- a/test/type/opaque.swift +++ b/test/type/opaque.swift @@ -122,7 +122,8 @@ func typeIdentity() { var af = alice af = alice af = bob // expected-error{{}} - af = grace // expected-error{{}} + af = grace // expected-error{{generic parameter 'T' could not be inferred}} + // expected-error@-1 {{cannot assign value of type '(T) -> some P' to type '() -> some P'}} } do { diff --git a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake index c555925568d40..8c4f510fde58e 100644 --- a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake +++ b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake @@ -101,7 +101,6 @@ endfunction() # # Usage: # add_sourcekit_library(name # Name of the library -# [LINK_LIBS dep1 ...] # Libraries this library will be linked with # [DEPENDS dep1 ...] # Targets this library depends on # [LLVM_LINK_COMPONENTS comp1 ...] # LLVM components this library depends on # [INSTALL_IN_COMPONENT comp] # The Swift installation component that this library belongs to. @@ -111,7 +110,7 @@ macro(add_sourcekit_library name) cmake_parse_arguments(SOURCEKITLIB "SHARED" "INSTALL_IN_COMPONENT" - "HEADERS;LINK_LIBS;DEPENDS;LLVM_LINK_COMPONENTS" + "HEADERS;DEPENDS;LLVM_LINK_COMPONENTS" ${ARGN}) set(srcs ${SOURCEKITLIB_UNPARSED_ARGUMENTS}) @@ -163,21 +162,6 @@ macro(add_sourcekit_library name) add_dependencies(${name} ${SOURCEKITLIB_DEPENDS}) endif(SOURCEKITLIB_DEPENDS) - set(prefixed_link_libraries) - foreach(dep ${SOURCEKITLIB_LINK_LIBS}) - if("${dep}" MATCHES "^clang") - set(dep "${LLVM_LIBRARY_OUTPUT_INTDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${dep}${CMAKE_STATIC_LIBRARY_SUFFIX}") - endif() - list(APPEND prefixed_link_libraries "${dep}") - endforeach() - set(SOURCEKITLIB_LINK_LIBS "${prefixed_link_libraries}") - - if("${libkind}" STREQUAL "SHARED") - target_link_libraries("${name}" PRIVATE ${SOURCEKITLIB_LINK_LIBS}) - else() - target_link_libraries("${name}" INTERFACE ${SOURCEKITLIB_LINK_LIBS}) - endif() - swift_common_llvm_config(${name} ${SOURCEKITLIB_LLVM_LINK_COMPONENTS}) if(SOURCEKITLIB_SHARED AND EXPORTED_SYMBOL_FILE) @@ -227,7 +211,6 @@ endmacro() # # Usage: # add_sourcekit_executable(name # Name of the executable -# [LINK_LIBS dep1 ...] # Libraries this executable depends on # [LLVM_LINK_COMPONENTS comp1 ...] # LLVM components this executable # # depends on # [EXCLUDE_FROM_ALL] # Whether to exclude this executable from @@ -238,7 +221,8 @@ macro(add_sourcekit_executable name) "EXCLUDE_FROM_ALL" "" # SWIFT_ENABLE_TENSORFLOW - "C_COMPILE_FLAGS;LINK_LIBS;LLVM_LINK_COMPONENTS" + "C_COMPILE_FLAGS;LLVM_LINK_COMPONENTS" + # SWIFT_ENABLE_TENSORFLOW END ${ARGN}) if (${SOURCEKITEXE_EXCLUDE_FROM_ALL}) @@ -259,7 +243,6 @@ macro(add_sourcekit_executable name) add_dependencies(${name} ${LLVM_COMMON_DEPENDS}) endif() - target_link_libraries(${name} PRIVATE ${SOURCEKITEXE_LINK_LIBS}) swift_common_llvm_config(${name} ${SOURCEKITEXE_LLVM_LINK_COMPONENTS}) target_link_libraries(${name} PRIVATE ${LLVM_COMMON_LIBS}) @@ -284,14 +267,13 @@ endmacro() # # Usage: # add_sourcekit_framework(name # Name of the framework -# [LINK_LIBS dep1 ...] # Libraries this framework will link with # [LLVM_LINK_COMPONENTS comp1 ...] # LLVM components this framework depends on # [MODULEMAP modulemap] # Module map file for this framework # [INSTALL_IN_COMPONENT comp] # The Swift installation component that this framework belongs to. # source1 [source2 source3 ...]) # Sources to add into this framework macro(add_sourcekit_framework name) cmake_parse_arguments(SOURCEKITFW - "" "MODULEMAP;INSTALL_IN_COMPONENT" "LINK_LIBS;LLVM_LINK_COMPONENTS" ${ARGN}) + "" "MODULEMAP;INSTALL_IN_COMPONENT" "LLVM_LINK_COMPONENTS" ${ARGN}) set(srcs ${SOURCEKITFW_UNPARSED_ARGUMENTS}) set(lib_dir ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR}) @@ -333,7 +315,6 @@ macro(add_sourcekit_framework name) add_dependencies(${name} ${LLVM_COMMON_DEPENDS}) endif(LLVM_COMMON_DEPENDS) - target_link_libraries(${name} PRIVATE ${SOURCEKITFW_LINK_LIBS}) swift_common_llvm_config(${name} ${SOURCEKITFW_LLVM_LINK_COMPONENTS}) if (EXPORTED_SYMBOL_FILE) @@ -411,11 +392,10 @@ endmacro(add_sourcekit_framework) # # Usage: # add_sourcekit_xpc_service(name # Name of the XPC service -# [LINK_LIBS dep1 ...] # Libraries this service will link with # [LLVM_LINK_COMPONENTS comp1 ...] # LLVM components this service depends on # source1 [source2 source3 ...]) # Sources to add into this service macro(add_sourcekit_xpc_service name framework_target) - cmake_parse_arguments(SOURCEKITXPC "" "" "LINK_LIBS;LLVM_LINK_COMPONENTS" ${ARGN}) + cmake_parse_arguments(SOURCEKITXPC "" "" "LLVM_LINK_COMPONENTS" ${ARGN}) set(srcs ${SOURCEKITXPC_UNPARSED_ARGUMENTS}) set(lib_dir ${SOURCEKIT_LIBRARY_OUTPUT_INTDIR}) @@ -456,7 +436,6 @@ macro(add_sourcekit_xpc_service name framework_target) add_dependencies(${name} ${LLVM_COMMON_DEPENDS}) endif(LLVM_COMMON_DEPENDS) - target_link_libraries(${name} PRIVATE ${SOURCEKITXPC_LINK_LIBS}) swift_common_llvm_config(${name} ${SOURCEKITXPC_LLVM_LINK_COMPONENTS}) target_link_libraries(${name} PRIVATE ${LLVM_COMMON_LIBS}) diff --git a/tools/SourceKit/lib/Core/CMakeLists.txt b/tools/SourceKit/lib/Core/CMakeLists.txt index ce80d3bbea066..4416c61229f42 100644 --- a/tools/SourceKit/lib/Core/CMakeLists.txt +++ b/tools/SourceKit/lib/Core/CMakeLists.txt @@ -3,5 +3,6 @@ add_sourcekit_library(SourceKitCore Context.cpp LangSupport.cpp NotificationCenter.cpp - LINK_LIBS SourceKitSupport ) +target_link_libraries(SourceKitCore PRIVATE + SourceKitSupport) diff --git a/tools/SourceKit/lib/Support/CMakeLists.txt b/tools/SourceKit/lib/Support/CMakeLists.txt index 587f2b62395d6..901720a521069 100644 --- a/tools/SourceKit/lib/Support/CMakeLists.txt +++ b/tools/SourceKit/lib/Support/CMakeLists.txt @@ -1,18 +1,19 @@ -set(SourceKitSupport_sources +add_sourcekit_library(SourceKitSupport Concurrency-libdispatch.cpp FuzzyStringMatcher.cpp Logging.cpp ImmutableTextBuffer.cpp ThreadSafeRefCntPtr.cpp Tracing.cpp - UIDRegistry.cpp -) - -add_sourcekit_library(SourceKitSupport - ${SourceKitSupport_sources} - LINK_LIBS swiftBasic swiftSyntax clangBasic clangRewrite -) -if(SWIFT_NEED_EXPLICIT_LIBDISPATCH) - target_link_libraries(SourceKitSupport INTERFACE dispatch BlocksRuntime) + UIDRegistry.cpp) +target_link_libraries(SourceKitSupport PRIVATE + swiftBasic + swiftSyntax + clangBasic + clangRewrite) +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + target_link_libraries(SourceKitSupport INTERFACE + dispatch + BlocksRuntime) endif() diff --git a/tools/SourceKit/lib/SwiftLang/CMakeLists.txt b/tools/SourceKit/lib/SwiftLang/CMakeLists.txt index 92fe7299dd8d5..de505e29847f7 100644 --- a/tools/SourceKit/lib/SwiftLang/CMakeLists.txt +++ b/tools/SourceKit/lib/SwiftLang/CMakeLists.txt @@ -10,31 +10,6 @@ add_sourcekit_library(SourceKitSwiftLang SwiftLangSupport.cpp SwiftSourceDocInfo.cpp SwiftTypeContextInfo.cpp - LINK_LIBS - SourceKitCore swiftDriver swiftFrontend - swiftClangImporter swiftIDE - swiftAST swiftMarkup swiftParse swiftParseSIL swiftSIL swiftSILGen - swiftSILOptimizer swiftIRGen swiftSema swiftBasic swiftSerialization - swiftSyntax swiftOption libcmark_static - # Clang dependencies. - clangIndex - clangFormat - clangToolingCore - clangFrontendTool - clangFrontend - clangDriver - clangCodeGen - clangSerialization - clangParse - clangSema - clangAnalysis - clangEdit - clangRewriteFrontend - clangRewrite - clangLex - clangAST - clangAPINotes - clangBasic LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader bitwriter @@ -49,5 +24,43 @@ add_sourcekit_library(SourceKitSwiftLang objcarcopts profiledata ) - +target_link_libraries(SourceKitSwiftLang PRIVATE + SourceKitCore + swiftDriver + swiftFrontend + swiftClangImporter + swiftIDE + swiftAST + swiftMarkup + swiftParse + swiftParseSIL + swiftSIL + swiftSILGen + swiftSILOptimizer + swiftIRGen + swiftSema + swiftBasic + swiftSerialization + swiftSyntax + swiftOption + libcmark_static + # Clang dependencies. + clangIndex + clangFormat + clangToolingCore + clangFrontendTool + clangFrontend + clangDriver + clangCodeGen + clangSerialization + clangParse + clangSema + clangAnalysis + clangEdit + clangRewriteFrontend + clangRewrite + clangLex + clangAST + clangAPINotes + clangBasic) add_dependencies(SourceKitSwiftLang clang-tablegen-targets) diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp index 48631c363fc40..bc69d52d4b9a9 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp @@ -451,6 +451,7 @@ static FrontendInputsAndOutputs resolveSymbolicLinksInInputs( llvm::SmallString<128> newFilename; if (auto err = FileSystem->getRealPath(input.file(), newFilename)) newFilename = input.file(); + llvm::sys::path::native(newFilename); bool newIsPrimary = input.isPrimary() || (!PrimaryFile.empty() && PrimaryFile == newFilename); if (newIsPrimary) { diff --git a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp index 4ab794506e2ff..6a9ee7b491a1b 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftCompletion.cpp @@ -172,6 +172,10 @@ static bool swiftCodeCompleteImpl( return false; } + // Disable source location resolutions from .swiftsourceinfo file because + // they are somewhat heavy operations and are not needed for completions. + Invocation.getFrontendOptions().IgnoreSwiftSourceInfo = true; + const char *Position = InputFile->getBufferStart() + CodeCompletionOffset; std::unique_ptr NewBuffer = llvm::WritableMemoryBuffer::getNewUninitMemBuffer( @@ -212,7 +216,7 @@ static bool swiftCodeCompleteImpl( SwiftConsumer.setContext(&CI.getASTContext(), &Invocation, &CompletionContext); registerIDETypeCheckRequestFunctions(CI.getASTContext().evaluator); - CI.performSema(); + CI.performParseAndResolveImportsOnly(); SwiftConsumer.clearContext(); return true; diff --git a/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp b/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp index 2876879da1d5e..76c308d534136 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftConformingMethodList.cpp @@ -67,6 +67,10 @@ static bool swiftConformingMethodListImpl( return false; } + // Disable source location resolutions from .swiftsourceinfo file because + // they are somewhat heavy operations and are not needed for completions. + Invocation.getFrontendOptions().IgnoreSwiftSourceInfo = true; + Invocation.setCodeCompletionPoint(newBuffer.get(), Offset); // Create a factory for code completion callbacks that will feed the @@ -82,7 +86,7 @@ static bool swiftConformingMethodListImpl( return true; } registerIDERequestFunctions(CI.getASTContext().evaluator); - CI.performSema(); + CI.performParseAndResolveImportsOnly(); return true; } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp index a911eab4f072a..8914b992bcc22 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp @@ -700,6 +700,7 @@ class SwiftDocumentSyntaxInfo { Parser.reset( new ParserUnit(SM, SourceFileKind::Main, BufferID, CompInv.getLangOptions(), + CompInv.getTypeCheckerOptions(), CompInv.getModuleName(), SynTreeCreator, CompInv.getMainFileSyntaxParsingCache()) @@ -1119,6 +1120,76 @@ static UIdent getAccessLevelUID(AccessLevel Access) { llvm_unreachable("Unhandled access level in switch."); } +static Optional +inferDefaultAccessSyntactically(const ExtensionDecl *ED) { + // Check if the extension has an explicit access control attribute. + if (auto *AA = ED->getAttrs().getAttribute()) + return std::min(std::max(AA->getAccess(), AccessLevel::FilePrivate), + AccessLevel::Public); + return None; +} + +/// Document structure is a purely syntactic request that shouldn't require name lookup +/// or type-checking, so this is a best-effort computation, particularly where extensions +/// are concerned. +static Optional inferAccessSyntactically(const ValueDecl *D) { + assert(D); + + // Check if the decl has an explicit access control attribute. + if (auto *AA = D->getAttrs().getAttribute()) + return AA->getAccess(); + + DeclContext *DC = D->getDeclContext(); + + if (D->getKind() == DeclKind::Destructor || + D->getKind() == DeclKind::EnumElement) { + if (auto container = dyn_cast(D->getDeclContext())) { + if (auto containerAccess = inferAccessSyntactically(container)) + return std::max(containerAccess.getValue(), AccessLevel::Internal); + return None; + } + return AccessLevel::Private; + } + + switch (DC->getContextKind()) { + case DeclContextKind::TopLevelCodeDecl: + return AccessLevel::FilePrivate; + case DeclContextKind::SerializedLocal: + case DeclContextKind::AbstractClosureExpr: + case DeclContextKind::EnumElementDecl: + case DeclContextKind::Initializer: + case DeclContextKind::AbstractFunctionDecl: + case DeclContextKind::SubscriptDecl: + return AccessLevel::Private; + case DeclContextKind::Module: + case DeclContextKind::FileUnit: + return AccessLevel::Internal; + case DeclContextKind::GenericTypeDecl: { + auto generic = cast(DC); + AccessLevel access = AccessLevel::Internal; + if (isa(generic)) { + if (auto protoAccess = inferAccessSyntactically(generic)) + access = std::max(AccessLevel::FilePrivate, protoAccess.getValue()); + } + return access; + } + case DeclContextKind::ExtensionDecl: + auto *ED = cast(DC); + return inferDefaultAccessSyntactically(ED); + } + + llvm_unreachable("Unhandled DeclContextKind in switch."); +} + +static Optional +inferSetterAccessSyntactically(const AbstractStorageDecl *D) { + if (!D->isSettable(/*UseDC=*/nullptr)) + return None; + if (auto *AA = D->getAttrs().getAttribute()) + return AA->getAccess(); + return inferAccessSyntactically(D); +} + class SwiftDocumentStructureWalker: public ide::SyntaxModelWalker { SourceManager &SrcManager; EditorConsumer &Consumer; @@ -1175,16 +1246,15 @@ class SwiftDocumentStructureWalker: public ide::SyntaxModelWalker { Node.Kind != SyntaxStructureKind::LocalVariable && Node.Kind != SyntaxStructureKind::GenericTypeParam) { if (auto *VD = dyn_cast_or_null(Node.Dcl)) { - AccessLevel = getAccessLevelUID(VD->getFormalAccess()); + if (auto Access = inferAccessSyntactically(VD)) + AccessLevel = getAccessLevelUID(Access.getValue()); } else if (auto *ED = dyn_cast_or_null(Node.Dcl)) { - auto StrictAccess = ED->getDefaultAccessLevel(); - AccessLevel = getAccessLevelUID(StrictAccess); + if (auto DefaultAccess = inferDefaultAccessSyntactically(ED)) + AccessLevel = getAccessLevelUID(DefaultAccess.getValue()); } if (auto *ASD = dyn_cast_or_null(Node.Dcl)) { - if (ASD->isSettable(/*UseDC=*/nullptr)) { - swift::AccessLevel SetAccess = ASD->getSetterFormalAccess(); - SetterAccessLevel = getAccessLevelUID(SetAccess); - } + if (auto SetAccess = inferSetterAccessSyntactically(ASD)) + SetterAccessLevel = getAccessLevelUID(SetAccess.getValue()); } } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp index 827ce50cad7b6..efce517d4b6d2 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp @@ -984,36 +984,10 @@ void SwiftLangSupport::printMemberDeclDescription(const swift::ValueDecl *VD, std::string SwiftLangSupport::resolvePathSymlinks(StringRef FilePath) { std::string InputPath = FilePath; -#if !defined(_WIN32) - char full_path[MAXPATHLEN]; - if (const char *path = realpath(InputPath.c_str(), full_path)) - return path; - - return InputPath; -#else - wchar_t full_path[MAX_PATH] = {0}; - llvm::SmallVector utf16Path; - llvm::convertUTF8ToUTF16String(InputPath.c_str(), utf16Path); - - HANDLE fileHandle = CreateFileW( - (LPCWSTR)utf16Path.data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - - if (fileHandle == INVALID_HANDLE_VALUE) + llvm::SmallString<256> output; + if (llvm::sys::fs::real_path(InputPath, output)) return InputPath; - - DWORD numChars = GetFinalPathNameByHandleW(fileHandle, full_path, MAX_PATH, - FILE_NAME_NORMALIZED); - CloseHandle(fileHandle); - std::string utf8Path; - if (numChars > 0 && numChars <= MAX_PATH) { - llvm::ArrayRef pathRef((const char *)full_path, - (const char *)(full_path + numChars)); - return llvm::convertUTF16ToUTF8String(pathRef, utf8Path) ? utf8Path - : InputPath; - } - return InputPath; -#endif + return output.str(); } void SwiftLangSupport::getStatistics(StatisticsReceiver receiver) { diff --git a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp index 74e8ee8c05978..63710d6f8d6c6 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp @@ -21,6 +21,7 @@ #include "swift/AST/ASTPrinter.h" #include "swift/AST/Decl.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/NameLookupRequests.h" #include "swift/AST/SwiftNameTranslation.h" #include "swift/AST/GenericSignature.h" #include "swift/Basic/SourceManager.h" @@ -495,10 +496,14 @@ void walkRelatedDecls(const ValueDecl *VD, const FnTy &Fn) { // FIXME: Extract useful related declarations, overloaded functions, // if VD is an initializer, we should extract other initializers etc. - // For now we use UnqualifiedLookup to fetch other declarations with the same + // For now we use unqualified lookup to fetch other declarations with the same // base name. - UnqualifiedLookup Lookup(VD->getBaseName(), VD->getDeclContext()); - for (auto result : Lookup.Results) { + auto &ctx = VD->getASTContext(); + auto descriptor = UnqualifiedLookupDescriptor(VD->getBaseName(), + VD->getDeclContext()); + auto lookup = evaluateOrDefault(ctx.evaluator, + UnqualifiedLookupRequest{descriptor}, {}); + for (auto result : lookup) { ValueDecl *RelatedVD = result.getValueDecl(); if (RelatedVD->getAttrs().isUnavailable(VD->getASTContext())) continue; @@ -778,12 +783,11 @@ static bool passCursorInfoForDecl(SourceFile* SF, unsigned USREnd = SS.size(); unsigned TypenameBegin = SS.size(); - if (auto vdType = VD->getInterfaceType()) { - llvm::raw_svector_ostream OS(SS); - PrintOptions Options; - Options.PrintTypeAliasUnderlyingType = true; - vdType.print(OS, Options); - } + llvm::raw_svector_ostream OS(SS); + PrintOptions Options; + Options.PrintTypeAliasUnderlyingType = true; + VD->getInterfaceType().print(OS, Options); + unsigned TypenameEnd = SS.size(); unsigned MangledTypeStart = SS.size(); diff --git a/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp b/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp index af7edc90b91bc..285052d3a2895 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftTypeContextInfo.cpp @@ -67,6 +67,10 @@ static bool swiftTypeContextInfoImpl(SwiftLangSupport &Lang, return false; } + // Disable source location resolutions from .swiftsourceinfo file because + // they are somewhat heavy operations and are not needed for completions. + Invocation.getFrontendOptions().IgnoreSwiftSourceInfo = true; + Invocation.setCodeCompletionPoint(newBuffer.get(), Offset); // Create a factory for code completion callbacks that will feed the @@ -81,7 +85,7 @@ static bool swiftTypeContextInfoImpl(SwiftLangSupport &Lang, return true; } registerIDETypeCheckRequestFunctions(CI.getASTContext().evaluator); - CI.performSema(); + CI.performParseAndResolveImportsOnly(); return true; } diff --git a/tools/SourceKit/tools/complete-test/CMakeLists.txt b/tools/SourceKit/tools/complete-test/CMakeLists.txt index f65a890c4c2b6..71a9ffde2c46d 100644 --- a/tools/SourceKit/tools/complete-test/CMakeLists.txt +++ b/tools/SourceKit/tools/complete-test/CMakeLists.txt @@ -1,16 +1,16 @@ -if(SWIFT_SOURCEKIT_USE_INPROC_LIBRARY) - set(SOURCEKITD_TEST_LINK_LIBS sourcekitdInProc) -else() - set(SOURCEKITD_TEST_LINK_LIBS sourcekitd) -endif() - add_sourcekit_executable(complete-test complete-test.cpp - LINK_LIBS ${SOURCEKITD_TEST_LINK_LIBS} - LLVM_LINK_COMPONENTS support option coverage lto + LLVM_LINK_COMPONENTS option coverage lto ) -if(SWIFT_NEED_EXPLICIT_LIBDISPATCH) - target_link_libraries(complete-test PRIVATE dispatch BlocksRuntime) +if(SWIFT_SOURCEKIT_USE_INPROC_LIBRARY) + target_link_libraries(complete-test PRIVATE sourcekitdInProc) +else() + target_link_libraries(complete-test PRIVATE sourcekitd) +endif() +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + target_link_libraries(complete-test PRIVATE + dispatch + BlocksRuntime) endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") diff --git a/tools/SourceKit/tools/sourcekitd-repl/CMakeLists.txt b/tools/SourceKit/tools/sourcekitd-repl/CMakeLists.txt index 32e49a17b6e7f..49c40efe5b9ff 100644 --- a/tools/SourceKit/tools/sourcekitd-repl/CMakeLists.txt +++ b/tools/SourceKit/tools/sourcekitd-repl/CMakeLists.txt @@ -2,19 +2,20 @@ set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} edit) check_symbol_exists(el_wgets "histedit.h" HAVE_UNICODE_LIBEDIT) if(HAVE_UNICODE_LIBEDIT) - if(SWIFT_SOURCEKIT_USE_INPROC_LIBRARY) - set(SOURCEKITD_REPL_LINK_LIBS sourcekitdInProc) - else() - set(SOURCEKITD_REPL_LINK_LIBS sourcekitd) - endif() - add_sourcekit_executable(sourcekitd-repl sourcekitd-repl.cpp - LINK_LIBS ${SOURCEKITD_REPL_LINK_LIBS} edit - LLVM_LINK_COMPONENTS support coverage lto + LLVM_LINK_COMPONENTS coverage lto ) - if(SWIFT_NEED_EXPLICIT_LIBDISPATCH) - target_link_libraries(sourcekitd-repl PRIVATE dispatch BlocksRuntime) + target_link_libraries(sourcekitd-repl PRIVATE edit) + if(SWIFT_SOURCEKIT_USE_INPROC_LIBRARY) + target_link_libraries(sourcekitd-repl PRIVATE sourcekitdInProc) + else() + target_link_libraries(sourcekitd-repl PRIVATE sourcekitd) + endif() + if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + target_link_libraries(sourcekitd-repl PRIVATE + dispatch + BlocksRuntime) endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") diff --git a/tools/SourceKit/tools/sourcekitd-test/CMakeLists.txt b/tools/SourceKit/tools/sourcekitd-test/CMakeLists.txt index 15e5d0e2bda11..822f338a452d1 100644 --- a/tools/SourceKit/tools/sourcekitd-test/CMakeLists.txt +++ b/tools/SourceKit/tools/sourcekitd-test/CMakeLists.txt @@ -2,24 +2,34 @@ set(LLVM_TARGET_DEFINITIONS Options.td) swift_tablegen(Options.inc -gen-opt-parser-defs) swift_add_public_tablegen_target(sourcekitdTestOptionsTableGen) +# SWIFT_ENABLE_TENSORFLOW if(SWIFT_SOURCEKIT_USE_INPROC_LIBRARY) - set(SOURCEKITD_TEST_LINK_LIBS sourcekitdInProc) set(SOURCEKITD_TEST_CFLAGS "-DSWIFT_SOURCEKIT_USE_INPROC_LIBRARY") else() - set(SOURCEKITD_TEST_LINK_LIBS sourcekitd) set(SOURCEKITD_TEST_CFLAGS) endif() +# SWIFT_ENABLE_TENSORFLOW END add_sourcekit_executable(sourcekitd-test sourcekitd-test.cpp TestOptions.cpp C_COMPILE_FLAGS ${SOURCEKITD_TEST_CFLAGS} - LINK_LIBS ${SOURCEKITD_TEST_LINK_LIBS} SourceKitSupport - clangRewrite clangLex clangBasic - LLVM_LINK_COMPONENTS core support option coverage lto + LLVM_LINK_COMPONENTS core option coverage lto ) -if(SWIFT_NEED_EXPLICIT_LIBDISPATCH) - target_link_libraries(sourcekitd-test PRIVATE dispatch BlocksRuntime) +target_link_libraries(sourcekitd-test PRIVATE + SourceKitSupport + clangRewrite + clangLex + clangBasic) +if(SWIFT_SOURCEKIT_USE_INPROC_LIBRARY) + target_link_libraries(sourcekitd-test PRIVATE sourcekitdInProc) +else() + target_link_libraries(sourcekitd-test PRIVATE sourcekitd) +endif() +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + target_link_libraries(sourcekitd-test PRIVATE + dispatch + BlocksRuntime) endif() add_dependencies(sourcekitd-test sourcekitdTestOptionsTableGen) diff --git a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp index d5aabc5351bb6..11713849c9fc2 100644 --- a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp @@ -16,6 +16,7 @@ #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" using namespace sourcekitd_test; @@ -374,8 +375,10 @@ bool TestOptions::parseArgs(llvm::ArrayRef Args) { for (const char *vfsFile : InputArg->getValues()) { StringRef name, target; std::tie(name, target) = StringRef(vfsFile).split('='); + llvm::SmallString<64> nativeName; + llvm::sys::path::native(name, nativeName); bool passAsSourceText = target.consume_front("@"); - VFSFiles.try_emplace(name, VFSFile(target.str(), passAsSourceText)); + VFSFiles.try_emplace(nativeName.str(), VFSFile(target.str(), passAsSourceText)); } break; diff --git a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp index e79b44c24f378..a0b6ef78fe6f5 100644 --- a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp @@ -29,6 +29,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Threading.h" @@ -53,35 +54,6 @@ using namespace sourcekitd_test; #if defined(_WIN32) namespace { int STDOUT_FILENO = _fileno(stdout); -const constexpr size_t MAXPATHLEN = MAX_PATH + 1; -char *realpath(const char *path, char *resolved_path) { - wchar_t full_path[MAXPATHLEN] = {0}; - llvm::SmallVector utf16Path; - llvm::convertUTF8ToUTF16String(path, utf16Path); - - HANDLE fileHandle = CreateFileW( - (LPCWSTR)utf16Path.data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - - if (fileHandle == INVALID_HANDLE_VALUE) - return nullptr; - DWORD success = GetFinalPathNameByHandleW(fileHandle, full_path, MAX_PATH, - FILE_NAME_NORMALIZED); - CloseHandle(fileHandle); - if (!success) return nullptr; - - std::string utf8Path; - llvm::ArrayRef pathRef((const char *)full_path, - (const char *)(full_path + MAX_PATH)); - if (!llvm::convertUTF16ToUTF8String(pathRef, utf8Path)) - return nullptr; - - if (!resolved_path) { - resolved_path = static_cast(malloc(utf8Path.length() + 1)); - } - std::copy(std::begin(utf8Path), std::end(utf8Path), resolved_path); - return resolved_path; -} } #endif @@ -316,6 +288,7 @@ static inline std::string getInterfaceGenDocumentName() { // "Absolute path" on all platforms since handleTestInvocation will attempt to make this absolute llvm::SmallString<64> path = llvm::StringRef("/"); llvm::sys::fs::make_absolute(path); + llvm::sys::path::native(path); return path.str(); } @@ -489,6 +462,7 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) { llvm::SmallString<64> AbsSourceFile; AbsSourceFile += SourceFile; llvm::sys::fs::make_absolute(AbsSourceFile); + llvm::sys::path::native(AbsSourceFile); SourceFile = AbsSourceFile.str(); } std::string SemaName = !Opts.Name.empty() ? Opts.Name : SourceFile; @@ -1459,9 +1433,9 @@ static void printCursorInfo(sourcekitd_variant_t Info, StringRef FilenameIn, } std::string Filename = FilenameIn; - char full_path[MAXPATHLEN]; - if (const char *path = realpath(Filename.c_str(), full_path)) - Filename = path; + llvm::SmallString<256> output; + if (!llvm::sys::fs::real_path(Filename, output)) + Filename = output.str(); const char *Kind = sourcekitd_uid_get_string_ptr(KindUID); const char *USR = sourcekitd_variant_dictionary_get_string(Info, KeyUSR); @@ -1631,9 +1605,9 @@ static void printRangeInfo(sourcekitd_variant_t Info, StringRef FilenameIn, } std::string Filename = FilenameIn; - char full_path[MAXPATHLEN]; - if (const char *path = realpath(Filename.c_str(), full_path)) - Filename = path; + llvm::SmallString<256> output; + if (llvm::sys::fs::real_path(Filename, output)) + Filename = output.str(); sourcekitd_variant_t OffsetObj = sourcekitd_variant_dictionary_get_value(Info, KeyOffset); diff --git a/tools/SourceKit/tools/sourcekitd/bin/InProc/CMakeLists.txt b/tools/SourceKit/tools/sourcekitd/bin/InProc/CMakeLists.txt index fb59e74837520..8c410713d850a 100644 --- a/tools/SourceKit/tools/sourcekitd/bin/InProc/CMakeLists.txt +++ b/tools/SourceKit/tools/sourcekitd/bin/InProc/CMakeLists.txt @@ -5,7 +5,6 @@ option(SOURCEKITD_BUILD_STATIC_INPROC set(sourcekitdInProc_args sourcekitdInProc.cpp - LINK_LIBS SourceKitSwiftLang sourcekitdAPI LLVM_LINK_COMPONENTS support coverage ) @@ -36,6 +35,9 @@ else() SHARED ) endif() +target_link_libraries(sourcekitdInProc PRIVATE + SourceKitSwiftLang + sourcekitdAPI) # While it is possible to build this as a static library, # to get the runtime paths correct, it must be linked into a binary @@ -46,6 +48,9 @@ if (SOURCEKITD_BUILD_STATIC_INPROC) ${SOURCEKITD_SOURCE_DIR}/include/sourcekitd/sourcekitd.h ${sourcekitdInProc_args} ) + target_link_libraries(sourcekitdInProc_Static PRIVATE + SourceKitSwiftLang + sourcekitdAPI) endif() if (SOURCEKIT_BUILT_STANDALONE) diff --git a/tools/SourceKit/tools/sourcekitd/bin/XPC/Client/CMakeLists.txt b/tools/SourceKit/tools/sourcekitd/bin/XPC/Client/CMakeLists.txt index 638d3ac7e1561..fda4baa96d524 100644 --- a/tools/SourceKit/tools/sourcekitd/bin/XPC/Client/CMakeLists.txt +++ b/tools/SourceKit/tools/sourcekitd/bin/XPC/Client/CMakeLists.txt @@ -10,11 +10,11 @@ set(EXPORTED_SYMBOL_FILE "${SOURCEKITD_SOURCE_DIR}/bin/sourcekitd.exports") add_sourcekit_framework(sourcekitd ${public_headers} sourcekitd.cpp - LINK_LIBS sourcekitdAPI LLVM_LINK_COMPONENTS support MODULEMAP module.modulemap INSTALL_IN_COMPONENT sourcekit-xpc-service ) +target_link_libraries(sourcekitd PRIVATE sourcekitdAPI) add_definitions(-DSOURCEKIT_XPCSERVICE_IDENTIFIER="com.apple.SourceKitService.${SOURCEKIT_VERSION_STRING}_${SOURCEKIT_PLATFORM_NAME}") diff --git a/tools/SourceKit/tools/sourcekitd/bin/XPC/Service/CMakeLists.txt b/tools/SourceKit/tools/sourcekitd/bin/XPC/Service/CMakeLists.txt index 4a007bd7439e3..f7928fc5bc5e1 100644 --- a/tools/SourceKit/tools/sourcekitd/bin/XPC/Service/CMakeLists.txt +++ b/tools/SourceKit/tools/sourcekitd/bin/XPC/Service/CMakeLists.txt @@ -1,9 +1,11 @@ if (NOT SOURCEKIT_INSTALLING_INPROC) add_sourcekit_xpc_service(SourceKitService sourcekitd XPCService.cpp - LINK_LIBS SourceKitSwiftLang sourcekitdAPI LLVM_LINK_COMPONENTS support coverage ) + target_link_libraries(SourceKitService PRIVATE + SourceKitSwiftLang + sourcekitdAPI) endif() if (NOT SOURCEKIT_DEPLOYMENT_OS MATCHES "^macosx") diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/CMakeLists.txt b/tools/SourceKit/tools/sourcekitd/lib/API/CMakeLists.txt index c29f9d32ff208..adb608642216e 100644 --- a/tools/SourceKit/tools/sourcekitd/lib/API/CMakeLists.txt +++ b/tools/SourceKit/tools/sourcekitd/lib/API/CMakeLists.txt @@ -1,5 +1,8 @@ +set(LLVM_OPTIONAL_SOURCES + sourcekitdAPI-XPC.cpp + sourcekitdAPI-InProc.cpp) -set(sourcekitdAPI_sources +add_sourcekit_library(sourcekitdAPI CodeCompletionResultsArray.cpp CompactArray.cpp DocStructureArray.cpp @@ -10,21 +13,14 @@ set(sourcekitdAPI_sources TokenAnnotationsArray.cpp ExpressionTypeArray.cpp ) - -set(sourcekitdAPI_Darwin_sources - sourcekitdAPI-XPC.cpp) -set(sourcekitdAPI_NonDarwin_InProc_sources - sourcekitdAPI-InProc.cpp) -set(LLVM_OPTIONAL_SOURCES ${sourcekitdAPI_Darwin_sources} ${sourcekitdAPI_NonDarwin_InProc_sources}) +target_link_libraries(sourcekitdAPI PRIVATE + SourceKitSupport + SourceKitSwiftLang) if(APPLE AND HAVE_XPC_H) - list(APPEND sourcekitdAPI_sources ${sourcekitdAPI_Darwin_sources}) + target_sources(sourcekitdAPI PRIVATE + sourcekitdAPI-XPC.cpp) elseif(SWIFT_SOURCEKIT_USE_INPROC_LIBRARY) - list(APPEND sourcekitdAPI_sources ${sourcekitdAPI_NonDarwin_InProc_sources}) + target_sources(sourcekitdAPI PRIVATE + sourcekitdAPI-InProc.cpp) endif() - -add_sourcekit_library(sourcekitdAPI - ${sourcekitdAPI_sources} - LINK_LIBS - SourceKitSupport SourceKitSwiftLang -) diff --git a/tools/SourceKit/tools/swift-lang/CMakeLists.txt b/tools/SourceKit/tools/swift-lang/CMakeLists.txt index 61824c85dac10..8db6dbe81a7d9 100644 --- a/tools/SourceKit/tools/swift-lang/CMakeLists.txt +++ b/tools/SourceKit/tools/swift-lang/CMakeLists.txt @@ -1,9 +1,4 @@ if(NOT SWIFT_SOURCEKIT_USE_INPROC_LIBRARY AND SWIFT_BUILD_STDLIB AND SWIFT_BUILD_SDK_OVERLAY) - set(EXTRA_COMPILE_FLAGS "-F" "${SWIFT_LIBRARY_OUTPUT_INTDIR}") - set(SOURCEKITD_LINK_LIBS sourcekitd) - set(INSTALLED_COMP sourcekit-xpc-service) - set(DEPENDS_LIST "sourcekitd-test") - # The build type of swiftlang should agree with stdlib # This setting could avoid us adding additional search paths when building # executables using SwiftLang. @@ -25,11 +20,11 @@ if(NOT SWIFT_SOURCEKIT_USE_INPROC_LIBRARY AND SWIFT_BUILD_STDLIB AND SWIFT_BUILD GYB_SOURCES UIDs.swift.gyb - DEPENDS ${DEPENDS_LIST} + DEPENDS sourcekitd-test SWIFT_MODULE_DEPENDS_OSX Darwin Foundation - PRIVATE_LINK_LIBRARIES ${SOURCEKITD_LINK_LIBS} - SWIFT_COMPILE_FLAGS ${EXTRA_COMPILE_FLAGS} - INSTALL_IN_COMPONENT ${INSTALLED_COMP} + PRIVATE_LINK_LIBRARIES sourcekitd + SWIFT_COMPILE_FLAGS -F${SWIFT_LIBRARY_OUTPUT_INTDIR} + INSTALL_IN_COMPONENT sourcekit-xpc-service DARWIN_INSTALL_NAME_DIR "@rpath" TARGET_SDKS ${SOURCEKIT_DEFAULT_TARGET_SDK} IS_STDLIB) diff --git a/tools/driver/modulewrap_main.cpp b/tools/driver/modulewrap_main.cpp index 886d7a62fba45..57e4f64996613 100644 --- a/tools/driver/modulewrap_main.cpp +++ b/tools/driver/modulewrap_main.cpp @@ -27,7 +27,7 @@ #include "swift/SIL/TypeLowering.h" #include "swift/Subsystems.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/FileSystem.h" @@ -156,20 +156,17 @@ int modulewrap_main(ArrayRef Args, const char *Argv0, // Wrap the bitstream in a module object file. To use the ClangImporter to // create the module loader, we need to properly set the runtime library path. SearchPathOptions SearchPathOpts; - // FIXME: This logic has been duplicated from - // CompilerInvocation::setMainExecutablePath. ModuleWrapInvocation - // should share its implementation. - SmallString<128> RuntimeResourcePath(MainExecutablePath); - llvm::sys::path::remove_filename(RuntimeResourcePath); // Remove /swift - llvm::sys::path::remove_filename(RuntimeResourcePath); // Remove /bin - llvm::sys::path::append(RuntimeResourcePath, "lib", "swift"); + SmallString<128> RuntimeResourcePath; + CompilerInvocation::computeRuntimeResourcePathFromExecutablePath( + MainExecutablePath, RuntimeResourcePath); SearchPathOpts.RuntimeResourcePath = RuntimeResourcePath.str(); SourceManager SrcMgr; + TypeCheckerOptions TypeCheckOpts; LangOptions LangOpts; LangOpts.Target = Invocation.getTargetTriple(); - ASTContext &ASTCtx = *ASTContext::get(LangOpts, SearchPathOpts, SrcMgr, - Instance.getDiags()); + ASTContext &ASTCtx = *ASTContext::get(LangOpts, TypeCheckOpts, SearchPathOpts, + SrcMgr, Instance.getDiags()); registerParseRequestFunctions(ASTCtx.evaluator); registerTypeCheckerRequestFunctions(ASTCtx.evaluator); diff --git a/tools/driver/swift_indent_main.cpp b/tools/driver/swift_indent_main.cpp index 2c57d7d95aedd..bb44ea8a085b4 100644 --- a/tools/driver/swift_indent_main.cpp +++ b/tools/driver/swift_indent_main.cpp @@ -61,6 +61,7 @@ class FormatterDocument { BufferID = SM.addNewSourceBuffer(std::move(Buffer)); Parser.reset(new ParserUnit(SM, SourceFileKind::Main, BufferID, CompInv.getLangOptions(), + CompInv.getTypeCheckerOptions(), CompInv.getModuleName())); Parser->getDiagnosticEngine().addConsumer(DiagConsumer); Parser->parse(); diff --git a/tools/libSwiftSyntaxParser/CMakeLists.txt b/tools/libSwiftSyntaxParser/CMakeLists.txt index 86818279b9f77..42dda212164de 100644 --- a/tools/libSwiftSyntaxParser/CMakeLists.txt +++ b/tools/libSwiftSyntaxParser/CMakeLists.txt @@ -45,8 +45,9 @@ endif() set_property(TARGET libSwiftSyntaxParser APPEND_STRING PROPERTY COMPILE_FLAGS " -fblocks") -if(SWIFT_NEED_EXPLICIT_LIBDISPATCH) - target_link_libraries(libSwiftSyntaxParser PRIVATE BlocksRuntime) +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + target_link_libraries(libSwiftSyntaxParser PRIVATE + BlocksRuntime) endif() add_dependencies(parser-lib libSwiftSyntaxParser) diff --git a/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp b/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp index 177b2ed07c969..006ca9fa6e67b 100644 --- a/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp +++ b/tools/libSwiftSyntaxParser/libSwiftSyntaxParser.cpp @@ -274,6 +274,7 @@ swiftparse_client_node_t SynParser::parse(const char *source) { SourceManager SM; unsigned bufID = SM.addNewSourceBuffer( llvm::MemoryBuffer::getMemBuffer(source, "syntax_parse_source")); + TypeCheckerOptions tyckOpts; LangOptions langOpts; langOpts.BuildSyntaxTree = true; langOpts.CollectParsedToken = false; @@ -285,7 +286,7 @@ swiftparse_client_node_t SynParser::parse(const char *source) { std::make_shared(*this, SM, bufID); // We have to use SourceFileKind::Main to avoid diagnostics like // illegal_top_level_expr - ParserUnit PU(SM, SourceFileKind::Main, bufID, langOpts, + ParserUnit PU(SM, SourceFileKind::Main, bufID, langOpts, tyckOpts, "syntax_parse_module", std::move(parseActions), /*SyntaxCache=*/nullptr); // Evaluating pound conditions may lead to unknown syntax. diff --git a/tools/sil-opt/SILOpt.cpp b/tools/sil-opt/SILOpt.cpp index 38178cf6657b4..4c9cfb0701de0 100644 --- a/tools/sil-opt/SILOpt.cpp +++ b/tools/sil-opt/SILOpt.cpp @@ -222,6 +222,14 @@ EnableExperimentalStaticAssert( "enable-experimental-static-assert", llvm::cl::Hidden, llvm::cl::init(false), llvm::cl::desc("Enable experimental #assert")); +static llvm::cl::opt EnableExperimentalDifferentiableProgramming( + "enable-experimental-differentiable-programming", llvm::cl::Hidden, + // SWIFT_ENABLE_TENSORFLOW + // Use default value true on `tensorflow` branch. + llvm::cl::init(true), + // SWIFT_ENABLE_TENSORFLOW END + llvm::cl::desc("Enable experimental differentiable programming")); + /// Regular expression corresponding to the value given in one of the /// -pass-remarks* command line flags. Passes whose name matches this regexp /// will emit a diagnostic. @@ -338,6 +346,9 @@ int main(int argc, char **argv) { Invocation.getLangOptions().EnableExperimentalStaticAssert = EnableExperimentalStaticAssert; + Invocation.getLangOptions().EnableExperimentalDifferentiableProgramming = + EnableExperimentalDifferentiableProgramming; + // Setup the SIL Options. SILOptions &SILOpts = Invocation.getSILOptions(); SILOpts.InlineThreshold = SILInlineThreshold; diff --git a/tools/swift-api-digester/ModuleDiagsConsumer.cpp b/tools/swift-api-digester/ModuleDiagsConsumer.cpp index 43461821d1b57..dcb9902633de3 100644 --- a/tools/swift-api-digester/ModuleDiagsConsumer.cpp +++ b/tools/swift-api-digester/ModuleDiagsConsumer.cpp @@ -42,7 +42,6 @@ static StringRef getCategoryName(uint32_t ID) { return "/* Renamed Decls */"; case LocalDiagID::decl_attr_change: case LocalDiagID::decl_new_attr: - case LocalDiagID::var_let_changed: case LocalDiagID::func_self_access_change: case LocalDiagID::new_decl_without_intro: return "/* Decl Attribute changes */"; diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index e1c63597f87dc..dcc6e06131126 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -962,9 +962,6 @@ void swift::ide::api::SDKNodeDeclVar::diagnose(SDKNode *Right) { if (hasFixedBinaryOrder() != RV->hasFixedBinaryOrder()) { emitDiag(Loc, diag::var_has_fixed_order_change, hasFixedBinaryOrder()); } - if (isLet() != RV->isLet()) { - emitDiag(Loc, diag::var_let_changed, isLet()); - } } } diff --git a/tools/swift-ast-script/ASTScriptEvaluator.cpp b/tools/swift-ast-script/ASTScriptEvaluator.cpp index 7731d5976d94f..8158783563e67 100644 --- a/tools/swift-ast-script/ASTScriptEvaluator.cpp +++ b/tools/swift-ast-script/ASTScriptEvaluator.cpp @@ -21,6 +21,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/NameLookup.h" +#include "swift/AST/NameLookupRequests.h" #include "swift/Frontend/Frontend.h" using namespace swift; @@ -114,7 +115,10 @@ bool ASTScript::execute() const { return true; } - UnqualifiedLookup viewLookup(ctx.getIdentifier("View"), swiftUI); + auto descriptor = UnqualifiedLookupDescriptor(ctx.getIdentifier("View"), + swiftUI); + auto viewLookup = evaluateOrDefault(ctx.evaluator, + UnqualifiedLookupRequest{descriptor}, {}); auto viewProtocol = dyn_cast_or_null(viewLookup.getSingleTypeResult()); if (!viewProtocol) { diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index 64829bb8cd6ce..266bac16e6e2b 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -22,6 +22,7 @@ #include "swift/AST/DiagnosticConsumer.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/ImportCache.h" +#include "swift/AST/NameLookupRequests.h" #include "swift/AST/PrintOptions.h" #include "swift/AST/RawComment.h" #include "swift/AST/USRGeneration.h" @@ -740,6 +741,10 @@ static int doTypeContextInfo(const CompilerInvocation &InitInvok, CompilerInvocation Invocation(InitInvok); + // Disable source location resolutions from .swiftsourceinfo file because + // they are somewhat heavy operations and are not needed for completions. + Invocation.getFrontendOptions().IgnoreSwiftSourceInfo = true; + Invocation.setCodeCompletionPoint(CleanFile.get(), Offset); // Create a CodeCompletionConsumer. @@ -766,7 +771,7 @@ static int doTypeContextInfo(const CompilerInvocation &InitInvok, if (CI.setup(Invocation)) return 1; registerIDERequestFunctions(CI.getASTContext().evaluator); - CI.performSema(); + CI.performParseAndResolveImportsOnly(); return 0; } @@ -801,6 +806,10 @@ doConformingMethodList(const CompilerInvocation &InitInvok, CompilerInvocation Invocation(InitInvok); + // Disable source location resolutions from .swiftsourceinfo file because + // they are somewhat heavy operations and are not needed for completions. + Invocation.getFrontendOptions().IgnoreSwiftSourceInfo = true; + Invocation.setCodeCompletionPoint(CleanFile.get(), Offset); SmallVector typeNames; @@ -831,7 +840,7 @@ doConformingMethodList(const CompilerInvocation &InitInvok, if (CI.setup(Invocation)) return 1; registerIDERequestFunctions(CI.getASTContext().evaluator); - CI.performSema(); + CI.performParseAndResolveImportsOnly(); return 0; } @@ -870,6 +879,10 @@ static int doCodeCompletion(const CompilerInvocation &InitInvok, Invocation.setCodeCompletionPoint(CleanFile.get(), CodeCompletionOffset); + // Disable source location resolutions from .swiftsourceinfo file because + // they are somewhat heavy operations and are not needed for completions. + Invocation.getFrontendOptions().IgnoreSwiftSourceInfo = true; + // Disable to build syntax tree because code-completion skips some portion of // source text. That breaks an invariant of syntax tree building. Invocation.getLangOptions().BuildSyntaxTree = false; @@ -908,7 +921,7 @@ static int doCodeCompletion(const CompilerInvocation &InitInvok, if (CI.setup(Invocation)) return 1; registerIDERequestFunctions(CI.getASTContext().evaluator); - CI.performSema(); + CI.performParseAndResolveImportsOnly(); return 0; } @@ -2233,9 +2246,11 @@ static int doPrintDecls(const CompilerInvocation &InitInvok, for (const auto &name : DeclsToPrint) { ASTContext &ctx = CI.getASTContext(); - UnqualifiedLookup lookup(ctx.getIdentifier(name), - CI.getPrimarySourceFile()); - for (auto result : lookup.Results) { + auto descriptor = UnqualifiedLookupDescriptor(ctx.getIdentifier(name), + CI.getPrimarySourceFile()); + auto lookup = evaluateOrDefault(ctx.evaluator, + UnqualifiedLookupRequest{descriptor}, {}); + for (auto result : lookup) { result.getValueDecl()->print(*Printer, Options); if (auto typeDecl = dyn_cast(result.getValueDecl())) { @@ -3359,12 +3374,11 @@ int main(int argc, char *argv[]) { for (auto &Arg : options::ClangXCC) { InitInvok.getClangImporterOptions().ExtraArgs.push_back(Arg); } - InitInvok.getLangOptions().DebugForbidTypecheckPrefix = - options::DebugForbidTypecheckPrefix; InitInvok.getLangOptions().EnableObjCAttrRequiresFoundation = !options::DisableObjCAttrRequiresFoundationModule; - - InitInvok.getLangOptions().DebugConstraintSolver = + InitInvok.getTypeCheckerOptions().DebugForbidTypecheckPrefix = + options::DebugForbidTypecheckPrefix; + InitInvok.getTypeCheckerOptions().DebugConstraintSolver = options::DebugConstraintSolver; for (auto ConfigName : options::BuildConfigs) diff --git a/tools/swift-syntax-parser-test/CMakeLists.txt b/tools/swift-syntax-parser-test/CMakeLists.txt index 259f60211fd5c..e5cdd6d5b83dc 100644 --- a/tools/swift-syntax-parser-test/CMakeLists.txt +++ b/tools/swift-syntax-parser-test/CMakeLists.txt @@ -27,6 +27,7 @@ endif() set_property(TARGET swift-syntax-parser-test APPEND_STRING PROPERTY COMPILE_FLAGS " -fblocks") -if(SWIFT_NEED_EXPLICIT_LIBDISPATCH) - target_link_libraries(swift-syntax-parser-test PRIVATE BlocksRuntime) +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + target_link_libraries(swift-syntax-parser-test PRIVATE + BlocksRuntime) endif() diff --git a/unittests/AST/TestContext.cpp b/unittests/AST/TestContext.cpp index bf7865245b1d6..d246d8a0fce33 100644 --- a/unittests/AST/TestContext.cpp +++ b/unittests/AST/TestContext.cpp @@ -34,7 +34,8 @@ static void declareOptionalType(ASTContext &ctx, SourceFile *fileForLookups, } TestContext::TestContext(ShouldDeclareOptionalTypes optionals) - : Ctx(*ASTContext::get(LangOpts, SearchPathOpts, SourceMgr, Diags)) { + : Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SearchPathOpts, SourceMgr, + Diags)) { registerParseRequestFunctions(Ctx.evaluator); registerTypeCheckerRequestFunctions(Ctx.evaluator); auto stdlibID = Ctx.getIdentifier(STDLIB_NAME); diff --git a/unittests/AST/TestContext.h b/unittests/AST/TestContext.h index 428a933b0cd01..46aa8d985b62b 100644 --- a/unittests/AST/TestContext.h +++ b/unittests/AST/TestContext.h @@ -27,6 +27,7 @@ namespace unittest { class TestContextBase { public: LangOptions LangOpts; + TypeCheckerOptions TypeCheckerOpts; SearchPathOptions SearchPathOpts; SourceManager SourceMgr; DiagnosticEngine Diags; diff --git a/unittests/ClangImporter/ClangImporterTests.cpp b/unittests/ClangImporter/ClangImporterTests.cpp index 2c922f88e6284..94d021452a1c1 100644 --- a/unittests/ClangImporter/ClangImporterTests.cpp +++ b/unittests/ClangImporter/ClangImporterTests.cpp @@ -69,12 +69,13 @@ TEST(ClangImporterTest, emitPCHInMemory) { // Set up the importer and emit a bridging PCH. swift::LangOptions langOpts; langOpts.Target = llvm::Triple("x86_64", "apple", "darwin"); + swift::TypeCheckerOptions typeckOpts; INITIALIZE_LLVM(); swift::SearchPathOptions searchPathOpts; swift::SourceManager sourceMgr; swift::DiagnosticEngine diags(sourceMgr); std::unique_ptr context( - ASTContext::get(langOpts, searchPathOpts, sourceMgr, diags)); + ASTContext::get(langOpts, typeckOpts, searchPathOpts, sourceMgr, diags)); auto importer = ClangImporter::create(*context, options); std::string PCH = createFilename(cache, "bridging.h.pch"); diff --git a/unittests/FrontendTool/ModuleLoadingTests.cpp b/unittests/FrontendTool/ModuleLoadingTests.cpp index 0dda275ddaace..2015d27f624d7 100644 --- a/unittests/FrontendTool/ModuleLoadingTests.cpp +++ b/unittests/FrontendTool/ModuleLoadingTests.cpp @@ -94,10 +94,12 @@ class ModuleInterfaceLoaderTest : public testing::Test { PrintingDiagnosticConsumer printingConsumer; DiagnosticEngine diags(sourceMgr); diags.addConsumer(printingConsumer); + TypeCheckerOptions typeckOpts; LangOptions langOpts; langOpts.Target = llvm::Triple(llvm::sys::getDefaultTargetTriple()); SearchPathOptions searchPathOpts; - auto ctx = ASTContext::get(langOpts, searchPathOpts, sourceMgr, diags); + auto ctx = + ASTContext::get(langOpts, typeckOpts, searchPathOpts, sourceMgr, diags); auto loader = ModuleInterfaceLoader::create( *ctx, cacheDir, prebuiltCacheDir, diff --git a/unittests/Parse/TokenizerTests.cpp b/unittests/Parse/TokenizerTests.cpp index 2ae73865f403b..36faa9634c010 100644 --- a/unittests/Parse/TokenizerTests.cpp +++ b/unittests/Parse/TokenizerTests.cpp @@ -82,7 +82,8 @@ class TokenizerTest : public ::testing::Test { } std::vector parseAndGetSplitTokens(unsigned BufID) { - swift::ParserUnit PU(SM, SourceFileKind::Main, BufID, LangOpts, "unknown"); + swift::ParserUnit PU(SM, SourceFileKind::Main, BufID, + LangOpts, TypeCheckerOptions(), "unknown"); bool Done = false; while (!Done) { diff --git a/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp b/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp index 004b9ad94e4c4..193c8fcd4fad9 100644 --- a/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp +++ b/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp @@ -189,10 +189,10 @@ class CursorInfoTest : public ::testing::Test { } // anonymous namespace TEST_F(CursorInfoTest, FileNotExist) { - const char *DocName = "/test.swift"; + const char *DocName = "test.swift"; const char *Contents = "let foo = 0\n"; - const char *Args[] = { "/" }; + const char *Args[] = { "" }; open(DocName, Contents); auto FooOffs = findOffset("foo =", Contents); @@ -205,7 +205,7 @@ static const char *ExpensiveInit = "[0:0,0:0,0:0,0:0,0:0,0:0,0:0]"; TEST_F(CursorInfoTest, EditAfter) { - const char *DocName = "/test.swift"; + const char *DocName = "test.swift"; const char *Contents = "let value = foo\n" "let foo = 0\n"; @@ -240,7 +240,7 @@ TEST_F(CursorInfoTest, EditAfter) { } TEST_F(CursorInfoTest, EditBefore) { - const char *DocName = "/test.swift"; + const char *DocName = "test.swift"; const char *Contents = "let foo = 0\n" "let value = foo;\n"; @@ -277,7 +277,7 @@ TEST_F(CursorInfoTest, EditBefore) { } TEST_F(CursorInfoTest, CursorInfoMustWaitDueDeclLoc) { - const char *DocName = "/test.swift"; + const char *DocName = "test.swift"; const char *Contents = "let value = foo\n" "let foo = 0\n"; @@ -307,7 +307,7 @@ TEST_F(CursorInfoTest, CursorInfoMustWaitDueDeclLoc) { } TEST_F(CursorInfoTest, CursorInfoMustWaitDueOffset) { - const char *DocName = "/test.swift"; + const char *DocName = "test.swift"; const char *Contents = "let value = foo\n" "let foo = 0\n"; @@ -337,7 +337,7 @@ TEST_F(CursorInfoTest, CursorInfoMustWaitDueOffset) { } TEST_F(CursorInfoTest, CursorInfoMustWaitDueToken) { - const char *DocName = "/test.swift"; + const char *DocName = "test.swift"; const char *Contents = "let value = foo\n" "let foo = 0\n"; @@ -368,7 +368,7 @@ TEST_F(CursorInfoTest, CursorInfoMustWaitDueToken) { } TEST_F(CursorInfoTest, CursorInfoMustWaitDueTokenRace) { - const char *DocName = "/test.swift"; + const char *DocName = "test.swift"; const char *Contents = "let value = foo\n" "let foo = 0\n"; const char *Args[] = {"-parse-as-library"}; diff --git a/unittests/SourceKit/SwiftLang/EditingTest.cpp b/unittests/SourceKit/SwiftLang/EditingTest.cpp index 85b62da5f2487..b383a133982bf 100644 --- a/unittests/SourceKit/SwiftLang/EditingTest.cpp +++ b/unittests/SourceKit/SwiftLang/EditingTest.cpp @@ -197,7 +197,7 @@ static UIdent SemaDiagStage("source.diagnostic.stage.swift.sema"); static UIdent ParseDiagStage("source.diagnostic.stage.swift.parse"); TEST_F(EditTest, DiagsAfterEdit) { - const char *DocName = "/test.swift"; + const char *DocName = "test.swift"; const char *Contents = "func foo {}\n" "let v = 0\n"; @@ -234,7 +234,7 @@ TEST_F(EditTest, DiagsAfterEdit) { void EditTest::doubleOpenWithDelay(std::chrono::microseconds delay, bool closeDoc) { - const char *DocName = "/test.swift"; + const char *DocName = "test.swift"; const char *Contents = "func foo() { _ = unknown_name }\n"; const char *Args[] = { "-parse-as-library" }; diff --git a/unittests/SyntaxParser/CMakeLists.txt b/unittests/SyntaxParser/CMakeLists.txt index bfb9e46ba9fd2..48e82ac3b6d8d 100644 --- a/unittests/SyntaxParser/CMakeLists.txt +++ b/unittests/SyntaxParser/CMakeLists.txt @@ -24,6 +24,7 @@ endif() set_property(TARGET SwiftSyntaxParserTests APPEND_STRING PROPERTY COMPILE_FLAGS " -fblocks") -if(SWIFT_NEED_EXPLICIT_LIBDISPATCH) - target_link_libraries(SwiftSyntaxParserTests PRIVATE BlocksRuntime) +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + target_link_libraries(SwiftSyntaxParserTests PRIVATE + BlocksRuntime) endif() diff --git a/utils/android/README.md b/utils/android/README.md deleted file mode 100644 index 28ad49b365caa..0000000000000 --- a/utils/android/README.md +++ /dev/null @@ -1,16 +0,0 @@ - -# Build Android Toolchain - -This toolchain will generate the .so and .swiftmodule files of the Swift standard library and Foundation framework for the Android environment, armv7 architecture. Those files are needed when building any Swift library to be included in an application for Android. - -To build the toolchain run: - -``` -android$ ./build-toolchain -``` - -It will be built on: - -``` -path/to/swift-source/swift-android-toolchain -``` diff --git a/utils/build-script-impl b/utils/build-script-impl index 4139eed1ede3f..95741439eec15 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1191,9 +1191,9 @@ function should_build_stdlib_target() { # NINJA_SOURCE_DIR="${WORKSPACE}/ninja" SWIFT_SOURCE_DIR="${WORKSPACE}/swift" -LLVM_SOURCE_DIR="${WORKSPACE}/llvm" +LLVM_SOURCE_DIR="${WORKSPACE}/llvm-project/llvm" CMARK_SOURCE_DIR="${WORKSPACE}/cmark" -LLDB_SOURCE_DIR="${WORKSPACE}/lldb" +LLDB_SOURCE_DIR="${WORKSPACE}/llvm-project/lldb" LLBUILD_SOURCE_DIR="${WORKSPACE}/llbuild" STRESSTEST_PACKAGE_DIR="${WORKSPACE}/swift-stress-tester" XCTEST_SOURCE_DIR="${WORKSPACE}/swift-corelibs-xctest" @@ -1202,7 +1202,7 @@ FOUNDATION_STATIC_SOURCE_DIR="${WORKSPACE}/swift-corelibs-foundation" LIBDISPATCH_SOURCE_DIR="${WORKSPACE}/swift-corelibs-libdispatch" LIBDISPATCH_STATIC_SOURCE_DIR="${WORKSPACE}/swift-corelibs-libdispatch" LIBICU_SOURCE_DIR="${WORKSPACE}/icu" -LIBCXX_SOURCE_DIR="${WORKSPACE}/libcxx" +LIBCXX_SOURCE_DIR="${WORKSPACE}/llvm-project/libcxx" PLAYGROUNDSUPPORT_SOURCE_DIR="${WORKSPACE}/swift-xcode-playground-support" # SWIFT_ENABLE_TENSORFLOW TENSORFLOW_SOURCE_DIR="${WORKSPACE}/tensorflow" @@ -1226,29 +1226,18 @@ fi # Symlink clang into the llvm tree. CLANG_SOURCE_DIR="${LLVM_SOURCE_DIR}/tools/clang" -if [ ! -e "${WORKSPACE}/clang" ] ; then - # If llvm/tools/clang is already a directory, use that and skip the symlink. - if [ ! -d "${CLANG_SOURCE_DIR}" ] ; then - echo "Can't find source directory for clang (tried ${WORKSPACE}/clang and ${CLANG_SOURCE_DIR})" - exit 1 - fi -fi if [ ! -d "${CLANG_SOURCE_DIR}" ] ; then - make_relative_symlink "${WORKSPACE}/clang" "${CLANG_SOURCE_DIR}" + make_relative_symlink "${WORKSPACE}/llvm-project/clang" "${CLANG_SOURCE_DIR}" fi # Don't symlink clang-tools-extra into the tree as the 'clang' symlink prevents # make_relative_symlink from working correctly. -if [ -e "${WORKSPACE}/clang-tools-extra" ] ; then - CLANG_TOOLS_EXTRA_SOURCE_DIR="${WORKSPACE}/clang-tools-extra" -fi +CLANG_TOOLS_EXTRA_SOURCE_DIR="${WORKSPACE}/llvm-project/clang-tools-extra" # Symlink compiler-rt into the llvm tree, if it exists. COMPILER_RT_SOURCE_DIR="${LLVM_SOURCE_DIR}/projects/compiler-rt" -if [ -e "${WORKSPACE}/compiler-rt" ] ; then - if [ ! -d "${COMPILER_RT_SOURCE_DIR}" ] ; then - make_relative_symlink "${WORKSPACE}/compiler-rt" "${COMPILER_RT_SOURCE_DIR}" - fi +if [ ! -d "${COMPILER_RT_SOURCE_DIR}" ] ; then + make_relative_symlink "${WORKSPACE}/llvm-project/compiler-rt" "${COMPILER_RT_SOURCE_DIR}" fi PRODUCTS=(cmark llvm) @@ -1360,234 +1349,12 @@ function get_host_specific_variable() { } function calculate_targets_for_host() { - local host=$1 - - SWIFT_STDLIB_TARGETS=() - SWIFT_SDKS=() - SWIFT_BENCHMARK_TARGETS=() - SWIFT_RUN_BENCHMARK_TARGETS=() - SWIFT_TEST_TARGETS=() - - # Get the list of Target platforms for the Host - local stdlib_targets=($(get_stdlib_targets_for_host ${host})) - - for stdlib_deployment_target in "${stdlib_targets[@]}"; do - local swift_sdk= - local is_in_build_list=$(should_build_stdlib_target ${stdlib_deployment_target} ${host}) - local build_for_this_target=1 - local test_this_target=1 - local test_host_only= - local build_benchmark_this_target= - local build_external_benchmark_this_target= - local test_benchmark_this_target= - - case ${stdlib_deployment_target} in - linux-*) - swift_sdk="LINUX" - build_for_this_target=$(not ${SKIP_BUILD_LINUX}) - test_this_target=$(not ${SKIP_TEST_LINUX}) - ;; - freebsd-*) - swift_sdk="FREEBSD" - build_for_this_target=$(not ${SKIP_BUILD_FREEBSD}) - test_this_target=$(not ${SKIP_TEST_FREEBSD}) - ;; - cygwin-*) - swift_sdk="CYGWIN" - build_for_this_target=$(not ${SKIP_BUILD_CYGWIN}) - test_this_target=$(not ${SKIP_TEST_CYGWIN}) - ;; - haiku-*) - swift_sdk="HAIKU" - build_for_this_target=$(not ${SKIP_BUILD_HAIKU}) - test_this_target=$(not ${SKIP_TEST_HAIKU}) - ;; - macosx-*) - swift_sdk="OSX" - build_for_this_target=$(not ${SKIP_BUILD_OSX}) - test_this_target=$(not ${SKIP_TEST_OSX}) - build_benchmark_this_target=$(not ${SKIP_BUILD_OSX}) - build_external_benchmark_this_target=$(not ${SKIP_BUILD_OSX}) - test_benchmark_this_target=$(not ${SKIP_BUILD_OSX}) - ;; - iphoneos-*) - swift_sdk="IOS" - build_for_this_target=$(not ${SKIP_BUILD_IOS_DEVICE}) - if [[ ! "${SKIP_TEST_IOS_HOST}" ]] ; then - test_host_only=1 - else - test_this_target= - fi - build_benchmark_this_target=$(not ${SKIP_BUILD_IOS_DEVICE}) - build_external_benchmark_this_target=$(not ${SKIP_BUILD_IOS_DEVICE}) - - # Never build iOS armv7s benchmarks. - if [[ "${stdlib_deployment_target}" == "iphoneos-armv7s" ]]; then - build_benchmark_this_target= - build_external_benchmark_this_target= - fi - ;; - iphonesimulator-x86_64) - swift_sdk="IOS_SIMULATOR" - build_for_this_target=$(not ${SKIP_BUILD_IOS_SIMULATOR}) - test_this_target=$(not ${SKIP_TEST_IOS_SIMULATOR}) - ;; - iphonesimulator-i386) - swift_sdk="IOS_SIMULATOR" - build_for_this_target=$(not ${SKIP_BUILD_IOS_SIMULATOR}) - if [[ "${SKIP_TEST_IOS_SIMULATOR}" == "1" ]] ; then - SKIP_TEST_IOS_32BIT_SIMULATOR="${SKIP_TEST_IOS_SIMULATOR}" - fi - test_this_target=$(not ${SKIP_TEST_IOS_32BIT_SIMULATOR}) - ;; - appletvos-*) - swift_sdk="TVOS" - build_for_this_target=$(not ${SKIP_BUILD_TVOS_DEVICE}) - if [[ ! "${SKIP_TEST_TVOS_HOST}" ]] ; then - test_host_only=1 - else - test_this_target= - fi - build_benchmark_this_target=$(not ${SKIP_BUILD_TVOS_DEVICE}) - build_external_benchmark_this_target=$(not ${SKIP_BUILD_TVOS_DEVICE}) - ;; - appletvsimulator-*) - swift_sdk="TVOS_SIMULATOR" - build_for_this_target=$(not ${SKIP_BUILD_TVOS_SIMULATOR}) - test_this_target=$(not ${SKIP_TEST_TVOS_SIMULATOR}) - ;; - watchos-*) - swift_sdk="WATCHOS" - build_for_this_target=$(not ${SKIP_BUILD_WATCHOS_DEVICE}) - if [[ ! "${SKIP_TEST_WATCHOS_HOST}" ]] ; then - test_host_only=1 - else - test_this_target= - fi - build_benchmark_this_target=$(not ${SKIP_BUILD_WATCHOS_DEVICE}) - build_external_benchmark_this_target=$(not ${SKIP_BUILD_WATCHOS_DEVICE}) - ;; - watchsimulator-*) - swift_sdk="WATCHOS_SIMULATOR" - build_for_this_target=$(not ${SKIP_BUILD_WATCHOS_SIMULATOR}) - test_this_target=$(not ${SKIP_TEST_WATCHOS_SIMULATOR}) - ;; - android-*) - swift_sdk="ANDROID" - build_for_this_target=$(not ${SKIP_BUILD_ANDROID}) - if [[ ! "${SKIP_TEST_ANDROID_HOST}" ]] ; then - test_host_only=1 - else - test_this_target=$(not ${SKIP_TEST_ANDROID}) - fi - ;; - *) - echo "Unknown compiler deployment target: ${stdlib_deployment_target}" - exit 1 - ;; - esac - - SWIFT_SDKS+=("${swift_sdk}") - - if [[ "${build_for_this_target}" ]] && [[ "${is_in_build_list}" ]]; then - - if [[ "${BUILD_SWIFT_STDLIB_UNITTEST_EXTRA}" == "1" ]] ; then - SWIFT_STDLIB_TARGETS+=("swift-stdlib-${stdlib_deployment_target}") - else - if [[ "${VALIDATION_TEST}" == "1" || "${LONG_TEST}" == "1" ]] ; then - SWIFT_STDLIB_TARGETS+=("swift-stdlib-${stdlib_deployment_target}") - else - SWIFT_STDLIB_TARGETS+=("swift-test-stdlib-${stdlib_deployment_target}") - fi - fi - fi - if [[ "${build_benchmark_this_target}" ]] && [[ "${is_in_build_list}" ]]; then - SWIFT_BENCHMARK_TARGETS+=("swift-benchmark-${stdlib_deployment_target}") - if [[ $(not ${SKIP_TEST_BENCHMARKS}) ]] ; then - SWIFT_RUN_BENCHMARK_TARGETS+=("check-swift-benchmark-${stdlib_deployment_target}") - fi - fi - - if [[ "$(true_false ${SKIP_BUILD_EXTERNAL_BENCHMARKS})" == "FALSE" ]] && - [[ "${build_external_benchmark_this_target}" ]] && - [[ "${is_in_build_list}" ]] ; then - SWIFT_BENCHMARK_TARGETS+=("swift-benchmark-${stdlib_deployment_target}-external") - if [[ $(not ${SKIP_TEST_BENCHMARKS}) ]] ; then - SWIFT_RUN_BENCHMARK_TARGETS+=("check-swift-benchmark-${stdlib_deployment_target}-external") - fi - fi - - if [[ "${test_this_target}" ]] && [[ "${is_in_build_list}" ]]; then - test_target_suffix="" - if [[ -n "${test_host_only}" ]] ; then - test_target_suffix="-only_non_executable" - elif [[ -n "${ONLY_EXECUTABLE_TEST}" ]] ; then - test_target_suffix="-only_executable" - fi - - test_subset_target_suffix="" - if [[ "${VALIDATION_TEST}" == "1" ]] ; then - if [[ "${LONG_TEST}" == "1" ]] ; then - test_subset_target_suffix="-all" - else - test_subset_target_suffix="-validation" - fi - else - if [[ "${LONG_TEST}" == "1" ]] ; then - test_subset_target_suffix="-only_long" - fi - fi - - SWIFT_TEST_TARGETS+=("check-swift${test_subset_target_suffix}${test_target_suffix}-${stdlib_deployment_target}") - if [[ $(not ${SKIP_TEST_OPTIMIZED}) && ! -n "${test_host_only}" ]] ; then - SWIFT_TEST_TARGETS+=("check-swift${test_subset_target_suffix}-optimize-${stdlib_deployment_target}") - fi - if [[ $(not ${SKIP_TEST_OPTIMIZE_FOR_SIZE}) && ! -n "${test_host_only}" ]] ; then - SWIFT_TEST_TARGETS+=("check-swift${test_subset_target_suffix}-optimize_size-${stdlib_deployment_target}") - fi - if [[ $(not ${SKIP_TEST_OPTIMIZE_NONE_WITH_IMPLICIT_DYNAMIC}) && ! -n "${test_host_only}" ]] ; then - SWIFT_TEST_TARGETS+=("check-swift${test_subset_target_suffix}-optimize_none_with_implicit_dynamic-${stdlib_deployment_target}") - fi - fi - done - - # Filter duplicate SWIFT_SDKs - # We will get them if building for multiple architecture variants - SWIFT_SDKS=($(echo "${SWIFT_SDKS[@]}" | tr " " "\n" | sort -u | tr "\n" " ")) - # Get the values passed by `build-script`. - LEGACY_SWIFT_STDLIB_TARGETS=(${SWIFT_STDLIB_TARGETS[@]}) - LEGACY_SWIFT_SDKS=(${SWIFT_SDKS[@]}) - LEGACY_SWIFT_BENCHMARK_TARGETS=(${SWIFT_BENCHMARK_TARGETS[@]}) - LEGACY_SWIFT_RUN_BENCHMARK_TARGETS=(${SWIFT_RUN_BENCHMARK_TARGETS[@]}) - LEGACY_SWIFT_TEST_TARGETS=(${SWIFT_TEST_TARGETS[@]}) SWIFT_STDLIB_TARGETS=($(get_host_specific_variable ${host} SWIFT_STDLIB_TARGETS)) SWIFT_SDKS=($(get_host_specific_variable ${host} SWIFT_SDKS)) SWIFT_BENCHMARK_TARGETS=($(get_host_specific_variable ${host} SWIFT_BENCHMARK_TARGETS)) SWIFT_RUN_BENCHMARK_TARGETS=($(get_host_specific_variable ${host} SWIFT_RUN_BENCHMARK_TARGETS)) SWIFT_TEST_TARGETS=($(get_host_specific_variable ${host} SWIFT_TEST_TARGETS)) - - # Validate the parameters match. - if [[ "${SWIFT_STDLIB_TARGETS[*]}" != "${LEGACY_SWIFT_STDLIB_TARGETS[*]}" ]]; then - printf "error: invalid build-script refactor for 'SWIFT_STDLIB_TARGETS': '%s' vs '%s'\n" "${SWIFT_STDLIB_TARGETS[*]}" "${LEGACY_SWIFT_STDLIB_TARGETS[*]}" - exit 1 - fi - if [[ "${SWIFT_SDKS[*]}" != "${LEGACY_SWIFT_SDKS[*]}" ]]; then - printf "error: invalid build-script for 'SWIFT_SDKS' refactor: '%s' vs '%s'\n" "${SWIFT_SDKS[*]}" "${LEGACY_SWIFT_SDKS[*]}" - exit 1 - fi - if [[ "${SWIFT_BENCHMARK_TARGETS[*]}" != "${LEGACY_SWIFT_BENCHMARK_TARGETS[*]}" ]]; then - printf "error: invalid build-script refactor for 'SWIFT_BENCHMARK_TARGETS': '%s' vs '%s'\n" "${SWIFT_BENCHMARK_TARGETS[*]}" "${LEGACY_SWIFT_BENCHMARK_TARGETS[*]}" - exit 1 - fi - if [[ "${SWIFT_RUN_BENCHMARK_TARGETS[*]}" != "${LEGACY_SWIFT_RUN_BENCHMARK_TARGETS[*]}" ]]; then - printf "error: invalid build-script refactor for 'SWIFT_RUN_BENCHMARK_TARGETS': '%s' vs '%s'\n" "${SWIFT_RUN_BENCHMARK_TARGETS[*]}" "${LEGACY_SWIFT_RUN_BENCHMARK_TARGETS[*]}" - exit 1 - fi - if [[ "${SWIFT_TEST_TARGETS[*]}" != "${LEGACY_SWIFT_TEST_TARGETS[*]}" ]]; then - printf "error: invalid build-script refactor for 'SWIFT_TEST_TARGETS': '%s' vs '%s'\n" "${SWIFT_TEST_TARGETS[*]}" "${LEGACY_SWIFT_TEST_TARGETS[*]}" - exit 1 - fi } @@ -1941,6 +1708,9 @@ for host in "${ALL_HOSTS[@]}"; do tmp_product=libdispatch LIBDISPATCH_STATIC_CMAKE_OPTIONS=${LIBDISPATCH_CMAKE_OPTIONS[@]} fi + if [[ ${tmp_product} == "foundation_static" ]]; then + tmp_product=foundation + fi if ! [[ $(should_execute_action "${host}-${tmp_product}-build") ]]; then continue fi @@ -2024,11 +1794,9 @@ for host in "${ALL_HOSTS[@]}"; do -DLLVM_TOOL_LLD_BUILD:BOOL=TRUE ) - if [[ ! -z "${CLANG_TOOLS_EXTRA_SOURCE_DIR}" ]] ; then - cmake_options+=( - -DLLVM_EXTERNAL_CLANG_TOOLS_EXTRA_SOURCE_DIR="${CLANG_TOOLS_EXTRA_SOURCE_DIR}" - ) - fi + cmake_options+=( + -DLLVM_EXTERNAL_CLANG_TOOLS_EXTRA_SOURCE_DIR="${CLANG_TOOLS_EXTRA_SOURCE_DIR}" + ) if [[ "${BUILD_TOOLCHAIN_ONLY}" ]]; then cmake_options+=( @@ -2565,15 +2333,18 @@ for host in "${ALL_HOSTS[@]}"; do -DCMAKE_BUILD_TYPE:STRING="${XCTEST_BUILD_TYPE}" -DCMAKE_C_COMPILER:PATH="${LLVM_BIN}/clang" -DCMAKE_CXX_COMPILER:PATH="${LLVM_BIN}/clang++" - -DCMAKE_SWIFT_COMPILER:PATH="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc" + -DCMAKE_Swift_COMPILER:PATH="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc" -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})" -DCMAKE_INSTALL_LIBDIR:PATH="lib" + -Ddispatch_DIR=$(build_directory ${host} libdispatch)/cmake/modules + -DFoundation_DIR=$(build_directory ${host} foundation)/cmake/modules + -DLLVM_DIR=$(build_directory ${host} llvm)/lib/cmake/llvm + -DXCTEST_PATH_TO_LIBDISPATCH_SOURCE:PATH=${LIBDISPATCH_SOURCE_DIR} -DXCTEST_PATH_TO_LIBDISPATCH_BUILD:PATH=$(build_directory ${host} libdispatch) - -DXCTEST_PATH_TO_FOUNDATION_BUILD:PATH=${FOUNDATION_BUILD_DIR} - + -DCMAKE_SWIFT_COMPILER:PATH="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc" -DCMAKE_PREFIX_PATH:PATH=$(build_directory ${host} llvm) -DENABLE_TESTING=YES @@ -3101,6 +2872,7 @@ for host in "${ALL_HOSTS[@]}"; do LIBDISPATCH_BUILD_ARGS=( -DFOUNDATION_PATH_TO_LIBDISPATCH_SOURCE=${LIBDISPATCH_SOURCE_DIR} -DFOUNDATION_PATH_TO_LIBDISPATCH_BUILD=${LIBDISPATCH_BUILD_DIR} + -Ddispatch_DIR=${LIBDISPATCH_BUILD_DIR}/cmake/modules ) else LIBDISPATCH_BUILD_ARGS=( -DFOUNDATION_ENABLE_LIBDISPATCH=NO ) @@ -3109,20 +2881,22 @@ for host in "${ALL_HOSTS[@]}"; do SWIFTC_BIN="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc" LLVM_BIN="$(build_directory_bin ${LOCAL_HOST} llvm)" + # NOTE(compnerd) the time has come to enable tests now cmake_options=( ${cmake_options[@]} -DCMAKE_BUILD_TYPE:STRING=${FOUNDATION_BUILD_TYPE} -DCMAKE_C_COMPILER:PATH=${LLVM_BIN}/clang -DCMAKE_CXX_COMPILER:PATH=${LLVM_BIN}/clang++ - -DCMAKE_SWIFT_COMPILER:PATH=${SWIFTC_BIN} -DCMAKE_Swift_COMPILER:PATH=${SWIFTC_BIN} -DCMAKE_INSTALL_PREFIX:PATH=$(get_host_install_prefix ${host}) ${LIBICU_BUILD_ARGS[@]} ${LIBDISPATCH_BUILD_ARGS[@]} - # NOTE(compnerd) the time has come to enable tests now -DENABLE_TESTING:BOOL=YES + -DXCTest_DIR=$(build_directory ${host} xctest)/cmake/modules + + -DCMAKE_SWIFT_COMPILER:PATH=${SWIFTC_BIN} -DFOUNDATION_PATH_TO_XCTEST_BUILD:PATH=$(build_directory ${host} xctest) ) @@ -3287,6 +3061,9 @@ for host in "${ALL_HOSTS[@]}"; do if [[ ${tmp_product} == "libdispatch_static" ]]; then tmp_product=libdispatch fi + if [[ ${tmp_product} == "foundation_static" ]]; then + tmp_product=foundation + fi if ! [[ $(should_execute_action "${host}-${tmp_product}-install") ]]; then continue fi diff --git a/utils/build-windows.bat b/utils/build-windows.bat index 1fbd9a14d2b78..7529f0609b8ae 100644 --- a/utils/build-windows.bat +++ b/utils/build-windows.bat @@ -238,7 +238,7 @@ cmake "%source_root%\swift"^ -DSWIFT_BUILD_STATIC_SDK_OVERLAY:BOOL=NO^ -DLLVM_INSTALL_TOOLCHAIN_ONLY:BOOL=YES^ -DSWIFT_BUILD_SOURCEKIT:BOOL=YES^ - -DSWIFT_ENABLE_SOURCEKIT_TESTS:BOOL=NO^ + -DSWIFT_ENABLE_SOURCEKIT_TESTS:BOOL=YES^ -DSWIFT_INSTALL_COMPONENTS="autolink-driver;compiler;clang-resource-dir-symlink;stdlib;sdk-overlay;editor-integration;tools;sourcekit-inproc;swift-remote-mirror;swift-remote-mirror-headers"^ -DSWIFT_PARALLEL_LINK_JOBS=8^ -DPYTHON_EXECUTABLE:PATH=%PYTHON_HOME%\python.exe^ diff --git a/utils/gyb_syntax_support/AttributeNodes.py b/utils/gyb_syntax_support/AttributeNodes.py index cdc5531c81e6e..744f25338aab8 100644 --- a/utils/gyb_syntax_support/AttributeNodes.py +++ b/utils/gyb_syntax_support/AttributeNodes.py @@ -194,7 +194,21 @@ '''), ]), - # SWIFT_ENABLE_TENSORFLOW + # objc-selector-piece -> identifier? ':'? + Node('ObjCSelectorPiece', kind='Syntax', + description=''' + A piece of an Objective-C selector. Either consisiting of just an + identifier for a nullary selector, an identifier and a colon for a + labeled argument or just a colon for an unlabeled argument + ''', + children=[ + Child('Name', kind='IdentifierToken', is_optional=True), + Child('Colon', kind='ColonToken', is_optional=True), + ]), + + # objc-selector -> objc-selector-piece objc-selector? + Node('ObjCSelector', kind='SyntaxCollection', element='ObjCSelectorPiece'), + # The argument of '@differentiable(...)'. # differentiable-attr-arguments -> # differentiation-params-clause? ','? @@ -356,19 +370,4 @@ Child('DiffParams', kind='DifferentiationParamsClause', is_optional=True), ]), - - # objc-selector-piece -> identifier? ':'? - Node('ObjCSelectorPiece', kind='Syntax', - description=''' - A piece of an Objective-C selector. Either consisiting of just an - identifier for a nullary selector, an identifier and a colon for a - labeled argument or just a colon for an unlabeled argument - ''', - children=[ - Child('Name', kind='IdentifierToken', is_optional=True), - Child('Colon', kind='ColonToken', is_optional=True), - ]), - - # objc-selector -> objc-selector-piece objc-selector? - Node('ObjCSelector', kind='SyntaxCollection', element='ObjCSelectorPiece') ] diff --git a/utils/gyb_syntax_support/ExprNodes.py b/utils/gyb_syntax_support/ExprNodes.py index a321974b1bebc..67ae48a43bc04 100644 --- a/utils/gyb_syntax_support/ExprNodes.py +++ b/utils/gyb_syntax_support/ExprNodes.py @@ -112,7 +112,11 @@ Node('ExprList', kind='SyntaxCollection', element='Expr', - element_name='Expression'), + element_name='Expression', + description=''' + A list of expressions connected by operators. This list is contained + by a `SequenceExprSyntax`. + '''), # A #line expression. Node('PoundLineExpr', kind='Expr', diff --git a/utils/gyb_syntax_support/NodeSerializationCodes.py b/utils/gyb_syntax_support/NodeSerializationCodes.py index e4c7524985c77..e4b892dc19468 100644 --- a/utils/gyb_syntax_support/NodeSerializationCodes.py +++ b/utils/gyb_syntax_support/NodeSerializationCodes.py @@ -234,7 +234,6 @@ 'SomeType': 230, 'CustomAttribute': 231, 'GenericRequirement': 232, - # SWIFT_ENABLE_TENSORFLOW 'DifferentiableAttributeArguments': 233, 'DifferentiationParamsClause': 234, 'DifferentiationParams': 235, @@ -242,10 +241,12 @@ 'DifferentiationParam': 237, 'DifferentiableAttributeFuncSpecifier': 238, 'FunctionDeclName': 239, + # SWIFT_ENABLE_TENSORFLOW 'DerivativeRegistrationAttributeArguments': 240, 'QuoteLiteralExpr': 241, 'UnquoteExpr': 242, 'DeprecatedDerivativeRegistrationAttributeArguments': 243, + # SWIFT_ENABLE_TENSORFLOW END } diff --git a/utils/swift_build_support/swift_build_support/products/product.py b/utils/swift_build_support/swift_build_support/products/product.py index 6bdcb4f4f682f..6837e563c91ae 100644 --- a/utils/swift_build_support/swift_build_support/products/product.py +++ b/utils/swift_build_support/swift_build_support/products/product.py @@ -37,6 +37,16 @@ def product_source_name(cls): It provides a customization point for Product subclasses. It is set to the value of product_name() by default for this reason. """ + + llvm_projects = ['clang', + 'clang-tools-extra', + 'compiler-rt', + 'libcxx', + 'lldb', + 'llvm'] + + if cls.product_name() in llvm_projects: + return "llvm-project/{}".format(cls.product_name()) return cls.product_name() @classmethod diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index b4a310facd868..63b73fc9e54a4 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -67,7 +67,7 @@ "swift-integration-tests": "master", "swift-xcode-playground-support": "master", "ninja": "release", - "icu": "release-61-1", + "icu": "release-65-1", "cmake": "v3.15.1", "indexstore-db": "master", "sourcekit-lsp": "master", @@ -92,7 +92,7 @@ "swift-integration-tests": "master", "swift-xcode-playground-support": "master", "ninja": "release", - "icu": "release-61-1", + "icu": "release-65-1", "cmake": "v3.15.1", "indexstore-db": "master", "sourcekit-lsp": "master", @@ -250,7 +250,7 @@ "tensorflow": { "aliases": ["tensorflow"], "repos": { - "llvm-project": "b3338d3f55b4eba6433be56c5e05f5c04f79dcd5", + "llvm-project": "13eb6eb7bacb8e7302e77527fe477130a5a0885a", "swift": "tensorflow", "cmark": "swift-DEVELOPMENT-SNAPSHOT-2019-11-11-a", "llbuild": "swift-DEVELOPMENT-SNAPSHOT-2019-11-11-a", diff --git a/utils/update_checkout/update_checkout/update_checkout.py b/utils/update_checkout/update_checkout/update_checkout.py index 68810069810cd..c5e20888bc4d1 100755 --- a/utils/update_checkout/update_checkout/update_checkout.py +++ b/utils/update_checkout/update_checkout/update_checkout.py @@ -11,7 +11,6 @@ from __future__ import print_function import argparse -import errno import json import os import platform @@ -400,53 +399,6 @@ def skip_list_for_platform(config): return skip_list -# Python 2.7 in Windows doesn't support os.symlink -os_symlink = getattr(os, "symlink", None) -if callable(os_symlink): - pass -else: - def symlink_ms(source, link_name): - source = os.path.normpath(source) - link_name = os.path.normpath(link_name) - if os.path.isdir(link_name): - os.rmdir(link_name) - elif os.exists(link_name): - os.remove(link_name) - import ctypes - csl = ctypes.windll.kernel32.CreateSymbolicLinkW - csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32) - csl.restype = ctypes.c_ubyte - flags = 1 if os.path.isdir(source) else 0 - if csl(link_name, source, flags) == 0: - raise ctypes.WinError() - os.symlink = symlink_ms - - -def symlink_llvm_monorepo(args): - print("Create symlink for LLVM Project") - llvm_projects = ['clang', - 'llvm', - 'lldb', - 'compiler-rt', - 'libcxx', - 'clang-tools-extra'] - for project in llvm_projects: - src_path = os.path.join(args.source_root, - 'llvm-project', - project) - dst_path = os.path.join(args.source_root, project) - if not os.path.islink(dst_path): - try: - os.symlink(src_path, dst_path) - except OSError as e: - if e.errno == errno.EEXIST: - print("File '%s' already exists. Remove it, so " - "update-checkout can create the symlink to the " - "llvm-monorepo." % dst_path) - else: - raise e - - def main(): freeze_support() parser = argparse.ArgumentParser( @@ -599,7 +551,6 @@ def main(): if fail_count > 0: print("update-checkout failed, fix errors and try again") else: - symlink_llvm_monorepo(args) print("update-checkout succeeded") print_repo_hashes(args, config) sys.exit(fail_count) diff --git a/utils/vim/syntax/swift.vim b/utils/vim/syntax/swift.vim index 9a70c9bf3225b..d20dd3fe22756 100644 --- a/utils/vim/syntax/swift.vim +++ b/utils/vim/syntax/swift.vim @@ -154,40 +154,59 @@ syn region swiftCaseLabelRegion syn region swiftDefaultLabelRegion \ matchgroup=swiftKeyword start=/\/ matchgroup=Delimiter end=/:/ oneline -syn region swiftParenthesisRegion matchgroup=NONE start=/(/ end=/)/ contains=TOP - -syn region swiftString start=/"/ skip=/\\\\\|\\"/ end=/"/ contains=swiftInterpolationRegion -syn region swiftInterpolationRegion matchgroup=swiftInterpolation start=/\\(/ end=/)/ contained contains=TOP -syn region swiftComment start="/\*" end="\*/" contains=swiftComment,swiftTodo -syn region swiftLineComment start="//" end="$" contains=swiftTodo - -syn match swiftDecimal /[+\-]\?\<\([0-9][0-9_]*\)\([.][0-9_]*\)\?\([eE][+\-]\?[0-9][0-9_]*\)\?\>/ -syn match swiftHex /[+\-]\?\<0x[0-9A-Fa-f][0-9A-Fa-f_]*\(\([.][0-9A-Fa-f_]*\)\?[pP][+\-]\?[0-9][0-9_]*\)\?\>/ -syn match swiftOct /[+\-]\?\<0o[0-7][0-7_]*\>/ -syn match swiftBin /[+\-]\?\<0b[01][01_]*\>/ - -syn match swiftOperator +\.\@!&|^~]\@!&|^~]*\|*/\@![/=\-+*%<>!&|^~]*\|->\@![/=\-+*%<>!&|^~]*\|[=+%<>!&|^~][/=\-+*%<>!&|^~]*\)+ skipwhite skipempty nextgroup=swiftTypeParameters -syn match swiftOperator "\.\.[<.]" skipwhite skipempty nextgroup=swiftTypeParameters - -syn match swiftChar /'\([^'\\]\|\\\(["'tnr0\\]\|x[0-9a-fA-F]\{2}\|u[0-9a-fA-F]\{4}\|U[0-9a-fA-F]\{8}\)\)'/ +syn region swiftParenthesisRegion contains=TOP + \ matchgroup=NONE start=/(/ end=/)/ + +syn region swiftString contains=swiftInterpolationRegion + \ start=/"/ skip=/\\\\\|\\"/ end=/"/ +syn region swiftInterpolationRegion contained contains=TOP + \ matchgroup=swiftInterpolation start=/\\(/ end=/)/ +syn region swiftComment contains=swiftComment,swiftLineComment,swiftTodo + \ start="/\*" end="\*/" +syn region swiftLineComment contains=swiftComment,swiftTodo + \ start="//" end="$" + +syn match swiftDecimal + \ /[+\-]\?\<\([0-9][0-9_]*\)\([.][0-9_]*\)\?\([eE][+\-]\?[0-9][0-9_]*\)\?\>/ +syn match swiftHex + \ /[+\-]\?\<0x[0-9A-Fa-f][0-9A-Fa-f_]*\(\([.][0-9A-Fa-f_]*\)\?[pP][+\-]\?[0-9][0-9_]*\)\?\>/ +syn match swiftOct + \ /[+\-]\?\<0o[0-7][0-7_]*\>/ +syn match swiftBin + \ /[+\-]\?\<0b[01][01_]*\>/ + +syn match swiftOperator skipwhite skipempty nextgroup=swiftTypeParameters + \ "\.\@!&|^~]\@!&|^~]*\|*/\@![/=\-+*%<>!&|^~]*\|->\@![/=\-+*%<>!&|^~]*\|[=+%<>!&|^~][/=\-+*%<>!&|^~]*\)" +syn match swiftOperator skipwhite skipempty nextgroup=swiftTypeParameters + \ "\.\.[<.]" + +syn match swiftChar + \ /'\([^'\\]\|\\\(["'tnr0\\]\|x[0-9a-fA-F]\{2}\|u[0-9a-fA-F]\{4}\|U[0-9a-fA-F]\{8}\)\)'/ syn match swiftTupleIndexNumber contains=swiftDecimal \ /\.[0-9]\+/ syn match swiftDecimal contained \ /[0-9]\+/ -syn match swiftPreproc /#\(\\|\\|\\)/ -syn match swiftPreproc /^\s*#\(\\|\\|\\|\\|\\|\\)/ -syn region swiftPreprocFalse start="^\s*#\\s\+\" end="^\s*#\(\\|\\|\\)" +syn match swiftPreproc + \ /#\(\\|\\|\\)/ +syn match swiftPreproc + \ /^\s*#\(\\|\\|\\|\\|\\|\\)/ +syn region swiftPreprocFalse + \ start="^\s*#\\s\+\" end="^\s*#\(\\|\\|\\)" -syn match swiftAttribute /@\<\w\+\>/ skipwhite skipempty nextgroup=swiftType,swiftTypeDefinition +syn match swiftAttribute + \ /@\<\w\+\>/ skipwhite skipempty nextgroup=swiftType,swiftTypeDefinition syn keyword swiftTodo MARK TODO FIXME contained -syn match swiftCastOp "\" skipwhite skipempty nextgroup=swiftType -syn match swiftCastOp "\[!?]\?" skipwhite skipempty nextgroup=swiftType +syn match swiftCastOp skipwhite skipempty nextgroup=swiftType + \ "\" +syn match swiftCastOp skipwhite skipempty nextgroup=swiftType + \ "\[!?]\?" -syn match swiftNilOps "??" +syn match swiftNilOps + \ "??" syn region swiftReservedIdentifier oneline \ start=/`/ end=/`/ diff --git a/validation-test/Reflection/Inputs/EmptyStruct/EmptyStruct.h b/validation-test/Reflection/Inputs/EmptyStruct/EmptyStruct.h new file mode 100644 index 0000000000000..580b9fb4bd762 --- /dev/null +++ b/validation-test/Reflection/Inputs/EmptyStruct/EmptyStruct.h @@ -0,0 +1,3 @@ +struct EmptyStructC { + int trailing[0]; +}; diff --git a/validation-test/Reflection/Inputs/EmptyStruct/module.map b/validation-test/Reflection/Inputs/EmptyStruct/module.map new file mode 100644 index 0000000000000..42b486a7c3670 --- /dev/null +++ b/validation-test/Reflection/Inputs/EmptyStruct/module.map @@ -0,0 +1,3 @@ +module EmptyStruct { + header "EmptyStruct.h" +} diff --git a/validation-test/Reflection/reflect_empty_struct.swift b/validation-test/Reflection/reflect_empty_struct.swift new file mode 100644 index 0000000000000..32427344a3fc9 --- /dev/null +++ b/validation-test/Reflection/reflect_empty_struct.swift @@ -0,0 +1,70 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -lswiftSwiftReflectionTest -I %S/Inputs/EmptyStruct/ %s -o %t/reflect_empty_struct +// RUN: %target-codesign %t/reflect_empty_struct + +// RUN: %target-run %target-swift-reflection-test %t/reflect_empty_struct | %FileCheck %s --check-prefix=CHECK-%target-ptrsize --dump-input fail + +// REQUIRES: objc_interop +// REQUIRES: executable_test + +import SwiftReflectionTest + +import EmptyStruct + +@_alignment(1) struct EmptyStruct { } +class Class { + var a = EmptyStruct() + var b: Any = EmptyStruct() + var c = EmptyStructC() + var d: Any = EmptyStructC() +} + +var obj = Class() + +reflect(object: obj) + +// CHECK-64: Reflecting an object. +// CHECK-64: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}} +// CHECK-64: Type reference: +// CHECK-64: (class reflect_empty_struct.Class) + +// CHECK-64: Type info: +// CHECK-64: (class_instance size=80 alignment=8 stride=80 num_extra_inhabitants=0 bitwise_takable=1 +// CHECK-64: (field name=a offset=16 +// CHECK-64: (builtin size=0 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1)) +// CHECK-64: (field name=b offset=16 +// CHECK-64: (opaque_existential size=32 alignment=8 stride=32 num_extra_inhabitants=2147483647 bitwise_takable=1 +// CHECK-64: (field name=metadata offset=24 +// CHECK-64: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647 bitwise_takable=1)))) +// CHECK-64: (field name=c offset=48 +// CHECK-64: (builtin size=0 alignment=4 stride=1 num_extra_inhabitants=0 bitwise_takable=1)) +// CHECK-64: (field name=d offset=48 +// CHECK-64: (opaque_existential size=32 alignment=8 stride=32 num_extra_inhabitants=2147483647 bitwise_takable=1 +// CHECK-64: (field name=metadata offset=24 +// CHECK-64: (builtin size=8 alignment=8 stride=8 num_extra_inhabitants=2147483647 bitwise_takable=1))))) + +// CHECK-32: Reflecting an object. +// CHECK-32: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}} +// CHECK-32: Type reference: +// CHECK-32: (class reflect_empty_struct.Class) + +// CHECK-32: Type info: +// CHECK-32: (class_instance size=40 alignment=4 stride=40 num_extra_inhabitants=0 bitwise_takable=1 +// CHECK-32: (field name=a offset=8 +// CHECK-32: (builtin size=0 alignment=1 stride=1 num_extra_inhabitants=0 bitwise_takable=1)) +// CHECK-32: (field name=b offset=8 +// CHECK-32: (opaque_existential size=16 alignment=4 stride=16 num_extra_inhabitants=4096 bitwise_takable=1 +// CHECK-32: (field name=metadata offset=12 +// CHECK-32: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=4096 bitwise_takable=1)))) +// CHECK-32: (field name=c offset=24 +// CHECK-32: (builtin size=0 alignment=4 stride=1 num_extra_inhabitants=0 bitwise_takable=1)) +// CHECK-32: (field name=d offset=24 +// CHECK-32: (opaque_existential size=16 alignment=4 stride=16 num_extra_inhabitants=4096 bitwise_takable=1 +// CHECK-32: (field name=metadata offset=12 +// CHECK-32: (builtin size=4 alignment=4 stride=4 num_extra_inhabitants=4096 bitwise_takable=1))))) + +doneReflecting() + +// CHECK-64: Done. + +// CHECK-32: Done. diff --git a/validation-test/Sema/type_checker_perf/slow/rdar54580427.swift b/validation-test/Sema/type_checker_perf/slow/rdar54580427.swift index 346d9dccebab1..071587356ae13 100644 --- a/validation-test/Sema/type_checker_perf/slow/rdar54580427.swift +++ b/validation-test/Sema/type_checker_perf/slow/rdar54580427.swift @@ -1,6 +1,7 @@ // FIXME: This should be linear instead of exponential. // RUN: %scale-test --begin 1 --end 10 --step 1 --select NumLeafScopes --invert-result %s -Xfrontend=-solver-expression-time-threshold=1 // REQUIRES: asserts,no_asan +// REQUIRES: rdar57138194,SR11770 enum Val { case d([String: Val]) diff --git a/validation-test/compiler_crashers_2/rdar56398071.swift b/validation-test/compiler_crashers_2/rdar56398071.swift new file mode 100644 index 0000000000000..6f8bda87f6d8e --- /dev/null +++ b/validation-test/compiler_crashers_2/rdar56398071.swift @@ -0,0 +1,151 @@ +// RUN: not --crash %target-swift-frontend -primary-file %s -emit-silgen + +// REQUIRES: asserts + +public protocol WrappedSignedInteger: SignedInteger where Stride == Int { + typealias WrappedInteger = Int + + var wrappedNumber: WrappedInteger { get set } + init(wrappedNumber: WrappedInteger) +} + +public extension WrappedSignedInteger { + typealias IntegerLiteralType = WrappedInteger.IntegerLiteralType + typealias Magnitude = WrappedInteger.Magnitude + typealias Words = WrappedInteger.Words + + // MARK: - Initializers - + + init(_ source: T) where T : BinaryInteger { + self.init(wrappedNumber: WrappedInteger(source)) + } + + init(truncatingIfNeeded source: T) where T : BinaryInteger { + self.init(wrappedNumber: WrappedInteger(source)) + } + + init?(exactly source: T) where T : BinaryFloatingPoint { + if let wrappedNumber = WrappedInteger(exactly: source) { + self.init(wrappedNumber: wrappedNumber) + } else { + return nil + } + } + + init(_ source: T) where T : BinaryFloatingPoint { + self.init(wrappedNumber: WrappedInteger(source)) + } + + init(clamping source: T) where T : BinaryInteger { + self.init(wrappedNumber: WrappedInteger(source)) + } + + init?(exactly source: T) where T : BinaryInteger { + if let wrappedNumber = WrappedInteger(exactly: source) { + self.init(wrappedNumber: wrappedNumber) + } else { + return nil + } + } + + init(integerLiteral wrappedNumber: WrappedInteger.IntegerLiteralType) { + let wrapped = WrappedInteger(integerLiteral: wrappedNumber) + self.init(wrappedNumber: wrapped) + } + + // MARK: - Stride - + + func advanced(by n: Int) -> Self { + .init(wrappedNumber: wrappedNumber + n) + } + + func distance(to other: Self) -> Self.Stride { + other.wrappedNumber - wrappedNumber + } + + // MARK: - Properties - + + var magnitude: WrappedInteger.Magnitude { + wrappedNumber.magnitude + } + + var words: WrappedInteger.Words { + wrappedNumber.words + } + + var bitWidth: Int { + wrappedNumber.bitWidth + } + + var trailingZeroBitCount: Int { + wrappedNumber.trailingZeroBitCount + } + + // MARK: - Operators - + + static func <<= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.wrappedNumber <<= rhs + } + + static func >>= (lhs: inout Self, rhs: RHS) where RHS : BinaryInteger { + lhs.wrappedNumber >>= rhs + } + + static prefix func ~ (x: Self) -> Self { + .init(wrappedNumber: ~x.wrappedNumber) + } + + static func / (lhs: Self, rhs: Self) -> Self { + .init(wrappedNumber: lhs.wrappedNumber / rhs.wrappedNumber) + } + + static func /= (lhs: inout Self, rhs: Self) { + lhs.wrappedNumber /= rhs.wrappedNumber + } + + static func % (lhs: Self, rhs: Self) -> Self { + .init(wrappedNumber: lhs.wrappedNumber % rhs.wrappedNumber) + } + + static func %= (lhs: inout Self, rhs: Self) { + lhs.wrappedNumber %= rhs.wrappedNumber + } + + static func &= (lhs: inout Self, rhs: Self) { + lhs.wrappedNumber &= rhs.wrappedNumber + } + + static func |= (lhs: inout Self, rhs: Self) { + lhs.wrappedNumber |= rhs.wrappedNumber + } + + static func ^= (lhs: inout Self, rhs: Self) { + lhs.wrappedNumber ^= rhs.wrappedNumber + } + + static func + (lhs: Self, rhs: Self) -> Self { + .init(wrappedNumber: lhs.wrappedNumber + rhs.wrappedNumber) + } + + static func += (lhs: inout Self, rhs: Self) { + lhs.wrappedNumber += rhs.wrappedNumber + } + + static func - (lhs: Self, rhs: Self) -> Self { + .init(wrappedNumber: lhs.wrappedNumber - rhs.wrappedNumber) + } + + static func -= (lhs: inout Self, rhs: Self) { + lhs.wrappedNumber -= rhs.wrappedNumber + } + + static func * (lhs: Self, rhs: Self) -> Self { + .init(wrappedNumber: lhs.wrappedNumber * rhs.wrappedNumber) + } + + static func *= (lhs: inout Self, rhs: Self) { + lhs.wrappedNumber *= rhs.wrappedNumber + } + +} + diff --git a/validation-test/compiler_crashers_2_fixed/sr-10612.swift b/validation-test/compiler_crashers_2_fixed/sr-10612.swift new file mode 100644 index 0000000000000..ed2ccb14212fc --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr-10612.swift @@ -0,0 +1,16 @@ +// RUN: not %target-swift-frontend -typecheck %s + +protocol P1: class { + associatedtype P1P1: P1 + associatedtype P1AnyP2: AnyP2 + + var anyP2: P1AnyP2? { get set } +} + +protocol P2 { + associatedtype P2P1: P1 +} + +final class AnyP2: P2 { + typealias P2P1 = AP2P1 +} diff --git a/validation-test/compiler_crashers_2_fixed/sr10201.swift b/validation-test/compiler_crashers_2_fixed/sr10201.swift new file mode 100644 index 0000000000000..863b4e5aea3d9 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr10201.swift @@ -0,0 +1,37 @@ +// RUN: %target-swift-frontend -typecheck -verify %s + +struct A { + typealias Value = Int +} + +protocol B { + typealias Value = A.Value + typealias T = String +} + +protocol NestedProtocol { + typealias _B = B +} + +struct Something: NestedProtocol { + + struct InnerTest: _B { + var value: Value = 42 + var t: T = "wait what?" + } +} + +protocol X {} + +protocol Y { + typealias _X = X + var x: _X { get } +} + +struct Struct: Y { + var x: _X = __X() +} + +extension Struct { + struct __X: _X {} +} diff --git a/validation-test/compiler_crashers_2_fixed/sr11052-typealias.swift b/validation-test/compiler_crashers_2_fixed/sr11052-typealias.swift index 8460975c7d20e..352d50a754380 100644 --- a/validation-test/compiler_crashers_2_fixed/sr11052-typealias.swift +++ b/validation-test/compiler_crashers_2_fixed/sr11052-typealias.swift @@ -19,7 +19,7 @@ struct Concrete: ProtoB { fatalError() } - func protoFunc() -> Alias { // expected-error{{unsupported recursion for reference to type alias 'Alias' of type 'Concrete'}} + func protoFunc() -> Alias { fatalError() } } diff --git a/validation-test/compiler_crashers_2_fixed/sr11392.swift b/validation-test/compiler_crashers_2_fixed/sr11392.swift new file mode 100644 index 0000000000000..449615a072272 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/sr11392.swift @@ -0,0 +1,28 @@ +// RUN: %target-swift-frontend -verify -emit-ir %s + +// Ideally this would type check successfully; we should be able to +// infer that X == Int using the same-type constraint 'A.X == X'. + +protocol P1 { + associatedtype X + // expected-note@-1 {{protocol requires nested type 'X'; do you want to add it?}} + associatedtype A: P2 where A.X == X +} + +protocol P2 { + associatedtype X +} + +struct S {} + +extension S { + struct A: P2 { + typealias X = Int + } +} + + +extension S: P1 {} +// expected-error@-1 {{type 'S' does not conform to protocol 'P1'}} + +print(S.X.self)