diff --git a/.flake8 b/.flake8 index 24e50cd6104cb..39188cae5c115 100644 --- a/.flake8 +++ b/.flake8 @@ -1,32 +1,72 @@ [flake8] -ignore = W291 W504 -filename = *.py, - ./utils/80+-check, - ./utils/backtrace-check, - ./benchmark/scripts/Benchmark_Driver, - ./benchmark/scripts/Benchmark_DTrace.in, - ./benchmark/scripts/Benchmark_GuardMalloc.in, - ./benchmark/scripts/Benchmark_RuntimeLeaksRunner.in, - ./utils/build-script, - ./utils/check-incremental, - ./test/Driver/Inputs/fake-toolchain/clang++, - ./utils/coverage/coverage-build-db, - ./utils/coverage/coverage-generate-data, - ./utils/coverage/coverage-query-db, - ./utils/coverage/coverage-touch-tests, - ./utils/gyb, - ./test/Driver/Inputs/fake-toolchain/ld, - ./utils/line-directive, - ./utils/swift_build_support/tests/mock-distcc, - ./docs/scripts/ns-html2rst, - ./utils/PathSanitizingFileCheck, - ./utils/recursive-lipo, - ./utils/round-trip-syntax-test, - ./utils/rth, - ./utils/run-remote, - ./utils/run-test, - ./utils/scale-test, - ./utils/submit-benchmark-results, - ./utils/update-checkout, - ./utils/viewcfg, - ./utils/symbolicate-linux-fatal, + +filename = + *.py, + + ./benchmark/scripts/Benchmark_Driver, + ./benchmark/scripts/Benchmark_DTrace.in, + ./benchmark/scripts/Benchmark_GuardMalloc.in, + ./benchmark/scripts/Benchmark_RuntimeLeaksRunner.in, + + ./docs/scripts/ns-html2rst, + + ./test/Driver/Inputs/fake-toolchain/clang++, + ./test/Driver/Inputs/fake-toolchain/ld, + + ./utils/80+-check, + ./utils/backtrace-check, + ./utils/build-parser-lib, + ./utils/build-script, + ./utils/check-incremental, + ./utils/coverage/coverage-build-db, + ./utils/coverage/coverage-generate-data, + ./utils/coverage/coverage-query-db, + ./utils/coverage/coverage-touch-tests, + ./utils/dev-scripts/blockifyasm, + ./utils/dev-scripts/split-cmdline, + ./utils/gyb, + ./utils/line-directive, + ./utils/PathSanitizingFileCheck, + ./utils/recursive-lipo, + ./utils/round-trip-syntax-test, + ./utils/rth, + ./utils/run-remote, + ./utils/run-test, + ./utils/scale-test, + ./utils/submit-benchmark-results, + ./utils/swift_build_support/tests/mock-distcc, + ./utils/symbolicate-linux-fatal, + ./utils/update-checkout, + ./utils/viewcfg, + + # TODO: We should be linting the lit configs. + #lit.cfg, + +exclude = + .git, + __pycache__, + +ignore = + # The black tool treats slices consistently, the E203 warning is not PEP8 + # compliant (https://github.com/psf/black#slices). + E203, + + # FIXME: We should not have trailing whitespace. + W291, + + # Line breaks before binary operators are not explicitly disallowed in + # PEP8, rather it should be consistent throughout the project. The black + # tool puts them on new lines which is to be considered a best practice + # in the future. + W503, + + # Similarly ignore line break after binary operators. + W504, + + # TODO: Ignore Bugbear lints for now, but we should enable these in the + # future. + B, + +# 10% larger than the standard 80 character limit. Conforms to the black +# standard and Bugbear's B950. +max-line-length = 88 diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c93a24650a34..84f1c2ecf328a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -193,6 +193,23 @@ Swift 5.2 * `mutating func callAsFunction` is supported. * `func callAsFunction` works with `throws` and `rethrows`. * `func callAsFunction` works with trailing closures. + +* [SE-0249][]: + + A `\Root.value` key path expression is now allowed wherever a `(Root) -> Value` + function is allowed. Such an expression is implicitly converted to a key path + application of `{ $0[keyPath: \Root.value] }`. + + For example: + + ```swift + struct User { + let email: String + let isAdmin: Bool + } + + users.map(\.email) // this is equivalent to: users.map { $0[keyPath: \User.email] } + ``` * [SR-4206][]: @@ -7880,6 +7897,7 @@ Swift 1.0 [SE-0242]: [SE-0244]: [SE-0245]: +[SE-0249]: [SE-0252]: [SE-0253]: [SE-0254]: diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index fbf1709638d3b..d46c6326f174c 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -248,6 +248,10 @@ option(SWIFT_BENCHMARK_GENERATE_OPT_VIEW set(SWIFT_BENCHMARK_OPT_VIEWER "" CACHE FILEPATH "Path to opt-viewer") +option(SWIFT_BENCHMARK_GENERATE_DEBUG_INFO + "Produce debug info for benchmarks" + TRUE) + if(SWIFT_BENCHMARK_OPT_VIEWER) # If the path to the opt-viewer was specified manually and we have no access # to the LLVM tree, assume we have the modules for the opt-viewer installed. diff --git a/benchmark/README.md b/benchmark/README.md index 443d940bbb3af..0e133fbcc746c 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -67,6 +67,9 @@ The following build options are available: * Enable this option to link the benchmark binaries against the target machine's Swift standard library and runtime installed with the OS. (default: OFF) +* `-DSWIFT_BENCHMARK_GENERATE_DEBUG_INFO` + * Enable this option to compile benchmark binaries with debug info. + (default: ON) The following build targets are available: diff --git a/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake b/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake index bc05c8f864789..e21f9c87566cc 100644 --- a/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake +++ b/benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake @@ -355,6 +355,10 @@ function (swift_benchmark_compile_archopts) "-target" "${target}" "-${BENCH_COMPILE_ARCHOPTS_OPT}" ${PAGE_ALIGNMENT_OPTION}) + if(SWIFT_BENCHMARK_GENERATE_DEBUG_INFO) + list(APPEND common_options "-g") + endif() + if (is_darwin) list(APPEND common_options "-I" "${srcdir}/utils/ObjectiveCTests" @@ -384,6 +388,10 @@ function (swift_benchmark_compile_archopts) "-target" "${target}" "-${driver_opt}") + if(SWIFT_BENCHMARK_GENERATE_DEBUG_INFO) + list(APPEND common_options_driver "-g") + endif() + if (is_darwin) list(APPEND common_options_driver "-sdk" "${sdk}" diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 62e37b3b32d79..9e8156ccc82b1 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -1416,10 +1416,27 @@ function(_add_swift_library_single target name) # Include LLVM Bitcode slices for iOS, Watch OS, and Apple TV OS device libraries. if(SWIFT_EMBED_BITCODE_SECTION AND NOT SWIFTLIB_SINGLE_DONT_EMBED_BITCODE) if(${SWIFTLIB_SINGLE_SDK} MATCHES "(I|TV|WATCH)OS") - target_link_options(${target} PRIVATE - "LINKER:-bitcode_bundle" - $<$:"LINKER:-bitcode_hide_symbols"> - "LINKER:-lto_library,${LLVM_LIBRARY_DIR}/libLTO.dylib") + # The two branches of this if statement accomplish the same end result + # We are simply accounting for the fact that on CMake < 3.16 + # using a generator expression to + # specify a LINKER: argument does not work, + # since that seems not to allow the LINKER: prefix to be + # evaluated (i.e. it will be added as-is to the linker parameters) + if(CMAKE_VERSION VERSION_LESS 3.16) + target_link_options(${target} PRIVATE + "LINKER:-bitcode_bundle" + "LINKER:-lto_library,${LLVM_LIBRARY_DIR}/libLTO.dylib") + + if(SWIFT_EMBED_BITCODE_SECTION_HIDE_SYMBOLS) + target_link_options(${target} PRIVATE + "LINKER:-bitcode_hide_symbols") + endif() + else() + target_link_options(${target} PRIVATE + "LINKER:-bitcode_bundle" + $<$:"LINKER:-bitcode_hide_symbols"> + "LINKER:-lto_library,${LLVM_LIBRARY_DIR}/libLTO.dylib") + endif() endif() endif() endif() @@ -1554,6 +1571,9 @@ function(add_swift_host_library name) if(ASHL_DEPENDS) message(SEND_ERROR "library ${name} is using DEPENDS parameter which is deprecated. Please use add_dependencies instead") endif() + if(ASHL_FILE_DEPENDS) + message(SEND_ERROR "library ${name} is using FILE_DEPENDS parameter which is deprecated.") + endif() if(ASHL_LINK_LIBRARIES) message(SEND_ERROR "library ${name} is using LINK_LIBRARIES parameter which is deprecated. Please use target_link_libraries instead") endif() @@ -1573,7 +1593,6 @@ function(add_swift_host_library name) SDK ${SWIFT_HOST_VARIANT_SDK} ARCHITECTURE ${SWIFT_HOST_VARIANT_ARCH} LLVM_LINK_COMPONENTS ${ASHL_LLVM_LINK_COMPONENTS} - FILE_DEPENDS ${ASHL_FILE_DEPENDS} INSTALL_IN_COMPONENT "dev" ) @@ -2153,7 +2172,10 @@ function(add_swift_target_library name) list(APPEND swiftlib_swift_compile_flags_all "-Fsystem" "${ios_support_frameworks_path}") list(APPEND swiftlib_c_compile_flags_all "-iframework" "${ios_support_frameworks_path}") - list(APPEND swiftlib_link_flags_all "-F" "${ios_support_frameworks_path}") + # We collate -F with the framework path to avoid unwanted deduplication + # of options by target_compile_options -- this way no undesired + # side effects are introduced should a new search path be added. + list(APPEND swiftlib_link_flags_all "-F${ios_support_frameworks_path}") endif() if(sdk IN_LIST SWIFT_APPLE_PLATFORMS AND SWIFTLIB_IS_SDK_OVERLAY) @@ -2523,6 +2545,9 @@ function(_add_swift_executable_single name) if(SWIFTEXE_SINGLE_EXCLUDE_FROM_ALL) message(SEND_ERROR "${name} is using EXCLUDE_FROM_ALL option which is deprecated.") endif() + if(SWIFTEXE_SINGLE_LINK_LIBRARIES) + message(SEND_ERROR "${name} is using LINK_LIBRARIES parameter which is deprecated. Please use target_link_libraries instead") + endif() # Check arguments. precondition(SWIFTEXE_SINGLE_SDK MESSAGE "Should specify an SDK") @@ -2557,12 +2582,6 @@ function(_add_swift_executable_single name) LINK_LIBRARIES_VAR_NAME link_libraries LIBRARY_SEARCH_DIRECTORIES_VAR_NAME library_search_directories) - _list_add_string_suffix( - "${SWIFTEXE_SINGLE_LINK_LIBRARIES}" - "-${SWIFT_SDK_${SWIFTEXE_SINGLE_SDK}_LIB_SUBDIR}-${SWIFTEXE_SINGLE_ARCHITECTURE}" - SWIFTEXE_SINGLE_LINK_LIBRARIES_TARGETS) - set(SWIFTEXE_SINGLE_LINK_LIBRARIES ${SWIFTEXE_SINGLE_LINK_LIBRARIES_TARGETS}) - handle_swift_sources( dependency_target unused_module_dependency_target @@ -2626,7 +2645,6 @@ function(_add_swift_executable_single name) BINARY_DIR ${SWIFT_RUNTIME_OUTPUT_INTDIR} LIBRARY_DIR ${SWIFT_LIBRARY_OUTPUT_INTDIR}) - target_link_libraries("${name}" PRIVATE ${SWIFTEXE_SINGLE_LINK_LIBRARIES}) swift_common_llvm_config("${name}" ${SWIFTEXE_SINGLE_LLVM_LINK_COMPONENTS}) # NOTE(compnerd) use the C linker language to invoke `clang` rather than diff --git a/cmake/modules/SwiftSource.cmake b/cmake/modules/SwiftSource.cmake index 004d26b0fa8d3..a68f9ef423140 100644 --- a/cmake/modules/SwiftSource.cmake +++ b/cmake/modules/SwiftSource.cmake @@ -355,13 +355,9 @@ function(_compile_swift_files if(SWIFTFILE_SDK IN_LIST SWIFT_APPLE_PLATFORMS OR SWIFTFILE_SDK STREQUAL "MACCATALYST") set(specific_module_dir "${module_base}.swiftmodule") - set(specific_module_project_dir "${specific_module_dir}/Project") - set(source_info_file "${specific_module_project_dir}/${SWIFTFILE_ARCHITECTURE}.swiftsourceinfo") set(module_base "${module_base}.swiftmodule/${SWIFTFILE_ARCHITECTURE}") else() set(specific_module_dir) - set(specific_module_project_dir) - set(source_info_file "${module_base}.swiftsourceinfo") endif() set(module_file "${module_base}.swiftmodule") set(module_doc_file "${module_base}.swiftdoc") @@ -622,11 +618,10 @@ function(_compile_swift_files COMMAND "${CMAKE_COMMAND}" "-E" "make_directory" ${module_dir} ${specific_module_dir} - ${specific_module_project_dir} COMMAND "${PYTHON_EXECUTABLE}" "${line_directive_tool}" "@${file_path}" -- "${swift_compiler_tool}" "-emit-module" "-o" "${module_file}" - "-emit-module-source-info-path" "${source_info_file}" + "-avoid-emit-module-source-info" ${swift_flags} ${swift_module_flags} "@${file_path}" ${command_touch_module_outputs} OUTPUT ${module_outputs} diff --git a/docs/AndroidBuild.md b/docs/AndroidBuild.md index 03d5f9eddad27..c45f77bec0644 100644 --- a/docs/AndroidBuild.md +++ b/docs/AndroidBuild.md @@ -11,9 +11,9 @@ Windows. 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-foundation` into a directory named `swift-corelibs-foundation` 1. Clone `apple/swift-corelibs-xctest` into a directory named `swift-corelibs-xctest` -1. Clone `compnerd/swift-windows` into a directory named `swift-windows` +1. Clone `compnerd/swift-build` into a directory named `swift-build` - Currently, other repositories in the Swift project have not been tested and may not be supported. @@ -31,28 +31,27 @@ 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 +git clone https://github.com/compnerd/swift-build swift-build ``` ## 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`. + [Azure](https://dev.azure.com/compnerd/swift-build) 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. +- You can alternatively use `swift-build.py` from + [compnerd/swift-build](https://www.github.com/compnerd/swift-build) under + the utilities directory. ## 1. Configure LLVM ```cmd md S:\b\a\llvm cd S:\b\a\llvm -cmake -C S:\swift-windows\cmake\caches\android-armv7.cmake ^ +cmake -C S:\swift-build\cmake\caches\android-armv7.cmake ^ -G Ninja ^ -DCMAKE_BUILD_TYPE=Release ^ - -DCMAKE_TOOLCHAIN_FILE=S:\swift-windows\cmake\toolchains\android.toolchain.cmake ^ + -DCMAKE_TOOLCHAIN_FILE=S:\swift-build\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 @@ -66,12 +65,12 @@ cmake -C S:\swift-windows\cmake\caches\android-armv7.cmake ```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 ^ +cmake -C S:\swift-build\cmake\caches\android-armv7.cmake ^ + -C S:\swift-build\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 ^ + -DCMAKE_TOOLCHAIN_FILE=S:\swift-build\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 ^ @@ -92,14 +91,14 @@ ninja install ```cmd md S:\b\a\libdispatch cd S:\b\a\libdispatch -cmake -C S:\windows-swift\cmake\caches\android-armv7.cmake ^ +cmake -C S:\swift-build\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 ^ + -C S:\swift-build\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 ^ + -DCMAKE_TOOLCHAIN_FILE=S:\swift-build\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 ^ @@ -112,14 +111,14 @@ ninja ```cmd md S:\b\a\foundation cd S:\b\a\foundation -cmake -C S:\windows-swift\cmake\caches\android-armv7.cmake ^ +cmake -C S:\swift-build\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 ^ + -C S:\swift-build\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 ^ + -DCMAKE_TOOLCHAIN_FILE=S:\swift-build\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 ^ @@ -141,13 +140,13 @@ ninja ```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 ^ +cmake -C S:\swift-build\cmake\caches\android-armv7.cmake ^ + -C S:\swift-build\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 ^ + -DCMAKE_TOOLCHAIN_FILE=S:\swift-build\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 ^ diff --git a/docs/HowSwiftImportsCAPIs.md b/docs/HowSwiftImportsCAPIs.md new file mode 100644 index 0000000000000..69435bb020b6b --- /dev/null +++ b/docs/HowSwiftImportsCAPIs.md @@ -0,0 +1,1033 @@ +# How Swift imports C APIs + +When Swift imports a module, or parses a bridging header from a C-based language +(C, Objective-C), the APIs are mapped into Swift APIs and can be used directly +from Swift code. This provides the basis for Swift's Foreign Function Interface +(FFI), providing interoperability with existing libraries written in C-based +languages. + +This document describes how APIs from C-based languages are mapped into Swift +APIs. It is written for a broad audience, including Swift and C users who +might not be language experts. Therefore, it explains some advanced concepts +where necessary. + +* [Names, identifiers and keywords](#names-identifiers-and-keywords) + * [Unicode](#unicode) + * [Names that are keywords in Swift](#names-that-are-keywords-in-swift) + * [Name translation](#name-translation) + * [Name customization](#name-customization) +* [Size, stride, and alignment of types](#size-stride-and-alignment-of-types) +* [Fundamental types](#fundamental-types) +* [Free functions](#free-functions) + * [Argument labels](#argument-labels) + * [Variadic arguments](#variadic-arguments) + * [Inline functions](#inline-functions) +* [Global variables](#global-variables) +* [Pointers to data](#pointers-to-data) +* [Nullable and non-nullable pointers](#nullable-and-non-nullable-pointers) +* [Incomplete types and pointers to them](#incomplete-types-and-pointers-to-them) +* [Function pointers](#function-pointers) +* [Fixed-size arrays](#fixed-size-arrays) +* [Structs](#structs) +* [Unions](#unions) +* [Enums](#enums) +* [Typedefs](#typedefs) +* [Macros](#macros) + +## Names, identifiers and keywords + +### Unicode + +C (and C++) permit non-ASCII Unicode code points in identifiers. While Swift +does not permit arbitrary Unicode code points in identifiers (so compatibility +might not be perfect), it tries to allow reasonable ones. However, C, +Objective-C, and C++ code in practice does not tend to use non-ASCII code points +in identifiers, so mapping them to Swift is not an important concern. + +### Names that are keywords in Swift + +Some C and C++ identifiers are keywords in Swift. Despite that, such names are +imported as-is into Swift, because Swift permits escaping keywords to use them +as identifiers: + +```c +// C header. + +// The name of this function is a keyword in Swift. +void func(); +``` + +```swift +// C header imported in Swift. + +// The name of the function is still `func`, but it is escaped to make the +// keyword into an identifier. +func `func`() +``` + +```swift +// Swift user. + +func test() { + // Call the C function declared above. + `func`() +} +``` + +### Name translation + +Names of some C declarations appear in Swift differently. In particular, names +of enumerators (enum constants) go through a translation process that is +hardcoded into the compiler. For more details, see [Name Translation from C to +Swift](CToSwiftNameTranslation.md). + +### Name customization + +As a general principle of Swift/C interoperability, the C API vendor has broad +control over how their APIs appear in Swift. In particular, the vendor can use +the `swift_name` Clang attribute to customize the names of their C APIs in order +to be more idiomatic in Swift. For more details, see [Name Translation from C to +Swift](CToSwiftNameTranslation.md). + +## Size, stride, and alignment of types + +In C, every type has a size (computed with the `sizeof` operator), and an +alignment (computed with `alignof`). + +In Swift, types have size, stride, and alignment. + +The concept of alignment in C and Swift is exactly the same. + +Size and stride is more complicated. In Swift, stride is the distance between +two elements in an array. The size of a type in Swift is the stride minus the +tail padding. For example: + +```swift +struct SwiftStructWithPadding { + var x: Int16 + var y: Int8 +} + +print(MemoryLayout.size) // 3 +print(MemoryLayout.stride) // 4 +``` + +C's concept of size corresponds to Swift's stride (not size!) C does not have an +equivalent of Swift's size. + +Swift tracks the exact size of the data stored in a type so that it can pack +additional data into bytes that otherwise would be wasted as padding. Swift also +tracks possible and impossible bit patterns for each type, and reuses impossible +bit patterns to encode more information, similarly to `llvm::PointerIntPair` and +`llvm::PointerUnion`. The language does this automatically, and transparently +for users. For example: + +```swift +// This enum takes 1 byte in memory, which has 256 possible bit patterns. +// However, only 2 bit patterns are used. +enum Foo { + case A + case B +} + +print(MemoryLayout.size) // 1 +print(MemoryLayout.size) // also 1: `nil` is represented as one of the 254 bit patterns that are not used by `Foo.A` or `Foo.B`. +``` + +Nevertheless, for types imported from C, the size and the stride are equal. + +```c +// C header. + +struct CStructWithPadding { + int16_t x; + int8_t y; +}; +``` + +```swift +// C header imported in Swift. + +struct CStructWithPadding { + var x: Int16 + var y: Int8 +} +``` + +``` +print(MemoryLayout.size) // 4 +print(MemoryLayout.stride) // 4 +``` + +## Fundamental types + +In C, certain types (`char`, `int`, `float` etc.) are built into the language +and into the compiler. These builtin types have behaviors that are not possible +to imitate in user-defined types (e.g., usual arithmetic conversions). + +C and C++ standard libraries provide headers that define character and integer +types that are typedefs to one of the underlying builtin types, for example, +`int16_t`, `size_t`, and `ptrdiff_t`. + +Swift does not have such builtin types. Swift's equivalents to C's fundamental +types are defined in the Swift standard library as ordinary structs. They are +implemented using compiler intrinsics, but the API surface is defined in +ordinary Swift code: + +```swift +// From the Swift standard library: + +struct Int32 { + internal var _value: Builtin.Int32 + + // Note: `Builtin.Xyz` types are only accessible to the standard library. +} + +func +(lhs: Int32, rhs: Int32) -> Int32 { + return Int32(_value: Builtin.add_Int32(lhs._value, rhs._value)) +} +``` + +Memory layout of these "fundamental" Swift types does not have any surprises, +hidden vtable pointers, metadata, or reference counting; it is exactly what you +expect from a corresponding C type: just the data, stored inline. For example, +Swift's `Int32` is a contiguous chunk of four bytes, all of which store the +number. + +Fundamental types in C, with a few exceptions, have an implementation-defined +size, alignment, and stride (distance between two array elements). + +Swift's integer and floating point types have fixed size, alignment and stride +across platforms, with two exceptions: `Int` and `UInt`. The sizes of `Int` and +`UInt` match the size of the pointer on the platform, similarly to how `size_t`, +`ptrdiff_t`, `intptr_t`, and `uintptr_t` have the same size as a pointer in most +C implementations. `Int` and `UInt` are distinct types, they are not typealiases +to explicitly-sized types. An explicit conversion is required to convert between +`Int`, `UInt`, and any other integer type, even if sizes happen to match on the +current platform. + +The table below summarizes mapping between fundamental types of C and C++ and +Swift types. This table is based on +[`swift.git/include/swift/ClangImporter/BuiltinMappedTypes.def`](../include/swift/ClangImporter/BuiltinMappedTypes.def). + +| C and C++ types | Swift types | +| ------------------------------------ | ----------- | +| C `_Bool`, C++ `bool` | `typealias CBool = Bool` | +| `char`, regardless if the target defines it as signed or unsigned | `typealias CChar = Int8` | +| `signed char`, explicitly signed | `typealias CSignedChar = Int8` | +| `unsigned char`, explicitly unsigned | `typealias CUnsignedChar = UInt8` | +| `short`, `signed short` | `typealias CShort = Int16` | +| `unsigned short` | `typealias CUnsignedShort = UInt16` | +| `int`, `signed int` | `typealias CInt = Int32` | +| `unsigned int` | `typealias CUnsignedInt = UInt32` | +| `long`, `signed long` | Windows x86\_64: `typealias CLong = Int32`
Everywhere else: `typealias CLong = Int` | +| `unsigned long` | Windows x86\_64: `typealias CUnsignedLong = UInt32`
Everywhere else: `typealias CUnsignedLong = UInt` | +| `long long`, `signed long long` | `typealias CLongLong = Int64` | +| `unsigned long long` | `typealias CUnsignedLongLong = UInt64` | +| `wchar_t`, regardless if the target defines it as signed or unsigned | `typealias CWideChar = Unicode.Scalar`
`Unicode.Scalar` is a wrapper around `UInt32` | +| `char8_t` (proposed for C++20) | Not mapped | +| `char16_t` | `typealias CChar16 = UInt16` | +| `char32_t` | `typealias CChar32 = Unicode.Scalar` | +| `float` | `typealias CFloat = Float` | +| `double` | `typealias CDouble = Double` | +| `long double` | `CLongDouble`, which is a typealias to `Float80` or `Double`, depending on the platform.
There is no support for 128-bit floating point. | + +First of all, notice that C types are mapped to Swift typealiases, not directly +to the underlying Swift types. The names of the typealiases are based on the +original C types. These typealiases allow developers to easily write Swift code +and APIs that work with APIs and data imported from C without a lot of `#if` +conditions. + +This table is generally unsurprising: C types are mapped to corresponding +explicitly-sized Swift types, except for the C `long`, which is mapped to `Int` +on 32-bit and 64-bit LP64 platforms. This was done to enhance portability +between 32-bit and 64-bit code. + +The difficulty with the C `long` type is that it can be 32-bit or 64-bit +depending on the platform. If C `long` was mapped to an explicitly-sized Swift +type, it would map to different Swift types on different platforms, making it +more difficult to write portable Swift code (the user would have to compile +Swift code for both platforms to see all errors; fixing compilation errors on +one platform can break another platform.) By mapping `long` a distinct type, +`Int`, the language forces the user to think about both cases when compiling for +either platform. + +Nevertheless, mapping C `long` to `Int` does not work universally. +Specifically, it does not work on LLP64 platforms (for example, Windows +x86\_64), where C `long` is 32-bit and Swift's `Int` is 64-bit. On LLP64 +platforms, C `long` is mapped to Swift's explicitly-sized `Int32`. + +Typedefs for integer types in the C standard library are mapped like this (from +[`swift.git/swift/lib/ClangImporter/MappedTypes.def`](../lib/ClangImporter/MappedTypes.def): + +| C and C++ types | Swift types | +| ---------------- | ----------- | +| `uint8_t` | `UInt8` | +| `uint16_t` | `UInt16` | +| `uint32_t` | `UInt32` | +| `uint64_t` | `UInt64` | +| `int8_t` | `Int8` | +| `int16_t` | `Int16` | +| `int32_t` | `Int32` | +| `int64_t` | `Int64` | +| `intptr_t` | `Int` | +| `uintptr_t` | `UInt` | +| `ptrdiff_t` | `Int` | +| `size_t` | `Int` | +| `rsize_t` | `Int` | +| `ssize_t` | `Int` | + +```c +// C header. + +double Add(int x, long y); +``` + +```swift +// C header imported in Swift. + +func Add(_ x: CInt, _ y: CLong) -> CDouble +``` + +## Free functions + +C functions are imported as free functions in Swift. Each type in the signature +of the C function is mapped to the corresponding Swift type. + +### Argument labels + +Imported C functions don't have argument labels in Swift by default. Argument +labels can be added by API owners through annotations in the C header. + +```c +// C header. + +#define SWIFT_NAME(X) __attribute__((swift_name(#X))) + +// No argument labels by default. +void drawString(const char *, int xPos, int yPos); + +// The attribute specifies the argument labels. +void drawStringRenamed(const char *, int xPos, int yPos) + SWIFT_NAME(drawStringRenamed(_:x:y:)); +``` + +```swift +// C header imported in Swift. + +func drawString(_: UnsafePointer!, _ xPos: Int, _ yPos: Int) +func drawStringRenamed(_: UnsafePointer!, x: Int, y: Int) + +drawString("hello", 10, 20) +drawStringRenamed("hello", x: 10, y: 20) +``` + +### Variadic arguments + +C functions with variadic arguments are not imported into Swift, however, there +are no technical reasons why they can't be imported. + +Note that functions with `va_list` arguments are imported into Swift. `va_list` +corresponds to `CVaListPointer` in Swift. + +C APIs don't define a lot of variadic functions, so this limitation has not +caused a big problem so far. + +Often, for each variadic function there is a corresponding function that takes a +`va_list` which can be called from Swift. A motivated developer can write an +overlay that exposes a Swift variadic function that looks just like the C +variadic function, and implement it in terms of the `va_list`-based C API. You +can find examples of such overlays and wrappers by searching for usages of the +`withVaList` function in the [`swift.git/stdlib`](../stdlib) directory. + +See also Apple's documentation about this topic: [Use a CVaListPointer to Call +Variadic +Functions](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_functions_in_swift#2992073). + +### Inline functions + +Inline C functions that are defined in headers are imported as regular Swift +functions. However, unlike free functions, inline functions require the caller +to emit a definition of the function, because no other translation unit is +guaranteed to provide a definition. + +Therefore, the Swift compiler uses Clang's CodeGen library to emit LLVM IR for +the C inline function. LLVM IR for C inline functions and LLVM IR for Swift code +is put into one LLVM module, allowing all LLVM optimizations (like inlining) to +work transparently across language boundaries. + +## Global variables + +Global C variables are imported as Swift variables or constants, depending on +constness. + +```c +// C header. + +extern int NumAlpacas; +extern const int NumLlamas; +``` + +```swift +// C header imported in Swift. + +var NumAlpacas: CInt +let NumLlamas: CInt +``` + +## Pointers to data + +C has one way to form a pointer to a value of type `T` -- `T*`. + +Swift language does not provide a builtin pointer type. The standard library +defines multiple pointer types: + +* `UnsafePointer`: equivalent to `const T*` in C. + +* `UnsafeMutablePointer`: equivalent to `T*` in C, where `T` is non-const. + +* `UnsafeRawPointer`: a pointer for accessing data that is not statically typed, + similar to `const void*` in C. Unlike C pointer types, `UnsafeRawPointer` + allows type punning, and provides special APIs to do it correctly and safely. + +* `UnsafeMutableRawPointer`: like `UnsafeRawPointer`, but can mutate the data it + points to. + +* `OpaquePointer`: a pointer to typed data, however the type of the pointee is + not known, for example, it is determined by the value of some other variable, + or the type of the pointee is not representable in Swift. + +* `AutoreleasingUnsafeMutablePointer`: only used for Objective-C + interoperability; corresponds to an Objective-C pointer T `__autoreleasing *`, + where `T` is an Objective-C pointer type. + +C pointer types can be trivially imported in Swift as long as the memory layout +of the pointee is identical in C and Swift. So far, this document only described +primitive types, whose memory layout in C and Swift is indeed identical, for +example, `char` in C and `Int8` in Swift. Pointers to such types are trivial to +import into Swift, for example, `char*` in C corresponds to +`UnsafeMutablePointer!` in Swift. + +```c +// C header. + +void AddSecondToFirst(int *x, const long *y); +``` + +```swift +// C header imported in Swift. + +func AddSecondToFirst(_ x: UnsafeMutablePointer!, _ y: UnsafePointer!) +``` + +## Nullable and non-nullable pointers + +Any C pointer can be null. However, in practice, many pointers are never null. +Therefore, code often does not expect certain pointers to be null and does not +handle null values gracefully. + +C does not provide a way to distinguish nullable and non-nullable pointers. +However, Swift makes this distinction: all pointer types (for example, +`UnsafePointer` and `UnsafeMutablePointer`) are non-nullable. Swift +represents the possibility of a missing value with a type called "Optional", +spelled `T?` in the shorthand form, or `Optional` fully. The missing value is +called "nil". For example, `UnsafePointer?` (shorthand for +`Optional>`) can store a nil value. + +Swift also provides a different syntax for declaring an optional, `T!`, which +creates a so-called "implicitly unwrapped optional". These optionals are +automatically checked for nil and unwrapped if it is necessary for the +expression to compile. Unwrapping a `T?` or a `T!` optional that contains nil is +a fatal error (the program is terminated with an error message). + +Formally, since any C pointer can be null, C pointers must be imported as +optional unsafe pointers in Swift. However, that is not idiomatic in Swift: +optional should be used when value can be truly missing, and when it is +meaningful for the API. C APIs do not provide this information in a +machine-readable form. Information about which pointers are nullable is +typically provided in free-form documentation for C APIs, if it is provided at +all. + +Clang implements an [extension to the C language that allows C API vendors to +annotate pointers as nullable or +non-nullable](https://clang.llvm.org/docs/AttributeReference.html#nullability-attributes). + +Quoting the Clang manual: + +> The `_Nonnull` nullability qualifier indicates that null is not a meaningful +> value for a value of the `_Nonnull` pointer type. For example, given a +> declaration such as: + +```c +int fetch(int * _Nonnull ptr); +``` + +> a caller of `fetch` should not provide a null value, and the compiler will +> produce a warning if it sees a literal null value passed to fetch. Note that, +> unlike the declaration attribute `nonnull`, the presence of `_Nonnull` does +> not imply that passing null is undefined behavior: `fetch` is free to consider +> null undefined behavior or (perhaps for backward-compatibility reasons) +> defensively handle null. + +`_Nonnull` C pointers are imported in Swift as non-optional `UnsafePointer` +or `UnsafeMutablePointer`, depending on the constness of the pointer. + +```swift +// C declaration above imported in Swift. + +func fetch(_ ptr: UnsafeMutablePointer) -> CInt +``` + +Quoting the Clang manual: + +> The `_Nullable` nullability qualifier indicates that a value of the +> `_Nullable` pointer type can be null. For example, given: + +```c +int fetch_or_zero(int * _Nullable ptr); +``` + +> a caller of `fetch_or_zero` can provide null. + +`_Nullable` pointers are imported in Swift as `UnsafePointer?` or +`UnsafeMutablePointer?`, depending on the constness of the pointer. + +```swift +// C declaration above imported in Swift. + +func fetch_or_zero(_ ptr: UnsafeMutablePointer?) -> CInt +``` + +Quoting the Clang manual: + +> The `_Null_unspecified` nullability qualifier indicates that neither the +> `_Nonnull` nor `_Nullable` qualifiers make sense for a particular pointer +> type. It is used primarily to indicate that the role of null with specific +> pointers in a nullability-annotated header is unclear, e.g., due to +> overly-complex implementations or historical factors with a long-lived API. + +`_Null_unspecified` and not annotated C pointers are imported in Swift as +implicitly-unwrapped optional pointers, `UnsafePointer!` or +`UnsafeMutablePointer!`. This strategy provides ergonomics equivalent to the +original C API (no need to explicitly unwrap), and safety expected by Swift code +(a dynamic check for null during implicit unwrapping). + +These qualifiers do not affect program semantics in C and C++, allowing C API +vendors to safely add them to headers for the benefit of Swift users without +disturbing existing C and C++ users. + +In C APIs most pointers are non-nullable. To reduce the annotation burden, Clang +provides a way to mass-annotate pointers as non-nullable, and then mark +exceptions with `_Nullable`. + +```c +// C header. + +void Func1(int * _Nonnull x, int * _Nonnull y, int * _Nullable z); + +#pragma clang assume_nonnull begin + +void Func2(int *x, int *y, int * _Nullable z); + +#pragma clang assume_nonnull end +``` + +```swift +// C header imported in Swift. + +// Note that `Func1` and `Func2` are imported identically, but `Func2` required +// fewer annotations in the C header. + +func Func1( + _ x: UnsafeMutablePointer, + _ y: UnsafeMutablePointer, + _ z: UnsafeMutablePointer? +) + +func Func2( + _ x: UnsafeMutablePointer, + _ y: UnsafeMutablePointer, + _ z: UnsafeMutablePointer? +) +``` + +API owners that adopt nullability qualifiers usually wrap all declarations in +the header with a single `assume_nonnull begin/end` pair of pragmas, and then +annotate nullable pointers. + +See also Apple's documentation about this topic: [Designating Nullability in +Objective-C +APIs](https://developer.apple.com/documentation/swift/objective-c_and_c_code_customization/designating_nullability_in_objective-c_apis). + +## Incomplete types and pointers to them + +C and C++ have a notion of incomplete types; Swift does not have anything +similar. Incomplete C types are not imported in Swift in any form. + +Sometimes types are incomplete only accidentally, for example, when a file just +happens to forward declare a type instead of including a header with a complete +definition, although it could include that header. In cases like that, to enable +Swift to import the C API, it is recommended to change C headers and to replace +forward declarations with `#include`s of the header that defines the type. + +Incomplete types are often used intentionally to define opaque types. This is +done too often, and Swift could not ignore this use case. Swift imports +pointers to incomplete types as `OpaquePointer`. For example: + +```c +// C header. + +struct Foo; +void Print(const Foo* foo); +``` + +```swift +// C header imported in Swift. + +// Swift can't import the incomplete type `Foo` and has to drop some type +// information when importing a pointer to `Foo`. +func Print(_ foo: OpaquePointer) +``` + +## Function pointers + +C supports only one form of function pointers: `Result (*)(Arg1, Arg2, Arg3)`. + +Swift's closest native equivalent to a function pointer is a closure: `(Arg1, +Arg2, Arg3) -> Result`. Swift closures don't have the same memory layout as C +function pointers: closures in Swift consist of two pointers, a pointer to the +code and a pointer to the captured data (the context). A C function pointer can +be converted to a Swift closure; however, bridging is required to adjust the +memory layout. + +As discussed above, there are cases where bridging that adjusts memory layout is +not possible, for example, when importing pointers to function pointers. For +example, while C's int `(*)(char)` can be imported as `(Int8) -> Int` (requires +an adjustment of memory layout), C's `int (**)(char)` can't be imported as +`UnsafePointer<(Int8) -> Int>`, because the pointee must have identical memory +layout in C and in Swift. + +Therefore, we need a Swift type that has a memory layout identical to C function +pointers, at least for such fallback cases. This type is spelled `@convention(c) +(Arg1, Arg2, Arg3) -> Result`. + +Even though it is possible to import C function pointers as Swift closure with a +context pointer in some cases, C function pointers are always imported as +`@convention(c)` "closures" (in quotes because they don't have a context +pointer, so they are not real closures). Swift provides an implicit conversion +from `@convention(c)` closures to Swift closures with a context. + +Importing C function pointers also takes pointer nullability into account: a +nullable C function pointer is imported as optional. + +```c +// C header. + +void qsort( + void *base, + size_t nmemb, + size_t size, + int (*compar)(const void *, const void *)); + +void qsort_annotated( + void * _Nonnull base, + size_t nmemb, + size_t size, + int (* _Nonnull compar)(const void * _Nonnull, const void * _Nonnull)); +``` + +```swift +// C header imported in Swift. + +func qsort( + _ base: UnsafeMutableRawPointer!, + _ nmemb: Int, + _ size: Int, + _ compar: (@convention(c) (UnsafeRawPointer?, UnsafeRawPointer?) -> CInt)! +) + +func qsort_annotated( + _ base: UnsafeMutableRawPointer, + _ nmemb: Int, + _ size: Int, + _ compar: @convention(c) (UnsafeRawPointer, UnsafeRawPointer) -> CInt +) +``` + +See also Apple's documentation about this topic: [Using Imported C Functions in +Swift](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_functions_in_swift) + +## Fixed-size arrays + +C's fixed-size arrays are imported as Swift tuples. + +```c +// C header. + +extern int x[4]; +``` + +```swift +// C header imported in Swift. + +var x: (CInt, CInt, CInt, CInt) { get set } +``` + +This mapping strategy is widely recognized as being far from optimal because +ergonomics of Swift tuples does not match C's fixed-size arrays. For example, +Swift tuples cannot be accessed through an index that only becomes known at +runtime. If you need to access a tuple element by index, you have to get an +unsafe pointer to values in a homogeneous tuple with +`withUnsafeMutablePointer(&myTuple) { ... }`, and then perform pointer +arithmetic. + +Fixed-size arrays are a commonly requested feature in Swift, and a good proposal +is likely to be accepted. Once Swift has fixed-size arrays natively in the +language, we can use them to improve C interoperability. + +## Structs + +C structs are imported as Swift structs, their fields are mapped to stored Swift +properties. Bitfields are mapped to computed Swift properties. Swift structs +also get a synthesized default initializer (that sets all properties to zero), +and an elementwise initializer (that sets all properties to the provided +values). + +```c +// C header. + +struct Point { + int x; + int y; +}; + +struct Line { + struct Point start; + struct Point end; + unsigned int brush : 4; + unsigned int stroke : 3; +}; +``` + +```swift +// C header imported in Swift. + +struct Point { + var x: CInt { get set } + var y: CInt { get set } + init() + init(x: CInt, y: CInt) +} + +struct Line { + var start: Point { get set } + var end: Point { get set } + var brush: CUnsignedInt { get set } + var stroke: CUnsignedInt { get set } + + // Default initializer that sets all properties to zero. + init() + + // Elementwise initializer. + init(start: Point, end: Point, brush: CUnsignedInt, stroke: CUnsignedInt) +} +``` + +Swift can also import unnamed and anonymous structs. + +```c +// C header. + +struct StructWithAnonymousStructs { + struct { + int x; + }; + struct { + int y; + } containerForY; +}; +``` + +```swift +// C header imported in Swift. +struct StructWithAnonymousStructs { + struct __Unnamed_struct___Anonymous_field0 { + var x: CInt + init() + init(x: CInt) + } + struct __Unnamed_struct_containerForY { + var y: CInt + init() + init(y: CInt) + } + var __Anonymous_field0: StructWithAnonymousStructs.__Unnamed_struct___Anonymous_field0 + var x: CInt + var containerForY: StructWithAnonymousStructs.__Unnamed_struct_containerForY + + // Default initializer that sets all properties to zero. + init() + + // Elementwise initializer. + init( + _ __Anonymous_field0: StructWithAnonymousStructs.__Unnamed_struct___Anonymous_field0, + containerForY: StructWithAnonymousStructs.__Unnamed_struct_containerForY + ) +} +``` + +See also Apple's documentation about this topic: [Using Imported C Structs and +Unions in +Swift](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_structs_and_unions_in_swift). + +## Unions + +Swift does not have a direct equivalent to a C union. C unions are mapped to +Swift structs with computed properties that read from/write to the same +underlying storage. + +```c +// C header. + +union IntOrFloat { + int i; + float f; +}; +``` + +```swift +// C header imported in Swift. + +struct IntOrFloat { + var i: CInt { get set } // Computed property. + var f: Float { get set } // Computed property. + init(i: CInt) + init(f: Float) + init() +} +``` + +See also Apple's documentation about this topic: [Using Imported C Structs and +Unions in +Swift](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_structs_and_unions_in_swift). + +## Enums + +We would have liked to map C enums to Swift enums, like this: + +```c +// C header. + +// Enum that is not explicitly marked as either open or closed. +enum HomeworkExcuse { + EatenByPet, + ForgotAtHome, + ThoughtItWasDueNextWeek, +}; +``` + +```swift +// C header imported in Swift: aspiration, not an actual mapping! + +enum HomeworkExcuse: CUnsignedInt { + case EatenByPet + case ForgotAtHome + case ThoughtItWasDueNextWeek +} +``` + +However, in practice, plain C enums are mapped to Swift structs like this: + +```swift +// C header imported in Swift: actual mapping. + +struct HomeworkExcuse: Equatable, RawRepresentable { + init(_ rawValue: CUnsignedInt) + init(rawValue: CUnsignedInt) + var rawValue: CUnsignedInt { get } + typealias RawValue = CUnsignedInt +} +var EatenByPet: HomeworkExcuse { get } +var ForgotAtHome: HomeworkExcuse { get } +var ThoughtItWasDueNextWeek: HomeworkExcuse { get } +``` + +To explain why this mapping was chosen, we need to discuss certain features of C +enums: + +* In C, adding new enumerators is not source-breaking; in Itanium C ABI, it is + not ABI breaking either as long as the size of the enum does not change. + Therefore, C library vendors add enumerators without expecting downstream + breakage. + +* In C, it is common to use enums as bitfields: enumerators are assigned values + that are powers of two, and enum values are bitwise-or combinations of + enumerators. + +* Some C API vendors define two sets of enumerators: "public" enumerators that + are listed in the header file, and "private" enumerators that are used only in + the implementation of the library. + +Due to these coding patterns, at runtime, C enums can carry values that were not +listed in the enum declaration at compile time (either such values were added +after the code was compiled, or they are a result of an intentional cast from an +integer to an enum). + +Swift compiler performs exhaustiveness checks for switch statements, which +becomes problematic when performed on C enums, where expectations about +exhaustiveness are different. + +From Swift's point of view, C enums come in two flavors: closed AKA frozen, and +open AKA non-frozen. This distinction is aimed at supporting library evolution +and ABI stability, while allowing the user to ergonomically work with their +code. Swift's solution also supports the unusual C enum coding patterns. + +Frozen enums have a fixed set of cases (enumerators in C terms). A library +vendor can change (add or remove) cases in a frozen enum, however, it will be +both ABI-breaking and source-breaking. In other words, there is a guarantee that +the set of enum cases that was seen at compile time exactly matches the set of +values that an enum variable can carry at runtime. Swift performs an +exhaustiveness check for switch statements on frozen enums: if switch does not +handle all enum cases, the user gets a warning. Moreover, the optimizer can make +an assumption that a variable that has a frozen enum type will only store values +that correspond to enum cases visible at compile time; unused bit patterns can +be reused for other purposes. + +Non-frozen enums have an extensible set of cases. A library vendor can add cases +without breaking ABI or source compatibility. Swift performs a different flavor +of exhaustiveness check for switch statements on non-frozen enums: it always +requires an `@unknown default` clause, but only produces a warning if the code +does not handle all cases available at the compilation time. + +```c +// C header. + +// An open enum: we expect to add more kinds of input devices in future. +enum InputDevice { + Keyboard, + Mouse, + Touchscreen, +} __attribute__((enum_extensibility(open))); + +// A closed enum: we think we know enough about the geometry of Earth to +// confidently say that these are all cardinal directions we will ever need. +enum CardinalDirection { + East, + West, + North, + South, +} __attribute__((enum_extensibility(closed))); +``` + +```swift +// C header imported in Swift. + +enum InputDevice: CUnsignedInt, Hashable, RawRepresentable { + init?(rawValue: CUnsignedInt) + var rawValue: CUnsignedInt { get } + typealias RawValue = CUnsignedInt + case Keyboard + case Mouse + case Touchscreen +} + +@frozen +enum CardinalDirection: CUnsignedInt, Hashable, RawRepresentable { + init?(rawValue: CUnsignedInt) + var rawValue: CUnsignedInt { get } + typealias RawValue = CUnsignedInt + case East + case West + case North + case South +} +``` + +C enums that are not marked as open or closed are mapped to structs since Swift +1.0. At that time, we realized that mapping C enums to Swift enums is not +correct if the Swift compiler makes Swift-like assumptions about such imported +enums. Specifically, Swift compiler assumes that the only allowed bit patterns +of an enum value are declared in enum's cases. This assumption is valid for +frozen Swift enums (which were the only flavor of enums in Swift 1.0). However, +this assumption does not hold for C enums, for which any bit pattern is a valid +value; this assumption was creating an undefined behavior hazard. To resolve +this issue in Swift 1.0, C enums were imported as Swift structs by default, and +their enumerators were exposed as global computed variables. Objective-C enums +declared with `NS_ENUM` were assumed to have "enum nature" and were imported as +Swift enums. + +The concept of open enums was added in Swift 5 ([SE-0192 Handling Future +Enum +Cases](https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md)), +but that proposal did not change the importing strategy of non-annotated C +enums, in part because of source compatibility concerns. It might be still +possible to change C enums to be imported as open Swift enums, but as the time +passes, it will be more difficult to change. + +Another feature of C enums is that they expose integer values to the user; +furthermore, enum values are implicitly convertible to integers. Swift enums are +opaque by default. When imported in Swift, C enums conform to the +`RawRepresentable` protocol, allowing the user to explicitly convert between +numeric and typed values. + +```swift +// Converting enum values to integers and back. + +var south: CardinalDirection = .South +// var southAsInteger: CUnsignedInt = south // error: type mismatch +var southAsInteger: CUnsignedInt = south.rawValue // = 3 +var southAsEnum = CardinalDirection(rawValue: 3) // = .South +``` + +## Typedefs + +C typedefs are generally mapped to Swift typealiases, except for a few common C +coding patterns that are handled in a special way. + +```c +// C header. + +// An ordinary typedef. +typedef int Money; + +// A special case pattern that is mapped to a named struct. +typedef struct { + int x; + int y; +} Point; +``` + +```swift +// C header imported in Swift. + +typealias Money = Int + +struct Point { + var x: CInt { get set } + var y: CInt { get set } + init() + init(x: CInt, y: CInt) +} +``` + +## Macros + +C macros are generally not imported in Swift. Macros that define constants are +imported as readonly variables. + +```c +// C header. + +#define BUFFER_SIZE 4096 +#define SERVER_VERSION "3.14" +``` + +```swift +// C header imported in Swift. + +var BUFFER_SIZE: CInt { get } +var SERVER_VERSION: String { get } +``` + +See also Apple's documentation about this topic: [Using Imported C Macros in +Swift](https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_c_macros_in_swift). diff --git a/docs/SIL.rst b/docs/SIL.rst index 4358e2ec12f3a..29387e8819c51 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -1316,6 +1316,66 @@ variable cannot be used as l-value, i.e. the reference to the object cannot be modified. As a consequence the variable cannot be accessed with ``global_addr`` but only with ``global_value``. +Differentiability Witnesses +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:: + + decl ::= sil-differentiability-witness + sil-differentiability-witness ::= + 'sil_differentiability_witness' + sil-linkage? + '[' 'parameters' sil-differentiability-witness-function-index-list ']' + '[' 'results' sil-differentiability-witness-function-index-list ']' + generic-parameter-clause? + sil-function-name ':' sil-type + sil-differentiability-witness-body? + + sil-differentiability-witness-body ::= + '{' sil-differentiability-witness-entry? + sil-differentiability-witness-entry? '}' + + sil-differentiability-witness-entry ::= + sil-differentiability-witness-entry-kind ':' + sil-entry-name ':' sil-type + + sil-differentiability-witness-entry-kind ::= 'jvp' | 'vjp' + +SIL encodes function differentiability via differentiability witnesses. + +Differentiability witnesses map a "key" (including an "original" SIL function) +to derivative SIL functions. + +Differentiability witnesses are keyed by the following: + +- An "original" SIL function name. +- Differentiability parameter indices. +- Differentiability result indices. +- A generic parameter clause, representing differentiability generic + requirements. + +Differentiability witnesses may have a body, specifying derivative functions for +the key. Verification checks that derivative functions have the expected type +based on the key. + +:: + + sil_differentiability_witness hidden [parameters 0] [results 0] @id : $@convention(thin) (T) -> T { + jvp: @id_jvp : $@convention(thin) (T) -> (T, @owned @callee_guaranteed (T.TangentVector) -> T.TangentVector) + vjp: @id_vjp : $@convention(thin) (T) -> (T, @owned @callee_guaranteed (T.TangentVector) -> T.TangentVector) + } + +During SILGen, differentiability witnesses are emitted for the following: + +- `@differentiable` declaration attributes. +- `@derivative` declaration attributes. Registered derivative functions + become differentiability witness entries. + +The SIL differentiation transform canonicalizes differentiability witnesses, +filling in missing entries. + +Differentiability witness entries are accessed via the +`differentiability_witness_function` instruction. + Dataflow Errors --------------- @@ -3495,46 +3555,8 @@ partial_apply // %r will be of the substituted thick function type $(Z'...) -> R' Creates a closure by partially applying the function ``%0`` to a partial -sequence of its arguments. In the instruction syntax, the type of the callee is -specified after the argument list; the types of the argument and of the defined -value are derived from the function type of the callee. If the ``partial_apply`` -has an escaping function type (not ``[on_stack]``) the closure context will be -allocated with retain count 1 and initialized to contain the values ``%1``, -``%2``, etc. The closed-over values will not be retained; that must be done -separately before the ``partial_apply``. The closure does however take ownership -of the partially applied arguments (except for ``@inout_aliasable`` parameters); -when the closure reference count reaches zero, the contained values will be -destroyed. If the ``partial_apply`` has a ``@noescape`` function type -(``partial_apply [on_stack]``) the closure context is allocated on the stack and -initialized to contain the closed-over values. The closed-over values are not -retained, lifetime of the closed-over values must be managed separately. The -lifetime of the stack context of a ``partial_apply [on_stack]`` must be -terminated with a ``dealloc_stack``. - -If the callee is generic, all of its generic parameters must be bound by the -given substitution list. The arguments are given with these generic -substitutions applied, and the resulting closure is of concrete function -type with the given substitutions applied. The generic parameters themselves -cannot be partially applied; all of them must be bound. The result is always -a concrete function. - -If an address argument has ``@inout_aliasable`` convention, the closure -obtained from ``partial_apply`` will not own its underlying value. -The ``@inout_aliasable`` parameter convention is used when a ``@noescape`` -closure captures an ``inout`` argument. - -TODO: The instruction, when applied to a generic function, -currently implicitly performs abstraction difference transformations enabled -by the given substitutions, such as promoting address-only arguments and returns -to register arguments. This should be fixed. - -By default, ``partial_apply`` creates a closure whose invocation takes ownership -of the context, meaning that a call implicitly releases the closure. The -``[callee_guaranteed]`` change this to a caller-guaranteed model, where the -caller promises not to release the closure while the function is being called. - -This instruction is used to implement both curry thunks and closures. A -curried function in Swift:: +sequence of its arguments. This instruction is used to implement both curry +thunks and closures. A curried function in Swift:: func foo(_ a:A)(b:B)(c:C)(d:D) -> E { /* body of foo */ } @@ -3607,6 +3629,54 @@ lowers to an uncurried entry point and is curried in the enclosing function:: return %ret : $Int } +**Ownership Semantics of Closure Context during Invocation**: By default, an +escaping ``partial_apply`` (``partial_apply`` without ``[on_stack]]`` creates a +closure whose invocation takes ownership of the context, meaning that a call +implicitly releases the closure. If the ``partial_apply`` is marked with the +flag ``[callee_guaranteed]`` the invocation instead uses a caller-guaranteed +model, where the caller promises not to release the closure while the function +is being called. + +**Captured Value Ownership Semantics**: In the instruction syntax, the type of +the callee is specified after the argument list; the types of the argument and +of the defined value are derived from the function type of the callee. Even so, +the ownership requirements of the partial apply are not the same as that of the +callee function (and thus said signature). Instead: + +1. If the ``partial_apply`` has a ``@noescape`` function type (``partial_apply + [on_stack]``) the closure context is allocated on the stack and is + initialized to contain the closed-over values without taking ownership of + those values. The closed-over values are not retained and the lifetime of the + closed-over values must be managed by other instruction independently of the + ``partial_apply``. The lifetime of the stack context of a ``partial_apply + [on_stack]`` must be terminated with a ``dealloc_stack``. + +2. If the ``partial_apply`` has an escaping function type (not ``[on_stack]``) + then the closure context will be heap allocated with a retain count of 1. Any + closed over parameters (except for ``@inout`` parameters) will be consumed by + the partial_apply. This ensures that no matter when the ``partial_apply`` is + called, the captured arguments are alive. When the closure context's + reference count reaches zero, the contained values are destroyed. If the + callee requires an owned parameter, then the implicit partial_apply forwarder + created by IRGen will copy the underlying argument and pass it to the callee. + +3. If an address argument has ``@inout_aliasable`` convention, the closure + obtained from ``partial_apply`` will not own its underlying value. The + ``@inout_aliasable`` parameter convention is used when a ``@noescape`` + closure captures an ``inout`` argument. + +**NOTE:** If the callee is generic, all of its generic parameters must be bound +by the given substitution list. The arguments are given with these generic +substitutions applied, and the resulting closure is of concrete function type +with the given substitutions applied. The generic parameters themselves cannot +be partially applied; all of them must be bound. The result is always a concrete +function. + +**TODO:** The instruction, when applied to a generic function, currently +implicitly performs abstraction difference transformations enabled by the given +substitutions, such as promoting address-only arguments and returns to register +arguments. This should be fixed. + builtin ``````` :: diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index be98a06362e3c..126dfb5c587c6 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 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 @@ -538,6 +538,9 @@ class ASTContext final { ConcreteDeclRef getBuiltinInitDecl(NominalTypeDecl *decl, KnownProtocolKind builtinProtocol, llvm::function_ref initName) const; + + /// Retrieve the declaration of Swift.<(Int, Int) -> Bool. + FuncDecl *getLessThanIntDecl() const; /// Retrieve the declaration of Swift.==(Int, Int) -> Bool. FuncDecl *getEqualIntDecl() const; @@ -595,6 +598,10 @@ class ASTContext final { const FunctionType::ExtInfo incompleteExtInfo, FunctionTypeRepresentation trueRep); + /// Get the Swift declaration that a Clang declaration was exported from, + /// if applicable. + const Decl *getSwiftDeclForExportedClangDecl(const clang::Decl *decl); + /// Determine whether the given Swift type is representable in a /// given foreign language. ForeignRepresentationInfo @@ -631,6 +638,10 @@ class ASTContext final { /// compiler for the target platform. AvailabilityContext getSwift52Availability(); + /// Get the runtime availability of features introduced in the Swift 5.3 + /// compiler for the target platform. + AvailabilityContext getSwift53Availability(); + /// Get the runtime availability of features that have been introduced in the /// Swift compiler for future versions of the target platform. AvailabilityContext getSwiftFutureAvailability(); diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index f716daef40faf..95579605f2928 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -153,7 +153,15 @@ class ASTMangler : public Mangler { Type FromType, Type ToType, Type SelfType, ModuleDecl *Module); - + + /// Mangle a SIL differentiability witness key: + /// - Mangled original function name. + /// - Parameter indices. + /// - Result indices. + /// - Derivative generic signature (optional). + std::string + mangleSILDifferentiabilityWitnessKey(SILDifferentiabilityWitnessKey key); + std::string mangleKeyPathGetterThunkHelper(const AbstractStorageDecl *property, GenericSignature signature, CanType baseType, diff --git a/include/swift/AST/ASTWalker.h b/include/swift/AST/ASTWalker.h index 19dc8889278e7..fc7210c76ddd4 100644 --- a/include/swift/AST/ASTWalker.h +++ b/include/swift/AST/ASTWalker.h @@ -20,6 +20,7 @@ namespace swift { class Decl; class Expr; +class ClosureExpr; class ModuleDecl; class Stmt; class Pattern; @@ -219,7 +220,13 @@ class ASTWalker { /// For work that is performed for every top-level expression, this should /// be overridden to return false, to avoid duplicating work or visiting /// bodies of closures that have not yet been type checked. - virtual bool shouldWalkIntoNonSingleExpressionClosure() { return true; } + virtual bool shouldWalkIntoNonSingleExpressionClosure(ClosureExpr *) { + return true; + } + + /// This method configures whether the walker should visit the body of a + /// TapExpr. + virtual bool shouldWalkIntoTapExpression() { return true; } /// This method configures whether the walker should exhibit the legacy /// behavior where accessors appear as peers of their storage, rather diff --git a/include/swift/AST/AutoDiff.h b/include/swift/AST/AutoDiff.h index f3c74e9b1d632..80c0a19213e3c 100644 --- a/include/swift/AST/AutoDiff.h +++ b/include/swift/AST/AutoDiff.h @@ -29,6 +29,7 @@ namespace swift { class AnyFunctionType; +class SILFunctionType; class TupleType; /// A function type differentiability kind. @@ -222,6 +223,11 @@ class TangentSpace { NominalTypeDecl *getNominal() const; }; +/// The key type used for uniquing `SILDifferentiabilityWitness` in +/// `SILModule`: original function name, parameter indices, result indices, and +/// derivative generic signature. +using SILDifferentiabilityWitnessKey = std::pair; + /// Automatic differentiation utility namespace. namespace autodiff { @@ -231,6 +237,18 @@ void getSubsetParameterTypes(IndexSubset *indices, AnyFunctionType *type, SmallVectorImpl &results, bool reverseCurryLevels = false); +/// "Constrained" derivative generic signatures require all differentiability +/// parameters to conform to the `Differentiable` protocol. +/// +/// Returns the "constrained" derivative generic signature given: +/// - An original SIL function type. +/// - Differentiability parameter indices. +/// - A possibly "unconstrained" derivative generic signature. +GenericSignature +getConstrainedDerivativeGenericSignature(SILFunctionType *originalFnTy, + IndexSubset *diffParamIndices, + GenericSignature derivativeGenSig); + } // end namespace autodiff } // end namespace swift diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index 4b5cd1888a30a..6925fd42d7703 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -444,6 +444,31 @@ BUILTIN_SIL_OPERATION(AllocWithTailElems, "allocWithTailElems", Special) /// Projects the first tail-allocated element of type E from a class C. BUILTIN_SIL_OPERATION(ProjectTailElems, "projectTailElems", Special) +/// Unsafely convert a value of type T to an unowned value. +/// +/// It has type (T, @inout @unowned(unsafe) T) -> (). The reason for the weird +/// signature is to work around issues with results in SILGen builtin emission. +BUILTIN_SIL_OPERATION(ConvertStrongToUnownedUnsafe, "convertStrongToUnownedUnsafe", Special) + +/// Unsafely convert a value of type @inout @unowned(unsafe) T to a loaded +/// guaranteed T value that has a lifetime guaranteed by the passed in base +/// value of type BaseTy. +/// +/// It has type (@in_guaranteed BaseTy, @in_guaranteed @unowned (unsafe) T) -> @guaranteed T. +/// +/// NOTE: Saying the result is a guaranteed T is a bit of a misnomer. We aren't +/// emitting a builtin call, but are just emitting SIL directly. +/// +/// NOTE: Even though the signature is as mentioned above, we actually tell the +/// AST we have the signature: +/// +/// (BaseT, T) -> U +/// +/// We then perform the actual type checking in SILGen and assert on +/// failure. This is an early, unsupported feature so this is sufficient for +/// now. +BUILTIN_SIL_OPERATION(ConvertUnownedUnsafeToGuaranteed, "convertUnownedUnsafeToGuaranteed", Special) + #undef BUILTIN_SIL_OPERATION // BUILTIN_RUNTIME_CALL - A call into a runtime function. @@ -634,6 +659,12 @@ BUILTIN_MISC_OPERATION(PoundAssert, "poundAssert", "", Special) // BUILTIN_MISC_OPERATION_WITH_SILGEN - Miscellaneous operations that are // specially emitted during SIL generation. +// +// The intention is that this is meant for builtins that need a named +// builtin representation so one can create a builtin instruction in +// SIL, but that also need special SILGen behavior. If an operation +// just emits custom SIL and does not need to be able to form a +// builtin instruction, please use BUILTIN_SIL_OPERATION. #ifndef BUILTIN_MISC_OPERATION_WITH_SILGEN #define BUILTIN_MISC_OPERATION_WITH_SILGEN(Id, Name, Attrs, Overload) \ BUILTIN_MISC_OPERATION(Id, Name, Attrs, Overload) diff --git a/include/swift/AST/ClangModuleLoader.h b/include/swift/AST/ClangModuleLoader.h index 0e3d109226fd0..595c55b420c33 100644 --- a/include/swift/AST/ClangModuleLoader.h +++ b/include/swift/AST/ClangModuleLoader.h @@ -14,10 +14,12 @@ #define SWIFT_AST_CLANG_MODULE_LOADER_H #include "swift/AST/ModuleLoader.h" +#include "swift/Basic/TaggedUnion.h" namespace clang { class ASTContext; class CompilerInstance; +class Decl; class Preprocessor; class Sema; class TargetInfo; @@ -26,6 +28,7 @@ class Type; namespace swift { +class Decl; class DeclContext; class VisibleDeclConsumer; @@ -40,6 +43,69 @@ enum class ClangTypeKind { ObjCProtocol, }; +/// A path for serializing a declaration. +class StableSerializationPath { +public: + struct ExternalPath { + enum ComponentKind { + /// A named record type (but not a template specialization) + Record, + + /// A named enum type + Enum, + + /// A C++ namespace + Namespace, + + /// A typedef + Typedef, + + /// A typedef's anonymous tag declaration. Identifier is empty. + TypedefAnonDecl, + + /// An Objective-C interface. + ObjCInterface, + + /// An Objective-C protocol. + ObjCProtocol, + }; + + static bool requiresIdentifier(ComponentKind kind) { + return kind != TypedefAnonDecl; + } + + SmallVector, 2> Path; + + void add(ComponentKind kind, Identifier name) { + Path.push_back({kind, name}); + } + }; +private: + TaggedUnion Union; + +public: + StableSerializationPath() {} + StableSerializationPath(const Decl *d) : Union(d) {} + StableSerializationPath(ExternalPath ext) : Union(ext) {} + + explicit operator bool() const { return !Union.empty(); } + + bool isSwiftDecl() const { return Union.isa(); } + const Decl *getSwiftDecl() const { + assert(isSwiftDecl()); + return Union.get(); + } + + bool isExternalPath() const { return Union.isa(); } + const ExternalPath &getExternalPath() const { + assert(isExternalPath()); + return Union.get(); + } + + SWIFT_DEBUG_DUMP; + void dump(raw_ostream &os) const; +}; + class ClangModuleLoader : public ModuleLoader { private: virtual void anchor(); @@ -111,6 +177,41 @@ class ClangModuleLoader : public ModuleLoader { /// Print the Clang type. virtual void printClangType(const clang::Type *type, llvm::raw_ostream &os) const = 0; + + /// Try to find a stable serialization path for the given declaration, + /// if there is one. + virtual StableSerializationPath + findStableSerializationPath(const clang::Decl *decl) const = 0; + + /// Try to resolve a stable serialization path down to the original + /// declaration. + virtual const clang::Decl * + resolveStableSerializationPath(const StableSerializationPath &path) const = 0; + + /// Determine whether the given type is serializable. + /// + /// If \c checkCanonical is true, checks the canonical type, + /// not the given possibly-sugared type. In general: + /// - non-canonical representations should be preserving the + /// sugared type even if it isn't serializable, since that + /// maintains greater source fidelity; + /// - semantic checks need to be checking the serializability + /// of the canonical type, since it's always potentially + /// necessary to serialize that (e.g. in SIL); and + /// - serializers can try to serialize the sugared type to + /// maintain source fidelity and just fall back on the canonical + /// type if that's not possible. + /// + /// The expectation here is that this predicate is meaningful + /// independent of the actual form of serialization: the types + /// that we can't reliably binary-serialize without an absolute + /// Clang AST cross-reference are the same types that won't + /// reliably round-trip through a textual format. At the very + /// least, it's probably best to use conservative predicates + /// that work both ways so that language behavior doesn't differ + /// based on subtleties like the target module interface format. + virtual bool isSerializable(const clang::Type *type, + bool checkCanonical) const = 0; }; } // namespace swift diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 789de8f2df163..435710c1a8582 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -335,7 +335,7 @@ class alignas(1 << DeclAlignInBits) Decl { IsStatic : 1 ); - SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 1+1+1+1+1+1+1, + SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 1+1+1+1+1+1+1+1, /// Encodes whether this is a 'let' binding. Introducer : 1, @@ -358,7 +358,10 @@ class alignas(1 << DeclAlignInBits) Decl { IsLazyStorageProperty : 1, /// Whether this is the backing storage for a property wrapper. - IsPropertyWrapperBackingProperty : 1 + IsPropertyWrapperBackingProperty : 1, + + /// Whether this is a lazily top-level global variable from the main file. + IsTopLevelGlobal : 1 ); SWIFT_INLINE_BITFIELD(ParamDecl, VarDecl, 1+2+NumDefaultArgumentKindBits, @@ -2329,17 +2332,17 @@ class PoundDiagnosticDecl : public Decl { Bits.PoundDiagnosticDecl.HasBeenEmitted = false; } - DiagnosticKind getKind() { + DiagnosticKind getKind() const { return isError() ? DiagnosticKind::Error : DiagnosticKind::Warning; } - StringLiteralExpr *getMessage() { return Message; } + StringLiteralExpr *getMessage() const { return Message; } - bool isError() { + bool isError() const { return Bits.PoundDiagnosticDecl.IsError; } - bool hasBeenEmitted() { + bool hasBeenEmitted() const { return Bits.PoundDiagnosticDecl.HasBeenEmitted; } @@ -5084,6 +5087,10 @@ class VarDecl : public AbstractStorageDecl { Bits.VarDecl.IsLazyStorageProperty = IsLazyStorage; } + /// True if this is a top-level global variable from the main source file. + bool isTopLevelGlobal() const { return Bits.VarDecl.IsTopLevelGlobal; } + void setTopLevelGlobal(bool b) { Bits.VarDecl.IsTopLevelGlobal = b; } + /// Retrieve the custom attributes that attach property wrappers to this /// property. The returned list contains all of the attached property wrapper attributes in source order, /// which means the outermost wrapper attribute is provided first. diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 1cbb3766c86ee..223bfc9394ff8 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -470,6 +470,8 @@ ERROR(expected_precedencegroup_relation,none, (StringRef)) // SIL +ERROR(expected_sil_keyword,none, + "expected SIL keyword", ()) ERROR(inout_not_attribute, none, "@inout is no longer an attribute", ()) ERROR(only_allowed_in_sil,none, @@ -678,6 +680,18 @@ ERROR(sil_witness_assoc_conf_not_found,none, ERROR(sil_witness_protocol_conformance_not_found,none, "sil protocol conformance not found", ()) +// SIL differentiability witnesses +ERROR(sil_diff_witness_expected_token,PointsToFirstBadToken, + "expected '%0' in differentiability witness", (StringRef)) +ERROR(sil_diff_witness_serialized_declaration,none, + "differentiability witness declaration should not be serialized", ()) +ERROR(sil_diff_witness_undefined,PointsToFirstBadToken, + "reference to undefined differentiability witness", ()) +ERROR(sil_diff_witness_invalid_generic_signature,PointsToFirstBadToken, + "expected witness generic signature '%0' does not have same generic " + "parameters as original function generic signature '%1'", + (StringRef, StringRef)) + // SIL Coverage Map ERROR(sil_coverage_invalid_hash, none, "expected coverage hash", ()) @@ -1577,6 +1591,20 @@ ERROR(diff_params_clause_expected_parameter_unnamed,PointsToFirstBadToken, ERROR(autodiff_attr_expected_original_decl_name,PointsToFirstBadToken, "expected an original function name", ()) +// SIL autodiff +ERROR(sil_autodiff_expected_lsquare,PointsToFirstBadToken, + "expected '[' to start the %0", (StringRef)) +ERROR(sil_autodiff_expected_rsquare,PointsToFirstBadToken, + "expected ']' to complete the %0", (StringRef)) +ERROR(sil_autodiff_expected_index_list,PointsToFirstBadToken, + "expected a space-separated list of indices, e.g. '0 1'", ()) +ERROR(sil_autodiff_expected_index_list_label,PointsToFirstBadToken, + "expected label '%0' in index list", (StringRef)) +ERROR(sil_autodiff_expected_parameter_index,PointsToFirstBadToken, + "expected the index of a parameter to differentiate with respect to", ()) +ERROR(sil_autodiff_expected_result_index,PointsToFirstBadToken, + "expected the index of a result to differentiate from", ()) + //------------------------------------------------------------------------------ // MARK: Generics parsing diagnostics //------------------------------------------------------------------------------ diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index fef7af3b04473..c42896b356477 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -338,6 +338,10 @@ ERROR(cannot_convert_initializer_value,none, "cannot convert value of type %0 to specified type %1", (Type,Type)) ERROR(cannot_convert_initializer_value_protocol,none, "value of type %0 does not conform to specified type %1", (Type,Type)) +ERROR(cannot_convert_initializer_value_anyobject,none, + "value of type %0 expected to be instance of class or " + "class-constrained type", + (Type, Type)) ERROR(cannot_convert_initializer_value_nil,none, "'nil' cannot initialize specified type %0", (Type)) @@ -346,6 +350,10 @@ ERROR(cannot_convert_to_return_type,none, (Type,Type)) ERROR(cannot_convert_to_return_type_protocol,none, "return expression of type %0 does not conform to %1", (Type,Type)) +ERROR(cannot_convert_return_type_to_anyobject,none, + "return expression of type %0 expected to be an instance of " + "a class or class-constrained type", + (Type, Type)) ERROR(cannot_convert_to_return_type_nil,none, "'nil' is incompatible with return type %0", (Type)) @@ -440,7 +448,10 @@ NOTE(candidate_performs_illegal_ephemeral_conv,none, ERROR(cannot_convert_argument_value_protocol,none, "argument type %0 does not conform to expected type %1", (Type, Type)) - +ERROR(cannot_convert_argument_value_anyobject,none, + "argument type %0 expected to be an instance of " + "a class or class-constrained type", + (Type, Type)) ERROR(cannot_convert_argument_value_nil,none, "'nil' is not compatible with expected argument type %0", (Type)) @@ -536,6 +547,10 @@ NOTE(assign_protocol_conformance_fix_it,none, ERROR(cannot_convert_assign_protocol,none, "value of type %0 does not conform to %1 in assignment", (Type, Type)) +ERROR(cannot_convert_assign_anyobject,none, + "value of type %0 expected to be an instance of " + "a class or class-constrained type in assignment", + (Type, Type)) ERROR(cannot_convert_assign_nil,none, "'nil' cannot be assigned to type %0", (Type)) @@ -1138,14 +1153,12 @@ NOTE(candidate_expected_different_labels,none, "incorrect labels for candidate (have: '%0', expected: '%1')", (StringRef, StringRef)) +ERROR(member_shadows_function,none, + "use of %0 refers to %1 rather than %2 %3", + (DeclNameRef, DescriptiveDeclKind, DescriptiveDeclKind, DeclName)) ERROR(member_shadows_global_function,none, - "use of %0 refers to %1 %2 rather than %3 %4 in %5 %6", - (DeclNameRef, DescriptiveDeclKind, DeclName, DescriptiveDeclKind, - DeclName, DescriptiveDeclKind, DeclName)) -ERROR(member_shadows_global_function_near_match,none, - "use of %0 nearly matches %3 %4 in %5 %6 rather than %1 %2", - (DeclNameRef, DescriptiveDeclKind, DeclName, DescriptiveDeclKind, - DeclName, DescriptiveDeclKind, DeclName)) + "use of %0 refers to %1 rather than %2 %3 in module %4", + (DeclNameRef, DescriptiveDeclKind, DescriptiveDeclKind, DeclName, DeclName)) ERROR(instance_member_use_on_type,none, "instance member %1 cannot be used on type %0; " @@ -2647,6 +2660,10 @@ ERROR(assoc_conformance_from_implementation_only_module,none, "cannot use conformance of %0 to %1 in associated type %3 (inferred as " "%4); %2 has been imported as implementation-only", (Type, DeclName, Identifier, Type, Type)) +ERROR(unexportable_clang_function_type,none, + "cannot export the underlying C type of the function type %0; " + "it may use anonymous types or types defined outside of a module", + (Type)) WARNING(warn_implementation_only_conflict,none, "%0 inconsistently imported as implementation-only", @@ -2680,6 +2697,8 @@ ERROR(broken_case_iterable_requirement,none, "CaseIterable protocol is broken: unexpected requirement", ()) ERROR(broken_raw_representable_requirement,none, "RawRepresentable protocol is broken: unexpected requirement", ()) +ERROR(broken_comparable_requirement,none, + "Comparable protocol is broken: unexpected requirement", ()) ERROR(broken_equatable_requirement,none, "Equatable protocol is broken: unexpected requirement", ()) ERROR(broken_hashable_requirement,none, @@ -2692,6 +2711,8 @@ ERROR(broken_int_hashable_conformance,none, "Int type is broken: does not conform to Hashable", ()) ERROR(broken_int_integer_literal_convertible_conformance,none, "Int type is broken: does not conform to ExpressibleByIntegerLiteral", ()) +ERROR(no_less_than_overload_for_int,none, + "no overload of '<' for Int", ()) ERROR(no_equal_overload_for_int,none, "no overload of '==' for Int", ()) ERROR(broken_coding_key_requirement,none, @@ -3162,7 +3183,10 @@ NOTE(note_explicitly_compare_cftypeid,none, ERROR(optional_used_as_boolean,none, "optional type %0 cannot be used as a boolean; " - "test for '!= nil' instead", (Type)) + "test for '%select{!|=}1= nil' instead", (Type, bool)) +ERROR(integer_used_as_boolean,none, + "type %0 cannot be used as a boolean; " + "test for '%select{!|=}1= 0' instead", (Type, bool)) ERROR(interpolation_missing_proto,none, "string interpolation requires the protocol 'ExpressibleByStringInterpolation' to be defined", @@ -3177,6 +3201,9 @@ ERROR(object_literal_broken_proto,none, ERROR(discard_expr_outside_of_assignment,none, "'_' can only appear in a pattern or on the left side of an assignment", ()) +WARNING(discard_expr_void_result_redundant, none, + "using '_' to ignore the result of a Void-returning function " + "is redundant", ()) ERROR(collection_literal_heterogeneous,none, "heterogeneous collection literal could only be inferred to %0; add" " explicit type annotation if this is intentional", (Type)) diff --git a/include/swift/AST/FineGrainedDependencies.h b/include/swift/AST/FineGrainedDependencies.h index 50cba234d0e46..5f3424a189e84 100644 --- a/include/swift/AST/FineGrainedDependencies.h +++ b/include/swift/AST/FineGrainedDependencies.h @@ -721,7 +721,8 @@ class SourceFileDepGraphNode : public DepGraphNode { } std::string humanReadableName() const { - return DepGraphNode::humanReadableName("here"); + return DepGraphNode::humanReadableName(getIsProvides() ? "here" + : "somewhere else"); } bool verify() const { @@ -799,6 +800,7 @@ class SourceFileDepGraph { compoundNamesByRDK); static constexpr char noncascadingOrPrivatePrefix = '#'; + static constexpr char nameFingerprintSeparator = ','; static std::string noncascading(std::string name); @@ -882,6 +884,8 @@ class SourceFileDepGraph { bool verifySequenceNumber() const; + void emitDotFile(StringRef outputPath, DiagnosticEngine &diags); + private: void addNode(SourceFileDepGraphNode *n) { n->setSequenceNumber(allNodes.size()); diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 699385ad271d1..d28d7386473d6 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -262,7 +262,7 @@ class IRGenOptions { EnableAnonymousContextMangledNames(false), ForcePublicLinkage(false), LazyInitializeClassMetadata(false), LazyInitializeProtocolConformances(false), DisableLegacyTypeInfo(false), - PrespecializeGenericMetadata(false), UseIncrementalLLVMCodeGen(true), + PrespecializeGenericMetadata(true), UseIncrementalLLVMCodeGen(true), UseSwiftCall(false), GenerateProfile(false), EnableDynamicReplacementChaining(false), DisableRoundTripDebugTypes(false), DisableDebuggerShadowCopies(false), diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index fe8511ad4756f..0cbb400aa60f2 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -142,7 +142,10 @@ IDENTIFIER_WITH_NAME(NativeClassLayout, "_NativeClass") // Operators IDENTIFIER_WITH_NAME(MatchOperator, "~=") +IDENTIFIER_WITH_NAME(LessThanOperator, "<") IDENTIFIER_WITH_NAME(EqualsOperator, "==") +IDENTIFIER_WITH_NAME(NegationOperator, "!") +IDENTIFIER_WITH_NAME(derived_enum_less_than, "__derived_enum_less_than") IDENTIFIER_WITH_NAME(derived_enum_equals, "__derived_enum_equals") IDENTIFIER_WITH_NAME(derived_struct_equals, "__derived_struct_equals") diff --git a/include/swift/AST/KnownProtocols.def b/include/swift/AST/KnownProtocols.def index 42c55f634cdf3..363344f1c95b9 100644 --- a/include/swift/AST/KnownProtocols.def +++ b/include/swift/AST/KnownProtocols.def @@ -69,6 +69,7 @@ PROTOCOL_(ErrorCodeProtocol) PROTOCOL(OptionSet) PROTOCOL(CaseIterable) PROTOCOL(SIMDScalar) +PROTOCOL(BinaryInteger) PROTOCOL_(BridgedNSError) PROTOCOL_(BridgedStoredNSError) diff --git a/include/swift/AST/PrettyStackTrace.h b/include/swift/AST/PrettyStackTrace.h index b18b8c7a3fa41..350526d26e3e6 100644 --- a/include/swift/AST/PrettyStackTrace.h +++ b/include/swift/AST/PrettyStackTrace.h @@ -24,6 +24,10 @@ #include "swift/AST/Identifier.h" #include "swift/AST/Type.h" +namespace clang { + class Type; +} + namespace swift { class ASTContext; class Decl; @@ -132,6 +136,17 @@ class PrettyStackTraceType : public llvm::PrettyStackTraceEntry { virtual void print(llvm::raw_ostream &OS) const; }; +/// PrettyStackTraceClangType - Observe that we are processing a +/// specific Clang type. +class PrettyStackTraceClangType : public llvm::PrettyStackTraceEntry { + const clang::Type *TheType; + const char *Action; +public: + PrettyStackTraceClangType(const char *action, const clang::Type *type) + : TheType(type), Action(action) {} + virtual void print(llvm::raw_ostream &OS) const; +}; + /// Observe that we are processing a specific type representation. class PrettyStackTraceTypeRepr : public llvm::PrettyStackTraceEntry { ASTContext &Context; @@ -187,6 +202,24 @@ class PrettyStackTraceSelector : public llvm::PrettyStackTraceEntry { void print(llvm::raw_ostream &OS) const override; }; +/// PrettyStackTraceDifferentiabilityWitness - Observe that we are processing a +/// specific differentiability witness. +class PrettyStackTraceDifferentiabilityWitness + : public llvm::PrettyStackTraceEntry { + const SILDifferentiabilityWitnessKey Key; + const char *Action; + +public: + PrettyStackTraceDifferentiabilityWitness( + const char *action, const SILDifferentiabilityWitnessKey key) + : Key(key), Action(action) {} + virtual void print(llvm::raw_ostream &OS) const; +}; + +void printDifferentiabilityWitnessDescription( + llvm::raw_ostream &out, const SILDifferentiabilityWitnessKey key, + bool addNewline = true); + } // end namespace swift #endif diff --git a/include/swift/AST/SILGenRequests.h b/include/swift/AST/SILGenRequests.h index 3567673172577..339c448c6479b 100644 --- a/include/swift/AST/SILGenRequests.h +++ b/include/swift/AST/SILGenRequests.h @@ -74,8 +74,12 @@ struct SILGenDescriptor { } }; -class GenerateSILRequest : - public SimpleRequest(SILGenDescriptor), CacheKind::Uncached> { public: @@ -92,9 +96,23 @@ class GenerateSILRequest : bool isCached() const { return true; } }; -void simple_display(llvm::raw_ostream &out, const SILGenDescriptor &d); +class SILGenWholeModuleRequest : + public SimpleRequest(SILGenDescriptor), + CacheKind::Uncached> { +public: + using SimpleRequest::SimpleRequest; -SourceLoc extractNearestSourceLoc(const SILGenDescriptor &desc); +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected> + evaluate(Evaluator &evaluator, SILGenDescriptor desc) const; + +public: + bool isCached() const { return true; } +}; /// The zone number for SILGen. #define SWIFT_TYPEID_ZONE SILGen diff --git a/include/swift/AST/SILGenTypeIDZone.def b/include/swift/AST/SILGenTypeIDZone.def index b80a7e49664e7..f1cc214b6977a 100644 --- a/include/swift/AST/SILGenTypeIDZone.def +++ b/include/swift/AST/SILGenTypeIDZone.def @@ -14,6 +14,9 @@ // //===----------------------------------------------------------------------===// -SWIFT_REQUEST(SILGen, GenerateSILRequest, +SWIFT_REQUEST(SILGen, SILGenSourceFileRequest, + std::unique_ptr(SILGenDescriptor), + Uncached, NoLocationInfo) +SWIFT_REQUEST(SILGen, SILGenWholeModuleRequest, std::unique_ptr(SILGenDescriptor), Uncached, NoLocationInfo) diff --git a/include/swift/AST/SemanticAttrs.def b/include/swift/AST/SemanticAttrs.def index e810eb99c94e4..28be95549153b 100644 --- a/include/swift/AST/SemanticAttrs.def +++ b/include/swift/AST/SemanticAttrs.def @@ -60,6 +60,8 @@ SEMANTICS_ATTR(ARRAY_COUNT, "array.count") SEMANTICS_ATTR(ARRAY_DEALLOC_UNINITIALIZED, "array.dealloc_uninitialized") SEMANTICS_ATTR(ARRAY_UNINITIALIZED_INTRINSIC, "array.uninitialized_intrinsic") +SEMANTICS_ATTR(SEQUENCE_FOR_EACH, "sequence.forEach") + SEMANTICS_ATTR(OPTIMIZE_SIL_SPECIALIZE_GENERIC_NEVER, "optimize.sil.specialize.generic.never") SEMANTICS_ATTR(OPTIMIZE_SIL_SPECIALIZE_GENERIC_PARTIAL_NEVER, "optimize.sil.specialize.generic.partial.never") diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 4e0dc5e21bf63..125138553fe8d 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1959,8 +1959,7 @@ class DynamicallyReplacedDeclRequest class TypeCheckSourceFileRequest : public SimpleRequest { + bool (SourceFile *), CacheKind::SeparatelyCached> { public: using SimpleRequest::SimpleRequest; @@ -1968,8 +1967,7 @@ class TypeCheckSourceFileRequest : friend SimpleRequest; // Evaluation. - llvm::Expected evaluate(Evaluator &evaluator, - SourceFile *SF, unsigned StartElem) const; + llvm::Expected evaluate(Evaluator &evaluator, SourceFile *SF) const; public: // Separate caching. diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index ca3ceb160b567..e897a4397aef2 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -211,7 +211,7 @@ SWIFT_REQUEST(TypeChecker, HasDefaultInitRequest, SWIFT_REQUEST(TypeChecker, SynthesizeDefaultInitRequest, ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, TypeCheckSourceFileRequest, - bool(SouceFile *, unsigned), SeparatelyCached, NoLocationInfo) + bool(SouceFile *), SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, TypeWitnessRequest, TypeWitnessAndDecl(NormalProtocolConformance *, AssociatedTypeDecl *), diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 2d64b050c2f7b..cdbc1019f3e05 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -2853,6 +2853,10 @@ class AnyFunctionType : public TypeBase { Param getWithoutLabel() const { return Param(Ty, Identifier(), Flags); } Param withType(Type newType) const { return Param(newType, Label, Flags); } + + Param withFlags(ParameterTypeFlags flags) const { + return Param(Ty, Label, flags); + } }; class CanParam : public Param { @@ -3083,6 +3087,14 @@ class AnyFunctionType : public TypeBase { ExtInfo withClangFunctionType(const clang::Type *type) const { return ExtInfo(Bits, Uncommon(type)); } + LLVM_NODISCARD + ExtInfo + withDifferentiabilityKind(DifferentiabilityKind differentiability) const { + return ExtInfo( + (Bits & ~DifferentiabilityMask) | + ((unsigned)differentiability << DifferentiabilityMaskOffset), + Other); + } std::pair getFuncAttrKey() const { return std::make_pair(Bits, Other.ClangFunctionType); @@ -3742,7 +3754,7 @@ class SILParameterInfo { /// Return a version of this parameter info with the type replaced. SILParameterInfo getWithInterfaceType(CanType type) const { - return SILParameterInfo(type, getConvention()); + return SILParameterInfo(type, getConvention(), getDifferentiability()); } /// Transform this SILParameterInfo by applying the user-provided @@ -4431,6 +4443,22 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode, const clang::FunctionType *getClangFunctionType() const; + /// Given that `this` is a `@differentiable` or `@differentiable(linear)` + /// function type, returns an `IndexSubset` corresponding to the + /// differentiability/linearity parameters (e.g. all parameters except the + /// `@noDerivative` ones). + IndexSubset *getDifferentiabilityParameterIndices(); + + /// Returns the `@differentiable` or `@differentiable(linear)` function type + /// for the given differentiability kind and parameter indices representing + /// differentiability/linearity parameters. + CanSILFunctionType getWithDifferentiability(DifferentiabilityKind kind, + IndexSubset *parameterIndices); + + /// Returns the SIL function type stripping differentiability kind and + /// differentiability from all parameters. + CanSILFunctionType getWithoutDifferentiability(); + /// Returns the type of the derivative function for the given parameter /// indices, result index, derivative function kind, derivative function /// generic signature (optional), and other auxiliary parameters. diff --git a/include/swift/Basic/ExternalUnion.h b/include/swift/Basic/ExternalUnion.h index 8a82c78fd6d6c..2207a361b5415 100644 --- a/include/swift/Basic/ExternalUnion.h +++ b/include/swift/Basic/ExternalUnion.h @@ -87,6 +87,11 @@ struct ExternalUnionMembers { static constexpr int maybeIndexOf() { return ExternalUnionImpl::indexOf::value; } + + template + static constexpr bool contains() { + return ExternalUnionImpl::indexOf::value != -1; + } }; /// An external union that uses the member-list index as the user-facing @@ -237,7 +242,7 @@ class BasicExternalUnion { Members::Info::copyAssignSame(unsigned(thisIndex), Storage, other.Storage); } else { - destruct(thisIndex, Storage); + destruct(thisIndex); copyConstruct(otherIndex, other); } } diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index ae4e11c5f563d..c125f046281c9 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -304,7 +304,7 @@ namespace swift { /// the interface hash, hash them into per-iterable-decl-context /// fingerprints. Fine-grained dependency types won't dirty every provides /// in a file when the user adds a member to, e.g., a struct. - bool EnableTypeFingerprints = false; + bool EnableTypeFingerprints = true; /// When using fine-grained dependencies, emit dot files for every swiftdeps /// file. diff --git a/include/swift/Basic/SourceManager.h b/include/swift/Basic/SourceManager.h index ed4f5dc34126e..7cf754731c1ab 100644 --- a/include/swift/Basic/SourceManager.h +++ b/include/swift/Basic/SourceManager.h @@ -243,6 +243,9 @@ class SourceManager { llvm::Optional resolveOffsetForEndOfLine(unsigned BufferId, unsigned Line) const; + /// Get the length of the line + llvm::Optional getLineLength(unsigned BufferId, unsigned Line) const; + SourceLoc getLocForLineCol(unsigned BufferId, unsigned Line, unsigned Col) const { auto Offset = resolveFromLineCol(BufferId, Line, Col); return Offset.hasValue() ? getLocForOffset(BufferId, Offset.getValue()) : diff --git a/include/swift/Basic/TaggedUnion.h b/include/swift/Basic/TaggedUnion.h new file mode 100644 index 0000000000000..bd8f74b98833d --- /dev/null +++ b/include/swift/Basic/TaggedUnion.h @@ -0,0 +1,259 @@ +//===- TaggedUnion.h - A tagged union ---------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file provides a simple tagged union, like std::variant but without +// any effort to be exception-safe and therefore much simpler. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_BASIC_TAGGEDUNION_H +#define SWIFT_BASIC_TAGGEDUNION_H + +#include "swift/Basic/ExternalUnion.h" + +namespace swift { + +namespace TaggedUnionImpl { +template +using simplify_member_type + = typename std::remove_const::type>::type; + +/// Given a type `T` deduced from a `T &&` parameter, can it be used to +/// construct a member of the union? If so, `simplify_member_type` +/// will give the formal member type. +template +inline constexpr bool is_member_constructible() { + return Members::template contains>(); +} + +struct Empty {}; +} + +template ()> +class TaggedUnionBase; + +/// The base partial specialization. All the other partial specializations +/// will end up inheriting from this. +template +class TaggedUnionBase { +protected: + using StorageType = SimpleExternalUnionBase; + using Kind = typename KindHelper::Kind; + StorageType Storage; + Kind TheKind; + + TaggedUnionBase(Kind theKind) : TheKind(theKind) {} + +public: + /// Construct the union with a value of the given type, which must + /// (ignoring references) be one of the declared members of the union. + template + TaggedUnionBase(T &&value, + typename std::enable_if< + TaggedUnionImpl::is_member_constructible(), + TaggedUnionImpl::Empty>::type = {}) { + using TargetType = TaggedUnionImpl::simplify_member_type; + TheKind = StorageType::template kindForMember(); + Storage.template emplace(TheKind, std::forward(value)); + } + + template + typename std::enable_if(), + TaggedUnionBase &>::type + operator=(T &&value) { + using TargetType = TaggedUnionImpl::simplify_member_type; + TheKind = StorageType::template kindForMember(); + Storage.template emplace(TheKind, std::forward(value)); + return *this; + } + + /// Replace the current value in the union with a value of the given + /// type, which must be one of the declared members of the union. + /// + /// The value will be constructed from the arguments with an argument + /// list (i.e. `new(ptr) T(...)`). If aggregate initialization is required, + /// use `emplaceAggregate`. + template + T &emplace(Args &&... args) { + Storage.destruct(TheKind); + TheKind = StorageType::template kindForMember(); + return Storage.template emplace(TheKind, std::forward(args)...); + } + + /// Replace the current value in the union with a value of the given + /// type, which must be one of the declared members of the union. + /// + /// The value will be constructed from the arguments with a braced + /// initializer list (i.e. `T{...}`) and therefore may use aggregate + /// initialization. + template + T &emplaceAggregate(Args &&... args) { + Storage.destruct(TheKind); + TheKind = StorageType::template kindForMember(); + return Storage.template emplaceAggregate(TheKind, + std::forward(args)...); + } + + /// Return true if the union is storing a value of the given type, + /// which must be one of the declared members of the union. + template + bool isa() const { + return TheKind == StorageType::template kindForMember(); + } + + /// Return a pointer to the value if the union is storing a value of the + /// given type, which must be one of the declared members of the union. + template + T *dyn_cast() { + return Storage.template dyn_cast(TheKind); + } + + /// Return a pointer to the value if the union is storing a value of the + /// given type, which must be one of the declared members of the union. + template + const T *dyn_cast() const { + return Storage.template dyn_cast(TheKind); + } + + /// Assert that the union is storing a value of the given type and return + /// a reference to it. + template + T &get() { + return Storage.template get(TheKind); + } + + /// Assert that the union is storing a value of the given type and return + /// a reference to it. + template + const T &get() const { + return Storage.template get(TheKind); + } +}; + +/// The partial specialization for when the union isn't trivially-copyable. +template +class TaggedUnionBase + : public TaggedUnionBase { + using super = TaggedUnionBase; + +protected: + using super::Storage; + using super::TheKind; + + TaggedUnionBase(typename super::Kind kind) : super(kind) {} + +public: + template + TaggedUnionBase(T &&value, + typename std::enable_if< + TaggedUnionImpl::is_member_constructible(), + TaggedUnionImpl::Empty>::type = {}) + : super(std::forward(value)) {} + + TaggedUnionBase(const TaggedUnionBase &other) : super(other.TheKind) { + Storage.copyConstruct(other.TheKind, other.Storage); + } + + TaggedUnionBase(TaggedUnionBase &&other) : super(other.TheKind) { + Storage.moveConstruct(other.TheKind, std::move(other.Storage)); + } + + TaggedUnionBase &operator=(const TaggedUnionBase &other) { + Storage.copyAssign(TheKind, other.TheKind, other.Storage); + TheKind = other.TheKind; + return *this; + } + + TaggedUnionBase &operator=(TaggedUnionBase &&other) { + Storage.moveAssign(TheKind, other.TheKind, std::move(other.Storage)); + TheKind = other.TheKind; + return *this; + } + + ~TaggedUnionBase() { + Storage.destruct(TheKind); + } +}; + +/// The partial specialization for when `void` is a member of the union. +template +class TaggedUnionBase + : public TaggedUnionBase { + using super = TaggedUnionBase; + +protected: + using super::Storage; + using super::TheKind; + + static constexpr typename super::Kind kindForVoid() { + return super::StorageType::template kindForMember(); + } + +public: + template + TaggedUnionBase(T &&value, + typename std::enable_if< + TaggedUnionImpl::is_member_constructible(), + TaggedUnionImpl::Empty>::type = {}) + : super(std::forward(value)) {} + + /// Construct the union in the empty state. + TaggedUnionBase() : super(kindForVoid()) {} + + /// Test whether the union is in the empty state. + bool empty() const { + return TheKind == kindForVoid(); + } + + /// Reset the union to the empty state. + void reset() { + Storage.destruct(TheKind); + TheKind = kindForVoid(); + } +}; + +/// A tagged union of the given types. +/// +/// Non-trivial members are supported; they will make the union +/// non-trivial to copy, move, and destruct. +/// +/// The union provides the following members, as described in the +/// documentation for the primary partial specialization of +/// TaggedUnionBase. In the following, `M` must be a declared member +/// type of the union. +/// +/// ``` +/// TaggedUnion(M); +/// M &emplace(T...); +/// M &emplaceAggregate(T...); +/// bool isa() const; +/// M *dyn_cast(); +/// const M *dyn_cast() const; +/// M &get(); +/// const M &get() const; +/// ``` +/// +/// Additionally, if `void` is one of the types, the union supports an +/// empty state and provides a default constructor as well as `empty()` +/// and `reset()` methods. +template +using TaggedUnion = + TaggedUnionBase, + ExternalUnionMembers>; + +} + +#endif diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 9ac0d73ef7b9b..c736cdd2a9473 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -422,6 +422,16 @@ class ClangImporter final : public ClangModuleLoader { SourceLoc loc) const override; void printClangType(const clang::Type *type, llvm::raw_ostream &os) const override; + + StableSerializationPath + findStableSerializationPath(const clang::Decl *decl) const override; + + const clang::Decl * + resolveStableSerializationPath( + const StableSerializationPath &path) const override; + + bool isSerializable(const clang::Type *type, + bool checkCanonical) const override; }; ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN, diff --git a/include/swift/ClangImporter/SwiftAbstractBasicReader.h b/include/swift/ClangImporter/SwiftAbstractBasicReader.h new file mode 100644 index 0000000000000..f75f7261e0e60 --- /dev/null +++ b/include/swift/ClangImporter/SwiftAbstractBasicReader.h @@ -0,0 +1,95 @@ +//===- SwiftAbstractBasicReader.h - Clang serialization adapter -*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file provides an intermediate CRTP class which implements most of +// Clang's AbstractBasicReader interface, paralleling the behavior defined +// in SwiftAbstractBasicWriter. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_CLANGIMPORTER_SWIFTABSTRACTBASICREADER_H +#define SWIFT_CLANGIMPORTER_SWIFTABSTRACTBASICREADER_H + +#include "clang/AST/AbstractTypeReader.h" + +// This include is required to instantiate the template code in +// AbstractBasicReader.h, i.e. it's a workaround to an include-what-you-use +// violation. +#include "clang/AST/DeclObjC.h" + +namespace swift { + +/// An implementation of Clang's AbstractBasicReader interface for a Swift +/// datastream-based reader. This is paired with the AbstractBasicWriter +/// implementation in SwiftAbstractBasicWriter.h. Note that the general +/// expectation is that the types and declarations involved will have passed +/// a serializability check when this is used for actual deserialization. +/// +/// The subclass must implement: +/// uint64_t readUInt64(); +/// clang::IdentifierInfo *readIdentifier(); +/// clang::Stmt *readStmtRef(); +/// clang::Decl *readDeclRef(); +template +class DataStreamBasicReader + : public clang::serialization::DataStreamBasicReader { + using super = clang::serialization::DataStreamBasicReader; +public: + using super::asImpl; + using super::getASTContext; + + DataStreamBasicReader(clang::ASTContext &ctx) : super(ctx) {} + + /// Perform all the calls necessary to write out the given type. + clang::QualType readTypeRef() { + auto kind = clang::Type::TypeClass(asImpl().readUInt64()); + return clang::serialization::AbstractTypeReader(asImpl()).read(kind); + } + + bool readBool() { + return asImpl().readUInt64() != 0; + } + + uint32_t readUInt32() { + return uint32_t(asImpl().readUInt64()); + } + + clang::Selector readSelector() { + uint64_t numArgsPlusOne = asImpl().readUInt64(); + + // The null case. + if (numArgsPlusOne == 0) + return clang::Selector(); + + unsigned numArgs = unsigned(numArgsPlusOne - 1); + SmallVector chunks; + for (unsigned i = 0, e = std::max(numArgs, 1U); i != e; ++i) + chunks.push_back(asImpl().readIdentifier()); + + return getASTContext().Selectors.getSelector(numArgs, chunks.data()); + } + + clang::SourceLocation readSourceLocation() { + // Always read null. + return clang::SourceLocation(); + } + + clang::QualType readQualType() { + clang::Qualifiers quals = asImpl().readQualifiers(); + clang::QualType type = asImpl().readTypeRef(); + return getASTContext().getQualifiedType(type, quals); + } +}; + +} + +#endif diff --git a/include/swift/ClangImporter/SwiftAbstractBasicWriter.h b/include/swift/ClangImporter/SwiftAbstractBasicWriter.h new file mode 100644 index 0000000000000..486bee2d01b21 --- /dev/null +++ b/include/swift/ClangImporter/SwiftAbstractBasicWriter.h @@ -0,0 +1,90 @@ +//===- SwiftAbstractBasicWriter.h - Clang serialization adapter -*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file provides an intermediate CRTP class which implements most of +// Clang's AbstractBasicWriter interface, allowing largely the same logic +// to be used for both the importer's "can this be serialized" checks and +// the serializer's actual serialization logic. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_CLANGIMPORTER_SWIFTABSTRACTBASICWRITER_H +#define SWIFT_CLANGIMPORTER_SWIFTABSTRACTBASICWRITER_H + +#include "clang/AST/AbstractTypeWriter.h" + +namespace swift { + +/// An implementation of Clang's AbstractBasicWriter interface for a Swift +/// datastream-based reader. This is paired with the AbstractBasicReader +/// implementation in SwiftAbstractBasicReader.h. Note that the general +/// expectation is that the types and declarations involved will have passed +/// a serializability check when this is used for actual serialization. +/// The code in this class is also used when implementing that +/// serializability check and so must be a little more cautious. +/// +/// The subclass must implement: +/// void writeUInt64(uint64_t value); +/// void writeIdentifier(const clang::IdentifierInfo *ident); +/// void writeStmtRef(const clang::Stmt *stmt); +/// void writeDeclRef(const clang::Decl *decl); +template +class DataStreamBasicWriter + : public clang::serialization::DataStreamBasicWriter { + using super = clang::serialization::DataStreamBasicWriter; +public: + using super::asImpl; + + /// Perform all the calls necessary to write out the given type. + void writeTypeRef(const clang::Type *type) { + asImpl().writeUInt64(uint64_t(type->getTypeClass())); + clang::serialization::AbstractTypeWriter(asImpl()).write(type); + } + + void writeBool(bool value) { + asImpl().writeUInt64(uint64_t(value)); + } + + void writeUInt32(uint32_t value) { + asImpl().writeUInt64(uint64_t(value)); + } + + void writeSelector(clang::Selector selector) { + if (selector.isNull()) { + asImpl().writeUInt64(0); + return; + } + + asImpl().writeUInt64(selector.getNumArgs() + 1); + for (unsigned i = 0, e = std::max(selector.getNumArgs(), 1U); i != e; ++i) + asImpl().writeIdentifier(selector.getIdentifierInfoForSlot(i)); + } + + void writeSourceLocation(clang::SourceLocation loc) { + // DataStreamBasicReader will always read null; the serializability + // check overrides this to complain about non-null source locations. + } + + void writeQualType(clang::QualType type) { + assert(!type.isNull()); + + auto split = type.split(); + asImpl().writeQualifiers(split.Quals); + + // Just recursively visit the given type. + asImpl().writeTypeRef(split.Ty); + } +}; + +} + +#endif diff --git a/include/swift/Driver/FineGrainedDependencyDriverGraph.h b/include/swift/Driver/FineGrainedDependencyDriverGraph.h index af7b2f5116c06..36ab089d6c029 100644 --- a/include/swift/Driver/FineGrainedDependencyDriverGraph.h +++ b/include/swift/Driver/FineGrainedDependencyDriverGraph.h @@ -123,6 +123,8 @@ class ModuleDepGraphNode : public DepGraphNode { return DepGraphNode::humanReadableName(where); } + void dump(raw_ostream &) const; + SWIFT_DEBUG_DUMP; }; @@ -312,9 +314,11 @@ class ModuleDepGraph { } /// For unit tests. - ModuleDepGraph(const bool EnableTypeFingerprints) - : ModuleDepGraph(true, false, EnableTypeFingerprints, false, nullptr) {} - + ModuleDepGraph(const bool EnableTypeFingerprints, + const bool EmitDotFilesForDebugging = false) + : ModuleDepGraph( + true, /*emitFineGrainedDependencyDotFileAfterEveryImport=*/ + EmitDotFilesForDebugging, EnableTypeFingerprints, false, nullptr) {} //============================================================================ // MARK: ModuleDepGraph - updating from a switdeps file @@ -328,18 +332,18 @@ class ModuleDepGraph { /// compensates. Changes loadFromPath(const driver::Job *, StringRef, DiagnosticEngine &); - Changes loadFromSourceFileDepGraph(const driver::Job *cmd, - const SourceFileDepGraph &); + const SourceFileDepGraph &, + DiagnosticEngine &); - /// Also for unit tests - Changes - simulateLoad(const driver::Job *cmd, - llvm::StringMap> simpleNames, - llvm::StringMap>> - compoundNames = {}, - const bool includePrivateDeps = false, - const bool hadCompilationError = false); + /// Also for unit tests + Changes + simulateLoad(const driver::Job *cmd, + llvm::StringMap> simpleNames, + llvm::StringMap>> + compoundNames = {}, + const bool includePrivateDeps = false, + const bool hadCompilationError = false); private: @@ -347,7 +351,8 @@ class ModuleDepGraph { /// and integrate it into the ModuleDepGraph. /// Used both the first time, and to reload the SourceFileDepGraph. /// If any changes were observed, indicate same in the return vale. - Changes loadFromBuffer(const driver::Job *, llvm::MemoryBuffer &); + Changes loadFromBuffer(const driver::Job *, llvm::MemoryBuffer &, + DiagnosticEngine &); /// Integrate a SourceFileDepGraph into the receiver. /// Integration happens when the driver needs to read SourceFileDepGraph. @@ -365,8 +370,9 @@ class ModuleDepGraph { const SourceFileDepGraphNode *integrand) const; /// Integrate the \p integrand into the receiver. - /// Return the changed node if any.. - NullablePtr + /// If an illegal value was found, return \c None, otherwise + /// return the changed node if any.. + Optional> integrateSourceFileDepGraphNode(const SourceFileDepGraph &g, const SourceFileDepGraphNode *integrand, const PreexistingNodeIfAny preexistingMatch, @@ -392,6 +398,12 @@ class ModuleDepGraph { /// After importing a provides node from the frontend, record its /// dependencies. /// Return true if moduleUseNode picks up a new external-dependency + /// + /// \param g The source file graph being integrated into the module graph + /// \param sourceFileUseNode The source file node just integrated, which may + /// also be a use (i.e. a "depends", a declaration used by something else) + /// \param moduleUseNode The module file node corresponding to the \c + /// sourceFileUseNode bool recordWhatUseDependsUpon(const SourceFileDepGraph &g, const SourceFileDepGraphNode *sourceFileUseNode, ModuleDepGraphNode *moduleUseNode); @@ -437,7 +449,7 @@ class ModuleDepGraph { /// Call \p fn for each node whose key matches \p key. void forEachMatchingNode(const DependencyKey &key, - function_ref) const; + function_ref) const; void forEachNodeInJob(StringRef swiftDeps, function_ref) const; @@ -486,17 +498,8 @@ class ModuleDepGraph { bool haveAnyNodesBeenTraversedIn(const driver::Job *) const; - /// Given a "cascading" job, that is a job whose dependents must be recompiled - /// when this job is recompiled, Compute two sets of jobs: - /// 1. Return value (via visited) is the set of jobs needing recompilation - /// after this one, and - /// 2. Jobs not previously known to need dependencies reexamined after they - /// are recompiled. - /// - /// Returns jobs to be run because of changes to any/ever node in the - /// argument. Only return jobs marked that were previously unmarked, assuming - /// previously marked jobs are already scheduled. - /// TODO: rewrite above comment + /// Find all jobs (possibly including the argument) requiring recompilation + /// assuming that every entity in \p jobToBeRecompiled has changed. std::vector findJobsToRecompileWhenWholeJobChanges(const driver::Job *jobToBeRecompiled); diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 5c6c833a4e65c..c2612775a77d1 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -653,8 +653,6 @@ class CompilerInstance { }; private: - void createREPLFile(const ImplicitImports &implicitImports); - void addMainFileToModule(const ImplicitImports &implicitImports); void performSemaUpTo(SourceFile::ASTStage_t LimitStage); diff --git a/include/swift/IDE/CodeCompletion.h b/include/swift/IDE/CodeCompletion.h index 186add43a425f..553fd504cd971 100644 --- a/include/swift/IDE/CodeCompletion.h +++ b/include/swift/IDE/CodeCompletion.h @@ -527,6 +527,11 @@ class CodeCompletionResult { /// Describes the relationship between the type of the completion results and /// the expected type at the code completion position. enum ExpectedTypeRelation { + /// The result does not have a type (e.g. keyword). + NotApplicable, + + /// The type relation have not been calculated. + Unknown, /// The relationship of the result's type to the expected type is not /// invalid, not convertible, and not identical. @@ -580,7 +585,7 @@ class CodeCompletionResult { CodeCompletionResult(ResultKind Kind, SemanticContextKind SemanticContext, unsigned NumBytesToErase, CodeCompletionString *CompletionString, - ExpectedTypeRelation TypeDistance = Unrelated, + ExpectedTypeRelation TypeDistance, CodeCompletionOperatorKind KnownOperatorKind = CodeCompletionOperatorKind::None) : Kind(Kind), KnownOperatorKind(unsigned(KnownOperatorKind)), @@ -605,7 +610,7 @@ class CodeCompletionResult { SemanticContextKind SemanticContext, unsigned NumBytesToErase, CodeCompletionString *CompletionString, - ExpectedTypeRelation TypeDistance = Unrelated) + ExpectedTypeRelation TypeDistance) : Kind(Keyword), KnownOperatorKind(0), SemanticContext(unsigned(SemanticContext)), NotRecommended(false), NotRecReason(NotRecommendedReason::NoReason), @@ -684,7 +689,7 @@ class CodeCompletionResult { AssociatedUSRs(AssociatedUSRs), DocWords(DocWords) { AssociatedKind = static_cast(DeclKind); assert(CompletionString); - TypeDistance = ExpectedTypeRelation::Unrelated; + TypeDistance = ExpectedTypeRelation::Unknown; assert(!isOperator() || getOperatorKind() != CodeCompletionOperatorKind::None); } diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index eeaabd8bbcbd9..f795082ddf37f 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -346,6 +346,9 @@ class LinkEntity { /// ProtocolConformance*. ProtocolWitnessTableLazyCacheVariable, + /// A SIL differentiability witness. + DifferentiabilityWitness, + // Everything following this is a type kind. /// A value witness for a type. @@ -535,6 +538,14 @@ class LinkEntity { return getAssociatedConformanceByIndex(conformance->getProtocol(), index); } + void + setForDifferentiabilityWitness(Kind kind, + const SILDifferentiabilityWitness *witness) { + Pointer = const_cast(static_cast(witness)); + SecondaryPointer = nullptr; + Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind)); + } + void setForType(Kind kind, CanType type) { assert(isTypeKind(kind)); Pointer = type.getPointer(); @@ -835,6 +846,14 @@ class LinkEntity { return entity; } + static LinkEntity + forDifferentiabilityWitness(const SILDifferentiabilityWitness *witness) { + LinkEntity entity; + entity.setForDifferentiabilityWitness(Kind::DifferentiabilityWitness, + witness); + return entity; + } + static LinkEntity forProtocolWitnessTable(const RootProtocolConformance *C) { LinkEntity entity; entity.setForProtocolConformance(Kind::ProtocolWitnessTable, C); @@ -1043,6 +1062,11 @@ class LinkEntity { return reinterpret_cast(Pointer); } + SILDifferentiabilityWitness *getSILDifferentiabilityWitness() const { + assert(getKind() == Kind::DifferentiabilityWitness); + return reinterpret_cast(Pointer); + } + const RootProtocolConformance *getRootProtocolConformance() const { assert(isRootProtocolConformanceKind(getKind())); return cast(getProtocolConformance()); diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index f8fd3abd492b0..f015556a4b6dd 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -651,9 +651,9 @@ def disable_verify_exclusivity : Flag<["-"], "disable-verify-exclusivity">, def disable_legacy_type_info : Flag<["-"], "disable-legacy-type-info">, HelpText<"Completely disable legacy type layout">; -def prespecialize_generic_metadata : Flag<["-"], "prespecialize-generic-metadata">, - HelpText<"Statically specialize metadata for generic types at types that " - "are known to be used in source.">; +def disable_generic_metadata_prespecialization : Flag<["-"], "disable-generic-metadata-prespecialization">, + HelpText<"Do not statically specialize metadata for generic types at types " + "that are known to be used in source.">; def read_legacy_type_info_path_EQ : Joined<["-"], "read-legacy-type-info-path=">, HelpText<"Read legacy type layout from the given path instead of default path">; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index dd2d0c0d026f4..1a5166a51d453 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -191,7 +191,7 @@ HelpText<"Emit dot files every time driver imports an fine-grained swiftdeps fil def fine_grained_dependency_include_intrafile : Flag<["-"], "fine-grained-dependency-include-intrafile">, -InternalDebugOpt, +Flags<[FrontendOption, HelpHidden]>, HelpText<"Include within-file dependencies.">; def emit_fine_grained_dependency_sourcefile_dot_files : @@ -419,6 +419,11 @@ def emit_module_interface_path : ArgumentIsPath]>, MetaVarName<"">, HelpText<"Output module interface file to ">; +def avoid_emit_module_source_info : + Flag<["-"], "avoid-emit-module-source-info">, + Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>, + HelpText<"don't emit Swift source info file">; + def emit_module_source_info_path : Separate<["-"], "emit-module-source-info-path">, Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild, diff --git a/include/swift/Parse/ParseSILSupport.h b/include/swift/Parse/ParseSILSupport.h index 00eaba3e80caf..2ead9961416e5 100644 --- a/include/swift/Parse/ParseSILSupport.h +++ b/include/swift/Parse/ParseSILSupport.h @@ -32,6 +32,7 @@ namespace swift { virtual bool parseSILGlobal(Parser &P) = 0; virtual bool parseSILWitnessTable(Parser &P) = 0; virtual bool parseSILDefaultWitnessTable(Parser &P) = 0; + virtual bool parseSILDifferentiabilityWitness(Parser &P) = 0; virtual bool parseSILCoverageMap(Parser &P) = 0; virtual bool parseSILProperty(Parser &P) = 0; virtual bool parseSILScope(Parser &P) = 0; diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 639a50d455340..0739540fdd9dd 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -413,7 +413,8 @@ class Parser { bool DelayBodyParsing = true); ~Parser(); - bool isInSILMode() const { return SIL != nullptr; } + /// Returns true if the buffer being parsed is allowed to contain SIL. + bool isInSILMode() const; /// Calling this function to finalize libSyntax tree creation without destroying /// the parser instance. @@ -430,9 +431,8 @@ class Parser { PreviousLoc); } - ParserPosition getParserPosition(const PersistentParserState::ParserPos &Pos){ - return ParserPosition(L->getStateForBeginningOfTokenLoc(Pos.Loc), - Pos.PrevLoc); + ParserPosition getParserPosition(SourceLoc loc, SourceLoc previousLoc) { + return ParserPosition(L->getStateForBeginningOfTokenLoc(loc), previousLoc); } void restoreParserPosition(ParserPosition PP, bool enableDiagnostics = false) { @@ -661,6 +661,9 @@ class Parser { /// Returns \c true if the parser hit the eof before finding matched '}'. bool skipBracedBlock(); + /// Skip over SIL decls until we encounter the start of a Swift decl or eof. + void skipSILUntilSwiftDecl(); + /// If the parser is generating only a syntax tree, try loading the current /// node from a previously generated syntax tree. /// Returns \c true if the node has been loaded and inserted into the current @@ -880,11 +883,18 @@ class Parser { //===--------------------------------------------------------------------===// // Decl Parsing - /// Return true if parser is at the start of a decl or decl-import. - bool isStartOfDecl(); + /// Returns true if parser is at the start of a Swift decl or decl-import. + bool isStartOfSwiftDecl(); + + /// Returns true if the parser is at the start of a SIL decl. + bool isStartOfSILDecl(); + /// Parse the top-level Swift decls into the source file. void parseTopLevel(); + /// Parse the top-level SIL decls into the SIL module. + void parseTopLevelSIL(); + /// Flags that control the parsing of declarations. enum ParseDeclFlags { PD_Default = 0, diff --git a/include/swift/Parse/PersistentParserState.h b/include/swift/Parse/PersistentParserState.h index 9e0678c5e3971..550c294842f71 100644 --- a/include/swift/Parse/PersistentParserState.h +++ b/include/swift/Parse/PersistentParserState.h @@ -59,23 +59,12 @@ class CodeCompletionDelayedDeclState { /// Parser state persistent across multiple parses. class PersistentParserState { public: - struct ParserPos { - SourceLoc Loc; - SourceLoc PrevLoc; - - bool isValid() const { return Loc.isValid(); } - }; - - bool InPoundLineEnvironment = false; // FIXME: When condition evaluation moves to a later phase, remove this bit // and adjust the client call 'performParseOnly'. bool PerformConditionEvaluation = true; private: swift::ScopeInfo ScopeInfo; - /// Parser sets this if it stopped parsing before the buffer ended. - ParserPosition MarkedPos; - std::unique_ptr CodeCompletionDelayedDeclStat; /// The local context for all top-level code. @@ -113,19 +102,6 @@ class PersistentParserState { TopLevelContext &getTopLevelContext() { return TopLevelCode; } - - void markParserPosition(ParserPosition Pos, - bool InPoundLineEnvironment) { - MarkedPos = Pos; - this->InPoundLineEnvironment = InPoundLineEnvironment; - } - - /// Returns the marked parser position and resets it. - ParserPosition takeParserPosition() { - ParserPosition Pos = MarkedPos; - MarkedPos = ParserPosition(); - return Pos; - } }; } // end namespace swift diff --git a/include/swift/SIL/BranchPropagatedUser.h b/include/swift/SIL/BranchPropagatedUser.h index 5e00ebf4ab9b5..1c85fb22e2637 100644 --- a/include/swift/SIL/BranchPropagatedUser.h +++ b/include/swift/SIL/BranchPropagatedUser.h @@ -108,6 +108,18 @@ class BranchPropagatedUser { llvm::PointerLikeTypeTraits::NumLowBitsAvailable }; + static ArrayRef + convertFromInstArray(ArrayRef instArray) { + assert(llvm::all_of( + instArray, + [](SILInstruction *i) { return !isa(i); }) && + "Passed cond branch to a non-BranchPropagatedUser API"); + auto *castData = + reinterpret_cast(instArray.data()); + ArrayRef castArray(castData, instArray.size()); + return castArray; + } + private: BranchPropagatedUser(SILInstruction *inst) : user(inst) { assert(!isa(inst)); diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index 8f72bb8ef4d0e..88d2a566c55e1 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -187,24 +187,9 @@ class LinearLifetimeChecker { bool validateLifetime(SILValue value, ArrayRef consumingUses, ArrayRef nonConsumingUses) { - assert(llvm::all_of( - consumingUses, - [](SILInstruction *i) { return !isa(i); }) && - "Passed cond branch to a non-BranchPropagatedUser API"); - assert(llvm::all_of( - nonConsumingUses, - [](SILInstruction *i) { return !isa(i); }) && - "Passed cond branch to a non-BranchPropagatedUser API"); - auto *consumingUsesCast = - reinterpret_cast(consumingUses.data()); - auto *nonConsumingUsesCast = - reinterpret_cast(nonConsumingUses.data()); - ArrayRef consumingUsesCastArray(consumingUsesCast, - consumingUses.size()); - ArrayRef nonConsumingUsesCastArray( - nonConsumingUsesCast, nonConsumingUses.size()); - return validateLifetime(value, consumingUsesCastArray, - nonConsumingUsesCastArray); + return validateLifetime( + value, BranchPropagatedUser::convertFromInstArray(consumingUses), + BranchPropagatedUser::convertFromInstArray(nonConsumingUses)); } }; diff --git a/include/swift/SIL/PatternMatch.h b/include/swift/SIL/PatternMatch.h index ef75ce6fa1237..8d451f9e73db8 100644 --- a/include/swift/SIL/PatternMatch.h +++ b/include/swift/SIL/PatternMatch.h @@ -397,7 +397,12 @@ template struct tupleextractoperation_ty { unsigned index; tupleextractoperation_ty(const LTy &Left, unsigned i) : L(Left), index(i) {} - bool match(SILValue v) { return match(v->getDefiningInstruction()); } + bool match(SILValue v) { + auto *inst = v->getDefiningInstruction(); + if (!inst) + return false; + return match(inst); + } template bool match(ITy *V) { if (auto *TEI = dyn_cast(V)) { diff --git a/include/swift/SIL/SILArgument.h b/include/swift/SIL/SILArgument.h index 4f23c1cd6ff46..d5d8537fd8c3b 100644 --- a/include/swift/SIL/SILArgument.h +++ b/include/swift/SIL/SILArgument.h @@ -173,6 +173,10 @@ class SILArgument : public ValueBase { /// is the enum itself (the operand of the switch_enum). SILValue getSingleTerminatorOperand() const; + /// If this SILArgument's parent block has a single predecessor whose + /// terminator has a single operand, return that terminator. + TermInst *getSingleTerminator() const; + /// Return the SILArgumentKind of this argument. SILArgumentKind getKind() const { return SILArgumentKind(ValueBase::getKind()); @@ -264,6 +268,10 @@ class SILPhiArgument : public SILArgument { /// is the enum itself (the operand of the switch_enum). SILValue getSingleTerminatorOperand() const; + /// If this SILArgument's parent block has a single predecessor whose + /// terminator has a single operand, return that terminator. + TermInst *getSingleTerminator() const; + static bool classof(const SILInstruction *) = delete; static bool classof(const SILUndef *) = delete; static bool classof(const SILNode *node) { @@ -403,6 +411,16 @@ inline bool SILArgument::getSingleTerminatorOperands( llvm_unreachable("Covered switch is not covered?!"); } +inline TermInst *SILArgument::getSingleTerminator() const { + switch (getKind()) { + case SILArgumentKind::SILPhiArgument: + return cast(this)->getSingleTerminator(); + case SILArgumentKind::SILFunctionArgument: + return nullptr; + } + llvm_unreachable("Covered switch is not covered?!"); +} + } // end swift namespace #endif diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index bda95ab9f3aca..f279acb259b18 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -802,16 +802,16 @@ class SILBuilder { } EndBorrowInst *createEndBorrow(SILLocation loc, SILValue borrowedValue) { + if (auto *arg = dyn_cast(borrowedValue)) { + if (auto *ti = arg->getSingleTerminator()) { + assert(!ti->isTransformationTerminator() && + "Transforming terminators do not have end_borrow"); + } + } return insert(new (getModule()) EndBorrowInst(getSILDebugLocation(loc), borrowedValue)); } - EndBorrowInst *createEndBorrow(SILLocation Loc, SILValue BorrowedValue, - SILValue OriginalValue) { - return insert(new (getModule()) - EndBorrowInst(getSILDebugLocation(Loc), BorrowedValue)); - } - BeginAccessInst *createBeginAccess(SILLocation loc, SILValue address, SILAccessKind accessKind, SILAccessEnforcement enforcement, diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index ff751f61d20c2..8563c2dcbe315 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -1177,9 +1177,8 @@ void SILCloner::visitEndBorrowInst(EndBorrowInst *Inst) { return; recordClonedInstruction( - Inst, - getBuilder().createEndBorrow(getOpLocation(Inst->getLoc()), - getOpValue(Inst->getOperand()), SILValue())); + Inst, getBuilder().createEndBorrow(getOpLocation(Inst->getLoc()), + getOpValue(Inst->getOperand()))); } template diff --git a/include/swift/SIL/SILDifferentiabilityWitness.h b/include/swift/SIL/SILDifferentiabilityWitness.h new file mode 100644 index 0000000000000..791bc98e8206b --- /dev/null +++ b/include/swift/SIL/SILDifferentiabilityWitness.h @@ -0,0 +1,166 @@ +//===--- SILDifferentiabilityWitness.h - Differentiability witnesses ------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 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 SILDifferentiabilityWitness class, which maps an +// original SILFunction and derivative configuration (parameter indices, result +// indices, derivative generic signature) to derivative functions (JVP and VJP). +// +// SIL differentiability witnesses are generated from the `@differentiable` +// and `@derivative` AST declaration attributes. +// +// Differentiability witnesses are canonicalized by the SIL differentiation +// transform, which fills in missing derivative functions. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SIL_SILDIFFERENTIABILITYWITNESS_H +#define SWIFT_SIL_SILDIFFERENTIABILITYWITNESS_H + +#include "swift/AST/Attr.h" +#include "swift/AST/AutoDiff.h" +#include "swift/AST/GenericSignature.h" +#include "swift/SIL/SILAllocated.h" +#include "swift/SIL/SILLinkage.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" + +namespace swift { + +class SILPrintContext; + +class SILDifferentiabilityWitness + : public llvm::ilist_node, + public SILAllocated { +private: + /// The module which contains the differentiability witness. + SILModule &Module; + /// The linkage of the differentiability witness. + SILLinkage Linkage; + /// The original function. + SILFunction *OriginalFunction; + /// The derivative configuration: parameter indices, result indices, and + /// derivative generic signature (optional). The derivative generic signature + /// may contain same-type requirements such that all generic parameters are + /// bound to concrete types. + AutoDiffConfig Config; + /// The JVP (Jacobian-vector products) derivative function. + SILFunction *JVP; + /// The VJP (vector-Jacobian products) derivative function. + SILFunction *VJP; + /// Whether or not this differentiability witness is a declaration. + bool IsDeclaration; + /// Whether or not this differentiability witness is serialized, which allows + /// devirtualization from another module. + bool IsSerialized; + /// The AST `@differentiable` or `@derivative` attribute from which the + /// differentiability witness is generated. Used for diagnostics. + /// Null if the differentiability witness is parsed from SIL or if it is + /// deserialized. + const DeclAttribute *Attribute = nullptr; + + SILDifferentiabilityWitness( + SILModule &module, SILLinkage linkage, SILFunction *originalFunction, + IndexSubset *parameterIndices, IndexSubset *resultIndices, + GenericSignature derivativeGenSig, SILFunction *jvp, SILFunction *vjp, + bool isDeclaration, bool isSerialized, const DeclAttribute *attribute) + : Module(module), Linkage(linkage), OriginalFunction(originalFunction), + Config(parameterIndices, resultIndices, derivativeGenSig.getPointer()), + JVP(jvp), VJP(vjp), IsDeclaration(isDeclaration), + IsSerialized(isSerialized), Attribute(attribute) {} + +public: + static SILDifferentiabilityWitness * + createDeclaration(SILModule &module, SILLinkage linkage, + SILFunction *originalFunction, + IndexSubset *parameterIndices, IndexSubset *resultIndices, + GenericSignature derivativeGenSig, + const DeclAttribute *attribute = nullptr); + + static SILDifferentiabilityWitness *createDefinition( + SILModule &module, SILLinkage linkage, SILFunction *originalFunction, + IndexSubset *parameterIndices, IndexSubset *resultIndices, + GenericSignature derivativeGenSig, SILFunction *jvp, SILFunction *vjp, + bool isSerialized, const DeclAttribute *attribute = nullptr); + + void convertToDefinition(SILFunction *jvp, SILFunction *vjp, + bool isSerialized); + + SILDifferentiabilityWitnessKey getKey() const; + SILModule &getModule() const { return Module; } + SILLinkage getLinkage() const { return Linkage; } + SILFunction *getOriginalFunction() const { return OriginalFunction; } + const AutoDiffConfig &getConfig() const { return Config; } + IndexSubset *getParameterIndices() const { return Config.parameterIndices; } + IndexSubset *getResultIndices() const { return Config.resultIndices; } + GenericSignature getDerivativeGenericSignature() const { + return Config.derivativeGenericSignature; + } + SILFunction *getJVP() const { return JVP; } + SILFunction *getVJP() const { return VJP; } + SILFunction *getDerivative(AutoDiffDerivativeFunctionKind kind) const { + switch (kind) { + case AutoDiffDerivativeFunctionKind::JVP: + return JVP; + case AutoDiffDerivativeFunctionKind::VJP: + return VJP; + } + } + void setJVP(SILFunction *jvp) { JVP = jvp; } + void setVJP(SILFunction *vjp) { VJP = vjp; } + void setDerivative(AutoDiffDerivativeFunctionKind kind, + SILFunction *derivative) { + switch (kind) { + case AutoDiffDerivativeFunctionKind::JVP: + JVP = derivative; + break; + case AutoDiffDerivativeFunctionKind::VJP: + VJP = derivative; + break; + } + } + bool isDeclaration() const { return IsDeclaration; } + bool isDefinition() const { return !IsDeclaration; } + bool isSerialized() const { return IsSerialized; } + const DeclAttribute *getAttribute() const { return Attribute; } + + /// Verify that the differentiability witness is well-formed. + void verify(const SILModule &module) const; + + void print(llvm::raw_ostream &os, bool verbose = false) const; + void dump() const; +}; + +} // end namespace swift + +namespace llvm { + +//===----------------------------------------------------------------------===// +// ilist_traits for SILDifferentiabilityWitness +//===----------------------------------------------------------------------===// + +template <> +struct ilist_traits<::swift::SILDifferentiabilityWitness> + : public ilist_node_traits<::swift::SILDifferentiabilityWitness> { + using SILDifferentiabilityWitness = ::swift::SILDifferentiabilityWitness; + +public: + static void deleteNode(SILDifferentiabilityWitness *DW) { + DW->~SILDifferentiabilityWitness(); + } + +private: + void createNode(const SILDifferentiabilityWitness &); +}; + +} // namespace llvm + +#endif // SWIFT_SIL_SILDIFFERENTIABILITYWITNESS_H diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 4afcb22beb988..ec22b11ea77c6 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -7042,6 +7042,30 @@ class TermInst : public NonValueInstruction { bool isProgramTerminating() const; TermKind getTermKind() const { return TermKind(getKind()); } + + /// Returns true if this is a transformation terminator. + bool isTransformationTerminator() const { + switch (getTermKind()) { + case TermKind::UnwindInst: + case TermKind::UnreachableInst: + case TermKind::ReturnInst: + case TermKind::ThrowInst: + case TermKind::YieldInst: + case TermKind::TryApplyInst: + case TermKind::BranchInst: + case TermKind::CondBranchInst: + case TermKind::SwitchValueInst: + case TermKind::SwitchEnumAddrInst: + case TermKind::DynamicMethodBranchInst: + case TermKind::CheckedCastAddrBranchInst: + case TermKind::CheckedCastValueBranchInst: + return false; + case TermKind::SwitchEnumInst: + case TermKind::CheckedCastBranchInst: + return true; + } + llvm_unreachable("Covered switch isn't covered."); + } }; /// UnreachableInst - Position in the code which would be undefined to reach. diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index 9b5f36b1280dd..d38c5b7741fa7 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -28,6 +28,7 @@ #include "swift/SIL/SILCoverageMap.h" #include "swift/SIL/SILDeclRef.h" #include "swift/SIL/SILDefaultWitnessTable.h" +#include "swift/SIL/SILDifferentiabilityWitness.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILGlobalVariable.h" #include "swift/SIL/SILPrintContext.h" @@ -105,6 +106,8 @@ enum class SILStage { /// when a Swift compilation context is lowered to SIL. class SILModule { friend class SILFunctionBuilder; + friend class SILGenSourceFileRequest; + friend class SILGenWholeModuleRequest; public: using FunctionListType = llvm::ilist; @@ -113,6 +116,8 @@ class SILModule { using PropertyListType = llvm::ilist; using WitnessTableListType = llvm::ilist; using DefaultWitnessTableListType = llvm::ilist; + using DifferentiabilityWitnessListType = + llvm::ilist; using CoverageMapCollectionType = llvm::MapVector; @@ -131,6 +136,7 @@ class SILModule { friend SILBasicBlock; friend SILCoverageMap; friend SILDefaultWitnessTable; + friend SILDifferentiabilityWitness; friend SILFunction; friend SILGlobalVariable; friend SILLayout; @@ -194,6 +200,17 @@ class SILModule { /// The list of SILDefaultWitnessTables in the module. DefaultWitnessTableListType defaultWitnessTables; + /// Lookup table for SIL differentiability witnesses, keyed by mangled name. + llvm::StringMap DifferentiabilityWitnessMap; + + /// Lookup table for SILDifferentiabilityWitnesses, keyed by original + /// function name. + llvm::StringMap> + DifferentiabilityWitnessesByFunction; + + /// The list of SILDifferentiabilityWitnesses in the module. + DifferentiabilityWitnessListType differentiabilityWitnesses; + /// Declarations which are externally visible. /// /// These are method declarations which are referenced from inlinable @@ -455,6 +472,25 @@ class SILModule { return {defaultWitnessTables.begin(), defaultWitnessTables.end()}; } + using differentiability_witness_iterator = DifferentiabilityWitnessListType::iterator; + using differentiability_witness_const_iterator = DifferentiabilityWitnessListType::const_iterator; + DifferentiabilityWitnessListType &getDifferentiabilityWitnessList() { return differentiabilityWitnesses; } + const DifferentiabilityWitnessListType &getDifferentiabilityWitnessList() const { return differentiabilityWitnesses; } + differentiability_witness_iterator differentiability_witness_begin() { return differentiabilityWitnesses.begin(); } + differentiability_witness_iterator differentiability_witness_end() { return differentiabilityWitnesses.end(); } + differentiability_witness_const_iterator differentiability_witness_begin() const { return differentiabilityWitnesses.begin(); } + differentiability_witness_const_iterator differentiability_witness_end() const { return differentiabilityWitnesses.end(); } + iterator_range + getDifferentiabilityWitnesses() { + return {differentiabilityWitnesses.begin(), + differentiabilityWitnesses.end()}; + } + iterator_range + getDifferentiabilityWitnesses() const { + return {differentiabilityWitnesses.begin(), + differentiabilityWitnesses.end()}; + } + void addExternallyVisibleDecl(ValueDecl *decl) { externallyVisible.insert(decl); } @@ -591,6 +627,21 @@ class SILModule { /// hierarchy of \p Class. SILFunction *lookUpFunctionInVTable(ClassDecl *Class, SILDeclRef Member); + /// Look up the differentiability witness with the given name. + SILDifferentiabilityWitness *lookUpDifferentiabilityWitness(StringRef name); + + /// Look up the differentiability witness corresponding to the given key. + SILDifferentiabilityWitness * + lookUpDifferentiabilityWitness(SILDifferentiabilityWitnessKey key); + + /// Look up the differentiability witness corresponding to the given function. + llvm::ArrayRef + lookUpDifferentiabilityWitnessesForFunction(StringRef name); + + /// Attempt to deserialize the SILDifferentiabilityWitness. Returns true if + /// deserialization succeeded, false otherwise. + bool loadDifferentiabilityWitness(SILDifferentiabilityWitness *dw); + // Given a protocol, attempt to create a default witness table declaration // for it. SILDefaultWitnessTable * diff --git a/include/swift/SIL/SILType.h b/include/swift/SIL/SILType.h index 0159b23b41ab6..4e15caf4c932f 100644 --- a/include/swift/SIL/SILType.h +++ b/include/swift/SIL/SILType.h @@ -459,6 +459,24 @@ class SILType { return SILType(getASTType().getReferenceStorageReferent(), getCategory()); } + /// Return the reference ownership of this type if it is a reference storage + /// type. Otherwse, return None. + Optional getReferenceStorageOwnership() const { + auto type = getASTType()->getAs(); + if (!type) + return None; + return type->getOwnership(); + } + + /// Attempt to wrap the passed in type as a type with reference ownership \p + /// ownership. For simplicity, we always return an address since reference + /// storage types may not be loadable (e.x.: weak ownership). + SILType getReferenceStorageType(const ASTContext &ctx, + ReferenceOwnership ownership) const { + auto *type = ReferenceStorageType::get(getASTType(), ownership, ctx); + return SILType::getPrimitiveAddressType(type->getCanonicalType()); + } + /// Transform the function type SILType by replacing all of its interface /// generic args with the appropriate item from the substitution. /// diff --git a/include/swift/SILOptimizer/Analysis/ArraySemantic.h b/include/swift/SILOptimizer/Analysis/ArraySemantic.h index fcca204fd1362..0dbe35c940843 100644 --- a/include/swift/SILOptimizer/Analysis/ArraySemantic.h +++ b/include/swift/SILOptimizer/Analysis/ArraySemantic.h @@ -41,7 +41,8 @@ enum class ArrayCallKind { // a function, and it has a self parameter, make sure that it is defined // before this comment. kArrayInit, - kArrayUninitialized + kArrayUninitialized, + kArrayUninitializedIntrinsic }; /// Wrapper around array semantic calls. @@ -183,6 +184,21 @@ class ArraySemanticsCall { /// Can this function be inlined by the early inliner. bool canInlineEarly() const; + /// If this is a call to ArrayUninitialized (or + /// ArrayUninitializedInstrinsic), identify the instructions that store + /// elements into the array indices. For every index, add the store + /// instruction that stores to that index to \p ElementStoreMap. + /// + /// \returns true iff this is an "array.uninitialized" semantic call, and the + /// stores into the array indices are identified and the \p ElementStoreMap is + /// populated. + /// + /// Note that this function does not support array initializations that use + /// copy_addr, which implies that arrays with address-only types would not + /// be recognized by this function as yet. + bool mapInitializationStores( + llvm::DenseMap &ElementStoreMap); + protected: /// Validate the signature of this call. bool isValidSignature(); diff --git a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h index c1d405c4d7f42..2d56b97d85695 100644 --- a/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/EscapeAnalysis.h @@ -449,7 +449,7 @@ class EscapeAnalysis : public BottomUpIPAnalysis { /// Sets the outgoing points-to edge. The \p To node must be a Content node. void setPointsToEdge(CGNode *To) { - assert(!To->mergeTo); + assert(!To->isMerged); assert(To->Type == NodeType::Content && "Wrong node type for points-to edge"); pointsToIsEdge = true; diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index b879b3a666795..5d048881ccd6f 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -319,6 +319,8 @@ PASS(NonInlinableFunctionSkippingChecker, "check-non-inlinable-function-skipping PASS(YieldOnceCheck, "yield-once-check", "Check correct usage of yields in yield-once coroutines") PASS(OSLogOptimization, "os-log-optimization", "Optimize os log calls") +PASS(ForEachLoopUnroll, "for-each-loop-unroll", + "Unroll forEach loops over array literals") PASS(MandatoryCombine, "mandatory-combine", "Perform mandatory peephole combines") PASS(BugReducerTester, "bug-reducer-tester", diff --git a/include/swift/SILOptimizer/Utils/InstOptUtils.h b/include/swift/SILOptimizer/Utils/InstOptUtils.h index d67600dbd17ef..e1665d5f466c0 100644 --- a/include/swift/SILOptimizer/Utils/InstOptUtils.h +++ b/include/swift/SILOptimizer/Utils/InstOptUtils.h @@ -145,6 +145,15 @@ class InstructionDeleter { SILInstruction *inst, llvm::function_ref callback = [](SILInstruction *) {}); + + /// Recursively visit users of \c inst (including \c inst)and force delete + /// them. Also, destroy the consumed operands of the deleted instructions + /// whenever necessary. Invoke the \c callback on instructions that are + /// deleted. + void recursivelyForceDeleteUsersAndFixLifetimes( + SILInstruction *inst, + llvm::function_ref callback = + [](SILInstruction *) {}); }; /// If \c inst is dead, delete it and recursively eliminate all code that diff --git a/include/swift/Serialization/SerializedSILLoader.h b/include/swift/Serialization/SerializedSILLoader.h index fd65af939be7d..8afe8fe5f7966 100644 --- a/include/swift/Serialization/SerializedSILLoader.h +++ b/include/swift/Serialization/SerializedSILLoader.h @@ -32,6 +32,7 @@ class SILModule; class SILVTable; class SILWitnessTable; class SILDefaultWitnessTable; +class SILDifferentiabilityWitness; /// Maintains a list of SILDeserializer, one for each serialized modules /// in ASTContext. It provides lookupSILFunction that will perform lookup @@ -64,6 +65,8 @@ class SerializedSILLoader { SILVTable *lookupVTable(const ClassDecl *C); SILWitnessTable *lookupWitnessTable(SILWitnessTable *C); SILDefaultWitnessTable *lookupDefaultWitnessTable(SILDefaultWitnessTable *C); + SILDifferentiabilityWitness * + lookupDifferentiabilityWitness(SILDifferentiabilityWitnessKey key); /// Invalidate the cached entries for deserialized SILFunctions. void invalidateCaches(); diff --git a/include/swift/Subsystems.h b/include/swift/Subsystems.h index 1bec596be277d..7f85858c8338d 100644 --- a/include/swift/Subsystems.h +++ b/include/swift/Subsystems.h @@ -106,29 +106,21 @@ namespace swift { /// Parse a single buffer into the given source file. /// - /// If the source file is the main file, stop parsing after the next - /// stmt-brace-item with side-effects. + /// \param SF The file within the module being parsed. /// - /// \param SF the file within the module being parsed. + /// \param BufferID The buffer to parse from. /// - /// \param BufferID the buffer to parse from. + /// \param PersistentState If non-null the same PersistentState object can be + /// used to save parser state for code completion. /// - /// \param[out] Done set to \c true if end of the buffer was reached. - /// - /// \param SIL if non-null, we're parsing a SIL file. - /// - /// \param PersistentState if non-null the same PersistentState object can - /// be used to resume parsing or parse delayed function bodies. - void parseIntoSourceFile(SourceFile &SF, unsigned BufferID, bool *Done, - SILParserState *SIL = nullptr, + /// \param DelayBodyParsing Whether parsing of type and function bodies can be + /// delayed. + void parseIntoSourceFile(SourceFile &SF, unsigned BufferID, PersistentParserState *PersistentState = nullptr, bool DelayBodyParsing = true); - /// Parse a single buffer into the given source file, until the full source - /// contents are parsed. - void parseIntoSourceFileFull(SourceFile &SF, unsigned BufferID, - PersistentParserState *PersistentState = nullptr, - bool DelayBodyParsing = true); + /// Parse a source file's SIL declarations into a given SIL module. + void parseSourceFileSIL(SourceFile &SF, SILParserState *sil); /// Finish the code completion. void performCodeCompletionSecondPass(PersistentParserState &PersistentState, @@ -145,10 +137,7 @@ namespace swift { /// Once parsing is complete, this walks the AST to resolve imports, record /// operators, and do other top-level validation. - /// - /// \param StartElem Where to start for incremental name binding in the main - /// source file. - void performNameBinding(SourceFile &SF, unsigned StartElem = 0); + void performNameBinding(SourceFile &SF); /// Once type-checking is complete, this instruments code with calls to an /// intrinsic that record the expected values of local variables so they can @@ -179,10 +168,7 @@ namespace swift { /// 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. - void performTypeChecking(SourceFile &SF, unsigned StartElem = 0); + void performTypeChecking(SourceFile &SF); /// Now that we have type-checked an entire module, perform any type /// checking that requires the full module, e.g., Objective-C method diff --git a/include/swift/Syntax/TokenKinds.def.gyb b/include/swift/Syntax/TokenKinds.def.gyb index 4627055832e9c..4afa4f0d48e76 100644 --- a/include/swift/Syntax/TokenKinds.def.gyb +++ b/include/swift/Syntax/TokenKinds.def.gyb @@ -165,6 +165,7 @@ SIL_KEYWORD(sil_vtable) SIL_KEYWORD(sil_global) SIL_KEYWORD(sil_witness_table) SIL_KEYWORD(sil_default_witness_table) +SIL_KEYWORD(sil_differentiability_witness) SIL_KEYWORD(sil_coverage_map) SIL_KEYWORD(sil_scope) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ef6969430da40..0743cc7c8b29c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Copyright (c) 2014 - 2020 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 @@ -224,6 +224,9 @@ struct ASTContext::Implementation { #define FUNC_DECL(Name, Id) FuncDecl *Get##Name = nullptr; #include "swift/AST/KnownDecls.def" + /// func Bool + FuncDecl *LessThanIntDecl = nullptr; + /// func ==(Int, Int) -> Bool FuncDecl *EqualIntDecl = nullptr; @@ -1083,30 +1086,37 @@ ASTContext::getBuiltinInitDecl(NominalTypeDecl *decl, return witness; } -FuncDecl *ASTContext::getEqualIntDecl() const { - if (getImpl().EqualIntDecl) - return getImpl().EqualIntDecl; +static +FuncDecl *getBinaryComparisonOperatorIntDecl(const ASTContext &C, StringRef op, FuncDecl *&cached) { + if (cached) + return cached; - if (!getIntDecl() || !getBoolDecl()) + if (!C.getIntDecl() || !C.getBoolDecl()) return nullptr; - auto intType = getIntDecl()->getDeclaredType(); + auto intType = C.getIntDecl()->getDeclaredType(); auto isIntParam = [&](AnyFunctionType::Param param) { return (!param.isVariadic() && !param.isInOut() && param.getPlainType()->isEqual(intType)); }; - auto boolType = getBoolDecl()->getDeclaredType(); - auto decl = lookupOperatorFunc(*this, "==", - intType, [=](FunctionType *type) { + auto boolType = C.getBoolDecl()->getDeclaredType(); + auto decl = lookupOperatorFunc(C, op, intType, + [=](FunctionType *type) { // Check for the signature: (Int, Int) -> Bool if (type->getParams().size() != 2) return false; if (!isIntParam(type->getParams()[0]) || !isIntParam(type->getParams()[1])) return false; return type->getResult()->isEqual(boolType); }); - getImpl().EqualIntDecl = decl; + cached = decl; return decl; } +FuncDecl *ASTContext::getLessThanIntDecl() const { + return getBinaryComparisonOperatorIntDecl(*this, "<", getImpl().LessThanIntDecl); +} +FuncDecl *ASTContext::getEqualIntDecl() const { + return getBinaryComparisonOperatorIntDecl(*this, "==", getImpl().EqualIntDecl); +} FuncDecl *ASTContext::getHashValueForDecl() const { if (getImpl().HashValueForDecl) @@ -2431,7 +2441,8 @@ AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD, if (isInitializingCtor) { // initializing constructors of value types always have an implicitly // inout self. - selfAccess = SelfAccessKind::Mutating; + if (!containerTy->hasReferenceSemantics()) + selfAccess = SelfAccessKind::Mutating; } else { // allocating constructors have metatype 'self'. isStatic = true; @@ -2459,10 +2470,6 @@ AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD, if (isStatic) return AnyFunctionType::Param(MetatypeType::get(selfTy, Ctx)); - // Reference types have 'self' of type T. - if (containerTy->hasReferenceSemantics()) - return AnyFunctionType::Param(selfTy); - auto flags = ParameterTypeFlags(); switch (selfAccess) { case SelfAccessKind::Consuming: @@ -4394,6 +4401,18 @@ ASTContext::getClangFunctionType(ArrayRef params, return impl.Converter.getValue().getFunctionType(params, resultTy, trueRep); } +const Decl * +ASTContext::getSwiftDeclForExportedClangDecl(const clang::Decl *decl) { + auto &impl = getImpl(); + + // If we haven't exported anything yet, this must not be how we found + // this declaration. + if (!impl.Converter) return nullptr; + + return impl.Converter->getSwiftDeclForExportedClangDecl(decl); +} + + CanGenericSignature ASTContext::getSingleGenericParameterSignature() const { if (auto theSig = getImpl().SingleGenericParameterSignature) return theSig; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index ae20364d0bb82..2a34900d480df 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -17,6 +17,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" +#include "swift/AST/ClangModuleLoader.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" @@ -3762,6 +3763,10 @@ void Type::dump() const { } void Type::dump(raw_ostream &os, unsigned indent) const { + #if SWIFT_BUILD_ONLY_SYNTAXPARSERLIB + return; // not needed for the parser library. + #endif + PrintType(os, indent).visit(*this, ""); os << "\n"; } @@ -3804,3 +3809,44 @@ StringRef swift::getAccessorKindString(AccessorKind value) { llvm_unreachable("Unhandled AccessorKind in switch."); } + +void StableSerializationPath::dump() const { + dump(llvm::errs()); +} + +static StringRef getExternalPathComponentKindString( + StableSerializationPath::ExternalPath::ComponentKind kind) { + switch (kind) { +#define CASE(ID, STRING) \ + case StableSerializationPath::ExternalPath::ID: return STRING; + CASE(Record, "record") + CASE(Enum, "enum") + CASE(Namespace, "namespace") + CASE(Typedef, "typedef") + CASE(TypedefAnonDecl, "anonymous tag") + CASE(ObjCInterface, "@interface") + CASE(ObjCProtocol, "@protocol") +#undef CASE + } + llvm_unreachable("bad kind"); +} + +void StableSerializationPath::dump(llvm::raw_ostream &os) const { + if (isSwiftDecl()) { + os << "clang decl of:\n"; + getSwiftDecl()->dump(os, 2); + } else { + auto &path = getExternalPath(); + using ExternalPath = StableSerializationPath::ExternalPath; + os << "external path: "; + size_t index = 0; + for (auto &entry : path.Path) { + if (index++) os << " -> "; + os << getExternalPathComponentKindString(entry.first); + if (ExternalPath::requiresIdentifier(entry.first)) { + os << "(" << entry.second << ")"; + } + } + os << "\n"; + } +} diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 1b7383421e320..6737ceed42f6e 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -379,6 +379,27 @@ std::string ASTMangler::mangleReabstractionThunkHelper( return finalize(); } +std::string ASTMangler::mangleSILDifferentiabilityWitnessKey( + SILDifferentiabilityWitnessKey key) { + // TODO(TF-20): Make the mangling scheme robust. Support demangling. + beginManglingWithoutPrefix(); + + auto originalName = key.first; + auto *parameterIndices = key.second.parameterIndices; + auto *resultIndices = key.second.resultIndices; + auto derivativeGenericSignature = key.second.derivativeGenericSignature; + + Buffer << "AD__" << originalName << '_'; + Buffer << "P" << parameterIndices->getString(); + Buffer << "R" << resultIndices->getString(); + if (derivativeGenericSignature) + appendGenericSignature(derivativeGenericSignature); + + auto result = Storage.str().str(); + Storage.clear(); + return result; +} + std::string ASTMangler::mangleTypeForDebugger(Type Ty, const DeclContext *DC) { PrettyStackTraceType prettyStackTrace(Ty->getASTContext(), "mangling type for debugger", Ty); diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index eeabdf4de8a65..45cc7d59752a5 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3529,24 +3529,7 @@ class TypePrinter : public TypeVisitor { return; } - bool isSimple = T->hasSimpleTypeRepr(); - if (!isSimple && T->is()) { - auto opaqueTy = T->castTo(); - switch (Options.OpaqueReturnTypePrinting) { - case PrintOptions::OpaqueReturnTypePrintingMode::StableReference: - case PrintOptions::OpaqueReturnTypePrintingMode::Description: - isSimple = true; - break; - case PrintOptions::OpaqueReturnTypePrintingMode::WithOpaqueKeyword: - isSimple = false; - break; - case PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword: { - isSimple = opaqueTy->getExistentialType()->hasSimpleTypeRepr(); - break; - } - } - } - + bool isSimple = isSimpleUnderPrintOptions(T); if (isSimple) { visit(T); } else { @@ -3556,6 +3539,28 @@ class TypePrinter : public TypeVisitor { } } + /// Determinee whether the given type has a simple representation + /// under the current print options. + bool isSimpleUnderPrintOptions(Type T) { + if (auto typealias = dyn_cast(T.getPointer())) { + if (shouldDesugarTypeAliasType(typealias)) + return isSimpleUnderPrintOptions(typealias->getSinglyDesugaredType()); + } else if (auto opaque = + dyn_cast(T.getPointer())) { + switch (Options.OpaqueReturnTypePrinting) { + case PrintOptions::OpaqueReturnTypePrintingMode::StableReference: + case PrintOptions::OpaqueReturnTypePrintingMode::Description: + return true; + case PrintOptions::OpaqueReturnTypePrintingMode::WithOpaqueKeyword: + return false; + case PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword: + return isSimpleUnderPrintOptions(opaque->getExistentialType()); + } + llvm_unreachable("bad opaque-return-type printing mode"); + } + return T->hasSimpleTypeRepr(); + } + template void printModuleContext(T *Ty) { FileUnit *File = cast(Ty->getDecl()->getModuleScopeContext()); @@ -3693,8 +3698,12 @@ class TypePrinter : public TypeVisitor { Printer << BUILTIN_TYPE_NAME_SILTOKEN; } + bool shouldDesugarTypeAliasType(TypeAliasType *T) { + return Options.PrintForSIL || Options.PrintTypeAliasUnderlyingType; + } + void visitTypeAliasType(TypeAliasType *T) { - if (Options.PrintForSIL || Options.PrintTypeAliasUnderlyingType) { + if (shouldDesugarTypeAliasType(T)) { visit(T->getSinglyDesugaredType()); return; } diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 004a848a870d6..95e7113bc7ef7 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -774,7 +774,7 @@ class Traversal : public ASTVisitorgetBody()) { diff --git a/lib/AST/AutoDiff.cpp b/lib/AST/AutoDiff.cpp index fa99620c4ab64..c1d20b10c86e3 100644 --- a/lib/AST/AutoDiff.cpp +++ b/lib/AST/AutoDiff.cpp @@ -11,10 +11,24 @@ //===----------------------------------------------------------------------===// #include "swift/AST/AutoDiff.h" +#include "swift/AST/ASTContext.h" +#include "swift/AST/TypeCheckRequests.h" #include "swift/AST/Types.h" using namespace swift; +void AutoDiffConfig::print(llvm::raw_ostream &s) const { + s << "(parameters="; + parameterIndices->print(s); + s << " results="; + resultIndices->print(s); + if (derivativeGenericSignature) { + s << " where="; + derivativeGenericSignature->print(s); + } + s << ')'; +} + // TODO(TF-874): This helper is inefficient and should be removed. Unwrapping at // most once (for curried method types) is sufficient. static void unwrapCurryLevels(AnyFunctionType *fnTy, @@ -67,6 +81,31 @@ void autodiff::getSubsetParameterTypes(IndexSubset *subset, } } +GenericSignature autodiff::getConstrainedDerivativeGenericSignature( + SILFunctionType *originalFnTy, IndexSubset *diffParamIndices, + GenericSignature derivativeGenSig) { + if (!derivativeGenSig) + derivativeGenSig = originalFnTy->getSubstGenericSignature(); + if (!derivativeGenSig) + return nullptr; + // Constrain all differentiability parameters to `Differentiable`. + auto &ctx = originalFnTy->getASTContext(); + auto *diffableProto = ctx.getProtocol(KnownProtocolKind::Differentiable); + SmallVector requirements; + for (unsigned paramIdx : diffParamIndices->getIndices()) { + auto paramType = originalFnTy->getParameters()[paramIdx].getInterfaceType(); + Requirement req(RequirementKind::Conformance, paramType, + diffableProto->getDeclaredType()); + requirements.push_back(req); + } + return evaluateOrDefault( + ctx.evaluator, + AbstractGenericSignatureRequest{derivativeGenSig.getPointer(), + /*addedGenericParams*/ {}, + std::move(requirements)}, + nullptr); +} + Type TangentSpace::getType() const { switch (kind) { case Kind::TangentVector: diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index 538924ed8a23b..251783aac808c 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -243,7 +243,7 @@ AvailabilityContext ASTContext::getTypesInAbstractMetadataStateAvailability() { } AvailabilityContext ASTContext::getPrespecializedGenericMetadataAvailability() { - return getSwiftFutureAvailability(); + return getSwift53Availability(); } AvailabilityContext ASTContext::getSwift52Availability() { @@ -263,6 +263,23 @@ AvailabilityContext ASTContext::getSwift52Availability() { } } +AvailabilityContext ASTContext::getSwift53Availability() { + auto target = LangOpts.Target; + + if (target.isMacOSX() ) { + return AvailabilityContext( + VersionRange::allGTE(llvm::VersionTuple(10, 99, 0))); + } else if (target.isiOS()) { + return AvailabilityContext( + VersionRange::allGTE(llvm::VersionTuple(99, 0, 0))); + } else if (target.isWatchOS()) { + return AvailabilityContext( + VersionRange::allGTE(llvm::VersionTuple(9, 99, 0))); + } else { + return AvailabilityContext::alwaysAvailable(); + } +} + AvailabilityContext ASTContext::getSwiftFutureAvailability() { auto target = LangOpts.Target; diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index 818d7ffb112d2..262f0222dcb77 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -940,6 +940,38 @@ static ValueDecl *getGlobalStringTablePointer(ASTContext &Context, return getBuiltinFunction(Id, {stringType}, Context.TheRawPointerType); } +static ValueDecl *getConvertStrongToUnownedUnsafe(ASTContext &ctx, + Identifier id) { + // We actually want this: + // + // (T, inout unowned (unsafe) T) -> () + // + // But for simplicity, we actually accept T, U and do the checking + // in the emission method that everything works up. This is a + // builtin, so we can crash. + BuiltinFunctionBuilder builder(ctx, 2); + builder.addParameter(makeGenericParam(0)); + builder.addParameter(makeGenericParam(1), ValueOwnership::InOut); + builder.setResult(makeConcrete(TupleType::getEmpty(ctx))); + return builder.build(id); +} + +static ValueDecl *getConvertUnownedUnsafeToGuaranteed(ASTContext &ctx, + Identifier id) { + // We actually want this: + // + /// (BaseT, @inout unowned(unsafe) T) -> T + // + // But for simplicity, we actually accept three generic params T, U and do the + // checking in the emission method that everything works up. This is a + // builtin, so we can crash. + BuiltinFunctionBuilder builder(ctx, 3); + builder.addParameter(makeGenericParam(0)); // Base + builder.addParameter(makeGenericParam(1), ValueOwnership::InOut); // Unmanaged + builder.setResult(makeGenericParam(2)); // Guaranteed Result + return builder.build(id); +} + static ValueDecl *getPoundAssert(ASTContext &Context, Identifier Id) { auto int1Type = BuiltinIntegerType::get(1, Context); auto optionalRawPointerType = BoundGenericEnumType::get( @@ -1996,6 +2028,12 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::GlobalStringTablePointer: return getGlobalStringTablePointer(Context, Id); + case BuiltinValueKind::ConvertStrongToUnownedUnsafe: + return getConvertStrongToUnownedUnsafe(Context, Id); + + case BuiltinValueKind::ConvertUnownedUnsafeToGuaranteed: + return getConvertUnownedUnsafeToGuaranteed(Context, Id); + case BuiltinValueKind::PoundAssert: return getPoundAssert(Context, Id); diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 45a6911b110b7..b5fa70c93317a 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -44,7 +44,6 @@ add_swift_host_library(swiftAST STATIC Evaluator.cpp Expr.cpp FineGrainedDependencies.cpp - FineGrainedDependenciesSourceFileDepGraphConstructor.cpp GenericEnvironment.cpp GenericSignature.cpp GenericSignatureBuilder.cpp @@ -68,6 +67,7 @@ add_swift_host_library(swiftAST STATIC RequirementEnvironment.cpp SyntaxASTMap.cpp SILLayout.cpp + SourceFileDepGraphConstructor.cpp Stmt.cpp SubstitutionMap.cpp SwiftNameTranslation.cpp diff --git a/lib/AST/ClangTypeConverter.cpp b/lib/AST/ClangTypeConverter.cpp index 56b07d0dcd17b..14b9aec5f289f 100644 --- a/lib/AST/ClangTypeConverter.cpp +++ b/lib/AST/ClangTypeConverter.cpp @@ -397,6 +397,8 @@ clang::QualType ClangTypeConverter::visitProtocolType(ProtocolType *type) { PDecl->getASTContext(), proto->getObjCRuntimeName(runtimeNameBuffer))); + registerExportedClangDecl(proto, PDecl); + auto clangType = clangCtx.getObjCObjectType(clangCtx.ObjCBuiltinIdTy, &PDecl, 1); return clangCtx.getObjCObjectPointerType(clangType); @@ -446,6 +448,8 @@ clang::QualType ClangTypeConverter::visitClassType(ClassType *type) { CDecl->getASTContext(), swiftDecl->getObjCRuntimeName(runtimeNameBuffer))); + registerExportedClangDecl(swiftDecl, CDecl); + auto clangType = clangCtx.getObjCInterfaceType(CDecl); return clangCtx.getObjCObjectPointerType(clangType); } @@ -726,3 +730,19 @@ clang::QualType ClangTypeConverter::convert(Type type) { Cache.insert({type, result}); return result; } + +void ClangTypeConverter::registerExportedClangDecl(Decl *swiftDecl, + const clang::Decl *clangDecl) { + assert(clangDecl->isCanonicalDecl() && + "generated Clang declaration for Swift declaration should not " + "have multiple declarations"); + ReversedExportMap.insert({clangDecl, swiftDecl}); +} + +Decl *ClangTypeConverter::getSwiftDeclForExportedClangDecl( + const clang::Decl *decl) const { + // We don't need to canonicalize the declaration because these exported + // declarations are never redeclarations. + auto it = ReversedExportMap.find(decl); + return (it != ReversedExportMap.end() ? it->second : nullptr); +} diff --git a/lib/AST/ClangTypeConverter.h b/lib/AST/ClangTypeConverter.h index b25f6b6dffb92..450b9e30cf19a 100644 --- a/lib/AST/ClangTypeConverter.h +++ b/lib/AST/ClangTypeConverter.h @@ -33,6 +33,7 @@ class ClangTypeConverter : using super = TypeVisitor; llvm::DenseMap Cache; + llvm::DenseMap ReversedExportMap; bool StdlibTypesAreCached = false; @@ -73,11 +74,19 @@ class ClangTypeConverter : ArrayRef params, Type resultTy, AnyFunctionType::Representation repr); + /// Check whether the given Clang declaration is an export of a Swift + /// declaration introduced by this converter, and if so, return the original + /// Swift declaration. + Decl *getSwiftDeclForExportedClangDecl(const clang::Decl *decl) const; + private: clang::QualType convert(Type type); clang::QualType convertMemberType(NominalTypeDecl *DC, StringRef memberName); + void registerExportedClangDecl(Decl *swiftDecl, + const clang::Decl *clangDecl); + clang::QualType reverseBuiltinTypeMapping(StructType *type); friend TypeVisitor; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 25f90c3d45002..8bdb94abff1c9 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -5312,6 +5312,7 @@ VarDecl::VarDecl(DeclKind kind, bool isStatic, VarDecl::Introducer introducer, Bits.VarDecl.IsLazyStorageProperty = false; Bits.VarDecl.HasNonPatternBindingInit = false; Bits.VarDecl.IsPropertyWrapperBackingProperty = false; + Bits.VarDecl.IsTopLevelGlobal = false; } Type VarDecl::getType() const { @@ -5410,11 +5411,7 @@ bool VarDecl::isLazilyInitializedGlobal() const { // Top-level global variables in the main source file and in the REPL are not // lazily initialized. - auto sourceFileContext = dyn_cast(getDeclContext()); - if (!sourceFileContext) - return true; - - return !sourceFileContext->isScriptMode(); + return !isTopLevelGlobal(); } SourceRange VarDecl::getSourceRange() const { diff --git a/lib/AST/FineGrainedDependencies.cpp b/lib/AST/FineGrainedDependencies.cpp index 69256f1cffc93..278fa6538a75e 100644 --- a/lib/AST/FineGrainedDependencies.cpp +++ b/lib/AST/FineGrainedDependencies.cpp @@ -15,10 +15,15 @@ #include "swift/AST/FineGrainedDependencies.h" // may not all be needed +#include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticsCommon.h" +#include "swift/AST/DiagnosticsFrontend.h" +#include "swift/AST/FileSystem.h" #include "swift/Basic/FileSystem.h" #include "swift/Basic/LLVM.h" #include "swift/Demangling/Demangle.h" #include "swift/Frontend/FrontendOptions.h" + #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" @@ -34,6 +39,28 @@ using namespace swift; using namespace fine_grained_dependencies; +//============================================================================== +// MARK: Emitting and reading SourceFileDepGraph +//============================================================================== + +Optional SourceFileDepGraph::loadFromPath(StringRef path) { + auto bufferOrError = llvm::MemoryBuffer::getFile(path); + if (!bufferOrError) + return None; + return loadFromBuffer(*bufferOrError.get()); +} + +Optional +SourceFileDepGraph::loadFromBuffer(llvm::MemoryBuffer &buffer) { + SourceFileDepGraph fg; + llvm::yaml::Input yamlReader(llvm::MemoryBufferRef(buffer), nullptr); + yamlReader >> fg; + if (yamlReader.error()) + return None; + // return fg; compiles for Mac but not Linux, because it cannot be copied. + return Optional(std::move(fg)); +} + //============================================================================== // MARK: SourceFileDepGraph access //============================================================================== @@ -229,6 +256,23 @@ raw_ostream &fine_grained_dependencies::operator<<(raw_ostream &out, bool DependencyKey::verify() const { assert((getKind() != NodeKind::externalDepend || isInterface()) && "All external dependencies must be interfaces."); + switch (getKind()) { + case NodeKind::topLevel: + case NodeKind::dynamicLookup: + case NodeKind::externalDepend: + case NodeKind::sourceFileProvide: + assert(context.empty() && !name.empty() && "Must only have a name"); + break; + case NodeKind::nominal: + case NodeKind::potentialMember: + assert(!context.empty() && name.empty() && "Must only have a context"); + break; + case NodeKind::member: + assert(!context.empty() && !name.empty() && "Must have both"); + break; + case NodeKind::kindCount: + llvm_unreachable("impossible"); + } return true; } @@ -300,6 +344,15 @@ void SourceFileDepGraph::verifySame(const SourceFileDepGraph &other) const { #endif } +void SourceFileDepGraph::emitDotFile(StringRef outputPath, + DiagnosticEngine &diags) { + std::string dotFileName = outputPath.str() + ".dot"; + withOutputFile(diags, dotFileName, [&](llvm::raw_pwrite_stream &out) { + DotFileEmitter(out, *this, false, false).emit(); + return false; + }); +} + //============================================================================== // MARK: SourceFileDepGraph YAML reading & writing //============================================================================== diff --git a/lib/AST/IndexSubset.cpp b/lib/AST/IndexSubset.cpp index fe64ee07d58ca..d5be9aa53363e 100644 --- a/lib/AST/IndexSubset.cpp +++ b/lib/AST/IndexSubset.cpp @@ -125,7 +125,7 @@ int IndexSubset::findPrevious(int endIndex) const { offset = (int)indexAndOffset.second - 1; } for (; bitWordIndex >= 0; --bitWordIndex, offset = numBitsPerBitWord - 1) { - for (; offset < (int)numBitsPerBitWord; --offset) { + for (; offset >= 0; --offset) { auto index = bitWordIndex * (int)numBitsPerBitWord + offset; auto bitWord = getBitWord(bitWordIndex); if (!bitWord) diff --git a/lib/AST/PrettyStackTrace.cpp b/lib/AST/PrettyStackTrace.cpp index 893a83502d1fd..837027427fb1e 100644 --- a/lib/AST/PrettyStackTrace.cpp +++ b/lib/AST/PrettyStackTrace.cpp @@ -27,6 +27,7 @@ #include "swift/AST/TypeRepr.h" #include "swift/AST/TypeVisitor.h" #include "swift/Basic/SourceManager.h" +#include "clang/AST/Type.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/MemoryBuffer.h" @@ -209,6 +210,15 @@ void swift::printTypeDescription(llvm::raw_ostream &out, Type type, if (addNewline) out << '\n'; } +void PrettyStackTraceClangType::print(llvm::raw_ostream &out) const { + out << "While " << Action << ' '; + if (TheType == nullptr) { + out << "NULL clang type!\n"; + return; + } + TheType->dump(out); +} + void PrettyStackTraceTypeRepr::print(llvm::raw_ostream &out) const { out << "While " << Action << " type "; TheType->print(out); @@ -263,3 +273,18 @@ void PrettyStackTraceGenericSignature::print(llvm::raw_ostream &out) const { void PrettyStackTraceSelector::print(llvm::raw_ostream &out) const { out << "While " << Action << " '" << Selector << "'"; } + +void PrettyStackTraceDifferentiabilityWitness::print( + llvm::raw_ostream &out) const { + out << "While " << Action << ' '; + printDifferentiabilityWitnessDescription(out, Key); +} + +void swift::printDifferentiabilityWitnessDescription( + llvm::raw_ostream &out, const SILDifferentiabilityWitnessKey key, + bool addNewline) { + out << key.first << " "; + key.second.print(out); + if (addNewline) + out << '\n'; +} diff --git a/lib/AST/FineGrainedDependenciesSourceFileDepGraphConstructor.cpp b/lib/AST/SourceFileDepGraphConstructor.cpp similarity index 91% rename from lib/AST/FineGrainedDependenciesSourceFileDepGraphConstructor.cpp rename to lib/AST/SourceFileDepGraphConstructor.cpp index 41df94b5fab71..fc87e2cb59b21 100644 --- a/lib/AST/FineGrainedDependenciesSourceFileDepGraphConstructor.cpp +++ b/lib/AST/SourceFileDepGraphConstructor.cpp @@ -46,32 +46,6 @@ using namespace swift; using namespace fine_grained_dependencies; -//============================================================================== -// MARK: Emitting and reading SourceFileDepGraph -//============================================================================== - -Optional SourceFileDepGraph::loadFromPath(StringRef path) { - auto bufferOrError = llvm::MemoryBuffer::getFile(path); - if (!bufferOrError) - return None; - return loadFromBuffer(*bufferOrError.get()); -} - -Optional -SourceFileDepGraph::loadFromBuffer(llvm::MemoryBuffer &buffer) { - SourceFileDepGraph fg; - llvm::yaml::Input yamlReader(llvm::MemoryBufferRef(buffer), nullptr); - yamlReader >> fg; - if (yamlReader.error()) - return None; - // return fg; compiles for Mac but not Linux, because it cannot be copied. - return Optional(std::move(fg)); -} - -//============================================================================== -// MARK: Start of SourceFileDepGraph building, specific to status quo -//============================================================================== - //============================================================================== // MARK: Helpers for key construction that must be in frontend //============================================================================== @@ -501,7 +475,7 @@ class SourceFileDepGraphConstructor { /// a flag indicating if the member is private to its enclosing file, and /// a flag indicating if the dependency cascades. const std::vector, bool>> - memberDepends; + dependsWithContexts; /// The base name of a class member depended-upon for dynamic lookup, and a /// cascades flag. @@ -534,7 +508,8 @@ class SourceFileDepGraphConstructor { bool hadCompilationError, const std::string &interfaceHash, ArrayRef> topLevelDepends, - ArrayRef, bool>> memberDepends, + ArrayRef, bool>> + dependsWithContexts, ArrayRef> dynamicLookupDepends, ArrayRef externalDependencies, @@ -554,7 +529,7 @@ class SourceFileDepGraphConstructor { interfaceHash(interfaceHash), topLevelDepends(topLevelDepends), - memberDepends(memberDepends), + dependsWithContexts(dependsWithContexts), dynamicLookupDepends(dynamicLookupDepends), externalDependencies(externalDependencies), @@ -569,11 +544,15 @@ class SourceFileDepGraphConstructor { classMembers(classMembers) {} - SourceFileDepGraphConstructor static forSourceFile(SourceFile *SF, - const DependencyTracker &depTracker, - StringRef swiftDeps, - const bool includePrivateDeps, - const bool hadCompilationError) { +// clang-format off +static SourceFileDepGraphConstructor +forSourceFile( + SourceFile *SF, + const DependencyTracker &depTracker, + StringRef swiftDeps, + const bool includePrivateDeps, + const bool hadCompilationError) { +// clang-format on SourceFileDeclFinder declFinder(SF, includePrivateDeps); std::vector> topLevelDepends; @@ -584,11 +563,11 @@ class SourceFileDepGraphConstructor { for (const auto &p: SF->getReferencedNameTracker()->getDynamicLookupNames()) dynamicLookupDepends.push_back(std::make_pair(p.getFirst().userFacingName(), p.getSecond())); - std::vector, bool>> memberDepends; + std::vector, bool>> dependsWithContexts; for (const auto &p: SF->getReferencedNameTracker()->getUsedMembers()) { const auto &member = p.getFirst().second; StringRef emptyOrUserFacingName = member.empty() ? "" : member.userFacingName(); - memberDepends.push_back( + dependsWithContexts.push_back( std::make_pair( std::make_tuple( mangleTypeAsContext(p.getFirst().first), @@ -604,7 +583,7 @@ class SourceFileDepGraphConstructor { getInterfaceHash(SF), topLevelDepends, - memberDepends, + dependsWithContexts, dynamicLookupDepends, depTracker.getDependencies(), @@ -680,12 +659,10 @@ class SourceFileDepGraphConstructor { for (const auto &contextNameFingerprint : contextNameFingerprints) { auto p = g.findExistingNodePairOrCreateAndAddIfNew( kind, contextNameFingerprint); - // When we don't have a fingerprint yet, must rebuild every provider when - // interfaceHash changes. So when interface (i.e. interface hash) of - // sourceFile changes, every provides is dirty. And since we don't know - // what happened, dirtyness might affect the interface. - if (!p.getInterface()->getFingerprint().hasValue()) - g.addArc(g.getSourceFileNodePair().getInterface(), p.getInterface()); + // Since the current type fingerprints only include tokens in the body, + // when the interface hash changes, it is possible that the type in the + // file has changed. + g.addArc(g.getSourceFileNodePair().getInterface(), p.getInterface()); } } @@ -784,7 +761,7 @@ void SourceFileDepGraphConstructor::addDependencyArcsToGraph() { // TODO: express the multiple provides and depends streams with variadic // templates addAllDependenciesFrom(topLevelDepends); - addAllDependenciesFrom(memberDepends); + addAllDependenciesFrom(dependsWithContexts); addAllDependenciesFrom(dynamicLookupDepends); addAllDependenciesFrom(externalDependencies); } @@ -800,7 +777,7 @@ void SourceFileDepGraphConstructor::recordThatThisWholeFileDependsOn( // Entry point from the Frontend to this whole system //============================================================================== -bool swift::fine_grained_dependencies::emitReferenceDependencies( +bool fine_grained_dependencies::emitReferenceDependencies( DiagnosticEngine &diags, SourceFile *const SF, const DependencyTracker &depTracker, StringRef outputPath, const bool alsoEmitDotFile) { @@ -809,8 +786,16 @@ bool swift::fine_grained_dependencies::emitReferenceDependencies( // that may have been there. No error handling -- this is just a nicety, it // doesn't matter if it fails. llvm::sys::fs::rename(outputPath, outputPath + "~"); + // Since, when fingerprints are enabled, + // the parser diverts token hashing into per-body fingerprints + // before it can know if a difference is in a private type, + // in order to be able to test the changed fingerprints + // we force the inclusion of private declarations when fingerprints + // are enabled. const bool includeIntrafileDeps = - SF->getASTContext().LangOpts.FineGrainedDependenciesIncludeIntrafileOnes; + SF->getASTContext() + .LangOpts.FineGrainedDependenciesIncludeIntrafileOnes || + SF->getASTContext().LangOpts.EnableTypeFingerprints; const bool hadCompilationError = SF->getASTContext().hadError(); auto gc = SourceFileDepGraphConstructor::forSourceFile( SF, depTracker, outputPath, includeIntrafileDeps, hadCompilationError); @@ -827,13 +812,9 @@ bool swift::fine_grained_dependencies::emitReferenceDependencies( // If path is stdout, cannot read it back, so check for "-" assert(outputPath == "-" || g.verifyReadsWhatIsWritten(outputPath)); - if (alsoEmitDotFile) { - std::string dotFileName = outputPath.str() + ".dot"; - withOutputFile(diags, dotFileName, [&](llvm::raw_pwrite_stream &out) { - DotFileEmitter(out, g, false, false).emit(); - return false; - }); - } + if (alsoEmitDotFile) + g.emitDotFile(outputPath, diags); + return hadError; } @@ -843,12 +824,29 @@ bool swift::fine_grained_dependencies::emitReferenceDependencies( static StringRef stripPrefix(const StringRef name) { return name.ltrim(SourceFileDepGraph::noncascadingOrPrivatePrefix); } +static StringRef stripFingerprint(const StringRef nameAndFingerprint) { + return nameAndFingerprint.split(SourceFileDepGraph::nameFingerprintSeparator) + .first; +} +static StringRef stripName(const StringRef nameAndFingerprint) { + return nameAndFingerprint.split(SourceFileDepGraph::nameFingerprintSeparator) + .second; +} +static std::string extractName(const StringRef prefixNameFingerprint) { + return stripFingerprint(stripPrefix(prefixNameFingerprint)).str(); +} +static Optional extractFingerprint( + const StringRef prefixNameFingerprint) { + const auto fp = stripName(stripPrefix(prefixNameFingerprint)); + return fp.empty() ? None : Optional(fp.str()); +} static std::vector getBaseNameProvides(ArrayRef simpleNames) { std::vector result; for (StringRef n : simpleNames) - result.push_back(ContextNameFingerprint("", stripPrefix(n).str(), None)); + result.push_back(ContextNameFingerprint("", extractName(n), + extractFingerprint(n))); return result; } @@ -856,7 +854,8 @@ static std::vector getMangledHolderProvides(ArrayRef simpleNames) { std::vector result; for (StringRef n : simpleNames) - result.push_back(ContextNameFingerprint(stripPrefix(n).str(), "", None)); + result.push_back(ContextNameFingerprint(extractName(n), "", + extractFingerprint(n))); return result; } @@ -864,12 +863,15 @@ static std::vector getCompoundProvides( ArrayRef> compoundNames) { std::vector result; for (const auto &p : compoundNames) - result.push_back(ContextNameFingerprint(stripPrefix(p.first), - stripPrefix(p.second), None)); + result.push_back(ContextNameFingerprint(extractName(p.first), + extractName(p.second), + extractFingerprint(p.second))); return result; } -static bool cascades(const std::string &s) { return s.empty() || s[0] != SourceFileDepGraph::noncascadingOrPrivatePrefix; } +static bool cascades(const std::string &s) { + return s.empty() || s[0] != SourceFileDepGraph::noncascadingOrPrivatePrefix; +} // Use '_' as a prefix for a file-private member static bool isPrivate(const std::string &s) { @@ -899,7 +901,8 @@ getCompoundDepends( // (On Linux, the compiler needs more verbosity than: // result.push_back({{n, "", false}, cascades(n)}); result.push_back( - std::make_pair(std::make_tuple(stripPrefix(n), std::string(), false), cascades(n))); + std::make_pair(std::make_tuple(stripPrefix(n), std::string(), false), + cascades(n))); } for (auto &p : compoundNames) { // Likewise, for Linux expand the following out: @@ -925,15 +928,19 @@ SourceFileDepGraph SourceFileDepGraph::simulateLoad( // clang-format off SourceFileDepGraphConstructor c( - swiftDepsFilename, includePrivateDeps, hadCompilationError, interfaceHash, + swiftDepsFilename, + includePrivateDeps, + hadCompilationError, + interfaceHash, getSimpleDepends(simpleNamesByRDK[dependsTopLevel]), - getCompoundDepends(simpleNamesByRDK[dependsNominal], compoundNamesByRDK[dependsMember]), + getCompoundDepends(simpleNamesByRDK[dependsNominal], + compoundNamesByRDK[dependsMember]), getSimpleDepends(simpleNamesByRDK[dependsDynamicLookup]), getExternalDepends(simpleNamesByRDK[dependsExternal]), {}, // precedence groups {}, // memberOperatorDecls {}, // operators - getMangledHolderProvides(simpleNamesByRDK[providesNominal]), // topNominals + {}, // topNominals getBaseNameProvides(simpleNamesByRDK[providesTopLevel]), // topValues getMangledHolderProvides(simpleNamesByRDK[providesNominal]), // allNominals getMangledHolderProvides(simpleNamesByRDK[providesNominal]), // potentialMemberHolders diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index fd60da8ff5379..491de85f96bb9 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -21,8 +21,8 @@ function(generate_revision_inc revision_inc_var name dir) add_custom_command(OUTPUT "${version_inc}" DEPENDS "${${name}_vc}" "${generate_vcs_version_script}" - COMMAND ${CMAKE_COMMAND} "-DNAMES=$" - "-D$_SOURCE_DIR=${dir}" + COMMAND ${CMAKE_COMMAND} "-DNAMES=$" + "-D$_SOURCE_DIR=${dir}" "-DHEADER_FILE=${version_inc}" -P "${generate_vcs_version_script}") diff --git a/lib/Basic/SourceLoc.cpp b/lib/Basic/SourceLoc.cpp index 7c66731e41fe1..76547ff2e91f6 100644 --- a/lib/Basic/SourceLoc.cpp +++ b/lib/Basic/SourceLoc.cpp @@ -331,10 +331,20 @@ SourceManager::resolveOffsetForEndOfLine(unsigned BufferId, return resolveFromLineCol(BufferId, Line, ~0u); } +llvm::Optional +SourceManager::getLineLength(unsigned BufferId, unsigned Line) const { + auto BegOffset = resolveFromLineCol(BufferId, Line, 0); + auto EndOffset = resolveFromLineCol(BufferId, Line, ~0u); + if (BegOffset && EndOffset) { + return EndOffset.getValue() - BegOffset.getValue(); + } + return None; +} + llvm::Optional SourceManager::resolveFromLineCol(unsigned BufferId, unsigned Line, unsigned Col) const { - if (Line == 0 || Col == 0) { + if (Line == 0) { return None; } const bool LineEnd = Col == ~0u; @@ -353,6 +363,9 @@ llvm::Optional SourceManager::resolveFromLineCol(unsigned BufferId, return None; } Ptr = LineStart; + if (Col == 0) { + return Ptr - InputBuf->getBufferStart(); + } // The <= here is to allow for non-inclusive range end positions at EOF for (; ; ++Ptr) { --Col; diff --git a/lib/ClangImporter/CMakeLists.txt b/lib/ClangImporter/CMakeLists.txt index 6417184633427..d1fb2a6f8d0a0 100644 --- a/lib/ClangImporter/CMakeLists.txt +++ b/lib/ClangImporter/CMakeLists.txt @@ -17,6 +17,7 @@ add_swift_host_library(swiftClangImporter STATIC ImportMacro.cpp ImportName.cpp ImportType.cpp + Serializability.cpp SwiftLookupTable.cpp ) target_link_libraries(swiftClangImporter PRIVATE diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index f879e383d7bf1..8bf7829eaf9fc 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -3035,33 +3035,25 @@ void ClangImporter::loadObjCMethods( // Collect the set of visible Objective-C methods with this selector. clang::Selector clangSelector = Impl.exportSelector(selector); - SmallVector objcMethods; - auto &sema = Impl.Instance->getSema(); - sema.CollectMultipleMethodsInGlobalPool(clangSelector, objcMethods, - isInstanceMethod, - /*CheckTheOther=*/false); - // Check whether this method is in the class we care about. - SmallVector foundMethods; - for (auto objcMethod : objcMethods) { - // Find the owner of this method and determine whether it is the class - // we're looking for. - if (objcMethod->getClassInterface() != objcClass) - continue; + AbstractFunctionDecl *method = nullptr; + auto *objcMethod = objcClass->lookupMethod( + clangSelector, isInstanceMethod, + /*shallowCategoryLookup=*/false, + /*followSuper=*/false); + if (objcMethod) { // If we found a property accessor, import the property. if (objcMethod->isPropertyAccessor()) (void)Impl.importDecl(objcMethod->findPropertyDecl(true), Impl.CurrentVersion); - if (auto method = dyn_cast_or_null( - Impl.importDecl(objcMethod, Impl.CurrentVersion))) { - foundMethods.push_back(method); - } + method = dyn_cast_or_null( + Impl.importDecl(objcMethod, Impl.CurrentVersion)); } // If we didn't find anything, we're done. - if (foundMethods.empty()) + if (method == nullptr) return; // If we did find something, it might be a duplicate of something we found @@ -3070,10 +3062,9 @@ void ClangImporter::loadObjCMethods( // FIXME: We shouldn't need to do this. llvm::SmallPtrSet known; known.insert(methods.begin(), methods.end()); - for (auto method : foundMethods) { - if (known.insert(method).second) - methods.push_back(method); - } + + if (known.insert(method).second) + methods.push_back(method); } void @@ -3734,33 +3725,12 @@ void ClangImporter::Implementation::lookupAllObjCMembers( } } -// Force the members of the entire inheritance hierarchy to be loaded and -// deserialized before loading the named member of this class. This allows the -// decl members table to be warmed up and enables the correct identification of -// overrides. -// -// FIXME: Very low hanging fruit: Loading everything is extremely wasteful. We -// should be able to just load the name lazy member loading is asking for. -static void ensureSuperclassMembersAreLoaded(const ClassDecl *CD) { - if (!CD) - return; - - CD = CD->getSuperclassDecl(); - if (!CD || !CD->hasClangNode()) - return; - - CD->loadAllMembers(); - - for (auto *ED : const_cast(CD)->getExtensions()) - ED->loadAllMembers(); -} - Optional> ClangImporter::Implementation::loadNamedMembers( const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) { auto *D = IDC->getDecl(); - auto *DC = cast(D); + auto *DC = D->getInnermostDeclContext(); auto *CD = D->getClangDecl(); auto *CDC = cast(CD); assert(CD && "loadNamedMembers on a Decl without a clangDecl"); @@ -3768,18 +3738,6 @@ ClangImporter::Implementation::loadNamedMembers( auto *nominal = DC->getSelfNominalTypeDecl(); auto effectiveClangContext = getEffectiveClangContext(nominal); - // FIXME: The legacy of mirroring protocol members rears its ugly head, - // and as a result we have to bail on any @interface or @category that - // has a declared protocol conformance. - if (auto *ID = dyn_cast(CD)) { - if (ID->protocol_begin() != ID->protocol_end()) - return None; - } - if (auto *CCD = dyn_cast(CD)) { - if (CCD->protocol_begin() != CCD->protocol_end()) - return None; - } - // There are 3 cases: // // - The decl is from a bridging header, CMO is Some(nullptr) @@ -3803,7 +3761,16 @@ ClangImporter::Implementation::loadNamedMembers( assert(isa(CD) || isa(CD)); - ensureSuperclassMembersAreLoaded(dyn_cast(D)); + // Force the members of the entire inheritance hierarchy to be loaded and + // deserialized before loading the named member of a class. This warms up + // ClangImporter::Implementation::MembersForNominal, used for computing + // property overrides. + // + // FIXME: If getOverriddenDecl() kicked off a request for imported decls, + // we could postpone this until overrides are actually requested. + if (auto *classDecl = dyn_cast(D)) + if (auto *superclassDecl = classDecl->getSuperclassDecl()) + (void) const_cast(superclassDecl)->lookupDirect(N); TinyPtrVector Members; for (auto entry : table->lookup(SerializedSwiftName(N), @@ -3824,6 +3791,17 @@ ClangImporter::Implementation::loadNamedMembers( Members.push_back(V); } } + + // If the property's accessors have alternate decls, we might have + // to import those too. + if (auto *ASD = dyn_cast(TD)) { + for (auto *AD : ASD->getAllAccessors()) { + for (auto *D : getAlternateDecls(AD)) { + if (D->getBaseName() == N) + Members.push_back(D); + } + } + } } } @@ -3833,7 +3811,7 @@ ClangImporter::Implementation::loadNamedMembers( auto member = entry.get(); if (!isVisibleClangEntry(member)) continue; - // Skip Decls from different clang::DeclContexts + // Skip Decls from different clang::DeclContexts if (member->getDeclContext() != CDC) continue; SmallVector tmp; @@ -3857,6 +3835,16 @@ ClangImporter::Implementation::loadNamedMembers( Members.push_back(cast(ctor)); } } + + if (!isa(D)) { + if (auto *OCD = dyn_cast(CD)) { + SmallVector newMembers; + importMirroredProtocolMembers(OCD, DC, N, newMembers); + for (auto member : newMembers) + Members.push_back(cast(member)); + } + } + return Members; } diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 505eeb8e29c8c..6cc426f87d429 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2208,6 +2208,50 @@ namespace { return {nullptr, foundMethod}; } + // Attempt to identify the redeclaration of a property. + // + // Note that this function does not perform any additional member loading and + // is therefore subject to the relativistic effects of module import order. + // That is, suppose that a Clang Module and an Overlay module are in play. + // Depending on which module loads members first, a redeclaration point may + // or may not be identifiable. + VarDecl * + identifyPropertyRedeclarationPoint(ClangImporter::Implementation &Impl, + const clang::ObjCPropertyDecl *decl, + ClassDecl *subject, Identifier name) { + llvm::SetVector lookup; + // First, pull in all available members of the base class so we can catch + // redeclarations of APIs that are refined for Swift. + auto currentMembers = subject->getCurrentMembersWithoutLoading(); + lookup.insert(currentMembers.begin(), currentMembers.end()); + + // Now pull in any just-imported members from the overrides table. + auto foundNames = Impl.MembersForNominal.find(subject); + if (foundNames != Impl.MembersForNominal.end()) { + auto foundDecls = foundNames->second.find(name); + if (foundDecls != foundNames->second.end()) { + lookup.insert(foundDecls->second.begin(), foundDecls->second.end()); + } + } + + for (auto *result : lookup) { + auto *var = dyn_cast(result); + if (!var) + continue; + + if (var->isInstanceMember() != decl->isInstanceProperty()) + continue; + + // If the selectors of the getter match in Objective-C, we have a + // redeclaration. + if (var->getObjCGetterSelector() == + Impl.importSelector(decl->getGetterName())) { + return var; + } + } + return nullptr; + } + /// Convert Clang declarations into the corresponding Swift /// declarations. class SwiftDeclConverter @@ -4522,7 +4566,8 @@ namespace { /// methods become class methods on NSObject). void importMirroredProtocolMembers(const clang::ObjCContainerDecl *decl, DeclContext *dc, - SmallVectorImpl &members); + Optional name, + SmallVectorImpl &newMembers); void importNonOverriddenMirroredMethods(DeclContext *dc, MutableArrayRef entries, @@ -5093,12 +5138,21 @@ namespace { overrideContext->getSelfNominalTypeDecl() == dc->getSelfNominalTypeDecl()) { // We've encountered a redeclaration of the property. - // HACK: Just update the original declaration instead of importing a - // second property. handlePropertyRedeclaration(overridden, decl); return nullptr; } } + + // Try searching the class for a property redeclaration. We can use + // the redeclaration to refine the already-imported property with a + // setter and also cut off any double-importing behavior. + auto *redecl + = identifyPropertyRedeclarationPoint(Impl, decl, + dc->getSelfClassDecl(), name); + if (redecl) { + handlePropertyRedeclaration(redecl, decl); + return nullptr; + } } auto importedType = Impl.importPropertyType(decl, isInSystemModule(dc)); @@ -5769,23 +5823,38 @@ Decl *SwiftDeclConverter::importEnumCaseAlias( if (!importIntoDC) importIntoDC = importedEnum; - // Construct the original constant. Enum constants without payloads look - // like simple values, but actually have type 'MyEnum.Type -> MyEnum'. - auto constantRef = - new (Impl.SwiftContext) DeclRefExpr(original, DeclNameLoc(), - /*implicit*/ true); - constantRef->setType(original->getInterfaceType()); - Type importedEnumTy = importedEnum->getDeclaredInterfaceType(); - auto typeRef = TypeExpr::createImplicit(importedEnumTy, Impl.SwiftContext); - auto instantiate = new (Impl.SwiftContext) - DotSyntaxCallExpr(constantRef, SourceLoc(), typeRef); - instantiate->setType(importedEnumTy); - instantiate->setThrows(false); + + Expr *result = nullptr; + if (auto *enumElt = dyn_cast(original)) { + assert(!enumElt->hasAssociatedValues()); + + // Construct the original constant. Enum constants without payloads look + // like simple values, but actually have type 'MyEnum.Type -> MyEnum'. + auto constantRef = + new (Impl.SwiftContext) DeclRefExpr(enumElt, DeclNameLoc(), + /*implicit*/ true); + constantRef->setType(enumElt->getInterfaceType()); + + auto instantiate = new (Impl.SwiftContext) + DotSyntaxCallExpr(constantRef, SourceLoc(), typeRef); + instantiate->setType(importedEnumTy); + instantiate->setThrows(false); + + result = instantiate; + } else { + assert(isa(original)); + + result = + new (Impl.SwiftContext) MemberRefExpr(typeRef, SourceLoc(), + original, DeclNameLoc(), + /*implicit*/ true); + result->setType(original->getInterfaceType()); + } Decl *CD = Impl.createConstant(name, importIntoDC, importedEnumTy, - instantiate, ConstantConvertKind::None, + result, ConstantConvertKind::None, /*isStatic*/ true, alias); Impl.importAttributes(alias, CD); return CD; @@ -6585,6 +6654,13 @@ SwiftDeclConverter::importSubscript(Decl *decl, if (!counterpart) return nullptr; + // If we're looking at a class but the getter was found in a protocol, + // we're going to build the subscript later when we mirror the protocol + // member. Bail out here, otherwise we'll build it twice. + if (interface && + isa(counterpart->getDeclContext())) + return nullptr; + return cast_or_null( Impl.importDecl(counterpart, getActiveSwiftVersion())); }; @@ -6929,9 +7005,16 @@ Optional SwiftDeclConverter::importObjCGenericParams( genericParams, Impl.importSourceLoc(typeParamList->getRAngleLoc())); } +void ClangImporter::Implementation::importMirroredProtocolMembers( + const clang::ObjCContainerDecl *decl, DeclContext *dc, + Optional name, SmallVectorImpl &members) { + SwiftDeclConverter converter(*this, CurrentVersion); + converter.importMirroredProtocolMembers(decl, dc, name, members); +} + void SwiftDeclConverter::importMirroredProtocolMembers( const clang::ObjCContainerDecl *decl, DeclContext *dc, - SmallVectorImpl &members) { + Optional name, SmallVectorImpl &members) { assert(dc); const clang::ObjCInterfaceDecl *interfaceDecl = nullptr; const ClangModuleUnit *declModule; @@ -6971,16 +7054,16 @@ void SwiftDeclConverter::importMirroredProtocolMembers( const auto &languageVersion = Impl.SwiftContext.LangOpts.EffectiveLanguageVersion; - for (auto member : proto->getMembers()) { + auto importProtocolRequirement = [&](Decl *member) { // Skip compatibility stubs; there's no reason to mirror them. if (member->getAttrs().isUnavailableInSwiftVersion(languageVersion)) - continue; + return; if (auto prop = dyn_cast(member)) { auto objcProp = dyn_cast_or_null(prop->getClangDecl()); if (!objcProp) - continue; + return; // We can't import a property if there's already a method with this // name. (This also covers other properties with that same name.) @@ -6988,7 +7071,7 @@ void SwiftDeclConverter::importMirroredProtocolMembers( // not already there. clang::Selector sel = objcProp->getGetterName(); if (interfaceDecl->getInstanceMethod(sel)) - continue; + return; bool inNearbyCategory = std::any_of(interfaceDecl->visible_categories_begin(), @@ -7005,7 +7088,7 @@ void SwiftDeclConverter::importMirroredProtocolMembers( return category->getInstanceMethod(sel); }); if (inNearbyCategory) - continue; + return; if (auto imported = Impl.importMirroredDecl(objcProp, dc, getVersion(), proto)) { @@ -7014,24 +7097,38 @@ void SwiftDeclConverter::importMirroredProtocolMembers( // metatype. } - continue; + return; } auto afd = dyn_cast(member); if (!afd) - continue; + return; if (isa(afd)) - continue; + return; auto objcMethod = dyn_cast_or_null(member->getClangDecl()); if (!objcMethod) - continue; + return; // For now, just remember that we saw this method. methodsByName[objcMethod->getSelector()] .push_back(MirroredMethodEntry{objcMethod, proto}); + }; + + if (name) { + // If we're asked to import a specific name only, look for that in the + // protocol. + auto results = proto->lookupDirect(*name); + for (auto *member : results) + if (member->getDeclContext() == proto) + importProtocolRequirement(member); + + } else { + // Otherwise, import all mirrored members. + for (auto *member : proto->getMembers()) + importProtocolRequirement(member); } } @@ -7175,112 +7272,108 @@ void SwiftDeclConverter::importNonOverriddenMirroredMethods(DeclContext *dc, void SwiftDeclConverter::importInheritedConstructors( const ClassDecl *classDecl, SmallVectorImpl &newMembers) { - if (!classDecl->hasSuperclass()) + auto superclassDecl = classDecl->getSuperclassDecl(); + if (!superclassDecl) + return; + + auto superclassClangDecl = superclassDecl->getClangDecl(); + if (!superclassClangDecl || + !isa(superclassClangDecl)) return; auto curObjCClass = cast(classDecl->getClangDecl()); - auto inheritConstructors = [&](TinyPtrVector members, - Optional kind) { - const auto &languageVersion = - Impl.SwiftContext.LangOpts.EffectiveLanguageVersion; + // The kind of initializer to import. If this class has designated + // initializers, everything it inherits is a convenience initializer. + Optional kind; + if (curObjCClass->hasDesignatedInitializers()) + kind = CtorInitializerKind::Convenience; - for (auto member : members) { - auto ctor = dyn_cast(member); - if (!ctor) - continue; + const auto &languageVersion = + Impl.SwiftContext.LangOpts.EffectiveLanguageVersion; - // Don't inherit compatibility stubs. - if (ctor->getAttrs().isUnavailableInSwiftVersion(languageVersion)) - continue; + auto members = superclassDecl->lookupDirect( + DeclBaseName::createConstructor()); - // Don't inherit (non-convenience) factory initializers. - // Note that convenience factories return instancetype and can be - // inherited. - switch (ctor->getInitKind()) { - case CtorInitializerKind::Factory: - continue; - case CtorInitializerKind::ConvenienceFactory: - case CtorInitializerKind::Convenience: - case CtorInitializerKind::Designated: - break; - } + for (auto member : members) { + auto ctor = dyn_cast(member); + if (!ctor) + continue; - auto objcMethod = - dyn_cast_or_null(ctor->getClangDecl()); - if (!objcMethod) - continue; + // Don't inherit compatibility stubs. + if (ctor->getAttrs().isUnavailableInSwiftVersion(languageVersion)) + continue; - auto &clangSourceMgr = Impl.getClangASTContext().getSourceManager(); - clang::PrettyStackTraceDecl trace(objcMethod, clang::SourceLocation(), - clangSourceMgr, - "importing (inherited)"); - - // If this initializer came from a factory method, inherit - // it as an initializer. - if (objcMethod->isClassMethod()) { - assert(ctor->getInitKind() == CtorInitializerKind::ConvenienceFactory); - - Optional correctSwiftName; - ImportedName importedName = - importFullName(objcMethod, correctSwiftName); - assert( - !correctSwiftName && - "Import inherited initializers never references correctSwiftName"); - importedName.setHasCustomName(); - bool redundant; - if (auto newCtor = - importConstructor(objcMethod, classDecl, - /*implicit=*/true, ctor->getInitKind(), - /*required=*/false, ctor->getObjCSelector(), - importedName, objcMethod->parameters(), - objcMethod->isVariadic(), redundant)) { - // If this is a compatibility stub, mark it as such. - if (correctSwiftName) - markAsVariant(newCtor, *correctSwiftName); - - Impl.importAttributes(objcMethod, newCtor, curObjCClass); - newMembers.push_back(newCtor); - } - continue; - } + // Don't inherit (non-convenience) factory initializers. + // Note that convenience factories return instancetype and can be + // inherited. + switch (ctor->getInitKind()) { + case CtorInitializerKind::Factory: + continue; + case CtorInitializerKind::ConvenienceFactory: + case CtorInitializerKind::Convenience: + case CtorInitializerKind::Designated: + break; + } - // Figure out what kind of constructor this will be. - CtorInitializerKind myKind; - bool isRequired = false; - if (ctor->isRequired()) { - // Required initializers are always considered designated. - isRequired = true; - myKind = CtorInitializerKind::Designated; - } else if (kind) { - myKind = *kind; - } else { - myKind = ctor->getInitKind(); - } + auto objcMethod = + dyn_cast_or_null(ctor->getClangDecl()); + if (!objcMethod) + continue; - // Import the constructor into this context. + auto &clangSourceMgr = Impl.getClangASTContext().getSourceManager(); + clang::PrettyStackTraceDecl trace(objcMethod, clang::SourceLocation(), + clangSourceMgr, + "importing (inherited)"); + + // If this initializer came from a factory method, inherit + // it as an initializer. + if (objcMethod->isClassMethod()) { + assert(ctor->getInitKind() == CtorInitializerKind::ConvenienceFactory); + + Optional correctSwiftName; + ImportedName importedName = + importFullName(objcMethod, correctSwiftName); + assert( + !correctSwiftName && + "Import inherited initializers never references correctSwiftName"); + importedName.setHasCustomName(); + bool redundant; if (auto newCtor = importConstructor(objcMethod, classDecl, - /*implicit=*/true, myKind, isRequired)) { + /*implicit=*/true, ctor->getInitKind(), + /*required=*/false, ctor->getObjCSelector(), + importedName, objcMethod->parameters(), + objcMethod->isVariadic(), redundant)) { + // If this is a compatibility stub, mark it as such. + if (correctSwiftName) + markAsVariant(newCtor, *correctSwiftName); + Impl.importAttributes(objcMethod, newCtor, curObjCClass); newMembers.push_back(newCtor); } + continue; } - }; - - // The kind of initializer to import. If this class has designated - // initializers, everything it inherits is a convenience initializer. - Optional kind; - if (curObjCClass->hasDesignatedInitializers()) - kind = CtorInitializerKind::Convenience; + // Figure out what kind of constructor this will be. + CtorInitializerKind myKind; + bool isRequired = false; + if (ctor->isRequired()) { + // Required initializers are always considered designated. + isRequired = true; + myKind = CtorInitializerKind::Designated; + } else if (kind) { + myKind = *kind; + } else { + myKind = ctor->getInitKind(); + } - // If we have a superclass, import from it. - auto superclass = classDecl->getSuperclassDecl(); - if (auto superclassClangDecl = superclass->getClangDecl()) { - if (isa(superclassClangDecl)) { - inheritConstructors(superclass->lookupDirect(DeclBaseName::createConstructor()), - kind); + // Import the constructor into this context. + if (auto newCtor = + importConstructor(objcMethod, classDecl, + /*implicit=*/true, myKind, isRequired)) { + Impl.importAttributes(objcMethod, newCtor, curObjCClass); + newMembers.push_back(newCtor); } } } @@ -8660,11 +8753,11 @@ void ClangImporter::Implementation::insertMembersAndAlternates( void ClangImporter::Implementation::importInheritedConstructors( const clang::ObjCInterfaceDecl *curObjCClass, const ClassDecl *classDecl, SmallVectorImpl &newMembers) { - if (curObjCClass->getName() != "Protocol") { - SwiftDeclConverter converter(*this, CurrentVersion); - converter.importInheritedConstructors(classDecl, newMembers); - } - } + if (curObjCClass->getName() != "Protocol") { + SwiftDeclConverter converter(*this, CurrentVersion); + converter.importInheritedConstructors(classDecl, newMembers); + } +} void ClangImporter::Implementation::collectMembersToAdd( const clang::ObjCContainerDecl *objcContainer, Decl *D, DeclContext *DC, @@ -8677,7 +8770,12 @@ void ClangImporter::Implementation::collectMembersToAdd( insertMembersAndAlternates(nd, members); } - SwiftDeclConverter converter(*this, CurrentVersion); + // Objective-C protocols don't require any special handling. + if (isa(objcContainer)) + return; + + // Objective-C interfaces can inherit constructors from their superclass, + // which we must model explicitly. if (auto clangClass = dyn_cast(objcContainer)) { objcContainer = clangClass = clangClass->getDefinition(); importInheritedConstructors(clangClass, cast(D), members); @@ -8685,10 +8783,12 @@ void ClangImporter::Implementation::collectMembersToAdd( = dyn_cast(objcContainer)) { objcContainer = clangProto->getDefinition(); } - // Import mirrored declarations for protocols to which this category - // or extension conforms. + + // Interfaces and categories can declare protocol conformances, and + // members of those protocols are mirrored into the interface or + // category. // FIXME: This is supposed to be a short-term hack. - converter.importMirroredProtocolMembers(objcContainer, DC, members); + importMirroredProtocolMembers(objcContainer, DC, None, members); } void ClangImporter::Implementation::loadAllConformances( diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 6c851d5468d8d..f39a1194c7ce1 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -818,7 +818,10 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation void importInheritedConstructors(const clang::ObjCInterfaceDecl *curObjCClass, const ClassDecl *classDecl, SmallVectorImpl &newMembers); - + void importMirroredProtocolMembers(const clang::ObjCContainerDecl *decl, + DeclContext *dc, Optional name, + SmallVectorImpl &members); + /// Utility function for building simple generic signatures. GenericSignature buildGenericSignature(GenericParamList *genericParams, DeclContext *dc); @@ -960,6 +963,22 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation bool isOverAligned(const clang::TypeDecl *typeDecl); bool isOverAligned(clang::QualType type); + /// Determines whether the given Clang type is serializable in a + /// Swift AST. This should only be called after successfully importing + /// the type, because it will look for a stable serialization path for any + /// referenced declarations, which may depend on whether there's a known + /// import of it. (It will not try to import the declaration to avoid + /// circularity problems.) + /// + /// Note that this will only check the requested sugaring of the given + /// type (depending on \c checkCanonical); the canonical type may be + /// serializable even if the non-canonical type is not, or vice-versa. + bool isSerializable(clang::QualType type, bool checkCanonical); + + /// Try to find a stable Swift serialization path for the given Clang + /// declaration. + StableSerializationPath findStableSerializationPath(const clang::Decl *decl); + /// Look up and attempt to import a Clang declaration with /// the given name. Decl *importDeclByName(StringRef name); diff --git a/lib/ClangImporter/Serializability.cpp b/lib/ClangImporter/Serializability.cpp new file mode 100644 index 0000000000000..2606964d6d078 --- /dev/null +++ b/lib/ClangImporter/Serializability.cpp @@ -0,0 +1,329 @@ +//===--- Serializability.cpp - Swift serializability of Clang AST refs ----===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file implements support for working with StableSerializationPaths +// and determining whether references to Clang declarations and types are +// serializable. +// +// The expectation here is that the same basic predicates are +// interesting for both binary (.swiftmodule) and textual +// (.swiftinterface) serialization. For textual serialization, the +// key question is whether a printed representation will round-trip. +// +//===----------------------------------------------------------------------===// + +#include "ImporterImpl.h" +#include "swift/ClangImporter/SwiftAbstractBasicWriter.h" + +using namespace swift; + +using ExternalPath = StableSerializationPath::ExternalPath; + +static bool isSameDecl(const clang::Decl *lhs, const clang::Decl *rhs) { + return lhs == rhs || lhs->getCanonicalDecl() == rhs->getCanonicalDecl(); +} + +namespace { +class SerializationPathFinder { + ClangImporter::Implementation &Impl; +public: + SerializationPathFinder(ClangImporter::Implementation &impl) : Impl(impl) {} + + StableSerializationPath find(const clang::Decl *decl) { + // We can't do anything with non-NamedDecl declarations. + auto named = dyn_cast(decl); + if (!named) return StableSerializationPath(); + + if (decl->isFromASTFile()) { + return findImportedPath(named); + } + + // If the declaration isn't from an AST file, it might be something that + // we built automatically when exporting a Swift type. + if (auto swiftDecl = + Impl.SwiftContext.getSwiftDeclForExportedClangDecl(decl)) + return swiftDecl; + + // Otherwise we have no way to find it. + return StableSerializationPath(); + } + +private: + Identifier getIdentifier(const clang::IdentifierInfo *clangIdent) { + return Impl.SwiftContext.getIdentifier(clangIdent->getName()); + } + + StableSerializationPath findImportedPath(const clang::NamedDecl *decl) { + // We've almost certainly imported this declaration, look for it. + if (auto swiftDecl = Impl.importDeclCached(decl, Impl.CurrentVersion)) { + // The serialization code doesn't allow us to cross-reference + // typealias declarations directly. We could fix that, but it's + // easier to just avoid doing so and fall into the external-path code. + if (!isa(swiftDecl)) { + // Only accept this declaration if it round-trips. + if (auto swiftClangDecl = swiftDecl->getClangDecl()) + if (isSameDecl(decl, swiftClangDecl)) + return swiftDecl; + } + } + + // Otherwise, check to see if it's something we can easily find. + ExternalPath path; + if (findExternalPath(decl, path)) + return std::move(path); + + // Otherwise we have no way to find it. + return StableSerializationPath(); + } + + bool findExternalPath(const clang::NamedDecl *decl, ExternalPath &path) { + if (auto tag = dyn_cast(decl)) + return findExternalPath(tag, path); + if (auto alias = dyn_cast(decl)) + return findExternalPath(alias, path); + if (auto proto = dyn_cast(decl)) + return findExternalPath(proto, path); + if (auto iface = dyn_cast(decl)) + return findExternalPath(iface, path); + return false; + } + + bool findExternalPath(const clang::TagDecl *decl, ExternalPath &path) { + // We can't handle class template specializations right now. + if (isa(decl)) + return false; + + // Named tags are straightforward. + if (auto name = decl->getIdentifier()) { + if (!findExternalPath(decl->getDeclContext(), path)) return false; + path.add(decl->isEnum() ? ExternalPath::Enum : ExternalPath::Record, + getIdentifier(name)); + return true; + } + + // We can handle anonymous tags if they're defined in an obvious + // position in a typedef. + if (auto alias = decl->getTypedefNameForAnonDecl()) { + auto aliasTag = alias->getAnonDeclWithTypedefName(/*any*/true); + if (aliasTag && isSameDecl(decl, aliasTag)) { + if (!findExternalPath(alias, path)) return false; + path.add(ExternalPath::TypedefAnonDecl, Identifier()); + return true; + } + } + + // Otherwise we're stuck. + return false; + } + + bool findExternalPath(const clang::TypedefNameDecl *decl, + ExternalPath &path) { + auto name = decl->getIdentifier(); + if (!name) return false; + if (!findExternalPath(decl->getDeclContext(), path)) return false; + path.add(ExternalPath::Typedef, getIdentifier(name)); + return true; + } + + bool findExternalPath(const clang::ObjCProtocolDecl *decl, + ExternalPath &path) { + auto name = decl->getIdentifier(); + if (!name) return false; + path.add(ExternalPath::ObjCProtocol, getIdentifier(name)); + return true; + } + + bool findExternalPath(const clang::ObjCInterfaceDecl *decl, + ExternalPath &path) { + auto name = decl->getIdentifier(); + if (!name) return false; + path.add(ExternalPath::ObjCInterface, getIdentifier(name)); + return true; + } + + bool findExternalPath(const clang::DeclContext *dc, ExternalPath &path) { + // If we've reached the translation unit, we're done. + if (isa(dc)) + return true; + + // Linkage specifications don't contribute to the path. + if (isa(dc)) + return findExternalPath(dc->getParent(), path); + + // Handle namespaces. + if (auto ns = dyn_cast(dc)) { + // Don't try to handle anonymous namespaces. + auto name = ns->getIdentifier(); + if (!name) return false; + + // Drill to the parent. + if (!findExternalPath(dc->getParent(), path)) return false; + + path.Path.push_back({ExternalPath::Namespace, getIdentifier(name)}); + return true; + } + + // Handle types. + if (auto tag = dyn_cast(dc)) + return findExternalPath(tag, path); + + // Can't handle anything else. + return false; + } +}; +} // end anonymous namespace + + +StableSerializationPath +ClangImporter::findStableSerializationPath(const clang::Decl *decl) const { + return Impl.findStableSerializationPath(decl); +} + +StableSerializationPath +ClangImporter::Implementation::findStableSerializationPath( + const clang::Decl *decl) { + return SerializationPathFinder(*this).find(decl); +} + +const clang::Decl * +ClangImporter::resolveStableSerializationPath( + const StableSerializationPath &path) const { + if (!path) return nullptr; + + if (path.isSwiftDecl()) { + return path.getSwiftDecl()->getClangDecl(); + } + + auto &extpath = path.getExternalPath(); + auto &clangCtx = getClangASTContext(); + + const clang::Decl *decl = nullptr; + + // Perform a lookup in the current context (`decl` if set, and + // otherwise the translation unit). + auto lookup = [&](Identifier name) -> clang::DeclContext::lookup_result { + if (name.empty()) return clang::DeclContext::lookup_result(); + + const clang::DeclContext *dc; + if (decl) { + dc = dyn_cast(decl); + if (!dc) return clang::DeclContext::lookup_result(); + } else { + dc = clangCtx.getTranslationUnitDecl(); + } + + auto ident = &clangCtx.Idents.get(name.str()); + return dc->lookup(ident); + }; + + for (auto step : extpath.Path) { + // Handle the non-lookup steps here. + if (step.first == ExternalPath::TypedefAnonDecl) { + if (auto alias = dyn_cast_or_null(decl)) + return alias->getAnonDeclWithTypedefName(); + return nullptr; + } + + assert(ExternalPath::requiresIdentifier(step.first) && + "should've handled all non-lookup kinds above"); + + const clang::Decl *resultDecl = nullptr; + for (auto lookupDecl : lookup(step.second)) { + auto isAcceptable = [](const clang::Decl *decl, + ExternalPath::ComponentKind kind) { + switch (kind) { + case ExternalPath::Record: + return isa(decl); + case ExternalPath::Enum: + return isa(decl); + case ExternalPath::Namespace: + return isa(decl); + case ExternalPath::Typedef: + return isa(decl); + case ExternalPath::ObjCInterface: + return isa(decl); + case ExternalPath::ObjCProtocol: + return isa(decl); + case ExternalPath::TypedefAnonDecl: + llvm_unreachable("should have been filtered above"); + } + llvm_unreachable("bad kind"); + }; + + // Ignore unacceptable declarations. + if (!isAcceptable(lookupDecl, step.first)) + continue; + + // Bail out if we find multiple matching declarations. + // TODO: make an effort to filter by the target module? + if (resultDecl && !isSameDecl(resultDecl, lookupDecl)) + return nullptr; + + resultDecl = lookupDecl; + } + + // Bail out if lookup found nothing. + if (!resultDecl) return nullptr; + + decl = resultDecl; + } + + return decl; +} + +namespace { + /// The logic here for the supported cases must match the logic in + /// ClangToSwiftBasicWriter in Serialization.cpp. + struct ClangTypeSerializationChecker : + DataStreamBasicWriter { + ClangImporter::Implementation &Impl; + bool IsSerializable = true; + + ClangTypeSerializationChecker(ClangImporter::Implementation &impl) + : Impl(impl) {} + + void writeUInt64(uint64_t value) {} + void writeIdentifier(const clang::IdentifierInfo *ident) {} + void writeStmtRef(const clang::Stmt *stmt) { + if (stmt != nullptr) + IsSerializable = false; + } + void writeDeclRef(const clang::Decl *decl) { + if (decl && !Impl.findStableSerializationPath(decl)) + IsSerializable = false; + } + void writeSourceLocation(clang::SourceLocation loc) { + // If a source location is written into a type, it's likely to be + // something like the location of a VLA which we shouldn't simply + // replace with a meaningless location. + if (loc.isValid()) + IsSerializable = false; + } + }; +} + +bool ClangImporter::isSerializable(const clang::Type *type, + bool checkCanonical) const { + return Impl.isSerializable(clang::QualType(type, 0), checkCanonical); +} + +bool ClangImporter::Implementation::isSerializable(clang::QualType type, + bool checkCanonical) { + if (checkCanonical) + type = getClangASTContext().getCanonicalType(type); + + // Make a pass over the type as if we were serializing it, flagging + // anything that we can't stably serialize. + ClangTypeSerializationChecker checker(*this); + checker.writeQualType(type); + return checker.IsSerializable; +} diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index cac9af11f2be9..d596d4ebdbb5f 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2176,6 +2176,11 @@ bool Driver::handleImmediateArgs(const ArgList &Args, const ToolChain &TC) { commandLine.push_back("-target"); commandLine.push_back(targetArg->getValue()); } + if (const Arg *targetVariantArg = + Args.getLastArg(options::OPT_target_variant)) { + commandLine.push_back("-target-variant"); + commandLine.push_back(targetVariantArg->getValue()); + } if (const Arg *sdkArg = Args.getLastArg(options::OPT_sdk)) { commandLine.push_back("-sdk"); commandLine.push_back(sdkArg->getValue()); @@ -2188,6 +2193,7 @@ bool Driver::handleImmediateArgs(const ArgList &Args, const ToolChain &TC) { std::string executable = getSwiftProgramPath(); + // FIXME: This bypasses mechanisms like -v and -###. (SR-12119) sys::TaskQueue queue; queue.addTask(executable.c_str(), commandLine); queue.execute(nullptr, @@ -2718,7 +2724,10 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA, if (OI.ShouldGenerateModule && (isa(JA) || isa(JA))) { chooseSwiftModuleDocOutputPath(C, OutputMap, workingDirectory, Output.get()); - chooseSwiftSourceInfoOutputPath(C, OutputMap, workingDirectory, Output.get()); + if (!C.getArgs().hasArg(options::OPT_avoid_emit_module_source_info)) { + chooseSwiftSourceInfoOutputPath(C, OutputMap, workingDirectory, + Output.get()); + } } if (C.getArgs().hasArg(options::OPT_emit_module_interface, diff --git a/lib/Driver/FineGrainedDependencyDriverGraph.cpp b/lib/Driver/FineGrainedDependencyDriverGraph.cpp index dd997a283f1ca..95ce4e6c33fa6 100644 --- a/lib/Driver/FineGrainedDependencyDriverGraph.cpp +++ b/lib/Driver/FineGrainedDependencyDriverGraph.cpp @@ -12,9 +12,11 @@ #include "swift/Driver/FineGrainedDependencyDriverGraph.h" // Next two includes needed for reporting errors opening dot file for writing. +#include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/FileSystem.h" #include "swift/Basic/ReferenceDependencyKeys.h" +#include "swift/Basic/SourceManager.h" #include "swift/Basic/Statistic.h" #include "swift/Demangling/Demangle.h" #include "swift/Driver/Job.h" @@ -57,7 +59,14 @@ ModuleDepGraph::simulateLoad(const Job *cmd, swiftDeps, includePrivateDeps, hadCompilationError, interfaceHash, simpleNames, compoundNames); - return loadFromSourceFileDepGraph(cmd, sfdg); + SourceManager sm; + DiagnosticEngine diags(sm); + // help for debugging: emit imported file, too + if (emitFineGrainedDependencyDotFileAfterEveryImport) { + sfdg.emitDotFile(swiftDeps, diags); + } + + return loadFromSourceFileDepGraph(cmd, sfdg, diags); } std::string SourceFileDepGraph::noncascading(std::string name) { @@ -104,31 +113,35 @@ ModuleDepGraph::Changes ModuleDepGraph::loadFromPath(const Job *Cmd, auto buffer = llvm::MemoryBuffer::getFile(path); if (!buffer) return None; - auto r = loadFromBuffer(Cmd, *buffer.get()); + auto r = loadFromBuffer(Cmd, *buffer.get(), diags); assert(path == getSwiftDeps(Cmd) && "Should be reading the job's swiftdeps"); assert(!r || !nodeMap[path].empty() && "Must have a node for the whole file"); - if (emitFineGrainedDependencyDotFileAfterEveryImport) - emitDotFileForJob(diags, Cmd); - if (verifyFineGrainedDependencyGraphAfterEveryImport) - verify(); return r; } /// Returns None for error or a set of changed keys ModuleDepGraph::Changes -ModuleDepGraph::loadFromBuffer(const Job *job, llvm::MemoryBuffer &buffer) { +ModuleDepGraph::loadFromBuffer(const Job *job, llvm::MemoryBuffer &buffer, + DiagnosticEngine &diags) { Optional sourceFileDepGraph = SourceFileDepGraph::loadFromBuffer(buffer); if (!sourceFileDepGraph) return None; - return loadFromSourceFileDepGraph(job, sourceFileDepGraph.getValue()); + return loadFromSourceFileDepGraph(job, sourceFileDepGraph.getValue(), diags); } ModuleDepGraph::Changes ModuleDepGraph::loadFromSourceFileDepGraph( - const Job *job, const SourceFileDepGraph &sourceFileDepGraph) { + const Job *job, const SourceFileDepGraph &sourceFileDepGraph, + DiagnosticEngine &diags) { registerJob(job); - return integrate(sourceFileDepGraph, getSwiftDeps(job)); + auto changes = integrate(sourceFileDepGraph, getSwiftDeps(job)); + + if (verifyFineGrainedDependencyGraphAfterEveryImport) + verify(); + if (emitFineGrainedDependencyDotFileAfterEveryImport) + emitDotFileForJob(diags, job); + return changes; } bool ModuleDepGraph::haveAnyNodesBeenTraversedIn(const Job *cmd) const { @@ -171,6 +184,11 @@ ModuleDepGraph::findJobsToRecompileWhenNodesChange< std::unordered_set>( const std::unordered_set &); +template std::vector +ModuleDepGraph::findJobsToRecompileWhenNodesChange< + std::vector>( + const std::vector &); + std::vector ModuleDepGraph::computeSwiftDepsFromNodes( ArrayRef nodes) const { llvm::StringSet<> swiftDepsOfNodes; @@ -249,7 +267,9 @@ ModuleDepGraph::Changes ModuleDepGraph::integrate(const SourceFileDepGraph &g, auto disappearedNodes = nodeMap[swiftDepsOfJob]; // When done, changeDependencyKeys contains a list of keys that changed // as a result of this integration. - auto changedNodes = std::unordered_set(); + // Or if the integration failed, None. + Optional> changedNodes = + std::unordered_set(); g.forEachNode([&](const SourceFileDepGraphNode *integrand) { const auto &key = integrand->getKey(); @@ -259,24 +279,30 @@ ModuleDepGraph::Changes ModuleDepGraph::integrate(const SourceFileDepGraph &g, preexistingMatch.getValue().first == LocationOfPreexistingNode::here) disappearedNodes.erase(key); // Node was and still is. Do not erase it. - NullablePtr newNodeOrChangedNode = + Optional> newNodeOrChangedNode = integrateSourceFileDepGraphNode(g, integrand, preexistingMatch, swiftDepsOfJob); - if (auto *n = newNodeOrChangedNode.getPtrOrNull()) - changedNodes.insert(n); + if (!newNodeOrChangedNode) + changedNodes = None; + else if (!changedNodes) + ; + else if (auto *n = newNodeOrChangedNode.getValue().getPtrOrNull()) + changedNodes.getValue().insert(n); }); + if (!changedNodes) + return None; for (auto &p : disappearedNodes) { - changedNodes.insert(p.second); + changedNodes.getValue().insert(p.second); eraseNodeFromJob(p.second); } // Make sure the changes can be retraced: - for (auto *n : changedNodes) + for (auto *n : changedNodes.getValue()) n->clearHasBeenTraced(); - return changedNodes; + return changedNodes.getValue(); } ModuleDepGraph::PreexistingNodeIfAny ModuleDepGraph::findPreexistingMatch( @@ -305,13 +331,20 @@ ModuleDepGraph::PreexistingNodeIfAny ModuleDepGraph::findPreexistingMatch( return None; } -NullablePtr ModuleDepGraph::integrateSourceFileDepGraphNode( +Optional> +ModuleDepGraph::integrateSourceFileDepGraphNode( const SourceFileDepGraph &g, const SourceFileDepGraphNode *integrand, const PreexistingNodeIfAny preexistingMatch, const StringRef swiftDepsOfJob) { + if (!EnableTypeFingerprints && + integrand->getKey().getKind() != NodeKind::sourceFileProvide && + integrand->getFingerprint()) + return None; + if (!integrand->getIsProvides()) - return nullptr; // depends are captured by recordWhatUseDependsUpon below + return NullablePtr(); // depends are captured by + // recordWhatUseDependsUpon below auto changedAndIntegrationResultNode = integrateSourceFileDeclNode(integrand, swiftDepsOfJob, preexistingMatch); @@ -441,7 +474,7 @@ void ModuleDepGraph::forEachNode( void ModuleDepGraph::forEachMatchingNode( const DependencyKey &key, - function_ref fn) const { + function_ref fn) const { nodeMap.forEachValueMatching( key, [&](const std::string &, ModuleDepGraphNode *n) { fn(n); }); } @@ -545,6 +578,14 @@ void ModuleDepGraph::emitDotFile(llvm::raw_ostream &out) { // MARK: ModuleDepGraph debugging //============================================================================== +void ModuleDepGraphNode::dump(llvm::raw_ostream &out) const { + DepGraphNode::dump(out); + if (getIsProvides()) + out << " swiftDeps: <" << getSwiftDepsOfProvides() << ">\n"; + else + out << " no swiftDeps\n"; +} + void ModuleDepGraphNode::dump() const { DepGraphNode::dump(); if (getIsProvides()) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 40762133ccb58..4c8f12330b8b6 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1338,8 +1338,8 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, Opts.DisableLegacyTypeInfo = true; } - if (Args.hasArg(OPT_prespecialize_generic_metadata)) { - Opts.PrespecializeGenericMetadata = true; + if (Args.hasArg(OPT_disable_generic_metadata_prespecialization)) { + Opts.PrespecializeGenericMetadata = false; } if (const Arg *A = Args.getLastArg(OPT_read_legacy_type_info_path_EQ)) { diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index a2cf2504c0665..9e10950b6db40 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -727,7 +727,15 @@ void CompilerInstance::performSemaUpTo(SourceFile::ASTStage_t LimitStage) { const ImplicitImports implicitImports(*this); if (Invocation.getInputKind() == InputFileKind::SwiftREPL) { - createREPLFile(implicitImports); + // Create the initial empty REPL file. This only exists to feed in the + // implicit imports such as the standard library. + auto *replFile = createSourceFileForMainModule( + SourceFileKind::REPL, implicitImports.kind, /*BufferID*/ None); + addAdditionalInitialImportsTo(replFile, implicitImports); + + // Given this file is empty, we can go ahead and just mark it as having been + // type checked. + replFile->ASTStage = SourceFile::TypeChecked; return; } @@ -824,12 +832,6 @@ void CompilerInstance::getImplicitlyImportedModules( } } -void CompilerInstance::createREPLFile(const ImplicitImports &implicitImports) { - auto *SingleInputFile = createSourceFileForMainModule( - Invocation.getSourceFileKind(), implicitImports.kind, None); - addAdditionalInitialImportsTo(SingleInputFile, implicitImports); -} - void CompilerInstance::addMainFileToModule( const ImplicitImports &implicitImports) { auto *MainFile = createSourceFileForMainModule( @@ -913,14 +915,8 @@ void CompilerInstance::parseLibraryFile( auto DidSuppressWarnings = Diags.getSuppressWarnings(); Diags.setSuppressWarnings(DidSuppressWarnings || !IsPrimary); - bool Done; - do { - // Parser may stop at some erroneous constructions like #else, #endif - // or '}' in some cases, continue parsing until we are done - parseIntoSourceFile(*NextInput, BufferID, &Done, nullptr, - PersistentState.get(), - /*DelayedBodyParsing=*/!IsPrimary); - } while (!Done); + parseIntoSourceFile(*NextInput, BufferID, PersistentState.get(), + /*DelayedBodyParsing=*/!IsPrimary); Diags.setSuppressWarnings(DidSuppressWarnings); @@ -953,6 +949,7 @@ bool CompilerInstance::parsePartialModulesAndLibraryFiles( void CompilerInstance::parseAndTypeCheckMainFileUpTo( SourceFile::ASTStage_t LimitStage) { + assert(LimitStage >= SourceFile::NameBound); FrontendStatsTracer tracer(Context->Stats, "parse-and-typecheck-main-file"); bool mainIsPrimary = @@ -965,45 +962,23 @@ void CompilerInstance::parseAndTypeCheckMainFileUpTo( auto DidSuppressWarnings = Diags.getSuppressWarnings(); Diags.setSuppressWarnings(DidSuppressWarnings || !mainIsPrimary); - SILParserState SILContext(TheSILModule.get()); - unsigned CurTUElem = 0; - bool Done; - do { - // Pump the parser multiple times if necessary. It will return early - // after parsing any top level code in a main module, or in SIL mode when - // there are chunks of swift decls (e.g. imports and types) interspersed - // with 'sil' definitions. - parseIntoSourceFile(MainFile, MainFile.getBufferID().getValue(), &Done, - TheSILModule ? &SILContext : nullptr, - PersistentState.get(), - !mainIsPrimary); - - // For SIL we actually have to interleave parsing and type checking - // because the SIL parser expects to see fully type checked declarations. - if (TheSILModule) { - if (Done || CurTUElem < MainFile.getTopLevelDecls().size()) { - assert(mainIsPrimary); - performTypeChecking(MainFile, CurTUElem); - } - } + // Parse the Swift decls into the source file. + parseIntoSourceFile(MainFile, MainBufferID, PersistentState.get(), + /*delayBodyParsing*/ !mainIsPrimary); - CurTUElem = MainFile.getTopLevelDecls().size(); - } while (!Done); - - if (!TheSILModule) { - if (mainIsPrimary) { - switch (LimitStage) { - case SourceFile::Parsing: - case SourceFile::Parsed: - llvm_unreachable("invalid limit stage"); - case SourceFile::NameBound: - performNameBinding(MainFile); - break; - case SourceFile::TypeChecked: - performTypeChecking(MainFile); - break; - } - } + // For a primary, also perform type checking if needed. Otherwise, just do + // name binding. + if (mainIsPrimary && LimitStage >= SourceFile::TypeChecked) { + performTypeChecking(MainFile); + } else { + assert(!TheSILModule && "Should perform type checking for SIL"); + performNameBinding(MainFile); + } + + // Parse the SIL decls if needed. + if (TheSILModule) { + SILParserState SILContext(TheSILModule.get()); + parseSourceFileSIL(MainFile, &SILContext); } Diags.setSuppressWarnings(DidSuppressWarnings); @@ -1012,12 +987,6 @@ void CompilerInstance::parseAndTypeCheckMainFileUpTo( Invocation.getFrontendOptions().DebuggerTestingTransform) { performDebuggerTestingTransform(MainFile); } - - if (!TheSILModule) { - if (!mainIsPrimary) { - performNameBinding(MainFile); - } - } } static void @@ -1109,8 +1078,8 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals, SourceFileKind::Library, SourceFile::ImplicitModuleImportKind::None, BufferID); - parseIntoSourceFileFull(*NextInput, BufferID, PersistentState.get(), - shouldDelayBodies(BufferID)); + parseIntoSourceFile(*NextInput, BufferID, PersistentState.get(), + shouldDelayBodies(BufferID)); } // Now parse the main file. @@ -1120,8 +1089,8 @@ void CompilerInstance::performParseOnly(bool EvaluateConditionals, MainFile.SyntaxParsingCache = Invocation.getMainFileSyntaxParsingCache(); assert(MainBufferID == MainFile.getBufferID()); - parseIntoSourceFileFull(MainFile, MainBufferID, PersistentState.get(), - shouldDelayBodies(MainBufferID)); + parseIntoSourceFile(MainFile, MainBufferID, PersistentState.get(), + shouldDelayBodies(MainBufferID)); } assert(Context->LoadedModules.size() == 1 && diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 2f7a40f255c21..fbbd92d99a095 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -347,6 +347,8 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( // optimization pipeline. SerializationOptions SerializationOpts; std::string OutPathStr = OutPath; + SerializationOpts.EnableNestedTypeLookupTable + = FEOpts.EnableSerializationNestedTypeLookupTable; SerializationOpts.OutputPath = OutPathStr.c_str(); SerializationOpts.ModuleLinkName = FEOpts.ModuleLinkName; SerializationOpts.AutolinkForceLoad = diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 02386f37e7102..912ce5cc572f8 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1894,39 +1894,54 @@ createJSONFixItDiagnosticConsumerIfNeeded( }); } -/// Print information about the selected target in JSON. -static void printTargetInfo(const CompilerInvocation &invocation, +/// Print information about the target triple in JSON. +static void printTripleInfo(const llvm::Triple &triple, llvm::raw_ostream &out) { out << "{\n"; - // Target information. - auto &langOpts = invocation.getLangOptions(); - out << " \"target\": {\n"; - out << " \"triple\": \""; - out.write_escaped(langOpts.Target.getTriple()); + out.write_escaped(triple.getTriple()); out << "\",\n"; out << " \"unversionedTriple\": \""; - out.write_escaped(getUnversionedTriple(langOpts.Target).getTriple()); + out.write_escaped(getUnversionedTriple(triple).getTriple()); out << "\",\n"; out << " \"moduleTriple\": \""; - out.write_escaped(getTargetSpecificModuleTriple(langOpts.Target).getTriple()); + out.write_escaped(getTargetSpecificModuleTriple(triple).getTriple()); out << "\",\n"; if (auto runtimeVersion = getSwiftRuntimeCompatibilityVersionForTarget( - langOpts.Target)) { + triple)) { out << " \"swiftRuntimeCompatibilityVersion\": \""; out.write_escaped(runtimeVersion->getAsString()); out << "\",\n"; } out << " \"librariesRequireRPath\": " - << (tripleRequiresRPathForSwiftInOS(langOpts.Target) ? "true" : "false") + << (tripleRequiresRPathForSwiftInOS(triple) ? "true" : "false") << "\n"; - out << " },\n"; + out << " }"; + +} + +/// Print information about the selected target in JSON. +static void printTargetInfo(const CompilerInvocation &invocation, + llvm::raw_ostream &out) { + out << "{\n"; + + // Target triple and target variant triple. + auto &langOpts = invocation.getLangOptions(); + out << " \"target\": "; + printTripleInfo(langOpts.Target, out); + out << ",\n"; + + if (auto &variant = langOpts.TargetVariant) { + out << " \"targetVariant\": "; + printTripleInfo(*variant, out); + out << ",\n"; + } // Various paths. auto &searchOpts = invocation.getSearchPathOptions(); diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index f8e20c52b1e38..155cdb72299bf 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -695,7 +695,7 @@ void CodeCompletionResult::print(raw_ostream &OS) const { Prefix.append(Twine(NumBytesToErase).str()); Prefix.append("]"); } - switch (TypeDistance) { + switch (getExpectedTypeRelation()) { case ExpectedTypeRelation::Invalid: Prefix.append("/TypeRelation[Invalid]"); break; @@ -705,6 +705,8 @@ void CodeCompletionResult::print(raw_ostream &OS) const { case ExpectedTypeRelation::Convertible: Prefix.append("/TypeRelation[Convertible]"); break; + case ExpectedTypeRelation::NotApplicable: + case ExpectedTypeRelation::Unknown: case ExpectedTypeRelation::Unrelated: break; } @@ -886,6 +888,11 @@ calculateTypeRelationForDecl(const Decl *D, Type ExpectedType, return relation; } } + if (auto EED = dyn_cast(VD)) { + return calculateTypeRelation( + EED->getParentEnum()->TypeDecl::getDeclaredInterfaceType(), + ExpectedType, DC); + } if (auto NTD = dyn_cast(VD)) { return std::max( calculateTypeRelation(NTD->getInterfaceType(), ExpectedType, DC), @@ -898,6 +905,9 @@ static CodeCompletionResult::ExpectedTypeRelation calculateMaxTypeRelationForDecl( const Decl *D, const ExpectedTypeContext &typeContext, bool IsImplicitlyCurriedInstanceMethod = false) { + if (typeContext.empty()) + return CodeCompletionResult::ExpectedTypeRelation::Unknown; + auto Result = CodeCompletionResult::ExpectedTypeRelation::Unrelated; for (auto Type : typeContext.possibleTypes) { // Do not use Void type context for a single-expression body, since the @@ -1029,7 +1039,7 @@ CodeCompletionResult *CodeCompletionResultBuilder::takeResult() { } auto typeRelation = ExpectedTypeRelation; - if (typeRelation == CodeCompletionResult::Unrelated) + if (typeRelation == CodeCompletionResult::Unknown) typeRelation = calculateMaxTypeRelationForDecl(AssociatedDecl, declTypeContext); @@ -3605,8 +3615,13 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { } // Fallback to showing the default type. - if (!defaultTypeName.empty()) + if (!defaultTypeName.empty()) { builder.addTypeAnnotation(defaultTypeName); + builder.setExpectedTypeRelation( + expectedTypeContext.possibleTypes.empty() + ? CodeCompletionResult::ExpectedTypeRelation::Unknown + : CodeCompletionResult::ExpectedTypeRelation::Unrelated); + } } /// Add '#file', '#line', et at. @@ -4303,6 +4318,8 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, SemanticContextKind::Super, {}); + Builder.setExpectedTypeRelation( + CodeCompletionResult::ExpectedTypeRelation::NotApplicable); Builder.setAssociatedDecl(FD); addValueOverride(FD, Reason, dynamicLookupInfo, Builder, hasFuncIntroducer); Builder.addBraceStmtWithCursor(); @@ -4330,6 +4347,8 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, SemanticContextKind::Super, {}); + Builder.setExpectedTypeRelation( + CodeCompletionResult::ExpectedTypeRelation::NotApplicable); Builder.setAssociatedDecl(SD); addValueOverride(SD, Reason, dynamicLookupInfo, Builder, false); Builder.addBraceStmtWithCursor(); @@ -4340,6 +4359,8 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer { CodeCompletionResultBuilder Builder(Sink, CodeCompletionResult::ResultKind::Declaration, SemanticContextKind::Super, {}); + Builder.setExpectedTypeRelation( + CodeCompletionResult::ExpectedTypeRelation::NotApplicable); Builder.setAssociatedDecl(ATD); if (!hasTypealiasIntroducer && !hasAccessModifier) addAccessControl(ATD, Builder); @@ -4356,6 +4377,8 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer { Sink, CodeCompletionResult::ResultKind::Declaration, SemanticContextKind::Super, {}); + Builder.setExpectedTypeRelation( + CodeCompletionResult::ExpectedTypeRelation::NotApplicable); Builder.setAssociatedDecl(CD); if (!hasAccessModifier) @@ -4840,16 +4863,19 @@ static bool isClangSubModule(ModuleDecl *TheModule) { return false; } -static void addKeyword(CodeCompletionResultSink &Sink, StringRef Name, - CodeCompletionKeywordKind Kind, - StringRef TypeAnnotation = "") { - CodeCompletionResultBuilder Builder( - Sink, CodeCompletionResult::ResultKind::Keyword, - SemanticContextKind::None, {}); - Builder.setKeywordKind(Kind); - Builder.addTextChunk(Name); - if (!TypeAnnotation.empty()) - Builder.addTypeAnnotation(TypeAnnotation); +static void +addKeyword(CodeCompletionResultSink &Sink, StringRef Name, + CodeCompletionKeywordKind Kind, StringRef TypeAnnotation = "", + CodeCompletionResult::ExpectedTypeRelation TypeRelation = + CodeCompletionResult::ExpectedTypeRelation::NotApplicable) { + CodeCompletionResultBuilder Builder(Sink, + CodeCompletionResult::ResultKind::Keyword, + SemanticContextKind::None, {}); + Builder.setKeywordKind(Kind); + Builder.addTextChunk(Name); + if (!TypeAnnotation.empty()) + Builder.addTypeAnnotation(TypeAnnotation); + Builder.setExpectedTypeRelation(TypeRelation); } static void addDeclKeywords(CodeCompletionResultSink &Sink) { diff --git a/lib/IDE/CodeCompletionCache.cpp b/lib/IDE/CodeCompletionCache.cpp index dd63357194c35..3d466f3bfdbc4 100644 --- a/lib/IDE/CodeCompletionCache.cpp +++ b/lib/IDE/CodeCompletionCache.cpp @@ -255,7 +255,7 @@ static bool readCachedModule(llvm::MemoryBuffer *in, } else { result = new (*V.Sink.Allocator) CodeCompletionResult(kind, context, numBytesToErase, string, - CodeCompletionResult::Unrelated, opKind); + CodeCompletionResult::NotApplicable, opKind); } V.Sink.Results.push_back(result); diff --git a/lib/IDE/CodeCompletionResultBuilder.h b/lib/IDE/CodeCompletionResultBuilder.h index cc4793d9eb1ba..f2ce02db97631 100644 --- a/lib/IDE/CodeCompletionResultBuilder.h +++ b/lib/IDE/CodeCompletionResultBuilder.h @@ -65,7 +65,7 @@ class CodeCompletionResultBuilder { CurrentModule; ExpectedTypeContext declTypeContext; CodeCompletionResult::ExpectedTypeRelation ExpectedTypeRelation = - CodeCompletionResult::Unrelated; + CodeCompletionResult::Unknown; bool Cancelled = false; ArrayRef> CommentWords; bool IsNotRecommended = false; diff --git a/lib/IDE/CompletionInstance.cpp b/lib/IDE/CompletionInstance.cpp index 446d80601a9c3..acfa3d6ae9860 100644 --- a/lib/IDE/CompletionInstance.cpp +++ b/lib/IDE/CompletionInstance.cpp @@ -217,7 +217,7 @@ bool CompletionInstance::performCachedOperaitonIfPossible( newSF->enableInterfaceHash(); // Ensure all non-function-body tokens are hashed into the interface hash Ctx->LangOpts.EnableTypeFingerprints = false; - parseIntoSourceFileFull(*newSF, tmpBufferID, &newState); + parseIntoSourceFile(*newSF, tmpBufferID, &newState); // Couldn't find any completion token? if (!newState.hasCodeCompletionDelayedDeclState()) return false; diff --git a/lib/IDE/REPLCodeCompletion.cpp b/lib/IDE/REPLCodeCompletion.cpp index 247ddb4d0e473..0568654dca0eb 100644 --- a/lib/IDE/REPLCodeCompletion.cpp +++ b/lib/IDE/REPLCodeCompletion.cpp @@ -204,22 +204,40 @@ doCodeCompletion(SourceFile &SF, StringRef EnteredCode, unsigned *BufferID, Ctx.SourceMgr.setCodeCompletionPoint(*BufferID, CodeCompletionOffset); - // Parse, typecheck and temporarily insert the incomplete code into the AST. - const unsigned OriginalDeclCount = SF.getTopLevelDecls().size(); + // Create a new module and file for the code completion buffer, similar to how + // we handle new lines of REPL input. + auto *newModule = + ModuleDecl::create(Ctx.getIdentifier("REPL_Code_Completion"), Ctx); + auto &newSF = + *new (Ctx) SourceFile(*newModule, SourceFileKind::REPL, *BufferID, + SourceFile::ImplicitModuleImportKind::None); + newModule->addFile(newSF); + + // Import the last module. + auto *lastModule = SF.getParentModule(); + ModuleDecl::ImportedModule importOfLastModule{/*AccessPath*/ {}, lastModule}; + newSF.addImports(SourceFile::ImportedModuleDesc(importOfLastModule, + SourceFile::ImportOptions())); + + // Carry over the private imports from the last module. + SmallVector imports; + lastModule->getImportedModules(imports, + ModuleDecl::ImportFilterKind::Private); + if (!imports.empty()) { + SmallVector importsWithOptions; + for (auto &import : imports) { + importsWithOptions.emplace_back( + SourceFile::ImportedModuleDesc(import, SourceFile::ImportOptions())); + } + newSF.addImports(importsWithOptions); + } PersistentParserState PersistentState; - bool Done; - do { - parseIntoSourceFile(SF, *BufferID, &Done, nullptr, &PersistentState); - } while (!Done); - performTypeChecking(SF, OriginalDeclCount); + parseIntoSourceFile(newSF, *BufferID, &PersistentState); + performTypeChecking(newSF); performCodeCompletionSecondPass(PersistentState, *CompletionCallbacksFactory); - // Now we are done with code completion. Remove the declarations we - // temporarily inserted. - SF.truncateTopLevelDecls(OriginalDeclCount); - // Reset the error state because it's only relevant to the code that we just // processed, which now gets thrown away. Ctx.Diags.resetHadAnyError(); diff --git a/lib/IRGen/CMakeLists.txt b/lib/IRGen/CMakeLists.txt index f7276a871cfb7..1d3563accaa99 100644 --- a/lib/IRGen/CMakeLists.txt +++ b/lib/IRGen/CMakeLists.txt @@ -16,6 +16,7 @@ add_swift_host_library(swiftIRGen STATIC GenControl.cpp GenCoverage.cpp GenDecl.cpp + GenDiffWitness.cpp GenEnum.cpp GenExistential.cpp GenFunc.cpp diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 6cffbd53e5d2b..b1cbe5d40457f 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1073,7 +1073,21 @@ void IRGenerator::emitGlobalTopLevel(llvm::StringSet<> *linkerDirectives) { CurrentIGMPtr IGM = getGenModule(prop.getDecl()->getInnermostDeclContext()); IGM->emitSILProperty(&prop); } - + + // Emit differentiability witnesses. + for (auto &dw : + PrimaryIGM->getSILModule().getDifferentiabilityWitnessList()) { + // Emit into same IRGenModule as the original function. + // NOTE(TF-894): Investigate whether `getGenModule(dw.getVJP())` is + // significant/desirable; `getGenModule` seems relevant for multi-threaded + // compilation. When the differentiation transform canonicalizes all + // differentiability witnesses to have JVP/VJP functions, we can assert + // that JVP/VJP functions exist and use `getGenModule(dw.getVJP())`. + CurrentIGMPtr IGM = getGenModule(dw.getOriginalFunction()); + + IGM->emitSILDifferentiabilityWitness(&dw); + } + // Emit code coverage mapping data. PrimaryIGM->emitCoverageMapping(); @@ -4500,6 +4514,13 @@ IRGenModule::getAddrOfWitnessTablePattern(const NormalProtocolConformance *conf, return getAddrOfLLVMVariable(entity, definition, DebugTypeInfo()); } +/// Look up the address of a differentiability witness. +llvm::Constant *IRGenModule::getAddrOfDifferentiabilityWitness( + const SILDifferentiabilityWitness *witness, ConstantInit definition) { + auto entity = LinkEntity::forDifferentiabilityWitness(witness); + return getAddrOfLLVMVariable(entity, definition, DebugTypeInfo()); +} + llvm::Function * IRGenModule::getAddrOfAssociatedTypeWitnessTableAccessFunction( const NormalProtocolConformance *conformance, diff --git a/lib/IRGen/GenDiffWitness.cpp b/lib/IRGen/GenDiffWitness.cpp new file mode 100644 index 0000000000000..f27a5861a8840 --- /dev/null +++ b/lib/IRGen/GenDiffWitness.cpp @@ -0,0 +1,54 @@ +//===--- GenDiffWitness.cpp - IRGen for differentiability witnesses -------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2020 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 implements IR generation for SIL differentiability witnesses. +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/PrettyStackTrace.h" +#include "swift/SIL/SILDifferentiabilityWitness.h" + +#include "ConstantBuilder.h" +#include "IRGenModule.h" + +using namespace swift; +using namespace irgen; + +void IRGenModule::emitSILDifferentiabilityWitness( + SILDifferentiabilityWitness *dw) { + PrettyStackTraceDifferentiabilityWitness _st( + "emitting differentiability witness for", dw->getKey()); + + // Don't emit declarations. + if (dw->isDeclaration()) + return; + + // Don't emit `public_external` witnesses. + if (dw->getLinkage() == SILLinkage::PublicExternal) + return; + + ConstantInitBuilder builder(*this); + auto diffWitnessContents = builder.beginStruct(); + + assert(dw->getJVP() && + "Differentiability witness definition should have JVP"); + assert(dw->getVJP() && + "Differentiability witness definition should have VJP"); + + diffWitnessContents.addBitCast( + getAddrOfSILFunction(dw->getJVP(), NotForDefinition), Int8PtrTy); + diffWitnessContents.addBitCast( + getAddrOfSILFunction(dw->getVJP(), NotForDefinition), Int8PtrTy); + + getAddrOfDifferentiabilityWitness( + dw, diffWitnessContents.finishAndCreateFuture()); +} diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 14c0b768f0cf1..9cc7efa9226a6 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -4370,6 +4370,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) { case KnownProtocolKind::CaseIterable: case KnownProtocolKind::Comparable: case KnownProtocolKind::SIMDScalar: + case KnownProtocolKind::BinaryInteger: case KnownProtocolKind::ObjectiveCBridgeable: case KnownProtocolKind::DestructorSafeContainer: case KnownProtocolKind::SwiftNewtypeWrapper: diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 3ed07808b4168..eee416bdee441 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -524,6 +524,9 @@ IRGenModule::IRGenModule(IRGenerator &irgen, DynamicReplacementKeyTy = createStructType(*this, "swift.dyn_repl_key", {RelativeAddressTy, Int32Ty}); + + DifferentiabilityWitnessTy = createStructType( + *this, "swift.differentiability_witness", {Int8PtrTy, Int8PtrTy}); } IRGenModule::~IRGenModule() { @@ -1340,7 +1343,8 @@ bool IRGenModule::shouldPrespecializeGenericMetadata() { AvailabilityContext::forDeploymentTarget(context); return IRGen.Opts.PrespecializeGenericMetadata && deploymentAvailability.isContainedIn( - context.getPrespecializedGenericMetadataAvailability()); + context.getPrespecializedGenericMetadataAvailability()) && + (Triple.isOSDarwin() || Triple.isTvOS() || Triple.isOSLinux()); } void IRGenerator::addGenModule(SourceFile *SF, IRGenModule *IGM) { diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 87e948c7aa176..da2cfa028f4c4 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -95,6 +95,7 @@ namespace swift { class RootProtocolConformance; struct SILDeclRef; class SILDefaultWitnessTable; + class SILDifferentiabilityWitness; class SILGlobalVariable; class SILModule; class SILProperty; @@ -672,6 +673,8 @@ class IRGenModule { *DynamicReplacementLinkEntryPtrTy; // %link_entry* llvm::StructType *DynamicReplacementKeyTy; // { i32, i32} + llvm::StructType *DifferentiabilityWitnessTy; // { i8*, i8* } + llvm::GlobalVariable *TheTrivialPropertyDescriptor = nullptr; /// Used to create unique names for class layout types with tail allocated @@ -1272,6 +1275,7 @@ private: \ void emitSILFunction(SILFunction *f); void emitSILWitnessTable(SILWitnessTable *wt); void emitSILProperty(SILProperty *prop); + void emitSILDifferentiabilityWitness(SILDifferentiabilityWitness *dw); void emitSILStaticInitializers(); llvm::Constant *emitFixedTypeLayout(CanType t, const FixedTypeInfo &ti); void emitProtocolConformance(const ConformanceDescription &record); @@ -1463,6 +1467,10 @@ private: \ llvm::Function *getAddrOfDefaultAssociatedConformanceAccessor( AssociatedConformance requirement); + llvm::Constant * + getAddrOfDifferentiabilityWitness(const SILDifferentiabilityWitness *witness, + ConstantInit definition = ConstantInit()); + Address getAddrOfObjCISAMask(); /// Retrieve the generic signature for the current generic context, or null if no diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp index 19cb5949d15aa..48fd8f1c1440b 100644 --- a/lib/IRGen/Linking.cpp +++ b/lib/IRGen/Linking.cpp @@ -414,6 +414,10 @@ std::string LinkEntity::mangleAsString() const { case Kind::ReflectionAssociatedTypeDescriptor: return mangler.mangleReflectionAssociatedTypeDescriptor( getProtocolConformance()); + case Kind::DifferentiabilityWitness: + return mangler.mangleSILDifferentiabilityWitnessKey( + {getSILDifferentiabilityWitness()->getOriginalFunction()->getName(), + getSILDifferentiabilityWitness()->getConfig()}); } llvm_unreachable("bad entity kind!"); } @@ -659,6 +663,8 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const { case Kind::ExtensionDescriptor: case Kind::AnonymousDescriptor: return SILLinkage::Shared; + case Kind::DifferentiabilityWitness: + return getSILDifferentiabilityWitness()->getLinkage(); } llvm_unreachable("bad link entity kind"); } @@ -783,6 +789,9 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const { ->getDeclContext() ->getInnermostTypeContext()); } + + case Kind::DifferentiabilityWitness: + return true; case Kind::ObjCMetadataUpdateFunction: case Kind::ObjCResilientClassStub: @@ -904,6 +913,8 @@ llvm::Type *LinkEntity::getDefaultDeclarationType(IRGenModule &IGM) const { return IGM.ObjCResilientClassStubTy; } llvm_unreachable("invalid metadata address"); + case Kind::DifferentiabilityWitness: + return IGM.DifferentiabilityWitnessTy; default: llvm_unreachable("declaration LLVM type not specified"); } @@ -951,6 +962,7 @@ Alignment LinkEntity::getAlignment(IRGenModule &IGM) const { case Kind::OpaqueTypeDescriptorAccessorKey: case Kind::OpaqueTypeDescriptorAccessorVar: case Kind::ObjCResilientClassStub: + case Kind::DifferentiabilityWitness: return IGM.getPointerAlignment(); case Kind::TypeMetadataDemanglingCacheVariable: return Alignment(8); @@ -1052,6 +1064,7 @@ bool LinkEntity::isWeakImported(ModuleDecl *module) const { case Kind::ReflectionBuiltinDescriptor: case Kind::ReflectionFieldDescriptor: case Kind::CoroutineContinuationPrototype: + case Kind::DifferentiabilityWitness: return false; } @@ -1181,6 +1194,7 @@ const SourceFile *LinkEntity::getSourceFileForEmission() const { case Kind::ReflectionBuiltinDescriptor: case Kind::ValueWitness: case Kind::ValueWitnessTable: + case Kind::DifferentiabilityWitness: return nullptr; } diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index bf919157c8036..660dbdad428b8 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -701,36 +701,40 @@ bool irgen::isNominalGenericContextTypeMetadataAccessTrivial( auto substitutions = type->getContextSubstitutionMap(IGM.getSwiftModule(), &nominal); - return llvm::all_of(environment->getGenericParams(), [&](auto parameter) { - auto conformances = - environment->getGenericSignature()->getConformsTo(parameter); - auto witnessTablesAreReferenceable = - llvm::all_of(conformances, [&](ProtocolDecl *conformance) { - return conformance->getModuleContext() == IGM.getSwiftModule() && - !conformance->isResilient(IGM.getSwiftModule(), - ResilienceExpansion::Minimal); - }); + auto allWitnessTablesAreReferenceable = llvm::all_of(environment->getGenericParams(), [&](auto parameter) { + auto signature = environment->getGenericSignature(); + auto protocols = signature->getConformsTo(parameter); auto argument = ((Type *)parameter)->subst(substitutions); - auto genericArgument = argument->getAnyGeneric(); - // For now, to avoid statically specializing generic protocol witness - // tables, don't statically specialize metadata for types any of whose - // arguments are generic. - // - // TODO: This is more pessimistic than necessary. Specialize even in - // the face of generic arguments so long as those arguments - // aren't required to conform to any protocols. - // + auto canonicalType = argument->getCanonicalType(); + auto witnessTablesAreReferenceable = [&]() { + return llvm::all_of(protocols, [&](ProtocolDecl *protocol) { + auto conformance = + signature->lookupConformance(canonicalType, protocol); + if (!conformance.isConcrete()) { + return false; + } + auto rootConformance = conformance.getConcrete()->getRootConformance(); + return !IGM.isDependentConformance(rootConformance) && + !IGM.isResilientConformance(rootConformance); + }); + }; // TODO: Once witness tables are statically specialized, check whether the // ConformanceInfo returns nullptr from tryGetConstantTable. - // early return. - auto isGeneric = genericArgument && genericArgument->isGenericContext(); - auto isNominal = argument->getNominalOrBoundGenericNominal(); - auto isExistential = argument->isExistentialType(); - return isNominal && !isGeneric && !isExistential && - witnessTablesAreReferenceable && - irgen::isTypeMetadataAccessTrivial(IGM, - argument->getCanonicalType()); - }) && IGM.getTypeInfoForUnlowered(type).isFixedSize(ResilienceExpansion::Maximal); + auto isGenericWithoutPrespecializedConformance = [&]() { + auto genericArgument = argument->getAnyGeneric(); + return genericArgument && genericArgument->isGenericContext() && + (protocols.size() > 0); + }; + auto isExistential = [&]() { return argument->isExistentialType(); }; + auto metadataAccessIsTrivial = [&]() { + return irgen::isTypeMetadataAccessTrivial(IGM, + argument->getCanonicalType()); + }; + return !isGenericWithoutPrespecializedConformance() && !isExistential() && + metadataAccessIsTrivial() && witnessTablesAreReferenceable(); + }); + return allWitnessTablesAreReferenceable + && IGM.getTypeInfoForUnlowered(type).isFixedSize(ResilienceExpansion::Maximal); } /// Is it basically trivial to access the given metadata? If so, we don't @@ -1753,28 +1757,33 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( SmallVector, 4> specializationBlocks; auto switchDestination = llvm::BasicBlock::Create(IGM.getLLVMContext()); - unsigned long index = 0; + unsigned long blockIndex = 0; for (auto specialization : specializations) { - auto conditionBlock = conditionBlocks[index]; + auto conditionBlock = conditionBlocks[blockIndex]; IGF.Builder.emitBlock(conditionBlock); - auto successorBlock = index < conditionBlocks.size() - 1 - ? conditionBlocks[index + 1] + auto successorBlock = blockIndex < conditionBlocks.size() - 1 + ? conditionBlocks[blockIndex + 1] : switchDestination; auto specializationBlock = llvm::BasicBlock::Create(IGM.getLLVMContext()); auto substitutions = specialization->getContextSubstitutionMap( IGM.getSwiftModule(), nominal); llvm::Value *condition = llvm::ConstantInt::get(IGM.Int1Ty, 1); - auto generic = specialization->getAnyGeneric(); - auto parameters = generic->getGenericEnvironment()->getGenericParams(); - for (size_t index = 0; index < parameters.size(); ++index) { - auto parameter = parameters[index]; - auto argument = ((Type *)parameter)->subst(substitutions); + auto nominal = specialization->getAnyNominal(); + auto requirements = GenericTypeRequirements(IGF.IGM, nominal); + int requirementIndex = 0; + for (auto requirement : requirements.getRequirements()) { + if (requirement.Protocol) { + continue; + } + auto parameter = requirement.TypeParameter; + auto argument = parameter.subst(substitutions); llvm::Constant *addr = IGM.getAddrOfTypeMetadata(argument->getCanonicalType()); auto addrInt = IGF.Builder.CreateBitCast(addr, IGM.Int8PtrTy); condition = IGF.Builder.CreateAnd( - condition, IGF.Builder.CreateICmpEQ(addrInt, valueAtIndex(index))); + condition, IGF.Builder.CreateICmpEQ(addrInt, valueAtIndex(requirementIndex))); + ++requirementIndex; } IGF.Builder.CreateCondBr(condition, specializationBlock, successorBlock); @@ -1793,7 +1802,7 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( response = IGF.Builder.CreateInsertValue( response, state, 1, "insert metadata state into response"); specializationBlocks.push_back({specializationBlock, response}); - ++index; + ++blockIndex; } for (auto pair : specializationBlocks) { diff --git a/lib/Immediate/REPL.cpp b/lib/Immediate/REPL.cpp index 67c26f1c7d2d3..42165afa9ea8e 100644 --- a/lib/Immediate/REPL.cpp +++ b/lib/Immediate/REPL.cpp @@ -187,11 +187,7 @@ typeCheckREPLInput(ModuleDecl *MostRecentModule, StringRef Name, REPLInputFile.addImports(ImportsWithOptions); } - bool Done; - do { - parseIntoSourceFile(REPLInputFile, BufferID, &Done, nullptr, - &PersistentState); - } while (!Done); + parseIntoSourceFile(REPLInputFile, BufferID, &PersistentState); performTypeChecking(REPLInputFile); return REPLModule; } @@ -1001,10 +997,6 @@ class REPLEnvironment { IRGenOpts.DebugInfoLevel = IRGenDebugInfoLevel::None; IRGenOpts.DebugInfoFormat = IRGenDebugInfoFormat::None; - // The very first module is a dummy. - CI.getMainModule()->getMainSourceFile(SourceFileKind::REPL).ASTStage = - SourceFile::TypeChecked; - if (!ParseStdlib) { // Force standard library to be loaded immediately. This forces any // errors to appear upfront, and helps eliminate some nasty lag after the diff --git a/lib/Option/CMakeLists.txt b/lib/Option/CMakeLists.txt index bb58724f945e6..70280746f2b28 100644 --- a/lib/Option/CMakeLists.txt +++ b/lib/Option/CMakeLists.txt @@ -1,7 +1,6 @@ add_swift_host_library(swiftOption STATIC Options.cpp - SanitizerOptions.cpp - FILE_DEPENDS SwiftOptions) + SanitizerOptions.cpp) add_dependencies(swiftOption SwiftOptions) target_link_libraries(swiftOption PRIVATE diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 15b3c1b33d293..a23cf13c9d71c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -198,52 +198,33 @@ void Parser::parseTopLevel() { // Parse the body of the file. SmallVector Items; + while (!Tok.is(tok::eof)) { + // If we run into a SIL decl, skip over until the next Swift decl. We need + // to delay parsing these, as SIL parsing currently requires type checking + // Swift decls. + if (isStartOfSILDecl()) { + assert(!isStartOfSwiftDecl() && "Start of both a Swift and SIL decl?"); + skipSILUntilSwiftDecl(); + continue; + } - // If we are in SIL mode, and if the first token is the start of a sil - // declaration, parse that one SIL function and return to the top level. This - // allows type declarations and other things to be parsed, name bound, and - // type checked in batches, similar to immediate mode. This also enforces - // that SIL bodies can only be at the top level. - switch (Tok.getKind()) { - default: parseBraceItems(Items, allowTopLevelCode() ? BraceItemListKind::TopLevelCode : BraceItemListKind::TopLevelLibrary); - break; -// For now, create 'UnknownDecl' for all SIL declarations. -#define CASE_SIL(KW, NAME) \ - case tok::kw_##KW: { \ - assert(isInSILMode() && "'" #KW "' should only be a keyword in SIL mode"); \ - SyntaxParsingContext itemCtxt(SyntaxContext, SyntaxKind::CodeBlockItem); \ - SyntaxParsingContext declCtxt(SyntaxContext, SyntaxContextKind::Decl); \ - SIL->parse##NAME(*this); \ - break; \ - } - CASE_SIL(sil, DeclSIL) - CASE_SIL(sil_stage, DeclSILStage) - CASE_SIL(sil_vtable, SILVTable) - CASE_SIL(sil_global, SILGlobal) - CASE_SIL(sil_witness_table, SILWitnessTable) - CASE_SIL(sil_default_witness_table, SILDefaultWitnessTable) - CASE_SIL(sil_coverage_map, SILCoverageMap) - CASE_SIL(sil_property, SILProperty) - CASE_SIL(sil_scope, SILScope) -#undef CASE_SIL - } - - // In the case of a catastrophic parse error, consume any trailing - // #else, #elseif, or #endif and move on to the next statement or declaration - // block. - if (Tok.is(tok::pound_else) || Tok.is(tok::pound_elseif) || - Tok.is(tok::pound_endif)) { - diagnose(Tok.getLoc(), - diag::unexpected_conditional_compilation_block_terminator); - // Create 'UnknownDecl' for orphan directives. - SyntaxParsingContext itemCtxt(SyntaxContext, SyntaxKind::CodeBlockItem); - SyntaxParsingContext declCtxt(SyntaxContext, SyntaxContextKind::Decl); + // In the case of a catastrophic parse error, consume any trailing + // #else, #elseif, or #endif and move on to the next statement or + // declaration block. + if (Tok.is(tok::pound_else) || Tok.is(tok::pound_elseif) || + Tok.is(tok::pound_endif)) { + diagnose(Tok.getLoc(), + diag::unexpected_conditional_compilation_block_terminator); + // Create 'UnknownDecl' for orphan directives. + SyntaxParsingContext itemCtxt(SyntaxContext, SyntaxKind::CodeBlockItem); + SyntaxParsingContext declCtxt(SyntaxContext, SyntaxContextKind::Decl); - consumeToken(); + consumeToken(); + } } // Add newly parsed decls to the module. @@ -258,15 +239,60 @@ void Parser::parseTopLevel() { SF.ASTStage = SourceFile::Parsed; verify(SF); - // Next time start relexing from the beginning of the comment so that we can - // attach it to the token. - State->markParserPosition(getParserPosition(), - InPoundLineEnvironment); + // Finalize the token receiver. + SyntaxContext->addToken(Tok, LeadingTrivia, TrailingTrivia); + TokReceiver->finalize(); +} + +void Parser::parseTopLevelSIL() { + assert(SIL && isInSILMode()); + + // Prime the lexer. + if (Tok.is(tok::NUM_TOKENS)) + consumeTokenWithoutFeedingReceiver(); + + auto skipToNextSILDecl = [&]() { + while (!Tok.is(tok::eof) && !isStartOfSILDecl()) + skipSingle(); + }; + + while (!Tok.is(tok::eof)) { + // If we run into a Swift decl, skip over until we find the next SIL decl. + if (isStartOfSwiftDecl()) { + assert(!isStartOfSILDecl() && "Start of both a Swift and SIL decl?"); + skipToNextSILDecl(); + continue; + } - // If we are done parsing the whole file, finalize the token receiver. - if (Tok.is(tok::eof)) { - SyntaxContext->addToken(Tok, LeadingTrivia, TrailingTrivia); - TokReceiver->finalize(); + switch (Tok.getKind()) { +#define CASE_SIL(KW, NAME) \ + case tok::kw_##KW: { \ + /* If we failed to parse a SIL decl, move onto the next SIL decl to \ + better help recovery. */ \ + if (SIL->parse##NAME(*this)) { \ + Lexer::SILBodyRAII sbr(*L); \ + skipToNextSILDecl(); \ + } \ + break; \ + } + CASE_SIL(sil, DeclSIL) + CASE_SIL(sil_stage, DeclSILStage) + CASE_SIL(sil_vtable, SILVTable) + CASE_SIL(sil_global, SILGlobal) + CASE_SIL(sil_witness_table, SILWitnessTable) + CASE_SIL(sil_default_witness_table, SILDefaultWitnessTable) + CASE_SIL(sil_differentiability_witness, SILDifferentiabilityWitness) + CASE_SIL(sil_coverage_map, SILCoverageMap) + CASE_SIL(sil_property, SILProperty) + CASE_SIL(sil_scope, SILScope) +#undef CASE_SIL + default: + // If we reached here, we have something malformed that isn't a Swift decl + // or a SIL decl. Emit an error and skip ahead to the next SIL decl. + diagnose(Tok, diag::expected_sil_keyword); + skipToNextSILDecl(); + break; + } } } @@ -3046,9 +3072,9 @@ bool Parser::parseDeclModifierList(DeclAttributes &Attributes, // treat 'class' as a modifier; in the case of a following CC // token, we cannot be sure there is no intention to override // or witness something static. - if (isStartOfDecl() || (isa(CurDeclContext) && - (Tok.is(tok::code_complete) || - Tok.getRawText().equals("override")))) { + if (isStartOfSwiftDecl() || (isa(CurDeclContext) && + (Tok.is(tok::code_complete) || + Tok.getRawText().equals("override")))) { /* We're OK */ } else { // This 'class' is a real ClassDecl introducer. @@ -3295,8 +3321,7 @@ static bool isParenthesizedUnowned(Parser &P) { (P.Tok.getText() == "safe" || P.Tok.getText() == "unsafe"); } - -bool Parser::isStartOfDecl() { +bool Parser::isStartOfSwiftDecl() { // If this is obviously not the start of a decl, then we're done. if (!isKeywordPossibleDeclStart(Tok)) return false; @@ -3347,7 +3372,36 @@ bool Parser::isStartOfDecl() { if (Tok.isAny(tok::r_brace, tok::eof, tok::pound_endif)) return true; - return isStartOfDecl(); + return isStartOfSwiftDecl(); + } + + // If we have a decl modifying keyword, check if the next token is a valid + // decl start. This is necessary to correctly handle Swift keywords that are + // shared by SIL, e.g 'private' in 'sil private @foo :'. We need to make sure + // this isn't considered a valid Swift decl start. + if (Tok.isKeyword()) { + auto DAK = DeclAttribute::getAttrKindFromString(Tok.getText()); + if (DAK != DAK_Count && DeclAttribute::isDeclModifier(DAK)) { + BacktrackingScope backtrack(*this); + consumeToken(); + + // Eat paren after modifier name; e.g. private(set) + if (consumeIf(tok::l_paren)) { + while (Tok.isNot(tok::r_brace, tok::eof, tok::pound_endif)) { + if (consumeIf(tok::r_paren)) + break; + + // If we found the start of a decl while trying to skip over the + // paren, then we have something incomplete like 'private('. Return + // true for better recovery. + if (isStartOfSwiftDecl()) + return true; + + skipSingle(); + } + } + return isStartOfSwiftDecl(); + } } // Otherwise, the only hard case left is the identifier case. @@ -3373,7 +3427,7 @@ bool Parser::isStartOfDecl() { consumeToken(tok::l_paren); consumeToken(tok::identifier); consumeToken(tok::r_paren); - return isStartOfDecl(); + return isStartOfSwiftDecl(); } // If the next token is obviously not the start of a decl, bail early. @@ -3383,7 +3437,31 @@ bool Parser::isStartOfDecl() { // Otherwise, do a recursive parse. Parser::BacktrackingScope Backtrack(*this); consumeToken(tok::identifier); - return isStartOfDecl(); + return isStartOfSwiftDecl(); +} + +bool Parser::isStartOfSILDecl() { + switch (Tok.getKind()) { + case tok::kw_sil: + case tok::kw_sil_stage: + case tok::kw_sil_property: + case tok::kw_sil_vtable: + case tok::kw_sil_global: + case tok::kw_sil_witness_table: + case tok::kw_sil_default_witness_table: + case tok::kw_sil_differentiability_witness: + case tok::kw_sil_coverage_map: + case tok::kw_sil_scope: + // SIL decls must start on a new line. + return Tok.isAtStartOfLine(); + case tok::kw_undef: + case tok::NUM_TOKENS: + return false; +#define SIL_KEYWORD(Name) +#define TOKEN(Name) case tok:: Name: return false; +#include "swift/Syntax/TokenKinds.def" + } + llvm_unreachable("Unhandled case in switch"); } void Parser::consumeDecl(ParserPosition BeginParserPosition, @@ -3929,7 +4007,8 @@ Parser::parseDeclListDelayed(IterableDeclContext *IDC) { return {std::vector(), None}; } - auto BeginParserPosition = getParserPosition({BodyRange.Start, SourceLoc()}); + auto BeginParserPosition = getParserPosition(BodyRange.Start, + /*previousLoc*/ SourceLoc()); auto EndLexerState = L->getStateForEndOfTokenLoc(BodyRange.End); // ParserPositionRAII needs a primed parser to restore to. @@ -5133,6 +5212,41 @@ bool Parser::skipBracedBlock() { return OpenBraces != 0; } +void Parser::skipSILUntilSwiftDecl() { + // For now, create 'UnknownDecl' for all SIL declarations. + SyntaxParsingContext itemCtxt(SyntaxContext, SyntaxKind::CodeBlockItem); + SyntaxParsingContext declCtxt(SyntaxContext, SyntaxContextKind::Decl); + + // Tell the lexer we're about to start lexing SIL. + Lexer::SILBodyRAII sbr(*L); + + // Enter a top-level scope. This is necessary as parseType may need to setup + // child scopes for generic params. + Scope topLevel(this, ScopeKind::TopLevel); + + while (!Tok.is(tok::eof) && !isStartOfSwiftDecl()) { + // SIL pound dotted paths need to be skipped specially as they can contain + // decl keywords like 'subscript'. + if (consumeIf(tok::pound)) { + do { + consumeToken(); + } while (consumeIf(tok::period)); + continue; + } + + // SIL types need to be skipped specially as they can contain attributes on + // tuples which can look like decl attributes. + if (consumeIf(tok::sil_dollar)) { + if (Tok.isAnyOperator() && Tok.getText().startswith("*")) { + consumeStartingCharacterOfCurrentToken(); + } + (void)parseType(); + continue; + } + skipSingle(); + } +} + /// Returns a descriptive name for the given accessor/addressor kind. static StringRef getAccessorNameForDiagnostic(AccessorKind accessorKind, bool article) { @@ -5840,6 +5954,7 @@ Parser::parseDeclVar(ParseDeclOptions Flags, VD->setStatic(StaticLoc.isValid()); VD->getAttrs() = Attributes; setLocalDiscriminator(VD); + VD->setTopLevelGlobal(topLevelDecl); // Set original declaration in `@differentiable` attributes. setOriginalDeclarationForDifferentiableAttributes(Attributes, VD); @@ -6307,7 +6422,8 @@ BraceStmt *Parser::parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD) { "function body should be delayed"); auto bodyRange = AFD->getBodySourceRange(); - auto BeginParserPosition = getParserPosition({bodyRange.Start, SourceLoc()}); + auto BeginParserPosition = getParserPosition(bodyRange.Start, + /*previousLoc*/ SourceLoc()); auto EndLexerState = L->getStateForEndOfTokenLoc(AFD->getEndLoc()); // ParserPositionRAII needs a primed parser to restore to. diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index eac6df3a4d0f8..ffe1e1e8836a0 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -3463,7 +3463,7 @@ ParserResult Parser::parseExprCollection() { // If The next token is at the beginning of a new line and can never start // an element, break. if (Tok.isAtStartOfLine() && (Tok.isAny(tok::r_brace, tok::pound_endif) || - isStartOfDecl() || isStartOfStmt())) + isStartOfSwiftDecl() || isStartOfStmt())) break; diagnose(Tok, diag::expected_separator, ",") diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 3805594342060..fd7d15acf87f1 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -306,14 +306,7 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl &Entries, Tok.isNot(tok::pound_elseif) && Tok.isNot(tok::pound_else) && Tok.isNot(tok::eof) && - Tok.isNot(tok::kw_sil) && - Tok.isNot(tok::kw_sil_scope) && - Tok.isNot(tok::kw_sil_stage) && - Tok.isNot(tok::kw_sil_vtable) && - Tok.isNot(tok::kw_sil_global) && - Tok.isNot(tok::kw_sil_witness_table) && - Tok.isNot(tok::kw_sil_default_witness_table) && - Tok.isNot(tok::kw_sil_property) && + !isStartOfSILDecl() && (isConditionalBlock || !isTerminatorForBraceItemListKind(Kind, Entries))) { @@ -400,7 +393,7 @@ ParserStatus Parser::parseBraceItems(SmallVectorImpl &Entries, ParserStatus Status = parseLineDirective(false); BraceItemsStatus |= Status; NeedParseErrorRecovery = Status.isError(); - } else if (isStartOfDecl()) { + } else if (isStartOfSwiftDecl()) { SmallVector TmpDecls; ParserResult DeclResult = parseDecl(IsTopLevel ? PD_AllowTopLevel : PD_Default, @@ -702,7 +695,7 @@ ParserResult Parser::parseStmtBreak() { // since the expression after the break is dead, we don't feel bad eagerly // parsing this. if (Tok.is(tok::identifier) && !Tok.isAtStartOfLine() && - !isStartOfStmt() && !isStartOfDecl()) + !isStartOfStmt() && !isStartOfSwiftDecl()) TargetLoc = consumeIdentifier(&Target); return makeParserResult(new (Context) BreakStmt(Loc, Target, TargetLoc)); @@ -725,7 +718,7 @@ ParserResult Parser::parseStmtContinue() { // since the expression after the continue is dead, we don't feel bad eagerly // parsing this. if (Tok.is(tok::identifier) && !Tok.isAtStartOfLine() && - !isStartOfStmt() && !isStartOfDecl()) + !isStartOfStmt() && !isStartOfSwiftDecl()) TargetLoc = consumeIdentifier(&Target); return makeParserResult(new (Context) ContinueStmt(Loc, Target, TargetLoc)); @@ -758,7 +751,7 @@ ParserResult Parser::parseStmtReturn(SourceLoc tryLoc) { if (Tok.isNot(tok::r_brace, tok::semi, tok::eof, tok::pound_if, tok::pound_error, tok::pound_warning, tok::pound_endif, tok::pound_else, tok::pound_elseif) && - !isStartOfStmt() && !isStartOfDecl()) { + !isStartOfStmt() && !isStartOfSwiftDecl()) { SourceLoc ExprLoc = Tok.getLoc(); // Issue a warning when the returned expression is on a different line than diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 43eb3d157d2cb..5894244ed0071 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -1636,7 +1636,7 @@ bool Parser::canParseOldStyleProtocolComposition() { bool Parser::canParseTypeTupleBody() { if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::r_brace) && - Tok.isNotEllipsis() && !isStartOfDecl()) { + Tok.isNotEllipsis() && !isStartOfSwiftDecl()) { do { // The contextual inout marker is part of argument lists. consumeIf(tok::kw_inout); @@ -1661,8 +1661,7 @@ bool Parser::canParseTypeTupleBody() { if (consumeIf(tok::equal)) { while (Tok.isNot(tok::eof) && Tok.isNot(tok::r_paren) && Tok.isNot(tok::r_brace) && Tok.isNotEllipsis() && - Tok.isNot(tok::comma) && - !isStartOfDecl()) { + Tok.isNot(tok::comma) && !isStartOfSwiftDecl()) { skipSingle(); } } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 8ac9ec0c6ffa0..48379169d47cb 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -148,7 +148,7 @@ void Parser::performCodeCompletionSecondPassImpl( if (info.PrevOffset != ~0U) prevLoc = SourceMgr.getLocForOffset(BufferID, info.PrevOffset); // Set the parser position to the start of the delayed decl or the body. - restoreParserPosition(getParserPosition({startLoc, prevLoc})); + restoreParserPosition(getParserPosition(startLoc, prevLoc)); // Do not delay parsing in the second pass. llvm::SaveAndRestore DisableDelayedBody(DelayBodyParsing, false); @@ -543,13 +543,6 @@ Parser::Parser(std::unique_ptr Lex, SourceFile &SF, // Set the token to a sentinel so that we know the lexer isn't primed yet. // This cannot be tok::unknown, since that is a token the lexer could produce. Tok.setKind(tok::NUM_TOKENS); - - auto ParserPos = State->takeParserPosition(); - if (ParserPos.isValid() && - L->isStateForCurrentBuffer(ParserPos.LS)) { - restoreParserPosition(ParserPos); - InPoundLineEnvironment = State->InPoundLineEnvironment; - } } Parser::~Parser() { @@ -558,6 +551,8 @@ Parser::~Parser() { delete SyntaxContext; } +bool Parser::isInSILMode() const { return SF.Kind == SourceFileKind::SIL; } + bool Parser::allowTopLevelCode() const { return SF.isScriptMode(); } @@ -713,7 +708,7 @@ SourceLoc Parser::skipUntilGreaterInTypeList(bool protocolComposition) { // 'Self' can appear in types, skip it. if (Tok.is(tok::kw_Self)) break; - if (isStartOfStmt() || isStartOfDecl() || Tok.is(tok::pound_endif)) + if (isStartOfStmt() || isStartOfSwiftDecl() || Tok.is(tok::pound_endif)) return lastLoc; break; @@ -742,7 +737,7 @@ void Parser::skipUntilDeclRBrace() { while (Tok.isNot(tok::eof, tok::r_brace, tok::pound_endif, tok::pound_else, tok::pound_elseif, tok::code_complete) && - !isStartOfDecl()) + !isStartOfSwiftDecl()) skipSingle(); } @@ -750,7 +745,7 @@ void Parser::skipUntilDeclStmtRBrace(tok T1) { while (Tok.isNot(T1, tok::eof, tok::r_brace, tok::pound_endif, tok::pound_else, tok::pound_elseif, tok::code_complete) && - !isStartOfStmt() && !isStartOfDecl()) { + !isStartOfStmt() && !isStartOfSwiftDecl()) { skipSingle(); } } @@ -759,7 +754,7 @@ void Parser::skipUntilDeclStmtRBrace(tok T1, tok T2) { while (Tok.isNot(T1, T2, tok::eof, tok::r_brace, tok::pound_endif, tok::pound_else, tok::pound_elseif, tok::code_complete) && - !isStartOfStmt() && !isStartOfDecl()) { + !isStartOfStmt() && !isStartOfSwiftDecl()) { skipSingle(); } } @@ -770,7 +765,7 @@ void Parser::skipListUntilDeclRBrace(SourceLoc startLoc, tok T1, tok T2) { bool hasDelimiter = Tok.getLoc() == startLoc || consumeIf(tok::comma); bool possibleDeclStartsLine = Tok.isAtStartOfLine(); - if (isStartOfDecl()) { + if (isStartOfSwiftDecl()) { // Could have encountered something like `_ var:` // or `let foo:` or `var:` @@ -800,7 +795,7 @@ void Parser::skipListUntilDeclRBrace(SourceLoc startLoc, tok T1, tok T2) { void Parser::skipUntilDeclRBrace(tok T1, tok T2) { while (Tok.isNot(T1, T2, tok::eof, tok::r_brace, tok::pound_endif, tok::pound_else, tok::pound_elseif) && - !isStartOfDecl()) { + !isStartOfSwiftDecl()) { skipSingle(); } } @@ -1106,7 +1101,7 @@ Parser::parseList(tok RightK, SourceLoc LeftLoc, SourceLoc &RightLoc, // If we're in a comma-separated list, the next token is at the // beginning of a new line and can never start an element, break. if (Tok.isAtStartOfLine() && - (Tok.is(tok::r_brace) || isStartOfDecl() || isStartOfStmt())) { + (Tok.is(tok::r_brace) || isStartOfSwiftDecl() || isStartOfStmt())) { break; } // If we found EOF or such, bailout. @@ -1238,11 +1233,7 @@ ParserUnit::~ParserUnit() { OpaqueSyntaxNode ParserUnit::parse() { auto &P = getParser(); - bool Done = false; - while (!Done) { - P.parseTopLevel(); - Done = P.Tok.is(tok::eof); - } + P.parseTopLevel(); return P.finalizeSyntaxTree(); } diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index 35aa6f9a2be75..8050a926fe572 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -76,6 +76,7 @@ class SILParserTUState : public SILParserTUStateBase { bool parseSILGlobal(Parser &P) override; bool parseSILWitnessTable(Parser &P) override; bool parseSILDefaultWitnessTable(Parser &P) override; + bool parseSILDifferentiabilityWitness(Parser &P) override; bool parseSILCoverageMap(Parser &P) override; bool parseSILProperty(Parser &P) override; bool parseSILScope(Parser &P) override; @@ -112,16 +113,9 @@ void PrettyStackTraceParser::print(llvm::raw_ostream &out) const { out << '\n'; } -static void parseIntoSourceFileImpl(SourceFile &SF, - unsigned BufferID, - bool *Done, - SILParserState *SIL, - PersistentParserState *PersistentState, - bool FullParse, - bool DelayBodyParsing) { - assert((!FullParse || (SF.canBeParsedInFull() && !SIL)) && - "cannot parse in full with the given parameters!"); - +void swift::parseIntoSourceFile(SourceFile &SF, unsigned int BufferID, + PersistentParserState *PersistentState, + bool DelayBodyParsing) { std::shared_ptr STreeCreator; if (SF.shouldBuildSyntaxTree()) { STreeCreator = std::make_shared( @@ -138,21 +132,15 @@ static void parseIntoSourceFileImpl(SourceFile &SF, DelayBodyParsing = false; if (SF.shouldBuildSyntaxTree()) DelayBodyParsing = false; - if (SIL) - DelayBodyParsing = false; FrontendStatsTracer tracer(SF.getASTContext().Stats, "Parsing"); - Parser P(BufferID, SF, SIL ? SIL->Impl.get() : nullptr, - PersistentState, STreeCreator, DelayBodyParsing); + Parser P(BufferID, SF, /*SIL*/ nullptr, PersistentState, STreeCreator, + DelayBodyParsing); PrettyStackTraceParser StackTrace(P); llvm::SaveAndRestore> S(P.CurrentTokenHash, SF.getInterfaceHashPtr()); - - do { - P.parseTopLevel(); - *Done = P.Tok.is(tok::eof); - } while (FullParse && !*Done); + P.parseTopLevel(); if (STreeCreator) { auto rawNode = P.finalizeSyntaxTree(); @@ -160,28 +148,18 @@ static void parseIntoSourceFileImpl(SourceFile &SF, } } -void swift::parseIntoSourceFile(SourceFile &SF, - unsigned BufferID, - bool *Done, - SILParserState *SIL, - PersistentParserState *PersistentState, - bool DelayBodyParsing) { - parseIntoSourceFileImpl(SF, BufferID, Done, SIL, - PersistentState, - /*FullParse=*/SF.shouldBuildSyntaxTree(), - DelayBodyParsing); -} +void swift::parseSourceFileSIL(SourceFile &SF, SILParserState *sil) { + auto bufferID = SF.getBufferID(); + assert(bufferID); -void swift::parseIntoSourceFileFull(SourceFile &SF, unsigned BufferID, - PersistentParserState *PersistentState, - bool DelayBodyParsing) { - bool Done = false; - parseIntoSourceFileImpl(SF, BufferID, &Done, /*SIL=*/nullptr, - PersistentState, /*FullParse=*/true, - DelayBodyParsing); + FrontendStatsTracer tracer(SF.getASTContext().Stats, "Parsing SIL"); + Parser parser(*bufferID, SF, sil->Impl.get(), + /*persistentParserState*/ nullptr, + /*syntaxTreeCreator*/ nullptr, /*delayBodyParsing*/ false); + PrettyStackTraceParser StackTrace(parser); + parser.parseTopLevelSIL(); } - //===----------------------------------------------------------------------===// // SILParser //===----------------------------------------------------------------------===// @@ -1156,9 +1134,6 @@ bool SILParser::performTypeLocChecking(TypeLoc &T, bool IsSILType, GenericEnvironment *GenericEnv, DeclContext *DC) { // Do some type checking / name binding for the parsed type. - assert(P.SF.ASTStage == SourceFile::Parsing && - "Unexpected stage during parsing!"); - if (GenericEnv == nullptr) GenericEnv = ContextGenericEnv; @@ -1176,12 +1151,6 @@ bool SILParser::performTypeLocChecking(TypeLoc &T, bool IsSILType, static llvm::PointerUnion lookupTopDecl(Parser &P, DeclBaseName Name, bool typeLookup) { // Use UnqualifiedLookup to look through all of the imports. - // We have to lie and say we're done with parsing to make this happen. - assert(P.SF.ASTStage == SourceFile::Parsing && - "Unexpected stage during parsing!"); - llvm::SaveAndRestore ASTStage(P.SF.ASTStage, - SourceFile::Parsed); - UnqualifiedLookupOptions options; if (typeLookup) options |= UnqualifiedLookupFlags::TypeLookup; @@ -2006,6 +1975,108 @@ static bool parseAssignOwnershipQualifier(AssignOwnershipQualifier &Result, return false; } +// Parse a list of integer indices, prefaced with the given string label. +// Returns true on error. +static bool parseIndexList(Parser &P, StringRef label, + SmallVectorImpl &indices, + const Diagnostic &parseIndexDiag) { + SourceLoc loc; + // Parse `[