diff --git a/CHANGELOG.md b/CHANGELOG.md index 84f1c2ecf328a..75263d8e63a6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,18 @@ CHANGELOG Swift Next ---------- +* [SE-0266][]: + + Enumerations with no associated values, or only `Comparable` associated values, can opt-in to synthesized `Comparable` conformance by declaring conformance to the `Comparable` protocol. The synthesized implementation orders the cases first by case-declaration order, and then by lexicographic order of the associated values (if any). + + ```swift + enum Foo: Comparable { + case a(Int), b(Int), c + } + + // .a(0) < .a(1) < .b(0) < .b(1) < .c + ``` + * [SE-0269][]: When an escaping closure explicitly captures `self` in its capture list, the @@ -7901,6 +7913,7 @@ Swift 1.0 [SE-0252]: [SE-0253]: [SE-0254]: +[SE-0266]: [SE-0269]: [SR-106]: diff --git a/README.md b/README.md index c0537d0ae9795..887258c0c2c0f 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,29 @@ Additionally, [Bazel](https://www.bazel.build) between v0.24.1 and v0.25.2 (incl For Ubuntu, you'll need the following development dependencies: - sudo apt-get install git cmake ninja-build clang python uuid-dev libicu-dev icu-devtools libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config libcurl4-openssl-dev libblocksruntime-dev systemtap-sdt-dev tzdata rsync - -Additionally, [Bazel](https://www.bazel.build) between v0.24.1 and v0.25.2 (inclusive) is required to build with TensorFlow support. Ubuntu installation instructions can be found [below](#bazel). +``` +sudo apt-get install \ + clang \ + cmake \ + git \ + icu-devtools \ + libcurl4-openssl-dev \ + libedit-dev \ + libicu-dev \ + libncurses5-dev \ + libpython-dev \ + libsqlite3-dev \ + libxml2-dev \ + ninja-build \ + pkg-config \ + python \ + python-six \ + rsync \ + swig \ + systemtap-sdt-dev \ + tzdata \ + uuid-dev +``` **Note:** LLDB currently requires at least `swig-1.3.40` but will successfully build with version 2 shipped with Ubuntu. diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index d46c6326f174c..325a4fd2a2ed6 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -62,6 +62,7 @@ set(SWIFT_BENCH_MODULES single-source/Combos single-source/DataBenchmarks single-source/DeadArray + single-source/DevirtualizeProtocolComposition single-source/DictOfArraysToArrayOfDicts single-source/DictTest single-source/DictTest2 diff --git a/benchmark/single-source/DevirtualizeProtocolComposition.swift b/benchmark/single-source/DevirtualizeProtocolComposition.swift new file mode 100644 index 0000000000000..d90bbd1da71e6 --- /dev/null +++ b/benchmark/single-source/DevirtualizeProtocolComposition.swift @@ -0,0 +1,45 @@ +//===--- DevirtualizeProtocolComposition.swift -------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import TestsUtils + +public let DevirtualizeProtocolComposition = [ + BenchmarkInfo(name: "DevirtualizeProtocolComposition", runFunction: run_DevirtualizeProtocolComposition, tags: [.validation, .api]), +] + +protocol Pingable { func ping() -> Int; func pong() -> Int} + +public class Game { + func length() -> Int { return 10 } +} + +public class PingPong: Game { } + +extension PingPong : Pingable { + func ping() -> Int { return 1 } + func pong() -> Int { return 2 } +} + +func playGame(_ x: Game & Pingable) -> Int { + var sum = 0 + for _ in 0..) + endforeach() + + if(${LIPO_SDK} IN_LIST SWIFT_APPLE_PLATFORMS) + if(LIPO_CODESIGN) + set(codesign_command COMMAND "codesign" "-f" "-s" "-" "${LIPO_OUTPUT}") + endif() + # Use lipo to create the final binary. + add_custom_command_target(unused_var + COMMAND "${SWIFT_LIPO}" "-create" "-output" "${LIPO_OUTPUT}" ${source_binaries} + ${codesign_command} + CUSTOM_TARGET_NAME "${LIPO_TARGET}" + OUTPUT "${LIPO_OUTPUT}" + DEPENDS ${source_targets}) + else() + # We don't know how to create fat binaries for other platforms. + add_custom_command_target(unused_var + COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${source_binaries}" "${LIPO_OUTPUT}" + CUSTOM_TARGET_NAME "${LIPO_TARGET}" + OUTPUT "${LIPO_OUTPUT}" + DEPENDS ${source_targets}) + endif() +endfunction() + +# Add a single variant of a new Swift library. +# +# Usage: +# _add_swift_host_library_single( +# target +# name +# [SHARED] +# [STATIC] +# [SDK sdk] +# [ARCHITECTURE architecture] +# [LLVM_LINK_COMPONENTS comp1 ...] +# SWIFT_ENABLE_TENSORFLOW +# [EXTRA_RPATHS rpath1 ...] +# END SWIFT_ENABLE_TENSORFLOW +# INSTALL_IN_COMPONENT comp +# source1 [source2 source3 ...]) +# +# target +# Name of the target (e.g., swiftParse-IOS-armv7). +# +# name +# Name of the library (e.g., swiftParse). +# +# SHARED +# Build a shared library. +# +# STATIC +# Build a static library. +# +# SDK sdk +# SDK to build for. +# +# ARCHITECTURE +# Architecture to build for. +# +# LLVM_LINK_COMPONENTS +# LLVM components this library depends on. +# +# SWIFT_ENABLE_TENSORFLOW +# EXTRA_RPATHS +# List of directories to add to this library's RPATH. +# END SWIFT_ENABLE_TENSORFLOW +# +# INSTALL_IN_COMPONENT comp +# The Swift installation component that this library belongs to. +# +# source1 ... +# Sources to add into this library +function(_add_swift_host_library_single target name) + set(SWIFTLIB_SINGLE_options + SHARED + STATIC) + set(SWIFTLIB_SINGLE_single_parameter_options + ARCHITECTURE + INSTALL_IN_COMPONENT + SDK) + set(SWIFTLIB_SINGLE_multiple_parameter_options + # SWIFT_ENABLE_TENSORFLOW + EXTRA_RPATHS + # END SWIFT_ENABLE_TENSORFLOW + GYB_SOURCES + LLVM_LINK_COMPONENTS) + + cmake_parse_arguments(SWIFTLIB_SINGLE + "${SWIFTLIB_SINGLE_options}" + "${SWIFTLIB_SINGLE_single_parameter_options}" + "${SWIFTLIB_SINGLE_multiple_parameter_options}" + ${ARGN}) + + set(SWIFTLIB_SINGLE_SOURCES ${SWIFTLIB_SINGLE_UNPARSED_ARGUMENTS}) + + translate_flags(SWIFTLIB_SINGLE "${SWIFTLIB_SINGLE_options}") + + # Check arguments. + precondition(SWIFTLIB_SINGLE_SDK MESSAGE "Should specify an SDK") + precondition(SWIFTLIB_SINGLE_ARCHITECTURE MESSAGE "Should specify an architecture") + precondition(SWIFTLIB_SINGLE_INSTALL_IN_COMPONENT MESSAGE "INSTALL_IN_COMPONENT is required") + + if(NOT SWIFTLIB_SINGLE_SHARED AND NOT SWIFTLIB_SINGLE_STATIC) + message(FATAL_ERROR "Either SHARED or STATIC must be specified") + endif() + + # Determine the subdirectory where this library will be installed. + set(SWIFTLIB_SINGLE_SUBDIR + "${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_LIB_SUBDIR}/${SWIFTLIB_SINGLE_ARCHITECTURE}") + + # Include LLVM Bitcode slices for iOS, Watch OS, and Apple TV OS device libraries. + set(embed_bitcode_arg) + if(SWIFT_EMBED_BITCODE_SECTION) + if("${SWIFTLIB_SINGLE_SDK}" STREQUAL "IOS" OR "${SWIFTLIB_SINGLE_SDK}" STREQUAL "TVOS" OR "${SWIFTLIB_SINGLE_SDK}" STREQUAL "WATCHOS") + list(APPEND SWIFTLIB_SINGLE_C_COMPILE_FLAGS "-fembed-bitcode") + set(embed_bitcode_arg EMBED_BITCODE) + endif() + endif() + + if(XCODE) + string(REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR}) + list(GET split_path -1 dir) + file(GLOB_RECURSE SWIFTLIB_SINGLE_HEADERS + ${SWIFT_SOURCE_DIR}/include/swift${dir}/*.h + ${SWIFT_SOURCE_DIR}/include/swift${dir}/*.def + ${CMAKE_CURRENT_SOURCE_DIR}/*.def) + + file(GLOB_RECURSE SWIFTLIB_SINGLE_TDS + ${SWIFT_SOURCE_DIR}/include/swift${dir}/*.td) + + set_source_files_properties(${SWIFTLIB_SINGLE_HEADERS} ${SWIFTLIB_SINGLE_TDS} + PROPERTIES + HEADER_FILE_ONLY true) + source_group("TableGen descriptions" FILES ${SWIFTLIB_SINGLE_TDS}) + + set(SWIFTLIB_SINGLE_SOURCES ${SWIFTLIB_SINGLE_SOURCES} ${SWIFTLIB_SINGLE_HEADERS} ${SWIFTLIB_SINGLE_TDS}) + endif() + + if(SWIFTLIB_SINGLE_SHARED) + set(libkind SHARED) + elseif(SWIFTLIB_SINGLE_STATIC) + set(libkind STATIC) + endif() + + if(SWIFTLIB_SINGLE_GYB_SOURCES) + handle_gyb_sources( + gyb_dependency_targets + SWIFTLIB_SINGLE_GYB_SOURCES + "${SWIFTLIB_SINGLE_ARCHITECTURE}") + set(SWIFTLIB_SINGLE_SOURCES ${SWIFTLIB_SINGLE_SOURCES} + ${SWIFTLIB_SINGLE_GYB_SOURCES}) + endif() + + add_library("${target}" ${libkind} + ${SWIFTLIB_SINGLE_SOURCES}) + _set_target_prefix_and_suffix("${target}" "${libkind}" "${SWIFTLIB_SINGLE_SDK}") + + if("${SWIFTLIB_SINGLE_SDK}" STREQUAL "WINDOWS") + swift_windows_include_for_arch(${SWIFTLIB_SINGLE_ARCHITECTURE} SWIFTLIB_INCLUDE) + target_include_directories("${target}" SYSTEM PRIVATE ${SWIFTLIB_INCLUDE}) + set_target_properties(${target} + PROPERTIES + CXX_STANDARD 14) + endif() + + if("${SWIFTLIB_SINGLE_SDK}" STREQUAL "WINDOWS" AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") + if("${libkind}" STREQUAL "SHARED") + # Each dll has an associated .lib (import library); since we may be + # building on a non-DLL platform (not windows), create an imported target + # for the library which created implicitly by the dll. + add_custom_command_target(${target}_IMPORT_LIBRARY + OUTPUT "${SWIFTLIB_DIR}/${SWIFTLIB_SINGLE_SUBDIR}/${name}.lib" + DEPENDS "${target}") + add_library(${target}_IMPLIB SHARED IMPORTED GLOBAL) + set_property(TARGET "${target}_IMPLIB" PROPERTY + IMPORTED_LOCATION "${SWIFTLIB_DIR}/${SWIFTLIB_SINGLE_SUBDIR}/${name}.lib") + add_dependencies(${target}_IMPLIB ${${target}_IMPORT_LIBRARY}) + endif() + set_property(TARGET "${target}" PROPERTY NO_SONAME ON) + endif() + + llvm_update_compile_flags(${target}) + + set_output_directory(${target} + BINARY_DIR ${SWIFT_RUNTIME_OUTPUT_INTDIR} + LIBRARY_DIR ${SWIFT_LIBRARY_OUTPUT_INTDIR}) + + if(SWIFTLIB_SINGLE_SDK IN_LIST SWIFT_APPLE_PLATFORMS) + set_target_properties("${target}" + PROPERTIES + INSTALL_NAME_DIR "@rpath") + elseif("${SWIFTLIB_SINGLE_SDK}" STREQUAL "LINUX") + set_target_properties("${target}" + PROPERTIES + INSTALL_RPATH "$ORIGIN:/usr/lib/swift/linux") + elseif("${SWIFTLIB_SINGLE_SDK}" STREQUAL "CYGWIN") + set_target_properties("${target}" + PROPERTIES + INSTALL_RPATH "$ORIGIN:/usr/lib/swift/cygwin") + elseif("${SWIFTLIB_SINGLE_SDK}" STREQUAL "ANDROID") + # Only set the install RPATH if cross-compiling the host tools, in which + # case both the NDK and Sysroot paths must be set. + if(NOT "${SWIFT_ANDROID_NDK_PATH}" STREQUAL "" AND + NOT "${SWIFT_ANDROID_NATIVE_SYSROOT}" STREQUAL "") + set_target_properties("${target}" + PROPERTIES + INSTALL_RPATH "$ORIGIN") + endif() + endif() + + # SWIFT_ENABLE_TENSORFLOW + # Hande extra RPATHs. + set(local_rpath "") + if("${SWIFTLIB_SINGLE_SDK}" STREQUAL "LINUX" AND NOT "${SWIFTLIB_SINGLE_SDK}" STREQUAL "ANDROID") + set(local_rpath "$ORIGIN:/usr/lib/swift/linux") + elseif("${SWIFTLIB_SINGLE_SDK}" STREQUAL "CYGWIN") + set(local_rpath "$ORIGIN:/usr/lib/swift/cygwin") + endif() + foreach(rpath_element ${SWIFTLIB_SINGLE_EXTRA_RPATHS}) + if("${local_rpath}" STREQUAL "") + set(local_rpath "${rpath_element}") + else() + set(local_rpath "${local_rpath}:${rpath_element}") + endif() + endforeach() + if(NOT "${local_rpath}" STREQUAL "") + set_target_properties("${target}" + PROPERTIES + INSTALL_RPATH "${local_rpath}") + endif() + # END SWIFT_ENABLE_TENSORFLOW + + set_target_properties("${target}" PROPERTIES BUILD_WITH_INSTALL_RPATH YES) + set_target_properties("${target}" PROPERTIES FOLDER "Swift libraries") + + set_target_properties(${target} + PROPERTIES + # Library name (without the variant information) + OUTPUT_NAME ${name}) + + # Handle linking and dependencies. + add_dependencies_multiple_targets( + TARGETS "${target}" + DEPENDS + ${gyb_dependency_targets} + ${LLVM_COMMON_DEPENDS}) + + # Call llvm_config() only for libraries that are part of the compiler. + swift_common_llvm_config("${target}" ${SWIFTLIB_SINGLE_LLVM_LINK_COMPONENTS}) + + # Collect compile and link flags for the static and non-static targets. + # Don't set PROPERTY COMPILE_FLAGS or LINK_FLAGS directly. + set(c_compile_flags ${SWIFTLIB_SINGLE_C_COMPILE_FLAGS}) + set(link_flags) + + set(library_search_subdir "${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_LIB_SUBDIR}") + set(library_search_directories + "${SWIFTLIB_DIR}/${SWIFTLIB_SINGLE_SUBDIR}" + "${SWIFT_NATIVE_SWIFT_TOOLS_PATH}/../lib/swift/${SWIFTLIB_SINGLE_SUBDIR}" + "${SWIFT_NATIVE_SWIFT_TOOLS_PATH}/../lib/swift/${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_LIB_SUBDIR}") + + # In certain cases when building, the environment variable SDKROOT is set to override + # where the sdk root is located in the system. If that environment variable has been + # set by the user, respect it and add the specified SDKROOT directory to the + # library_search_directories so we are able to link against those libraries + if(DEFINED ENV{SDKROOT} AND EXISTS "$ENV{SDKROOT}/usr/lib/swift") + list(APPEND library_search_directories "$ENV{SDKROOT}/usr/lib/swift") + endif() + + _add_variant_c_compile_flags( + SDK "${SWIFTLIB_SINGLE_SDK}" + ARCH "${SWIFTLIB_SINGLE_ARCHITECTURE}" + BUILD_TYPE ${CMAKE_BUILD_TYPE} + ENABLE_ASSERTIONS ${LLVM_ENABLE_ASSERTIONS} + ANALYZE_CODE_COVERAGE ${SWIFT_ANALYZE_CODE_COVERAGE} + ENABLE_LTO ${SWIFT_TOOLS_ENABLE_LTO} + RESULT_VAR_NAME c_compile_flags + ) + + if(SWIFTLIB_SINGLE_SDK STREQUAL WINDOWS) + if(libkind STREQUAL SHARED) + list(APPEND c_compile_flags -D_WINDLL) + endif() + endif() + _add_variant_link_flags( + SDK "${SWIFTLIB_SINGLE_SDK}" + ARCH "${SWIFTLIB_SINGLE_ARCHITECTURE}" + BUILD_TYPE ${CMAKE_BUILD_TYPE} + ENABLE_ASSERTIONS ${LLVM_ENABLE_ASSERTIONS} + ANALYZE_CODE_COVERAGE ${SWIFT_ANALYZE_CODE_COVERAGE} + ENABLE_LTO ${SWIFT_TOOLS_ENABLE_LTO} + LTO_OBJECT_NAME "${target}-${SWIFTLIB_SINGLE_SDK}-${SWIFTLIB_SINGLE_ARCHITECTURE}" + RESULT_VAR_NAME link_flags + LIBRARY_SEARCH_DIRECTORIES_VAR_NAME library_search_directories + ) + + # Set compilation and link flags. + if(SWIFTLIB_SINGLE_SDK STREQUAL WINDOWS) + swift_windows_include_for_arch(${SWIFTLIB_SINGLE_ARCHITECTURE} + ${SWIFTLIB_SINGLE_ARCHITECTURE}_INCLUDE) + target_include_directories(${target} SYSTEM PRIVATE + ${${SWIFTLIB_SINGLE_ARCHITECTURE}_INCLUDE}) + + if(NOT ${CMAKE_C_COMPILER_ID} STREQUAL MSVC) + swift_windows_get_sdk_vfs_overlay(SWIFTLIB_SINGLE_VFS_OVERLAY) + target_compile_options(${target} PRIVATE + "SHELL:-Xclang -ivfsoverlay -Xclang ${SWIFTLIB_SINGLE_VFS_OVERLAY}") + + # MSVC doesn't support -Xclang. We don't need to manually specify + # the dependent libraries as `cl` does so. + target_compile_options(${target} PRIVATE + "SHELL:-Xclang --dependent-lib=oldnames" + # TODO(compnerd) handle /MT, /MTd + "SHELL:-Xclang --dependent-lib=msvcrt$<$:d>") + endif() + endif() + + target_compile_options(${target} PRIVATE + ${c_compile_flags}) + target_link_options(${target} PRIVATE + ${link_flags}) + if(${SWIFTLIB_SINGLE_SDK} IN_LIST SWIFT_APPLE_PLATFORMS) + target_link_options(${target} PRIVATE + "LINKER:-compatibility_version,1") + if(SWIFT_COMPILER_VERSION) + target_link_options(${target} PRIVATE + "LINKER:-current_version,${SWIFT_COMPILER_VERSION}") + endif() + # Include LLVM Bitcode slices for iOS, Watch OS, and Apple TV OS device libraries. + if(SWIFT_EMBED_BITCODE_SECTION) + if(${SWIFTLIB_SINGLE_SDK} MATCHES "(I|TV|WATCH)OS") + # 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() - set("${result_var_name}" ${result_list} PARENT_SCOPE) + target_link_libraries(${target} PRIVATE + ${link_libraries}) + target_link_directories(${target} PRIVATE + ${library_search_directories}) + + # Do not add code here. endfunction() -# Add a universal binary target created from the output of the given -# set of targets by running 'lipo'. +# Add a new Swift host library. # # Usage: -# _add_swift_lipo_target( -# sdk # The name of the SDK the target was created for. -# # Examples include "OSX", "IOS", "ANDROID", etc. -# target # The name of the target to create -# output # The file to be created by this target -# source_targets... # The source targets whose outputs will be -# # lipo'd into the output. -# ) -function(_add_swift_lipo_target) - cmake_parse_arguments( - LIPO # prefix - "CODESIGN" # options - "SDK;TARGET;OUTPUT" # single-value args - "" # multi-value args - ${ARGN}) +# add_swift_host_library(name +# [SHARED] +# [STATIC] +# [LLVM_LINK_COMPONENTS comp1 ...] +# source1 [source2 source3 ...]) +# +# name +# Name of the library (e.g., swiftParse). +# +# SHARED +# Build a shared library. +# +# STATIC +# Build a static library. +# +# LLVM_LINK_COMPONENTS +# LLVM components this library depends on. +# +# source1 ... +# Sources to add into this library. +function(add_swift_host_library name) + set(options + SHARED + STATIC) + set(single_parameter_options) + set(multiple_parameter_options + LLVM_LINK_COMPONENTS) - precondition(LIPO_SDK MESSAGE "sdk is required") - precondition(LIPO_TARGET MESSAGE "target is required") - precondition(LIPO_OUTPUT MESSAGE "output is required") - precondition(LIPO_UNPARSED_ARGUMENTS MESSAGE "one or more inputs are required") + cmake_parse_arguments(ASHL + "${options}" + "${single_parameter_options}" + "${multiple_parameter_options}" + ${ARGN}) + set(ASHL_SOURCES ${ASHL_UNPARSED_ARGUMENTS}) - set(source_targets ${LIPO_UNPARSED_ARGUMENTS}) + translate_flags(ASHL "${options}") - # Gather the source binaries. - set(source_binaries) - foreach(source_target ${source_targets}) - list(APPEND source_binaries $) - endforeach() + if(NOT ASHL_SHARED AND NOT ASHL_STATIC) + message(FATAL_ERROR "Either SHARED or STATIC must be specified") + endif() - if(${LIPO_SDK} IN_LIST SWIFT_APPLE_PLATFORMS) - if(LIPO_CODESIGN) - set(codesign_command COMMAND "codesign" "-f" "-s" "-" "${LIPO_OUTPUT}") - endif() - # Use lipo to create the final binary. - add_custom_command_target(unused_var - COMMAND "${SWIFT_LIPO}" "-create" "-output" "${LIPO_OUTPUT}" ${source_binaries} - ${codesign_command} - CUSTOM_TARGET_NAME "${LIPO_TARGET}" - OUTPUT "${LIPO_OUTPUT}" - DEPENDS ${source_targets}) + _add_swift_host_library_single( + ${name} + ${name} + ${ASHL_SHARED_keyword} + ${ASHL_STATIC_keyword} + ${ASHL_SOURCES} + SDK ${SWIFT_HOST_VARIANT_SDK} + ARCHITECTURE ${SWIFT_HOST_VARIANT_ARCH} + LLVM_LINK_COMPONENTS ${ASHL_LLVM_LINK_COMPONENTS} + INSTALL_IN_COMPONENT "dev" + ) + + add_dependencies(dev ${name}) + if(NOT LLVM_INSTALL_TOOLCHAIN_ONLY) + swift_install_in_component(TARGETS ${name} + ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT dev + LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT dev + RUNTIME DESTINATION bin COMPONENT dev) + endif() + + swift_is_installing_component(dev is_installing) + if(NOT is_installing) + set_property(GLOBAL APPEND PROPERTY SWIFT_BUILDTREE_EXPORTS ${name}) else() - # We don't know how to create fat binaries for other platforms. - add_custom_command_target(unused_var - COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${source_binaries}" "${LIPO_OUTPUT}" - CUSTOM_TARGET_NAME "${LIPO_TARGET}" - OUTPUT "${LIPO_OUTPUT}" - DEPENDS ${source_targets}) + set_property(GLOBAL APPEND PROPERTY SWIFT_EXPORTS ${name}) endif() endfunction() # Add a single variant of a new Swift library. # # Usage: -# _add_swift_library_single( +# _add_swift_target_library_single( # target # name # [MODULE_TARGETS] @@ -677,9 +1099,6 @@ endfunction() # [SWIFT_COMPILE_FLAGS flag1...] # [LINK_FLAGS flag1...] # [FILE_DEPENDS target1 ...] -# SWIFT_ENABLE_TENSORFLOW -# [EXTRA_RPATHS rpath1 ...] -# END SWIFT_ENABLE_TENSORFLOW # [DONT_EMBED_BITCODE] # [IS_STDLIB] # [IS_STDLIB_CORE] @@ -736,11 +1155,6 @@ endfunction() # FILE_DEPENDS # Additional files this library depends on. # -# SWIFT_ENABLE_TENSORFLOW -# EXTRA_RPATHS -# List of directories to add to this library's RPATH. -# END SWIFT_ENABLE_TENSORFLOW -# # DONT_EMBED_BITCODE # Don't embed LLVM bitcode in this target, even if it is enabled globally. # @@ -761,7 +1175,7 @@ endfunction() # # source1 ... # Sources to add into this library -function(_add_swift_library_single target name) +function(_add_swift_target_library_single target name) set(SWIFTLIB_SINGLE_options DONT_EMBED_BITCODE IS_SDK_OVERLAY @@ -788,9 +1202,6 @@ function(_add_swift_library_single target name) C_COMPILE_FLAGS DEPENDS FILE_DEPENDS - # SWIFT_ENABLE_TENSORFLOW - EXTRA_RPATHS - # END SWIFT_ENABLE_TENSORFLOW FRAMEWORK_DEPENDS FRAMEWORK_DEPENDS_WEAK GYB_SOURCES @@ -915,6 +1326,11 @@ function(_add_swift_library_single target name) -libc;${SWIFT_STDLIB_MSVC_RUNTIME_LIBRARY}) endif() + if(sourcekitd IN_LIST SWIFTLIB_SINGLE_DEPENDS) + list(REMOVE_ITEM SWIFTLIB_SINGLE_DEPENDS sourcekitd) + set(SWIFTLIB_SINGLE_INJECT_SOURCEKITD_DEPENDENCY TRUE) + endif() + # FIXME: don't actually depend on the libraries in SWIFTLIB_SINGLE_LINK_LIBRARIES, # just any swiftmodule files that are associated with them. handle_swift_sources( @@ -940,6 +1356,10 @@ function(_add_swift_library_single target name) ${embed_bitcode_arg} INSTALL_IN_COMPONENT "${SWIFTLIB_SINGLE_INSTALL_IN_COMPONENT}" MACCATALYST_BUILD_FLAVOR "${SWIFTLIB_SINGLE_MACCATALYST_BUILD_FLAVOR}") + if(SWIFTLIB_SINGLE_INJECT_SOURCEKITD_DEPENDENCY) + add_dependencies(${swift_object_dependency_target} + sourcekitd) + endif() add_swift_source_group("${SWIFTLIB_SINGLE_EXTERNAL_SOURCES}") # If there were any swift sources, then a .swiftmodule may have been created. @@ -1149,28 +1569,6 @@ function(_add_swift_library_single target name) endif() endif() - # SWIFT_ENABLE_TENSORFLOW - # Hande extra RPATHs. - set(local_rpath "") - if("${SWIFTLIB_SINGLE_SDK}" STREQUAL "LINUX" AND NOT "${SWIFTLIB_SINGLE_SDK}" STREQUAL "ANDROID") - set(local_rpath "$ORIGIN:/usr/lib/swift/linux") - elseif("${SWIFTLIB_SINGLE_SDK}" STREQUAL "CYGWIN") - set(local_rpath "$ORIGIN:/usr/lib/swift/cygwin") - endif() - foreach(rpath_element ${SWIFTLIB_SINGLE_EXTRA_RPATHS}) - if("${local_rpath}" STREQUAL "") - set(local_rpath "${rpath_element}") - else() - set(local_rpath "${local_rpath}:${rpath_element}") - endif() - endforeach() - if(NOT "${local_rpath}" STREQUAL "") - set_target_properties("${target}" - PROPERTIES - INSTALL_RPATH "${local_rpath}") - endif() - # END SWIFT_ENABLE_TENSORFLOW - set_target_properties("${target}" PROPERTIES BUILD_WITH_INSTALL_RPATH YES) set_target_properties("${target}" PROPERTIES FOLDER "Swift libraries") @@ -1535,103 +1933,6 @@ function(_add_swift_library_single target name) # Do not add code here. endfunction() -# Add a new Swift host library. -# -# Usage: -# add_swift_host_library(name -# [SHARED] -# [STATIC] -# [LLVM_LINK_COMPONENTS comp1 ...] -# [FILE_DEPENDS target1 ...] -# source1 [source2 source3 ...]) -# -# name -# Name of the library (e.g., swiftParse). -# -# SHARED -# Build a shared library. -# -# STATIC -# Build a static library. -# -# LLVM_LINK_COMPONENTS -# LLVM components this library depends on. -# -# FILE_DEPENDS -# Additional files this library depends on. -# -# source1 ... -# Sources to add into this library. -function(add_swift_host_library name) - set(options - FORCE_BUILD_OPTIMIZED - SHARED - STATIC) - set(single_parameter_options) - set(multiple_parameter_options - C_COMPILE_FLAGS - DEPENDS - FILE_DEPENDS - LINK_LIBRARIES - LLVM_LINK_COMPONENTS) - - cmake_parse_arguments(ASHL - "${options}" - "${single_parameter_options}" - "${multiple_parameter_options}" - ${ARGN}) - set(ASHL_SOURCES ${ASHL_UNPARSED_ARGUMENTS}) - - if(ASHL_FORCE_BUILD_OPTIMIZED) - message(SEND_ERROR "library ${name} is using FORCE_BUILD_OPTIMIZED flag which is deprecated. Please use target_compile_options instead") - endif() - if(ASHL_C_COMPILE_FLAGS) - message(SEND_ERROR "library ${name} is using C_COMPILE_FLAGS parameter which is deprecated. Please use target_compile_definitions, target_compile_options, or target_include_directories instead") - endif() - 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() - - translate_flags(ASHL "${options}") - - if(NOT ASHL_SHARED AND NOT ASHL_STATIC) - message(FATAL_ERROR "Either SHARED or STATIC must be specified") - endif() - - _add_swift_library_single( - ${name} - ${name} - ${ASHL_SHARED_keyword} - ${ASHL_STATIC_keyword} - ${ASHL_SOURCES} - SDK ${SWIFT_HOST_VARIANT_SDK} - ARCHITECTURE ${SWIFT_HOST_VARIANT_ARCH} - LLVM_LINK_COMPONENTS ${ASHL_LLVM_LINK_COMPONENTS} - INSTALL_IN_COMPONENT "dev" - ) - - add_dependencies(dev ${name}) - if(NOT LLVM_INSTALL_TOOLCHAIN_ONLY) - swift_install_in_component(TARGETS ${name} - ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT dev - LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT dev - RUNTIME DESTINATION bin COMPONENT dev) - endif() - - swift_is_installing_component(dev is_installing) - if(NOT is_installing) - set_property(GLOBAL APPEND PROPERTY SWIFT_BUILDTREE_EXPORTS ${name}) - else() - set_property(GLOBAL APPEND PROPERTY SWIFT_EXPORTS ${name}) - endif() -endfunction() - # Add a new Swift target library. # # NOTE: This has not had the swift host code debrided from it yet. That will be @@ -2217,7 +2518,7 @@ function(add_swift_target_library name) list(APPEND swiftlib_c_compile_flags_all "-DSWIFT_TARGET_LIBRARY_NAME=${name}") # Add this library variant. - _add_swift_library_single( + _add_swift_target_library_single( ${variant_name} ${name} ${SWIFTLIB_SHARED_keyword} @@ -2551,22 +2852,22 @@ endfunction() # [ARCHITECTURE architecture] # Architecture to build for. function(_add_swift_executable_single name) - # Parse the arguments we were given. + set(options) + set(single_parameter_options + ARCHITECTURE + SDK) + set(multiple_parameter_options + COMPILE_FLAGS + DEPENDS + LLVM_LINK_COMPONENTS) cmake_parse_arguments(SWIFTEXE_SINGLE - "EXCLUDE_FROM_ALL" - "SDK;ARCHITECTURE" - "DEPENDS;LLVM_LINK_COMPONENTS;LINK_LIBRARIES;COMPILE_FLAGS" + "${options}" + "${single_parameter_options}" + "${multiple_parameter_options}" ${ARGN}) set(SWIFTEXE_SINGLE_SOURCES ${SWIFTEXE_SINGLE_UNPARSED_ARGUMENTS}) - 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") precondition(SWIFTEXE_SINGLE_ARCHITECTURE MESSAGE "Should specify an architecture") @@ -2709,7 +3010,7 @@ endmacro() function(add_swift_host_tool executable) set(options) set(single_parameter_options SWIFT_COMPONENT) - set(multiple_parameter_options LINK_LIBRARIES) + set(multiple_parameter_options) cmake_parse_arguments(ASHT "${options}" @@ -2717,10 +3018,6 @@ function(add_swift_host_tool executable) "${multiple_parameter_options}" ${ARGN}) - if(ASHT_LINK_LIBRARIES) - message(SEND_ERROR "${executable} is using LINK_LIBRARIES parameter which is deprecated. Please use target_link_libraries instead") - endif() - precondition(ASHT_SWIFT_COMPONENT MESSAGE "Swift Component is required to add a host tool") diff --git a/cmake/modules/AddSwiftUnittests.cmake b/cmake/modules/AddSwiftUnittests.cmake index 5da0ae3ac44e3..e088997741eb1 100644 --- a/cmake/modules/AddSwiftUnittests.cmake +++ b/cmake/modules/AddSwiftUnittests.cmake @@ -48,8 +48,13 @@ function(add_swift_unittest test_dirname) "${android_system_libs}") set_property(TARGET "${test_dirname}" APPEND PROPERTY LINK_LIBRARIES "log") elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - set_property(TARGET "${test_dirname}" APPEND PROPERTY LINK_LIBRARIES - "atomic") + if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") + target_compile_options(${test_dirname} PRIVATE + -march=core2) + endif() + elseif("${SWIFT_HOST_VARIANT}" STREQUAL "windows") + target_compile_definitions("${test_dirname}" PRIVATE + _ENABLE_EXTENDED_ALIGNED_STORAGE) endif() find_program(LDLLD_PATH "ld.lld") diff --git a/cmake/modules/SwiftHandleGybSources.cmake b/cmake/modules/SwiftHandleGybSources.cmake index d3aaeb55ad190..f8dc984ea0c68 100644 --- a/cmake/modules/SwiftHandleGybSources.cmake +++ b/cmake/modules/SwiftHandleGybSources.cmake @@ -1,6 +1,8 @@ include(SwiftAddCustomCommandTarget) include(SwiftSetIfArchBitness) +find_package(Python2 COMPONENTS Interpreter REQUIRED) + # Create a target to process single gyb source with the 'gyb' tool. # # handle_gyb_source_single( @@ -58,7 +60,7 @@ function(handle_gyb_source_single dependency_out_var_name) COMMAND "${CMAKE_COMMAND}" -E make_directory "${dir}" COMMAND - "${PYTHON_EXECUTABLE}" "${gyb_tool}" ${SWIFT_GYB_FLAGS} ${GYB_SINGLE_FLAGS} -o "${GYB_SINGLE_OUTPUT}.tmp" "${GYB_SINGLE_SOURCE}" + "$" "${gyb_tool}" ${SWIFT_GYB_FLAGS} ${GYB_SINGLE_FLAGS} -o "${GYB_SINGLE_OUTPUT}.tmp" "${GYB_SINGLE_SOURCE}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${GYB_SINGLE_OUTPUT}.tmp" "${GYB_SINGLE_OUTPUT}" COMMAND diff --git a/docs/Android.md b/docs/Android.md index 02ff3267d4bcc..d0bbd19180910 100644 --- a/docs/Android.md +++ b/docs/Android.md @@ -1,11 +1,11 @@ # Getting Started with Swift on Android -The Swift stdlib can be compiled for Android armv7 targets, which makes it -possible to execute Swift code on a mobile device running Android. This guide -explains: +The Swift stdlib can be compiled for Android armv7 and aarch64 targets, which +makes it possible to execute Swift code on a mobile device running Android. +This guide explains: 1. How to run a simple "Hello, world" program on your Android device. -2. How to run the Swift test suite, targeting Android, and on an Android device. +2. How to run the Swift test suite on an Android device. If you encounter any problems following the instructions below, please file a bug using https://bugs.swift.org/. @@ -30,13 +30,12 @@ Swift-to-Java bridging. To follow along with this guide, you'll need: 1. A Linux environment capable of building Swift from source, specifically - Ubuntu 16.04 or Ubuntu 15.10 (Ubuntu 14.04 has not been tested recently). - The stdlib is currently only buildable for Android from a Linux environment. - Before attempting to build for Android, please make sure you are able to build - for Linux by following the instructions in the Swift project README. -2. The latest version of the Android NDK (r16 at the time of this writing), + Ubuntu 18.04 or Ubuntu 16.04. Before attempting to build for Android, + please make sure you are able to build for Linux by following the + instructions in the Swift project README. +2. The latest version of the Android NDK (r21 at the time of this writing), available to download here: - http://developer.android.com/ndk/downloads/index.html. + https://developer.android.com/ndk/downloads/index.html. 3. An Android device with remote debugging enabled. We require remote debugging in order to deploy built stdlib products to the device. You may turn on remote debugging by following the official instructions: @@ -74,16 +73,18 @@ Android NDK, as well as the directories that contain the `libicuucswift.so` and ``` $ ARM_DIR=path/to/libicu-libiconv-android -$ NDK_PATH=path/to/android-ndk16 +$ NDK_PATH=path/to/android-ndk21 $ utils/build-script \ -R \ # Build in ReleaseAssert mode. --android \ # Build for Android. - --android-ndk $NDK_PATH \ # Path to an Android NDK. + --android-ndk $NDK_PATH \ # Path to an Android NDK. + --android-arch armv7 \ # Optionally specify Android architecture, alternately aarch64 --android-api-level 21 \ # The Android API level to target. Swift only supports 21 or greater. --android-icu-uc ${ARM_DIR}/libicuucswift.so \ --android-icu-uc-include ${ARM_DIR}/icu/source/common \ --android-icu-i18n ${ARM_DIR}/libicui18nswift.so \ - --android-icu-i18n-include ${ARM_DIR}/icu/source/i18n + --android-icu-i18n-include ${ARM_DIR}/icu/source/i18n \ + --android-icu-data ${ARM_DIR}/libicudataswift.so ``` ### 3. Compiling `hello.swift` to run on an Android device @@ -94,27 +95,18 @@ Create a simple Swift file named `hello.swift`: print("Hello, Android") ``` -To compile it, we need to make sure the correct linker is used. Symlink the -gold linker in the Android NDK into your `PATH`: - -``` -$ sudo ln -s \ - /path/to/android-ndk-r16/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/arm-linux-androideabi/bin/ld.gold \ - /usr/bin/armv7-none-linux-androideabi-ld.gold -``` - Then use the built Swift compiler from the previous step to compile a Swift source file, targeting Android: ``` -$ NDK_PATH="path/to/android-ndk16" -$ build/Ninja-ReleaseAssert/swift-linux-x86_64/bin/swiftc \ # The Swift compiler built in the previous step. - # The location of the tools used to build Android binaries - -tools-directory ${NDK_PATH}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/arm-linux-androideabi/bin - -target armv7-none-linux-androideabi \ # Targeting android-armv7. - -sdk ${NDK_PATH}/platforms/android-21/arch-arm \ # Use the same NDK path and API version as you used to build the stdlib in the previous step. - -L ${NDK_PATH}/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a \ # Link the Android NDK's libc++ and libgcc. - -L ${NDK_PATH}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x \ +$ NDK_PATH="path/to/android-ndk21" +$ build/Ninja-ReleaseAssert/swift-linux-x86_64/bin/swiftc \ # The Swift compiler built in the previous step. + # The location of the tools used to build Android binaries + -tools-directory ${NDK_PATH}/toolchains/llvm/prebuilt/linux-x86_64/bin/ \ + -target armv7a-none-linux-androideabi \ # Targeting android-armv7. + -sdk ${NDK_PATH}/platforms/android-21/arch-arm \ # Use the same architecture and API version as you used to build the stdlib in the previous step. + -Xclang-linker -nostdlib++ \ # Don't link libc++, and supply the path to libgcc. + -L ${NDK_PATH}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/armv7-a \ hello.swift ``` @@ -149,7 +141,6 @@ $ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswi $ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftGlibc.so /data/local/tmp $ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftSwiftOnoneSupport.so /data/local/tmp $ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftRemoteMirror.so /data/local/tmp -$ adb push build/Ninja-ReleaseAssert/swift-linux-x86_64/lib/swift/android/libswiftSwiftExperimental.so /data/local/tmp ``` You will also need to push the icu libraries: @@ -163,7 +154,7 @@ adb push /path/to/libicu-android/armeabi-v7a/libicuucswift.so /data/local/tmp In addition, you'll also need to copy the Android NDK's libc++: ``` -$ adb push /path/to/android-ndk-r14/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_shared.so /data/local/tmp +$ adb push /path/to/android-ndk-r21/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_shared.so /data/local/tmp ``` Finally, you'll need to copy the `hello` executable you built in the @@ -192,7 +183,7 @@ Congratulations! You've just run your first Swift program on Android. ## Running the Swift test suite hosted on an Android device When running the test suite, build products are automatically pushed to your -device. As in part one, you'll need to connect your Android device via USB: +device. As in part four, you'll need to connect your Android device via USB: 1. Connect your Android device to your computer via USB. Ensure that remote debugging is enabled for that device by following the official instructions: @@ -204,28 +195,14 @@ device. As in part one, you'll need to connect your Android device via USB: ``` $ utils/build-script \ -R \ # Build in ReleaseAssert mode. - -T \ # Run all tests. + -T --host-test \ # Run all tests, including on the Android host. --android \ # Build for Android. - --android-ndk ~/android-ndk-r13 \ # Path to an Android NDK. + --android-ndk ~/android-ndk-r21 \ # Path to an Android NDK. + --android-arch armv7 \ # Optionally specify Android architecture, alternately aarch64 --android-ndk-version 21 \ --android-icu-uc ~/libicu-android/armeabi-v7a/libicuuc.so \ --android-icu-uc-include ~/libicu-android/armeabi-v7a/icu/source/common \ --android-icu-i18n ~/libicu-android/armeabi-v7a/libicui18n.so \ - --android-icu-i18n-include ~/libicu-android/armeabi-v7a/icu/source/i18n/ -``` - -## Build Android Toolchain - -This toolchain will generate the .so and .swiftmodule files of the Swift standard library and Foundation framework for the Android environment, armv7 architecture. Those files are needed when building any Swift library to be included in an application for Android. - -To build the toolchain run: - -``` -$ utils/android/build-toolchain -``` - -It will be built on: - -``` -path/to/swift-source/swift-android-toolchain + --android-icu-i18n-include ~/libicu-android/armeabi-v7a/icu/source/i18n/ \ + --android-icu-data ~/libicu-android/armeabi-v7a/libicudata.so ``` diff --git a/docs/Lexicon.rst b/docs/Lexicon.rst index 8d0a76cafa134..ba1d29126bdfb 100644 --- a/docs/Lexicon.rst +++ b/docs/Lexicon.rst @@ -264,10 +264,32 @@ source code, tests, and commit messages. See also the `LLVM lexicon`_. compiler can do something with it. overlay - A library that is imported whenever a C library or framework by the same - name is imported. The purpose of an overlay is to augment and extend a - library on the system when the library on the system cannot be modified. - Apple has a number of overlays for its own SDKs in stdlib/public/SDK/. + A wrapper library that is implicitly imported "on top of" another library. + It contains an @_exported import of the underlying library, but it augments + it with additional APIs which, for one reason or another, are not included + in the underlying library directly. + + There are two kinds of overlays: + + A "clang overlay" (the older kind, so it's often just called an "overlay") + is a Swift library that adds Swift-specific functionality to a C-family + library or framework. Clang overlays are used with system libraries that + cannot be modified to add Swift features. A clang overlay has the same + module name as the underlying library and can do a few special things that + normal modules can't, like adding required initializers to classes. If a + module has a clang overlay, the Clang Importer will always load it unless it + is actually compiling the overlay itself. Apple has a number of clang + overlays for its own SDKs in stdlib/public/Darwin/. + + A "separately-imported overlay" is a separate module with its own name. + Unlike a clang overlay, it can be imported in some SourceFiles and not + others. When the compiler processes import declarations, it determines which + separately-imported overlays need to be imported and then adds them to the + list of imports for that file; name lookup also knows to look through the + overlay when it looks for declarations in the underlying module. + Separately-imported overlays are used to implement the "cross-import + overlays" feature, which is used to augment a module with additional + functionality when it is imported alongside another module. PCH Precompiled header, a type of file ending in .pch. A precompiled header is diff --git a/docs/OptimizationTips.rst b/docs/OptimizationTips.rst index 18ed2644e6707..dfbf0fc723de3 100644 --- a/docs/OptimizationTips.rst +++ b/docs/OptimizationTips.rst @@ -544,6 +544,38 @@ protocols as class-only protocols to get better runtime performance. .. https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html +The Cost of Let/Var when Captured by Escaping Closures +====================================================== + +While one may think that the distinction in between let/var is just +about language semantics, there are also performance +considerations. Remember that any time one creates a binding for a +closure, one is forcing the compiler to emit an escaping closure, +e.x.: + +:: + + let f: () -> () = { ... } // Escaping closure + // Contrasted with: + ({ ... })() // Non Escaping closure + x.map { ... } // Non Escaping closure + +When a var is captured by an escaping closure, the compiler must +allocate a heap box to store the var so that both the closure +creator/closure can read/write to the value. This even includes +situations where the underlying type of the captured binding is +trivial! In contrast, when captured a `let` is captured by value. As +such, the compiler stores a copy of the value directly into the +closure's storage without needing a box. + +Advice: Pass var as an `inout` if closure not actually escaping +--------------------------------------------------------------- + +If one is using an escaping closure for expressivity purposes, but is +actually using a closure locally, pass vars as inout parameters +instead of by using captures. The inout will ensure that a heap box is +not allocated for the variables and avoid any retain/release traffic +from the heap box being passed around. Unsupported Optimization Attributes =================================== diff --git a/docs/SIL.rst b/docs/SIL.rst index e4e9cbc8764ad..71088c71d75d3 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -5666,10 +5666,10 @@ destination (if it returns with ``throw``). The rules on generic substitutions are identical to those of ``apply``. -.. SWIFT_ENABLE_TENSORFLOW +Differentiable Programming +~~~~~~~~~~~~~~~~~~~~~~~~~~ -Automatic Differentiation -~~~~~~~~~~~~~~~~~~~~~~~~~ +.. SWIFT_ENABLE_TENSORFLOW differentiable_function ``````````````````````` @@ -5778,6 +5778,7 @@ Extracts the original function or a transpose function from the given ``@differentiable(linear)`` function. It must be provided with an extractee: ``[original]`` or ``[transpose]``. +.. SWIFT_ENABLE_TENSORFLOW END differentiability_witness_function `````````````````````````````````` @@ -5797,8 +5798,8 @@ differentiability_witness_function differentiability_witness_function [jvp] [parameters 0] [results 0] \ @foo : $(T) -> T -Looks up the differentiability witness function for the referenced function -using SIL differentiability witnesses. +Looks up a differentiability witness function (JVP, VJP, or transpose) for +a referenced function via SIL differentiability witnesses. The differentiability witness function kind identifies the witness function to look up: ``[jvp]``, ``[vjp]``, or ``[transpose]``. @@ -5812,7 +5813,6 @@ The remaining components identify the SIL differentiability witness: witness generic parameter clause is combined with the original function's generic signature to form the full witness generic signature. - Assertion configuration ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/TypeChecker.rst b/docs/TypeChecker.rst index b41381b24d1de..1deeaeb8441e5 100644 --- a/docs/TypeChecker.rst +++ b/docs/TypeChecker.rst @@ -985,4 +985,3 @@ The things in the queue yet to be ported are: - Missing explicit ``Self.`` and ``self.`` - Logic related to overload candidate ranking (``CalleeCandidateInfo``) - - ``diagnoseParameterErrors`` diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 951abc2cc3070..61482ffa4f29c 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -1426,6 +1426,32 @@ struct TargetEnumMetadata : public TargetValueMetadata { return *asWords; } + bool isCanonicalStaticallySpecializedGenericMetadata() const { + auto *description = getDescription(); + if (!description->isGeneric()) + return false; + + auto *trailingFlags = getTrailingFlags(); + if (trailingFlags == nullptr) + return false; + + return trailingFlags->isCanonicalStaticSpecialization(); + } + + const MetadataTrailingFlags *getTrailingFlags() const { + auto description = getDescription(); + auto flags = description->getFullGenericContextHeader() + .DefaultInstantiationPattern->PatternFlags; + if (!flags.hasTrailingFlags()) + return nullptr; + auto offset = + getGenericArgumentOffset() + + description->getFullGenericContextHeader().Base.getNumArguments() + + (hasPayloadSize() ? 1 : 0); + auto asWords = reinterpret_cast(this); + return reinterpret_cast(asWords + offset); + } + static constexpr int32_t getGenericArgumentOffset() { return sizeof(TargetEnumMetadata) / sizeof(StoredPointer); } diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 19cef4ff8852a..4ba46770a24b0 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -114,10 +114,10 @@ namespace swift { class VarDecl; class UnifiedStatsReporter; class IndexSubset; + struct SILAutoDiffDerivativeFunctionKey; // SWIFT_ENABLE_TENSORFLOW struct AutoDiffConfig; struct AutoDiffDerivativeFunctionKind; - struct SILAutoDiffDerivativeFunctionKey; class DerivativeAttr; class DifferentiableAttr; // SWIFT_ENABLE_TENSORFLOW END diff --git a/include/swift/AST/AbstractSourceFileDepGraphFactory.h b/include/swift/AST/AbstractSourceFileDepGraphFactory.h new file mode 100644 index 0000000000000..80ed4122ec1b2 --- /dev/null +++ b/include/swift/AST/AbstractSourceFileDepGraphFactory.h @@ -0,0 +1,85 @@ +//===----- AbstractSourceFileDepGraphFactory.h ----------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_SOURCE_FILE_DEP_GRAPH_CONSTRUCTOR_H +#define SWIFT_AST_SOURCE_FILE_DEP_GRAPH_CONSTRUCTOR_H + +#include "swift/AST/DeclContext.h" +#include "swift/AST/FineGrainedDependencies.h" + +namespace swift { +class DiagnosticEngine; +namespace fine_grained_dependencies { + +/// Abstract class for building a \c SourceFileDepGraph from either a real +/// \c SourceFile or a unit test +class AbstractSourceFileDepGraphFactory { +protected: + /// To match the existing system, set this to false. + /// To include even private entities and get intra-file info, set to true. + const bool includePrivateDeps; + + /// If there was an error, cannot get accurate info. + const bool hadCompilationError; + + /// The name of the swiftDeps file. + const std::string swiftDeps; + + /// The fingerprint of the whole file + const std::string fileFingerprint; + + /// For debugging + const bool emitDotFileAfterConstruction; + + DiagnosticEngine &diags; + + /// Graph under construction + SourceFileDepGraph g; + +public: + /// Expose this layer to enable faking up a constructor for testing. + /// See the instance variable comments for explanation. + AbstractSourceFileDepGraphFactory(bool includePrivateDeps, + bool hadCompilationError, + StringRef swiftDeps, + StringRef fileFingerprint, + bool emitDotFileAfterConstruction, + DiagnosticEngine &diags); + + virtual ~AbstractSourceFileDepGraphFactory() = default; + + /// Create a SourceFileDepGraph. + SourceFileDepGraph construct(); + +private: + void addSourceFileNodesToGraph(); + + /// Add the "provides" nodes when mocking up a graph + virtual void addAllDefinedDecls() = 0; + + /// Add the "depends" nodes and arcs when mocking a graph + virtual void addAllUsedDecls() = 0; + +protected: + /// Add an pair of interface, implementation nodes to the graph, which + /// represent some \c Decl defined in this source file. \param key the + /// interface key of the pair + void addADefinedDecl(const DependencyKey &key, + Optional fingerprint); + + void addAUsedDecl(const DependencyKey &def, const DependencyKey &use); +}; + +} // namespace fine_grained_dependencies +} // namespace swift + +#endif // SWIFT_AST_SOURCE_FILE_DEP_GRAPH_CONSTRUCTOR_H diff --git a/include/swift/AST/Attr.def b/include/swift/AST/Attr.def index 7f78a1786e9dc..b6980a3d132fa 100644 --- a/include/swift/AST/Attr.def +++ b/include/swift/AST/Attr.def @@ -523,6 +523,11 @@ SIMPLE_DECL_ATTR(_inheritsConvenienceInitializers, APIStableToAdd | ABIStableToAdd | APIBreakingToRemove | ABIBreakingToRemove, 93) +DECL_ATTR(_typeEraser, TypeEraser, + OnProtocol | UserInaccessible | NotSerialized | + ABIStableToAdd | ABIBreakingToRemove | APIStableToAdd | APIBreakingToRemove, + 94) + SIMPLE_DECL_ATTR(IBSegueAction, IBSegueAction, OnFunc | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove, @@ -539,7 +544,11 @@ DECL_ATTR(derivative, Derivative, ABIStableToAdd | ABIBreakingToRemove | APIStableToAdd | APIBreakingToRemove, 97) -// NOTE: 98 is unused +DECL_ATTR(_spi, SPIAccessControl, + OnFunc | OnExtension | OnGenericType | OnVar | OnSubscript | OnConstructor | + OnImport | AllowMultipleAttributes | UserInaccessible | + ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove, + 98) DECL_ATTR(transpose, Transpose, OnFunc | LongAttribute | AllowMultipleAttributes | diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index c12023eab0bf3..c664b42fb4790 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -1109,6 +1109,21 @@ class DynamicReplacementAttr final } }; +/// The \c @_typeEraser(TypeEraserType) attribute. +class TypeEraserAttr final : public DeclAttribute { + TypeLoc TypeEraserLoc; +public: + TypeEraserAttr(SourceLoc atLoc, SourceRange range, TypeLoc typeEraserLoc) + : DeclAttribute(DAK_TypeEraser, atLoc, range, /*Implicit=*/false), + TypeEraserLoc(typeEraserLoc) {} + + const TypeLoc &getTypeEraserLoc() const { return TypeEraserLoc; } + + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DAK_TypeEraser; + } +}; + /// Represents any sort of access control modifier. class AbstractAccessControlAttr : public DeclAttribute { protected: @@ -1157,6 +1172,36 @@ class SetterAccessAttr : public AbstractAccessControlAttr { } }; +/// SPI attribute applied to both decls and imports. +class SPIAccessControlAttr final : public DeclAttribute, + private llvm::TrailingObjects { + friend TrailingObjects; + + SPIAccessControlAttr(SourceLoc atLoc, SourceRange range, + ArrayRef spiGroups); + + // Number of trailing SPI group identifiers. + size_t numSPIGroups; + +public: + static SPIAccessControlAttr *create(ASTContext &context, SourceLoc atLoc, + SourceRange range, + ArrayRef spiGroups); + + /// Name of SPIs declared by the attribute. + /// + /// Note: A single SPI name per attribute is currently supported but this + /// may change with the syntax change. + ArrayRef getSPIGroups() const { + return { this->template getTrailingObjects(), + numSPIGroups }; + } + + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DAK_SPIAccessControl; + } +}; + /// Represents an inline attribute. class InlineAttr : public DeclAttribute { public: @@ -2093,6 +2138,15 @@ class DeclAttributes { return nullptr; } + /// Retrieve the first attribute with the given kind. + DeclAttribute *getAttribute(DeclAttrKind DK, + bool AllowInvalid = false) { + for (auto Attr : *this) + if (Attr->getKind() == DK && (Attr->isValid() || AllowInvalid)) + return Attr; + return nullptr; + } + private: /// Predicate used to filter MatchingAttributeRange. template struct ToAttributeKind { diff --git a/include/swift/AST/AutoDiff.h b/include/swift/AST/AutoDiff.h index eb5a20eeb1114..c3c9fccbd2484 100644 --- a/include/swift/AST/AutoDiff.h +++ b/include/swift/AST/AutoDiff.h @@ -75,6 +75,27 @@ struct AutoDiffDerivativeFunctionKind { } }; +/// The kind of a differentiability witness function. +struct DifferentiabilityWitnessFunctionKind { + enum innerty : uint8_t { + // The Jacobian-vector products function. + JVP = 0, + // The vector-Jacobian products function. + VJP = 1, + // The transpose function. + Transpose = 2 + } rawValue; + + DifferentiabilityWitnessFunctionKind() = default; + DifferentiabilityWitnessFunctionKind(innerty rawValue) : rawValue(rawValue) {} + explicit DifferentiabilityWitnessFunctionKind(unsigned rawValue) + : rawValue(static_cast(rawValue)) {} + explicit DifferentiabilityWitnessFunctionKind(StringRef name); + operator innerty() const { return rawValue; } + + Optional getAsDerivativeFunctionKind() const; +}; + /// Identifies an autodiff derivative function configuration: /// - Parameter indices. /// - Result indices. @@ -101,6 +122,16 @@ struct AutoDiffConfig { SWIFT_DEBUG_DUMP; }; +/// Key for caching SIL derivative function types. +struct SILAutoDiffDerivativeFunctionKey { + SILFunctionType *originalType; + IndexSubset *parameterIndices; + IndexSubset *resultIndices; + AutoDiffDerivativeFunctionKind kind; + CanGenericSignature derivativeFnGenSig; + bool isReabstractionThunk; +}; + class ParsedAutoDiffParameter { public: enum class Kind { Named, Ordered, Self }; @@ -269,8 +300,11 @@ namespace llvm { using swift::AutoDiffConfig; using swift::AutoDiffDerivativeFunctionKind; +using swift::CanGenericSignature; using swift::GenericSignature; using swift::IndexSubset; +using swift::SILAutoDiffDerivativeFunctionKey; +using swift::SILFunctionType; template struct DenseMapInfo; @@ -342,6 +376,50 @@ template <> struct DenseMapInfo { } }; +template <> struct DenseMapInfo { + static bool isEqual(const SILAutoDiffDerivativeFunctionKey lhs, + const SILAutoDiffDerivativeFunctionKey rhs) { + return lhs.originalType == rhs.originalType && + lhs.parameterIndices == rhs.parameterIndices && + lhs.resultIndices == rhs.resultIndices && + lhs.kind.rawValue == rhs.kind.rawValue && + lhs.derivativeFnGenSig == rhs.derivativeFnGenSig && + lhs.isReabstractionThunk == rhs.isReabstractionThunk; + } + + static inline SILAutoDiffDerivativeFunctionKey getEmptyKey() { + return {DenseMapInfo::getEmptyKey(), + DenseMapInfo::getEmptyKey(), + DenseMapInfo::getEmptyKey(), + AutoDiffDerivativeFunctionKind::innerty( + DenseMapInfo::getEmptyKey()), + CanGenericSignature(DenseMapInfo::getEmptyKey()), + (bool)DenseMapInfo::getEmptyKey()}; + } + + static inline SILAutoDiffDerivativeFunctionKey getTombstoneKey() { + return { + DenseMapInfo::getTombstoneKey(), + DenseMapInfo::getTombstoneKey(), + DenseMapInfo::getTombstoneKey(), + AutoDiffDerivativeFunctionKind::innerty( + DenseMapInfo::getTombstoneKey()), + CanGenericSignature(DenseMapInfo::getTombstoneKey()), + (bool)DenseMapInfo::getTombstoneKey()}; + } + + static unsigned getHashValue(const SILAutoDiffDerivativeFunctionKey &Val) { + return hash_combine( + DenseMapInfo::getHashValue(Val.originalType), + DenseMapInfo::getHashValue(Val.parameterIndices), + DenseMapInfo::getHashValue(Val.resultIndices), + DenseMapInfo::getHashValue((unsigned)Val.kind.rawValue), + DenseMapInfo::getHashValue(Val.derivativeFnGenSig), + DenseMapInfo::getHashValue( + (unsigned)Val.isReabstractionThunk)); + } +}; + } // end namespace llvm // SWIFT_ENABLE_TENSORFLOW @@ -366,27 +444,6 @@ class AnyFunctionType; typedef CanTypeWrapper CanSILFunctionType; enum class SILLinkage : uint8_t; -/// The kind of a differentiability witness function. -struct DifferentiabilityWitnessFunctionKind { - enum innerty : uint8_t { - // The Jacobian-vector products function. - JVP = 0, - // The vector-Jacobian products function. - VJP = 1, - // The transpose function. - Transpose = 2 - } rawValue; - - DifferentiabilityWitnessFunctionKind() = default; - DifferentiabilityWitnessFunctionKind(innerty rawValue) : rawValue(rawValue) {} - explicit DifferentiabilityWitnessFunctionKind(unsigned rawValue) - : rawValue(static_cast(rawValue)) {} - explicit DifferentiabilityWitnessFunctionKind(StringRef name); - operator innerty() const { return rawValue; } - - Optional getAsDerivativeFunctionKind() const; -}; - struct NormalDifferentiableFunctionTypeComponent { enum innerty : unsigned { Original = 0, @@ -485,15 +542,6 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &s, return s; } -struct SILAutoDiffDerivativeFunctionKey { - SILFunctionType *originalType; - IndexSubset *parameterIndices; - IndexSubset *resultIndices; - AutoDiffDerivativeFunctionKind kind; - CanGenericSignature derivativeFnGenSig; - bool isReabstractionThunk; -}; - /// In conjunction with the original function declaration, identifies an /// autodiff derivative function. /// @@ -628,59 +676,6 @@ template <> struct DenseMapInfo { } }; -using swift::SILAutoDiffDerivativeFunctionKey; -using swift::SILFunctionType; -using swift::IndexSubset; -using swift::AutoDiffDerivativeFunctionKind; -using swift::GenericSignature; -using swift::CanGenericSignature; - -template <> struct DenseMapInfo { - - static bool isEqual(const SILAutoDiffDerivativeFunctionKey lhs, - const SILAutoDiffDerivativeFunctionKey rhs) { - return lhs.originalType == rhs.originalType && - lhs.parameterIndices == rhs.parameterIndices && - lhs.resultIndices == rhs.resultIndices && - lhs.kind.rawValue == rhs.kind.rawValue && - lhs.derivativeFnGenSig == rhs.derivativeFnGenSig && - lhs.isReabstractionThunk == rhs.isReabstractionThunk; - } - - static inline SILAutoDiffDerivativeFunctionKey getEmptyKey() { - return { - DenseMapInfo::getEmptyKey(), - DenseMapInfo::getEmptyKey(), - DenseMapInfo::getEmptyKey(), - AutoDiffDerivativeFunctionKind::innerty( - DenseMapInfo::getEmptyKey()), - CanGenericSignature(DenseMapInfo::getEmptyKey()), - (bool)DenseMapInfo::getEmptyKey()}; - } - - static inline SILAutoDiffDerivativeFunctionKey getTombstoneKey() { - return { - DenseMapInfo::getTombstoneKey(), - DenseMapInfo::getTombstoneKey(), - DenseMapInfo::getTombstoneKey(), - AutoDiffDerivativeFunctionKind::innerty( - DenseMapInfo::getTombstoneKey()), - CanGenericSignature(DenseMapInfo::getTombstoneKey()), - (bool)DenseMapInfo::getTombstoneKey()}; - } - - static unsigned getHashValue(const SILAutoDiffDerivativeFunctionKey &Val) { - return hash_combine( - DenseMapInfo::getHashValue(Val.originalType), - DenseMapInfo::getHashValue(Val.parameterIndices), - DenseMapInfo::getHashValue(Val.resultIndices), - DenseMapInfo::getHashValue((unsigned)Val.kind.rawValue), - DenseMapInfo::getHashValue(Val.derivativeFnGenSig), - DenseMapInfo::getHashValue( - (unsigned)Val.isReabstractionThunk)); - } -}; - } // namespace llvm // SWIFT_ENABLE_TENSORFLOW END diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 12feefa0091b3..9a524ca9a3913 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -6444,6 +6444,10 @@ class AccessorDecl final : public FuncDecl { llvm_unreachable("bad accessor kind"); } + bool isImplicitGetter() const { + return isGetter() && getAccessorKeywordLoc().isInvalid(); + } + void setIsTransparent(bool transparent) { Bits.AccessorDecl.IsTransparent = transparent; Bits.AccessorDecl.IsTransparentComputed = 1; diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h index 04b5ab5a6cd9f..a6cbdd6ba0aec 100644 --- a/include/swift/AST/DeclContext.h +++ b/include/swift/AST/DeclContext.h @@ -578,6 +578,14 @@ class alignas(1 << DeclContextAlignInBits) DeclContext { SmallVectorImpl *diagnostics = nullptr) const; + /// Retrieves a list of separately imported overlays which are shadowing + /// \p declaring. If any \p overlays are returned, qualified lookups into + /// \p declaring should be performed into \p overlays instead; since they + /// are overlays, they will re-export \p declaring, but will also augment it + /// with additional symbols. + void getSeparatelyImportedOverlays( + ModuleDecl *declaring, SmallVectorImpl &overlays) const; + /// Retrieve the syntactic depth of this declaration context, i.e., /// the number of non-module-scoped contexts. /// diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index 54a2334da9aa4..77212755457db 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -165,6 +165,21 @@ WARNING(warn_property_wrapper_module_scope,none, "wrapper %0; please qualify the reference with %1", (DeclNameRef, Identifier)) +//------------------------------------------------------------------------------ +// MARK: Cross-import overlay loading diagnostics +//------------------------------------------------------------------------------ +ERROR(cannot_load_swiftoverlay_file, none, + "cannot load cross-import overlay for %0 and %1: %2 (declared by '%3')", + (Identifier, Identifier, StringRef, StringRef)) +ERROR(cannot_list_swiftcrossimport_dir, none, + "cannot list cross-import overlays for %0: %1 (declared in '%2')", + (Identifier, StringRef, StringRef)) +WARNING(cross_imported_by_both_modules, none, + "modules %0 and %1 both declare module %2 as a cross-import overlay, " + "which may cause paradoxical behavior when looking up names in them; " + "please report this bug to the maintainers of these modules", + (Identifier, Identifier, Identifier)) + #ifndef DIAG_NO_UNDEF # if defined(DIAG) # undef DIAG diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 00c708a7b85b1..b2ecfdd158f30 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -284,6 +284,9 @@ REMARK(platform_previous_install_name, none, ERROR(unknown_platform_name, none, "unkown platform name %0", (StringRef)) +ERROR(unknown_swift_module_name, none, + "cannot find Swift module with name %0", (StringRef)) + ERROR(cannot_find_install_name, none, "cannot find previous install name for module %0 in %1", (StringRef, StringRef)) diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 3ebcf45effc61..7d7b9edc9ccde 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1381,6 +1381,8 @@ ERROR(projection_value_property_not_identifier,none, // Access control ERROR(attr_access_expected_set,none, "expected 'set' as subject of '%0' modifier", (StringRef)) +ERROR(attr_access_expected_spi_name,none, + "expected an SPI identifier as subject of the '@_spi' attribute", ()) // Attributes ERROR(attr_renamed, none, @@ -1493,6 +1495,11 @@ ERROR(attr_dynamic_replacement_expected_for,none, ERROR(attr_dynamic_replacement_expected_colon,none, "expected ':' after @_dynamicReplacement(for", ()) +ERROR(attr_type_eraser_expected_type_name,none, + "expected a type name in @_typeEraser()", ()) +ERROR(attr_type_eraser_expected_rparen,none, + "expected ')' after type name for @_typeEraser", ()) + ERROR(attr_private_import_expected_rparen,none, "expected ')' after function name for @_private", ()) ERROR(attr_private_import_expected_sourcefile, none, @@ -1629,10 +1636,14 @@ ERROR(sil_inst_autodiff_expected_linear_extractee_kind,PointsToFirstBadToken, "and '[transpose]'", ()) ERROR(sil_inst_autodiff_expected_function_type_operand,PointsToFirstBadToken, "expected an operand of a function type", ()) +// SWIFT_ENABLE_TENSORFLOW END ERROR(sil_inst_autodiff_expected_differentiability_witness_kind,PointsToFirstBadToken, "expected a differentiability witness kind, which can be one of '[jvp]', " "'[vjp]', or '[transpose]'", ()) -// SWIFT_ENABLE_TENSORFLOW END +ERROR(sil_inst_autodiff_invalid_witness_generic_signature,PointsToFirstBadToken, + "expected witness_generic signature '%0' does not have same generic " + "parameters as original function generic signature '%1'", + (StringRef, StringRef)) //------------------------------------------------------------------------------ // MARK: Generics parsing diagnostics diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 44d9f89971794..bb557ffdfe1c9 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -557,12 +557,12 @@ NOTE(autodiff_missing_return,none, ERROR(non_physical_addressof,none, "addressof only works with purely physical lvalues; " - "use `withUnsafePointer` or `withUnsafeBytes` unless you're implementing " - "`withUnsafePointer` or `withUnsafeBytes`", ()) + "use 'withUnsafePointer' or 'withUnsafeBytes' unless you're implementing " + "'withUnsafePointer' or 'withUnsafeBytes'", ()) ERROR(non_borrowed_indirect_addressof,none, "addressof only works with borrowable in-memory rvalues; " - "use `withUnsafePointer` or `withUnsafeBytes` unless you're implementing " - "`withUnsafePointer` or `withUnsafeBytes`", ()) + "use 'withUnsafePointer' or 'withUnsafeBytes' unless you're implementing " + "'withUnsafePointer' or 'withUnsafeBytes'", ()) REMARK(opt_remark_passed, none, "%0", (StringRef)) REMARK(opt_remark_missed, none, "%0", (StringRef)) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 1e5238858cc7e..edfa542688b5e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -61,25 +61,13 @@ ERROR(ambiguous_member_overload_set,none, ERROR(ambiguous_reference_to_decl,none, "ambiguous reference to %0 %1", (DescriptiveDeclKind, DeclName)) ERROR(no_overloads_match_exactly_in_call,none, - "no exact matches in call to %0 %1", - (DescriptiveDeclKind, DeclName)) -ERROR(no_overloads_match_exactly_in_call_no_labels,none, - "no exact matches in call to %0 %1", - (DescriptiveDeclKind, DeclBaseName)) -ERROR(no_overloads_match_exactly_in_call_special,none, - "no exact matches in call to %0", - (DescriptiveDeclKind)) -ERROR(no_overloads_match_exactly_in_assignment,none, - "no exact matches in assignment to %0", - (DeclBaseName)) + "no exact matches in %select{reference|call}0 to %1 %select{%3|}2", + (bool, DescriptiveDeclKind, bool, DeclBaseName)) NOTE(candidate_partial_match,none, "candidate has partially matching parameter list %0", (StringRef)) -ERROR(ambiguous_subscript,none, - "ambiguous subscript with base type %0 and index type %1", - (Type, Type)) ERROR(could_not_find_value_subscript,none, "value of type %0 has no subscripts", (Type)) @@ -160,7 +148,7 @@ FIXIT(insert_type_qualification,"%0.",(Type)) ERROR(candidate_inaccessible,none, "%0 is inaccessible due to " - "'%select{private|fileprivate|internal|%error|%error}1' protection level", + "'%select{private|fileprivate|internal|SPI|SPI}1' protection level", (DeclBaseName, AccessLevel)) NOTE(note_candidate_inaccessible,none, @@ -170,7 +158,7 @@ NOTE(note_candidate_inaccessible,none, ERROR(init_candidate_inaccessible,none, "%0 initializer is inaccessible due to " - "'%select{private|fileprivate|internal|%error|%error}1' protection level", + "'%select{private|fileprivate|internal|SPI|SPI}1' protection level", (Type, AccessLevel)) ERROR(cannot_pass_rvalue_mutating_subelement,none, @@ -282,16 +270,6 @@ ERROR(no_candidates_match_result_type,none, "no '%0' candidates produce the expected contextual result type %1", (StringRef, Type)) -ERROR(candidates_no_match_result_type,none, - "'%0' produces %1, not the expected contextual result type %2", - (StringRef, Type, Type)) - - - -ERROR(invalid_callee_result_type,none, - "cannot convert call result type %0 to expected type %1", - (Type, Type)) - ERROR(cannot_invoke_closure,none, "cannot invoke closure expression with an argument list of type '%0'", @@ -407,6 +385,10 @@ ERROR(cannot_convert_argument_value_generic,none, "cannot convert value of type %0 (%1) to expected argument type %2 (%3)", (Type, StringRef, Type, StringRef)) +ERROR(conflicting_arguments_for_generic_parameter,none, + "conflicting arguments to generic parameter %0 (%1)", + (Type, StringRef)) + // @_nonEphemeral conversion diagnostics ERROR(cannot_pass_type_to_non_ephemeral,none, "cannot pass %0 to parameter; argument %1 must be a pointer that " @@ -1015,6 +997,11 @@ WARNING(conditional_downcast_coercion,none, "conditional cast from %0 to %1 always succeeds", (Type, Type)) +WARNING(literal_conditional_downcast_to_coercion,none, + "conditional downcast from literal to %0 always fails; " + "consider using 'as' coercion", + (Type)) + WARNING(forced_downcast_noop,none, "forced cast of %0 to same type has no effect", (Type)) @@ -1151,6 +1138,9 @@ ERROR(argument_out_of_order_unnamed_named,none, ERROR(argument_out_of_order_unnamed_unnamed,none, "unnamed argument #%0 must precede unnamed argument #%1", (unsigned, unsigned)) +ERROR(argument_out_of_order_binary_op,none, + "operator argument #%0 must precede operator argument #%1", + (unsigned, unsigned)) NOTE(candidate_expected_different_labels,none, "incorrect labels for candidate (have: '%0', expected: '%1')", (StringRef, StringRef)) @@ -1708,6 +1698,13 @@ ERROR(function_type_access,none, "because its %select{parameter|result}5 uses " "%select{a private|a fileprivate|an internal|%error|%error}3 type", (bool, AccessLevel, bool, AccessLevel, unsigned, bool)) +ERROR(function_type_spi,none, + "%select{function|method|initializer}0 " + "cannot be declared '@_spi' " + "because its %select{parameter|result}1 uses " + "%select{a private|a fileprivate|an internal|%error|%error}2 type " + "without a compatible '@_spi'", + (unsigned, bool, AccessLevel)) WARNING(function_type_access_warn,none, "%select{function|method|initializer}4 " "%select{should be declared %select{private|fileprivate|internal|%error|%error}1" @@ -1726,6 +1723,12 @@ WARNING(function_type_usable_from_inline_warn,none, "should be '@usableFromInline' or public", (unsigned, bool)) +ERROR(spi_attribute_on_non_public,none, + "%select{private|fileprivate|internal|%error|%error}0 %1 " + "cannot be declared '@_spi' because only public and open " + "declarations can be '@_spi'", + (AccessLevel, DescriptiveDeclKind)) + // Opaque return types ERROR(opaque_type_invalid_constraint,none, "an 'opaque' type must specify only 'Any', 'AnyObject', protocols, " @@ -2658,12 +2661,13 @@ NOTE(enum_raw_value_incrementing_from_zero,none, NOTE(construct_raw_representable_from_unwrapped_value,none, "construct %0 from unwrapped %1 value", (Type, Type)) -ERROR(decl_from_implementation_only_module,none, +ERROR(decl_from_hidden_module,none, "cannot use %0 %1 %select{here|" "in an extension with public or '@usableFromInline' members|" - "in an extension with conditional conformances}2; %3 has been imported " - "as implementation-only", - (DescriptiveDeclKind, DeclName, unsigned, Identifier)) + "in an extension with conditional conformances}2; " + "%select{%3 has been imported as implementation-only|" + "it is an SPI imported from %3}4", + (DescriptiveDeclKind, DeclName, unsigned, Identifier, unsigned)) ERROR(conformance_from_implementation_only_module,none, "cannot use conformance of %0 to %1 %select{here|" "in an extension with public or '@usableFromInline' members|" @@ -3035,18 +3039,18 @@ NOTE(protocol_witness_missing_differentiable_attr,none, // @derivative ERROR(derivative_attr_expected_result_tuple,none, "'@derivative(of:)' attribute requires function to return a two-element " - "tuple of type '(value: T..., pullback: (U.TangentVector) -> T.TangentVector...)' " - "or '(value: T..., differential: (T.TangentVector...) -> U.TangentVector)'", ()) + "tuple; first element must have label 'value:' and second element must " + "have label 'pullback:' or 'differential:'", ()) ERROR(derivative_attr_invalid_result_tuple_value_label,none, "'@derivative(of:)' attribute requires function to return a two-element " - "tuple (first element must have label 'value:')", ()) + "tuple; first element must have label 'value:'", ()) ERROR(derivative_attr_invalid_result_tuple_func_label,none, "'@derivative(of:)' attribute requires function to return a two-element " - "tuple (second element must have label 'pullback:' or 'differential:')", + "tuple; second element must have label 'pullback:' or 'differential:'", ()) ERROR(derivative_attr_result_value_not_differentiable,none, "'@derivative(of:)' attribute requires function to return a two-element " - "tuple (first element type %0 must conform to 'Differentiable')", (Type)) + "tuple; first element type %0 must conform to 'Differentiable'", (Type)) ERROR(derivative_attr_result_func_type_mismatch,none, "function result's %0 type does not match %1", (Identifier, DeclName)) NOTE(derivative_attr_result_func_type_mismatch_note,none, @@ -3820,18 +3824,14 @@ ERROR(pattern_type_mismatch_context,none, ERROR(tuple_pattern_in_non_tuple_context,none, "tuple pattern cannot match values of the non-tuple type %0", (Type)) -WARNING(matching_pattern_with_many_assoc_values, none, - "cannot match several associated values at once, " - "implicitly tupling the associated values and trying to match that " - "instead", ()) -WARNING(matching_tuple_pattern_with_many_assoc_values,none, - "a tuple pattern cannot match several associated values at once, " - "implicitly tupling the associated values and trying to match " - "that instead", ()) -WARNING(matching_many_patterns_with_tupled_assoc_value,none, - "the enum case has a single tuple as an associated value, but " - "there are several patterns here, implicitly tupling the patterns " - "and trying to match that instead", ()) +WARNING(found_one_pattern_for_several_associated_values,none, + "enum case '%0' has %1 associated values; matching them as a tuple " + "is deprecated", (StringRef, unsigned)) +WARNING(converting_tuple_into_several_associated_values,none, + "enum case '%0' has %1 associated values", (StringRef, unsigned)) +WARNING(converting_several_associated_values_into_tuple,none, + "enum case '%0' has one associated value that is a tuple of %1 " + "elements",(StringRef, unsigned)) ERROR(closure_argument_list_tuple,none, "contextual closure type %0 expects %1 argument%s1, " "but %2 %select{were|was}3 used in closure body", (Type, unsigned, unsigned, bool)) @@ -4731,10 +4731,16 @@ WARNING(resilience_decl_unavailable_warn, "should not be referenced from " FRAGILE_FUNC_KIND "3", (DescriptiveDeclKind, DeclName, AccessLevel, unsigned, bool)) -ERROR(inlinable_decl_ref_implementation_only, +ERROR(resilience_decl_unavailable_spi, + none, DECL_OR_ACCESSOR "4 %1 is imported as SPI; " + "it cannot be referenced from " FRAGILE_FUNC_KIND "3", + (DescriptiveDeclKind, DeclName, AccessLevel, unsigned, bool)) + +ERROR(inlinable_decl_ref_from_hidden_module, none, "%0 %1 cannot be used in " FRAGILE_FUNC_KIND "2 " - "because %3 was imported implementation-only", - (DescriptiveDeclKind, DeclName, unsigned, Identifier)) + "because %select{%3 was imported implementation-only|" + "it is an SPI imported from %3}4", + (DescriptiveDeclKind, DeclName, unsigned, Identifier, unsigned)) #undef FRAGILE_FUNC_KIND @@ -4990,10 +4996,10 @@ ERROR(property_wrapper_type_not_usable_from_inline,none, "must be '@usableFromInline' or public", (bool, bool)) WARNING(property_wrapper_wrapperValue,none, - "property wrapper's `wrapperValue` property should be renamed to " + "property wrapper's 'wrapperValue' property should be renamed to " "'projectedValue'; use of 'wrapperValue' is deprecated", ()) WARNING(property_wrapper_init_initialValue,none, - "property wrapper's `init(initialValue:)` should be renamed " + "property wrapper's 'init(initialValue:)' should be renamed " "to 'init(wrappedValue:)'; use of 'init(initialValue:)' is deprecated", ()) ERROR(property_wrapper_projection_value_missing,none, @@ -5047,6 +5053,14 @@ NOTE(function_builder_remove_attr, none, NOTE(function_builder_remove_returns, none, "remove 'return' statements to apply the function builder", ()) +//------------------------------------------------------------------------------ +// MARK: Tuple Shuffle Diagnostics +//------------------------------------------------------------------------------ + + WARNING(warn_reordering_tuple_shuffle_deprecated,none, + "expression shuffles the elements of this tuple; " + "this behavior is deprecated", ()) + //------------------------------------------------------------------------------ // MARK: differentiable programming diagnostics //------------------------------------------------------------------------------ diff --git a/include/swift/AST/FileUnit.h b/include/swift/AST/FileUnit.h index 020930dd5980a..70237b584ab51 100644 --- a/include/swift/AST/FileUnit.h +++ b/include/swift/AST/FileUnit.h @@ -101,6 +101,12 @@ class FileUnit : public DeclContext { ObjCSelector selector, SmallVectorImpl &results) const = 0; + /// Find all SPI names imported from \p importedModule by this module, + /// collecting the identifiers in \p spiGroups. + virtual void lookupImportedSPIGroups( + const ModuleDecl *importedModule, + SmallVectorImpl &spiGroups) const {}; + /// Returns the comment attached to the given declaration. /// /// This function is an implementation detail for comment serialization. @@ -214,6 +220,13 @@ class FileUnit : public DeclContext { virtual void collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {} + /// Returns the path of the file or directory that defines the module + /// represented by this \c FileUnit, or empty string if there is none. + /// Cross-import overlay specifiers are found relative to this path. + virtual StringRef getModuleDefiningPath() const { + return ""; + } + /// True if this file contains the main class for the module. bool hasMainClass() const { return getMainClass(); @@ -369,6 +382,7 @@ class LoadedFile : public FileUnit { } }; +void simple_display(llvm::raw_ostream &out, const FileUnit *file); inline FileUnit &ModuleDecl::getMainFile(FileUnitKind expectedKind) const { assert(expectedKind != FileUnitKind::Source && diff --git a/include/swift/AST/FineGrainedDependencies.h b/include/swift/AST/FineGrainedDependencies.h index 5f3424a189e84..e88ac80b2f972 100644 --- a/include/swift/AST/FineGrainedDependencies.h +++ b/include/swift/AST/FineGrainedDependencies.h @@ -93,14 +93,20 @@ template class Memoizer { public: Memoizer() = default; + Optional findExisting(KeyT key) { + auto iter = memos.find(key); + if (iter != memos.end()) + return iter->second; + return None; + } + /// \p createFn must create a \ref ValueT that corresponds to the \ref KeyT /// passed into it. ValueT findExistingOrCreateIfNew(KeyT key, function_ref createFn) { - auto iter = memos.find(key); - if (iter != memos.end()) - return iter->second; + if (auto existing = findExisting(key)) + return existing.getValue(); ValueT v = createFn(key); (void)insert(key, v); return v; @@ -499,10 +505,23 @@ class DependencyKey { } bool isInterface() const { return getAspect() == DeclAspect::interface; } + /// Create just the interface half of the keys for a provided Decl or Decl + /// pair + template + static DependencyKey createForProvidedEntityInterface(Entity); + /// Given some type of provided entity compute the context field of the key. template static std::string computeContextForProvidedEntity(Entity); + DependencyKey correspondingImplementation() const { + return withAspect(DeclAspect::implementation); + } + + DependencyKey withAspect(DeclAspect aspect) const { + return DependencyKey(kind, aspect, context, name); + } + /// Given some type of provided entity compute the name field of the key. template static std::string computeNameForProvidedEntity(Entity); @@ -514,7 +533,8 @@ class DependencyKey { template static DependencyKey createDependedUponKey(StringRef); - static DependencyKey createKeyForWholeSourceFile(StringRef swiftDeps); + static DependencyKey createKeyForWholeSourceFile(DeclAspect, + StringRef swiftDeps); std::string humanReadableName() const; @@ -555,6 +575,13 @@ struct std::hash { return size_t(aspect); } }; +template <> +struct std::hash { + size_t + operator()(const swift::fine_grained_dependencies::NodeKind kind) const { + return size_t(kind); + } +}; namespace swift { namespace fine_grained_dependencies { @@ -616,6 +643,10 @@ class DepGraphNode { /// See SourceFileDepGraphNode::SourceFileDepGraphNode(...) and /// ModuleDepGraphNode::ModuleDepGraphNode(...) Don't set swiftDeps on /// creation because this field can change if a node is moved. + DepGraphNode(DependencyKey key, Optional fingerprint) + : DepGraphNode(key, fingerprint ? fingerprint->str() + : Optional()) {} + DepGraphNode(DependencyKey key, Optional fingerprint) : key(key), fingerprint(fingerprint) {} DepGraphNode(const DepGraphNode &other) = default; @@ -627,8 +658,12 @@ class DepGraphNode { const DependencyKey &getKey() const { return key; } - const Optional &getFingerprint() const { return fingerprint; } - + const Optional getFingerprint() const { + if (fingerprint) { + return StringRef(fingerprint.getValue()); + } + return None; + } /// When driver reads a SourceFileDepGraphNode, it may be a node that was /// created to represent a name-lookup (a.k.a a "depend") in the frontend. In /// that case, the node represents an entity that resides in some other file @@ -637,7 +672,9 @@ class DepGraphNode { /// (someday) have a fingerprint. In order to preserve the /// ModuleDepGraphNode's identity but bring its fingerprint up to date, it /// needs to set the fingerprint *after* the node has been created. - void setFingerprint(Optional fp) { fingerprint = fp; } + void setFingerprint(Optional fp) { + fingerprint = fp ? fp->str() : Optional(); + } SWIFT_DEBUG_DUMP; void dump(llvm::raw_ostream &os) const; @@ -684,7 +721,7 @@ class SourceFileDepGraphNode : public DepGraphNode { SourceFileDepGraphNode() : DepGraphNode(), sequenceNumber(~0) {} /// Used by the frontend to build nodes. - SourceFileDepGraphNode(DependencyKey key, Optional fingerprint, + SourceFileDepGraphNode(DependencyKey key, Optional fingerprint, bool isProvides) : DepGraphNode(key, fingerprint), isProvides(isProvides) { assert(key.verify()); @@ -780,34 +817,6 @@ class SourceFileDepGraph { SourceFileDepGraph(const SourceFileDepGraph &g) = delete; SourceFileDepGraph(SourceFileDepGraph &&g) = default; - /// Simulate loading for unit testing: - /// \param swiftDepsFileName The name of the swiftdeps file of the phony job - /// \param includePrivateDeps Whether the graph includes intra-file arcs - /// \param hadCompilationError Simulate a compilation error - /// \param interfaceHash The interface hash of the simulated graph - /// \param simpleNamesByRDK A map of vectors of names keyed by reference - /// dependency key \param compoundNamesByRDK A map of (mangledHolder, - /// baseName) pairs keyed by reference dependency key. For single-name - /// dependencies, an initial underscore indicates that the name does not - /// cascade. For compound names, it is the first name, the holder which - /// indicates non-cascading. For member names, an initial underscore indicates - /// file-privacy. - static SourceFileDepGraph - simulateLoad(std::string swiftDepsFileName, const bool includePrivateDeps, - const bool hadCompilationError, std::string interfaceHash, - llvm::StringMap> simpleNamesByRDK, - llvm::StringMap>> - compoundNamesByRDK); - - static constexpr char noncascadingOrPrivatePrefix = '#'; - static constexpr char nameFingerprintSeparator = ','; - - static std::string noncascading(std::string name); - - LLVM_ATTRIBUTE_UNUSED - static std::string privatize(std::string name); - - /// Nodes are owned by the graph. ~SourceFileDepGraph() { forEachNode([&](SourceFileDepGraphNode *n) { delete n; }); @@ -851,12 +860,15 @@ class SourceFileDepGraph { /// The frontend creates a pair of nodes for every tracked Decl and the source /// file itself. InterfaceAndImplementationPair - findExistingNodePairOrCreateAndAddIfNew( - NodeKind k, const ContextNameFingerprint &contextNameFingerprint); + findExistingNodePairOrCreateAndAddIfNew(const DependencyKey &interfaceKey, + Optional fingerprint); + + NullablePtr + findExistingNode(const DependencyKey &key); SourceFileDepGraphNode * - findExistingNodeOrCreateIfNew(DependencyKey key, - const Optional &fingerprint, + findExistingNodeOrCreateIfNew(const DependencyKey &key, + const Optional fingerprint, bool isProvides); /// \p Use is the Node that must be rebuilt when \p def changes. diff --git a/include/swift/AST/FrontendSourceFileDepGraphFactory.h b/include/swift/AST/FrontendSourceFileDepGraphFactory.h new file mode 100644 index 0000000000000..7aa49cc00ef35 --- /dev/null +++ b/include/swift/AST/FrontendSourceFileDepGraphFactory.h @@ -0,0 +1,60 @@ +//===----- FrontendSourceFileDepGraphFactory.h -------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef FrontendSourceFileDepGraphFactory_h +#define FrontendSourceFileDepGraphFactory_h + +#include "swift/AST/AbstractSourceFileDepGraphFactory.h" +namespace swift { +namespace fine_grained_dependencies { + +/// Constructs a SourceFileDepGraph from a *real* \c SourceFile +/// Reads the information provided by the frontend and builds the +/// SourceFileDepGraph + +class FrontendSourceFileDepGraphFactory + : public AbstractSourceFileDepGraphFactory { + SourceFile *const SF; + const DependencyTracker &depTracker; + +public: + FrontendSourceFileDepGraphFactory(SourceFile *SF, StringRef outputPath, + const DependencyTracker &depTracker, + bool alsoEmitDotFile); + + ~FrontendSourceFileDepGraphFactory() override = default; + +private: + static std::string getFingerprint(SourceFile *SF); + + static bool computeIncludePrivateDeps(SourceFile *SF); + static std::string getInterfaceHash(SourceFile *SF); + + void addAllDefinedDecls() override; + void addAllUsedDecls() override; + + /// Given an array of Decls or pairs of them in \p declsOrPairs + /// create node pairs for context and name + template + void addAllDefinedDeclsOfAGivenType(std::vector &contentsVec); + + /// At present, only nominals, protocols, and extensions have (body) + /// fingerprints + static Optional + getFingerprintIfAny(std::pair); + static Optional getFingerprintIfAny(const Decl *d); +}; + +} // namespace fine_grained_dependencies +} // namespace swift + +#endif /* FrontendSourceFileDepGraphFactory_h */ diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index c5d2fa271ec74..6c3c659139bba 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(true), UseIncrementalLLVMCodeGen(true), + PrespecializeGenericMetadata(false), UseIncrementalLLVMCodeGen(true), UseSwiftCall(false), GenerateProfile(false), EnableDynamicReplacementChaining(false), // SWIFT_ENABLE_TENSORFLOW diff --git a/include/swift/AST/LazyResolver.h b/include/swift/AST/LazyResolver.h index afd90352852cf..7ee855601c8ba 100644 --- a/include/swift/AST/LazyResolver.h +++ b/include/swift/AST/LazyResolver.h @@ -81,10 +81,7 @@ class alignas(void*) LazyMemberLoader { /// Populates a vector with all members of \p IDC that have DeclName /// matching \p N. - /// - /// Returns None if an error occurred \em or named member-lookup - /// was otherwise unsupported in this implementation or Decl. - virtual Optional> + virtual TinyPtrVector loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) = 0; diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 09a04adbde89c..ca7c095292c10 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -124,6 +124,8 @@ enum class ResilienceStrategy : unsigned { Resilient }; +class OverlayFile; + /// The minimum unit of compilation. /// /// A module is made up of several file-units, which are all part of the same @@ -203,6 +205,9 @@ class ModuleDecl : public DeclContext, public TypeDecl { SmallVector Files; + llvm::SmallDenseMap> + declaredCrossImports; + std::unique_ptr Cache; SourceLookupCache &getSourceLookupCache() const; @@ -252,6 +257,22 @@ class ModuleDecl : public DeclContext, public TypeDecl { void addFile(FileUnit &newFile); void removeFile(FileUnit &existingFile); + /// Add a file declaring a cross-import overlay. + void addCrossImportOverlayFile(StringRef file); + + /// Append to \p overlayNames the names of all modules that this module + /// declares should be imported when \p bystanderName is imported. + /// + /// This operation is asymmetric: you will get different results if you + /// reverse the positions of the two modules involved in the cross-import. + void findDeclaredCrossImportOverlays( + Identifier bystanderName, SmallVectorImpl &overlayNames, + SourceLoc diagLoc) const; + + /// Get the list of all modules this module declares a cross-import with. + void getDeclaredCrossImportBystanders( + SmallVectorImpl &bystanderNames); + /// Convenience accessor for clients that know what kind of file they're /// dealing with. SourceFile &getMainSourceFile(SourceFileKind expectedKind) const; @@ -437,6 +458,11 @@ class ModuleDecl : public DeclContext, public TypeDecl { ObjCSelector selector, SmallVectorImpl &results) const; + /// Find all SPI names imported from \p importedModule by this module, + /// collecting the identifiers in \p spiGroups. + void lookupImportedSPIGroups(const ModuleDecl *importedModule, + SmallVectorImpl &spiGroups) const; + /// \sa getImportedModules enum class ImportFilterKind { /// Include imports declared with `@_exported`. @@ -444,7 +470,13 @@ class ModuleDecl : public DeclContext, public TypeDecl { /// Include "regular" imports with no special annotation. Private = 1 << 1, /// Include imports declared with `@_implementationOnly`. - ImplementationOnly = 1 << 2 + ImplementationOnly = 1 << 2, + /// Include imports of SPIs declared with `@_spi` + SPIAccessControl = 1 << 3, + /// Include imports shadowed by a separately-imported overlay (i.e. a + /// cross-import overlay). Unshadowed imports are included whether or not + /// this flag is specified. + ShadowedBySeparateOverlay = 1 << 4 }; /// \sa getImportedModules using ImportFilter = OptionSet; diff --git a/include/swift/AST/ModuleLoader.h b/include/swift/AST/ModuleLoader.h index d68f08625e5ce..113c5a8097d11 100644 --- a/include/swift/AST/ModuleLoader.h +++ b/include/swift/AST/ModuleLoader.h @@ -41,6 +41,7 @@ struct AutoDiffConfig; class AbstractFunctionDecl; class ClangImporterOptions; class ClassDecl; +class FileUnit; class ModuleDecl; class NominalTypeDecl; class TypeDecl; @@ -176,6 +177,10 @@ class ModuleLoader { /// Verify all modules loaded by this loader. virtual void verifyAllModules() { } + + /// Discover overlays declared alongside this file and add infomation about + /// them to it. + void findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module, FileUnit *file); }; } // namespace swift diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index aa5ec2a051b4b..c374533973038 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -270,6 +270,9 @@ struct PrintOptions { /// Whether to skip keywords with a prefix of underscore such as __consuming. bool SkipUnderscoredKeywords = false; + // Print SPI attributes and decls that are visible only as SPI. + bool PrintSPIs = true; + /// Prints type variables and unresolved types in an expanded notation suitable /// for debugging. bool PrintTypesForDebugging = false; @@ -515,14 +518,18 @@ struct PrintOptions { return result; } - /// Retrieve the set of options suitable for module interfaces. + /// Retrieve the set of options suitable for textual module interfaces. /// /// This is a format that will be parsed again later, so the output must be /// consistent and well-formed. /// + /// Set \p printSPIs to produce a module interface with the SPI decls and + /// attributes. + /// /// \see swift::emitSwiftInterface static PrintOptions printSwiftInterfaceFile(bool preferTypeRepr, - bool printFullConvention); + bool printFullConvention, + bool printSPIs); /// Retrieve the set of options suitable for "Generated Interfaces", which /// are a prettified representation of the public API of a module, to be diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index 9b0c84cbe9225..096a9c8b6bd69 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -54,7 +54,14 @@ class SourceFile final : public FileUnit { /// elsewhere. /// /// Mutually exclusive with Exported. - ImplementationOnly = 0x8 + ImplementationOnly = 0x8, + + // The module is imported to have access to named SPIs which is an + // implementation detail of this file. + SPIAccessControl = 0x10, + + /// Used for DenseMap. + Reserved = 0x80 }; /// \see ImportFlags @@ -63,13 +70,21 @@ class SourceFile final : public FileUnit { struct ImportedModuleDesc { ModuleDecl::ImportedModule module; ImportOptions importOptions; + + // Filename for a @_private import. StringRef filename; + // Names of explicitly imported SPIs. + ArrayRef spiGroups; + ImportedModuleDesc(ModuleDecl::ImportedModule module, ImportOptions options, - StringRef filename = {}) - : module(module), importOptions(options), filename(filename) { + StringRef filename = {}, + ArrayRef spiGroups = {}) + : module(module), importOptions(options), filename(filename), + spiGroups(spiGroups) { assert(!(importOptions.contains(ImportFlags::Exported) && - importOptions.contains(ImportFlags::ImplementationOnly))); + importOptions.contains(ImportFlags::ImplementationOnly)) || + importOptions.contains(ImportFlags::Reserved)); } }; @@ -125,6 +140,17 @@ class SourceFile final : public FileUnit { /// been validated. llvm::SetVector UnvalidatedDeclsWithOpaqueReturnTypes; + using SeparatelyImportedOverlayMap = + llvm::SmallDenseMap>; + + /// Keys are modules which are shadowed by one or more separately-imported + /// overlays; values are the list of overlays shadowing them. + /// + /// This is used by cross-import overlays to make their members appear to + /// be part of the underlying module. (ClangImporter overlays use a different + /// mechanism which is not SourceFile-dependent.) + SeparatelyImportedOverlayMap separatelyImportedOverlays; + friend ASTContext; friend Impl; @@ -261,11 +287,39 @@ class SourceFile final : public FileUnit { bool isImportedImplementationOnly(const ModuleDecl *module) const; - /// This is a hack for 'main' file parsing and the integrated REPL. + /// Find all SPI names imported from \p importedModule by this file, + /// collecting the identifiers in \p spiGroups. + virtual void + lookupImportedSPIGroups(const ModuleDecl *importedModule, + SmallVectorImpl &spiGroups) const override; + + // Is \p targetDecl accessible as an explictly imported SPI from this file? + bool isImportedAsSPI(const ValueDecl *targetDecl) const; + + bool shouldCrossImport() const; + + /// Register a separately-imported overlay as shadowing the module that + /// declares it. /// - /// FIXME: Refactor main file parsing to not pump the parser incrementally. - /// FIXME: Remove the integrated REPL. - void clearLookupCache(); + /// \returns true if the overlay was added; false if it already existed. + bool addSeparatelyImportedOverlay(ModuleDecl *overlay, + ModuleDecl *declaring) { + return std::get<1>(separatelyImportedOverlays[declaring].insert(overlay)); + } + + /// Retrieves a list of separately imported overlays which are shadowing + /// \p declaring. If any \p overlays are returned, qualified lookups into + /// \p declaring should be performed into \p overlays instead; since they + /// are overlays, they will re-export \p declaring, but will also augment it + /// with additional symbols. + void getSeparatelyImportedOverlays( + ModuleDecl *declaring, SmallVectorImpl &overlays) { + auto i = separatelyImportedOverlays.find(declaring); + if (i == separatelyImportedOverlays.end()) return; + + auto &value = std::get<1>(*i); + overlays.append(value.begin(), value.end()); + } void cacheVisibleDecls(SmallVectorImpl &&globals) const; const SmallVectorImpl &getCachedVisibleDecls() const; @@ -521,4 +575,58 @@ inline void simple_display(llvm::raw_ostream &out, const SourceFile *SF) { } } // end namespace swift +namespace llvm { + +template<> +struct DenseMapInfo { + using ImportOptions = swift::SourceFile::ImportOptions; + + using UnsignedDMI = DenseMapInfo; + + static inline ImportOptions getEmptyKey() { + return ImportOptions(UnsignedDMI::getEmptyKey()); + } + static inline ImportOptions getTombstoneKey() { + return ImportOptions(UnsignedDMI::getTombstoneKey()); + } + static inline unsigned getHashValue(ImportOptions options) { + return UnsignedDMI::getHashValue(options.toRaw()); + } + static bool isEqual(ImportOptions a, ImportOptions b) { + return UnsignedDMI::isEqual(a.toRaw(), b.toRaw()); + } +}; + +template<> +struct DenseMapInfo { + using ImportedModuleDesc = swift::SourceFile::ImportedModuleDesc; + + using ImportedModuleDMI = DenseMapInfo; + using ImportOptionsDMI = DenseMapInfo; + using StringRefDMI = DenseMapInfo; + + static inline ImportedModuleDesc getEmptyKey() { + return ImportedModuleDesc(ImportedModuleDMI::getEmptyKey(), + ImportOptionsDMI::getEmptyKey(), + StringRefDMI::getEmptyKey()); + } + static inline ImportedModuleDesc getTombstoneKey() { + return ImportedModuleDesc(ImportedModuleDMI::getTombstoneKey(), + ImportOptionsDMI::getTombstoneKey(), + StringRefDMI::getTombstoneKey()); + } + static inline unsigned getHashValue(const ImportedModuleDesc &import) { + return combineHashValue(ImportedModuleDMI::getHashValue(import.module), + combineHashValue(ImportOptionsDMI::getHashValue(import.importOptions), + StringRefDMI::getHashValue(import.filename))); + } + static bool isEqual(const ImportedModuleDesc &a, + const ImportedModuleDesc &b) { + return ImportedModuleDMI::isEqual(a.module, b.module) && + ImportOptionsDMI::isEqual(a.importOptions, b.importOptions) && + StringRefDMI::isEqual(a.filename, b.filename); + } +}; +} + #endif diff --git a/include/swift/AST/TBDGenRequests.h b/include/swift/AST/TBDGenRequests.h new file mode 100644 index 0000000000000..f8db98d47508d --- /dev/null +++ b/include/swift/AST/TBDGenRequests.h @@ -0,0 +1,124 @@ +//===--- TBDGenRequests.h - TBDGen Requests ---------------------*- C++ -*-===// +// +// 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 TBDGen requests. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_TBDGEN_REQUESTS_H +#define SWIFT_TBDGEN_REQUESTS_H + +#include "swift/AST/ASTTypeIDs.h" +#include "swift/AST/SimpleRequest.h" + +namespace llvm { +namespace MachO { +class InterfaceFile; +} // end namespace MachO + +template +class StringSet; +} // end namespace llvm + +namespace swift { + +class FileUnit; +class ModuleDecl; +struct TBDGenOptions; + +class TBDGenDescriptor final { + using FileOrModule = llvm::PointerUnion; + FileOrModule Input; + const TBDGenOptions &Opts; + + TBDGenDescriptor(FileOrModule input, const TBDGenOptions &opts) + : Input(input), Opts(opts) { + assert(input); + } + +public: + /// Returns the file or module we're emitting TBD for. + FileOrModule getFileOrModule() const { return Input; } + + /// If the input is a single file, returns that file. Otherwise returns + /// \c nullptr. + FileUnit *getSingleFile() const; + + /// Returns the parent module for TBD emission. + ModuleDecl *getParentModule() const; + + /// Returns the TBDGen options. + const TBDGenOptions &getOptions() const { return Opts; } + + bool operator==(const TBDGenDescriptor &other) const; + bool operator!=(const TBDGenDescriptor &other) const { + return !(*this == other); + } + + static TBDGenDescriptor forFile(FileUnit *file, const TBDGenOptions &opts) { + return TBDGenDescriptor(file, opts); + } + + static TBDGenDescriptor forModule(ModuleDecl *M, const TBDGenOptions &opts) { + return TBDGenDescriptor(M, opts); + } +}; + +llvm::hash_code hash_value(const TBDGenDescriptor &desc); +void simple_display(llvm::raw_ostream &out, const TBDGenDescriptor &desc); +SourceLoc extractNearestSourceLoc(const TBDGenDescriptor &desc); + +using TBDFileAndSymbols = + std::pair>; + +/// Computes the TBD file and public symbols for a given module or file. +class GenerateTBDRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + llvm::Expected evaluate(Evaluator &evaluator, + TBDGenDescriptor desc) const; +}; + +/// Report that a request of the given kind is being evaluated, so it +/// can be recorded by the stats reporter. +template +void reportEvaluatedRequest(UnifiedStatsReporter &stats, + const Request &request); + +/// The zone number for TBDGen. +#define SWIFT_TYPEID_ZONE TBDGen +#define SWIFT_TYPEID_HEADER "swift/AST/TBDGenTypeIDZone.def" +#include "swift/Basic/DefineTypeIDZone.h" +#undef SWIFT_TYPEID_ZONE +#undef SWIFT_TYPEID_HEADER + +// Set up reporting of evaluated requests. +#define SWIFT_REQUEST(Zone, RequestType, Sig, Caching, LocOptions) \ +template<> \ +inline void reportEvaluatedRequest(UnifiedStatsReporter &stats, \ + const RequestType &request) { \ + ++stats.getFrontendCounters().RequestType; \ +} +#include "swift/AST/TBDGenTypeIDZone.def" +#undef SWIFT_REQUEST + +} // end namespace swift + +#endif // SWIFT_TBDGEN_REQUESTS_H diff --git a/include/swift/AST/TBDGenTypeIDZone.def b/include/swift/AST/TBDGenTypeIDZone.def new file mode 100644 index 0000000000000..255499a2cb13a --- /dev/null +++ b/include/swift/AST/TBDGenTypeIDZone.def @@ -0,0 +1,18 @@ +//===--- TBDGenTypeIDZone.def -----------------------------------*- C++ -*-===// +// +// 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 definition file describes the requests in TBDGen's zone. +// +//===----------------------------------------------------------------------===// + +SWIFT_REQUEST(TBDGen, GenerateTBDRequest, TBDFileAndSymbols(TBDGenDescriptor), + Uncached, NoLocationInfo) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 79d2079358a7b..6b4eb42fdc6c4 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -2788,7 +2788,8 @@ class AnyFunctionType : public TypeBase { Identifier l = Identifier(), ParameterTypeFlags f = ParameterTypeFlags()) : Ty(t), Label(l), Flags(f) { - assert(!t || !t->is() && "set flags instead"); + assert(t && "param type must be non-null"); + assert(!t->is() && "set flags instead"); } private: diff --git a/include/swift/Basic/FileTypes.def b/include/swift/Basic/FileTypes.def index f2a832821a0f7..ae98137759593 100644 --- a/include/swift/Basic/FileTypes.def +++ b/include/swift/Basic/FileTypes.def @@ -50,6 +50,7 @@ TYPE("autolink", AutolinkFile, "autolink", "") TYPE("swiftmodule", SwiftModuleFile, "swiftmodule", "") TYPE("swiftdoc", SwiftModuleDocFile, "swiftdoc", "") TYPE("swiftinterface", SwiftModuleInterfaceFile, "swiftinterface", "") +TYPE("private-swiftinterface", PrivateSwiftModuleInterfaceFile, "private.swiftinterface", "") TYPE("swiftsourceinfo", SwiftSourceInfoFile, "swiftsourceinfo", "") TYPE("assembly", Assembly, "s", "") TYPE("raw-sil", RawSIL, "sil", "") @@ -73,6 +74,13 @@ TYPE("module-trace", ModuleTrace, "trace.json", "") TYPE("index-data", IndexData, "", "") TYPE("opt-record", OptRecord, "opt.yaml", "") +// Overlay files declare wrapper modules, called "separately-imported overlays", +// that should be automatically imported when a particular module is imported. +// Cross-import directories conditionalize overlay files so they only take +// effect when certain other modules are also loaded. +TYPE("swiftcrossimport", SwiftCrossImportDir, "swiftcrossimport","") +TYPE("swiftoverlay", SwiftOverlayFile, "swiftoverlay", "") + // Misc types TYPE("pcm", ClangModuleFile, "pcm", "") TYPE("pch", PCH, "pch", "") diff --git a/include/swift/Basic/FrozenMultiMap.h b/include/swift/Basic/FrozenMultiMap.h new file mode 100644 index 0000000000000..8b171dd3abcfa --- /dev/null +++ b/include/swift/Basic/FrozenMultiMap.h @@ -0,0 +1,189 @@ +//===--- FrozenMultiMap.h ----------------------------------*- C++ --------===// +// +// This source file is part of the Swift.org open source project +// +// 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 +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// A 2 stage multi-map. Initially the multimap is mutable and can only be +/// initialized. Once complete, the map is frozen and can be only used for map +/// operations. It is guaranteed that all values are still in insertion order. +/// +/// DISCUSSION: These restrictions flow from the internal implementation of the +/// multi-map being a pair of keys, values. We form the map property by +/// performing a stable_sort of the (key, value) in the process of freezing the +/// map. +/// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_BASIC_FROZENMULTIMAP_H +#define SWIFT_BASIC_FROZENMULTIMAP_H + +#include "swift/Basic/LLVM.h" +#include "swift/Basic/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include + +namespace swift { + +template >> +class FrozenMultiMap { + VectorStorage storage; + bool frozen = false; + +private: + struct PairToSecondElt; + +public: + using PairToSecondEltRange = + TransformRange>, PairToSecondElt>; + + FrozenMultiMap() = default; + + void insert(const Key &key, const Value &value) { + assert(!isFrozen() && "Can not insert new keys once map is frozen"); + storage.emplace_back(key, value); + } + + Optional find(const Key &key) const { + assert(isFrozen() && + "Can not perform a find operation until the map is frozen"); + // Since our array is sorted, we need to first find the first pair with our + // inst as the first element. + auto start = std::lower_bound( + storage.begin(), storage.end(), std::make_pair(key, Value()), + [&](const std::pair &p1, const std::pair &p2) { + return p1.first < p2.first; + }); + if (start == storage.end() || start->first != key) { + return None; + } + + // Ok, we found our first element. Now scan forward until we find a pair + // whose instruction is not our own instruction. + auto end = find_if_not( + start, storage.end(), + [&](const std::pair &pair) { return pair.first == key; }); + unsigned count = std::distance(start, end); + ArrayRef> slice(&*start, count); + return PairToSecondEltRange(slice, PairToSecondElt()); + } + + bool isFrozen() const { return frozen; } + + /// Set this map into its frozen state when we + void setFrozen() { + std::stable_sort(storage.begin(), storage.end(), + [&](const std::pair &lhs, + const std::pair &rhs) { + // Only compare the first entry so that we preserve + // insertion order. + return lhs.first < rhs.first; + }); + frozen = true; + } + + unsigned size() const { return storage.size(); } + bool empty() const { return storage.empty(); } + + struct iterator : std::iterator>> { + using base_iterator = typename decltype(storage)::iterator; + + FrozenMultiMap ↦ + base_iterator baseIter; + Optional> currentValue; + + iterator(FrozenMultiMap &map, base_iterator iter) + : map(map), baseIter(iter), currentValue() { + updateCurrentValue(); + } + + void updateCurrentValue() { + base_iterator end = map.storage.end(); + + // If we are end, set currentValue to be None. + if (baseIter == end) { + currentValue = None; + return; + } + + // Otherwise, determine the next range that we are visiting. + auto rangeEnd = std::find_if_not(std::next(baseIter), end, + [&](const std::pair &elt) { + return elt.first == baseIter->first; + }); + unsigned count = std::distance(baseIter, rangeEnd); + ArrayRef> slice(&*baseIter, count); + currentValue = {baseIter->first, + PairToSecondEltRange(slice, PairToSecondElt())}; + } + + iterator &operator++() { + baseIter = std::find_if_not(std::next(baseIter), map.storage.end(), + [&](const std::pair &elt) { + return elt.first == baseIter->first; + }); + updateCurrentValue(); + return *this; + } + + iterator operator++(int) { + auto tmp = *this; + baseIter = std::find_if_not(std::next(baseIter), map.storage.end(), + [&](const std::pair &elt) { + return elt.first == baseIter->first; + }); + updateCurrentValue(); + return tmp; + } + + std::pair operator*() const { + return *currentValue; + } + + bool operator==(const iterator &RHS) const { + return baseIter == RHS.baseIter; + } + + bool operator!=(const iterator &RHS) const { + return baseIter != RHS.baseIter; + } + }; + + /// Return a range of (key, ArrayRef) pairs. The keys are guaranteed to + /// be in key sorted order and the ArrayRef are in insertion order. + llvm::iterator_range getRange() const { + assert(isFrozen() && + "Can not create range until data structure is frozen?!"); + auto *self = const_cast(this); + iterator iter1 = iterator(*self, self->storage.begin()); + iterator iter2 = iterator(*self, self->storage.end()); + return llvm::make_range(iter1, iter2); + } +}; + +template +struct FrozenMultiMap::PairToSecondElt { + PairToSecondElt() {} + + Value operator()(const std::pair &pair) const { + return pair.second; + } +}; + +template +using SmallFrozenMultiMap = + FrozenMultiMap, SmallSize>>; + +} // namespace swift + +#endif diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 1899d2e5347f9..9dc07719c0e54 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -109,6 +109,9 @@ namespace swift { /// human-readable string. bool EnableConcisePoundFile = false; + /// Detect and automatically import modules' cross-import overlays. + bool EnableCrossImportOverlays = false; + /// /// Support for alternate usage modes /// diff --git a/include/swift/Basic/Lazy.h b/include/swift/Basic/Lazy.h index 594e2ed8b9fcd..6c899abeeffd6 100644 --- a/include/swift/Basic/Lazy.h +++ b/include/swift/Basic/Lazy.h @@ -16,6 +16,8 @@ #include #ifdef __APPLE__ #include +#elif defined(__wasi__) +// No pthread on wasi, see https://bugs.swift.org/browse/SR-12097 for more details. #else #include #endif diff --git a/include/swift/Basic/OptionSet.h b/include/swift/Basic/OptionSet.h index 0edab181404fa..03395be34666a 100644 --- a/include/swift/Basic/OptionSet.h +++ b/include/swift/Basic/OptionSet.h @@ -88,7 +88,7 @@ class OptionSet { } /// Check if this option set contains the exact same options as the given set. - bool containsOnly(OptionSet set) { + bool containsOnly(OptionSet set) const { return Storage == set.Storage; } diff --git a/include/swift/Basic/SourceManager.h b/include/swift/Basic/SourceManager.h index 41df4524e3be6..5a1f85e815668 100644 --- a/include/swift/Basic/SourceManager.h +++ b/include/swift/Basic/SourceManager.h @@ -81,6 +81,10 @@ class SourceManager { CodeCompletionBufferID = 0U; } + bool hasCodeCompletionBuffer() const { + return CodeCompletionBufferID != 0U; + } + unsigned getCodeCompletionBufferID() const { return CodeCompletionBufferID; } diff --git a/include/swift/Basic/Statistics.def b/include/swift/Basic/Statistics.def index e8ba372a18c7d..bbc9e0d12c5ae 100644 --- a/include/swift/Basic/Statistics.def +++ b/include/swift/Basic/Statistics.def @@ -187,6 +187,12 @@ FRONTEND_STATISTIC(Parse, NumIterableDeclContextParsed) /// Number of conformances that were deserialized by this frontend job. FRONTEND_STATISTIC(Sema, NumConformancesDeserialized) +/// Number of pairs of modules we've checked for cross-imports. +FRONTEND_STATISTIC(Sema, NumCrossImportsChecked) + +/// Number of pairs of modules we've actually found cross-imports for. +FRONTEND_STATISTIC(Sema, NumCrossImportsFound) + /// Number of constraint-solving scopes created in the typechecker, while /// solving expression type constraints. A rough proxy for "how much work the /// expression typechecker did". @@ -224,9 +230,6 @@ FRONTEND_STATISTIC(Sema, NumAccessorsSynthesized) /// Number of synthesized accessor bodies. FRONTEND_STATISTIC(Sema, NumAccessorBodiesSynthesized) -/// Number of full function bodies typechecked. -FRONTEND_STATISTIC(Sema, NumFunctionsTypechecked) - /// Number of generic signature builders constructed. Rough proxy for /// amount of work the GSB does analyzing type signatures. FRONTEND_STATISTIC(Sema, NumGenericSignatureBuilders) @@ -243,9 +246,6 @@ FRONTEND_STATISTIC(Sema, NumLazyIterableDeclContexts) /// Number of member-name lookups that avoided loading all members. FRONTEND_STATISTIC(Sema, NamedLazyMemberLoadSuccessCount) -/// Number of member-name lookups that wound up loading all members. -FRONTEND_STATISTIC(Sema, NamedLazyMemberLoadFailureCount) - /// Number of types deserialized. FRONTEND_STATISTIC(Sema, NumTypesDeserialized) @@ -286,10 +286,10 @@ FRONTEND_STATISTIC(SILModule, NumSILOptWitnessTables) FRONTEND_STATISTIC(SILModule, NumSILOptDefaultWitnessTables) FRONTEND_STATISTIC(SILModule, NumSILOptGlobalVariables) -/// The next 9 statistics count kinds of LLVM entities produced +/// The next 10 statistics count kinds of LLVM entities produced /// during the IRGen phase: globals, functions, aliases, ifuncs, /// named metadata, value and comdat symbols, basic blocks, -/// and instructions. +/// instructions, and GOT entries. FRONTEND_STATISTIC(IRModule, NumIRGlobals) FRONTEND_STATISTIC(IRModule, NumIRFunctions) FRONTEND_STATISTIC(IRModule, NumIRAliases) @@ -299,10 +299,15 @@ FRONTEND_STATISTIC(IRModule, NumIRValueSymbols) FRONTEND_STATISTIC(IRModule, NumIRComdatSymbols) FRONTEND_STATISTIC(IRModule, NumIRBasicBlocks) FRONTEND_STATISTIC(IRModule, NumIRInsts) +FRONTEND_STATISTIC(IRModule, NumGOTEntries) /// Number of bytes written to the object-file output stream /// of the frontend job, which should be the same as the size of /// the .o file you find on disk after the frontend exits. FRONTEND_STATISTIC(LLVM, NumLLVMBytesOutput) +#define SWIFT_REQUEST(ZONE, NAME, Sig, Caching, LocOptions) FRONTEND_STATISTIC(TBDGen, NAME) +#include "swift/AST/TBDGenTypeIDZone.def" +#undef SWIFT_REQUEST + #endif diff --git a/include/swift/Basic/SupplementaryOutputPaths.h b/include/swift/Basic/SupplementaryOutputPaths.h index 26c17e4627e90..5140d0c66d853 100644 --- a/include/swift/Basic/SupplementaryOutputPaths.h +++ b/include/swift/Basic/SupplementaryOutputPaths.h @@ -149,6 +149,13 @@ struct SupplementaryOutputPaths { /// \sa swift::emitSwiftInterface std::string ModuleInterfaceOutputPath; + /// The path to which we should emit a private module interface. + /// + /// The private module interface contains all SPI decls and attributes. + /// + /// \sa ModuleInterfaceOutputPath + std::string PrivateModuleInterfaceOutputPath; + /// The path to a .c file where we should declare $ld$add symbols for those /// symbols moved to the current module. /// When symbols are moved to this module, this module declares them as HIDE diff --git a/include/swift/Basic/TypeID.h b/include/swift/Basic/TypeID.h index 03145896e556a..4648b6e188791 100644 --- a/include/swift/Basic/TypeID.h +++ b/include/swift/Basic/TypeID.h @@ -38,6 +38,7 @@ enum class Zone : uint8_t { Parse = 8, TypeChecker = 10, SILGen = 12, + TBDGen = 14, // N.B. This is not a formal zone and exists solely to support the unit tests. ArithmeticEvaluator = 255, }; diff --git a/include/swift/ClangImporter/ClangModule.h b/include/swift/ClangImporter/ClangModule.h index baa65c5551ebf..90cc2c97c9166 100644 --- a/include/swift/ClangImporter/ClangModule.h +++ b/include/swift/ClangImporter/ClangModule.h @@ -118,6 +118,8 @@ class ClangModuleUnit final : public LoadedFile { Optional getASTSourceDescriptor() const; + virtual StringRef getModuleDefiningPath() const override; + static bool classof(const FileUnit *file) { return file->getKind() == FileUnitKind::ClangModule; } diff --git a/include/swift/Driver/Driver.h b/include/swift/Driver/Driver.h index d927f3908a14f..9723f4527ced4 100644 --- a/include/swift/Driver/Driver.h +++ b/include/swift/Driver/Driver.h @@ -364,6 +364,7 @@ class Driver { void chooseModuleInterfacePath(Compilation &C, const JobAction *JA, StringRef workingDirectory, llvm::SmallString<128> &buffer, + file_types::ID fileType, CommandOutput *output) const; void chooseRemappingOutputPath(Compilation &C, const TypeToPathMap *OutputMap, diff --git a/include/swift/Driver/FineGrainedDependencyDriverGraph.h b/include/swift/Driver/FineGrainedDependencyDriverGraph.h index 36ab089d6c029..71ecc27c506b6 100644 --- a/include/swift/Driver/FineGrainedDependencyDriverGraph.h +++ b/include/swift/Driver/FineGrainedDependencyDriverGraph.h @@ -57,8 +57,7 @@ class ModuleDepGraphNode : public DepGraphNode { bool hasBeenTracedAsADependent = false; public: - ModuleDepGraphNode(const DependencyKey &key, - Optional fingerprint, + ModuleDepGraphNode(const DependencyKey &key, Optional fingerprint, Optional swiftDeps) : DepGraphNode(key, fingerprint), swiftDeps(swiftDeps) {} @@ -187,11 +186,13 @@ class ModuleDepGraph { /// files for the same name distinct, keep a sequence number for each name. std::unordered_map dotFileSequenceNumber; +public: const bool verifyFineGrainedDependencyGraphAfterEveryImport; const bool emitFineGrainedDependencyDotFileAfterEveryImport; const bool EnableTypeFingerprints; +private: /// If tracing dependencies, holds a vector used to hold the current path /// def - use/def - use/def - ... Optional> currentPathIfTracing; @@ -336,15 +337,6 @@ class ModuleDepGraph { 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); - private: /// Read a SourceFileDepGraph belonging to \p job from \p buffer @@ -515,6 +507,8 @@ class ModuleDepGraph { /// Record a new (to this graph) Job. void registerJob(const driver::Job *); + std::vector getAllJobs() const; + /// Find jobs that were previously not known to need compilation but that /// depend on \c externalDependency. std::vector diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 4c2f6f8929899..d172f66a89462 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -375,6 +375,7 @@ class CompilerInvocation { /// mode, so return the ModuleInterfaceOutputPath when in that mode and /// fail an assert if not in that mode. std::string getModuleInterfaceOutputPathForWholeModule() const; + std::string getPrivateModuleInterfaceOutputPathForWholeModule() const; std::string getLdAddCFileOutputPathForWholeModule() const; diff --git a/include/swift/Frontend/FrontendInputsAndOutputs.h b/include/swift/Frontend/FrontendInputsAndOutputs.h index 7daf25d40b89c..b1bbeb0129457 100644 --- a/include/swift/Frontend/FrontendInputsAndOutputs.h +++ b/include/swift/Frontend/FrontendInputsAndOutputs.h @@ -239,6 +239,7 @@ class FrontendInputsAndOutputs { bool hasModuleDocOutputPath() const; bool hasModuleSourceInfoOutputPath() const; bool hasModuleInterfaceOutputPath() const; + bool hasPrivateModuleInterfaceOutputPath() const; bool hasTBDPath() const; bool hasDependencyTrackerPath() const; diff --git a/include/swift/Frontend/ModuleInterfaceSupport.h b/include/swift/Frontend/ModuleInterfaceSupport.h index 4289150c14554..04e8f637d7865 100644 --- a/include/swift/Frontend/ModuleInterfaceSupport.h +++ b/include/swift/Frontend/ModuleInterfaceSupport.h @@ -39,6 +39,9 @@ struct ModuleInterfaceOptions { /// generation time, re-applied to CompilerInvocation when reading /// back .swiftinterface and reconstructing .swiftmodule. std::string Flags; + + // Print SPI decls and attributes. + bool PrintSPIs = false; }; extern version::Version InterfaceFormatVersion; @@ -50,7 +53,7 @@ llvm::Regex getSwiftInterfaceModuleFlagsRegex(); /// source file to import this module, subject to options given by \p Opts. /// /// Unlike a serialized module, the textual format generated by -/// emitModuleInterface is intended to be stable across compiler versions while +/// emitSwiftInterface is intended to be stable across compiler versions while /// still describing the full ABI of the module in question. /// /// The initial plan for this format can be found at diff --git a/include/swift/IDE/CodeCompletion.h b/include/swift/IDE/CodeCompletion.h index 553fd504cd971..4aa390f9609ec 100644 --- a/include/swift/IDE/CodeCompletion.h +++ b/include/swift/IDE/CodeCompletion.h @@ -66,7 +66,7 @@ class CodeCompletionStringChunk { /// "open", "public", "internal", "fileprivate", or "private". AccessControlKeyword, - /// such as @"availability". + /// such as @"available". DeclAttrKeyword, /// such as "unavailable" etc. for @available. diff --git a/include/swift/IDE/RefactoringKinds.def b/include/swift/IDE/RefactoringKinds.def index b6565439a2016..0fbd03dbb7053 100644 --- a/include/swift/IDE/RefactoringKinds.def +++ b/include/swift/IDE/RefactoringKinds.def @@ -72,6 +72,8 @@ RANGE_REFACTORING(ConvertGuardExprToIfLetExpr, "Convert To IfLet Expression", co RANGE_REFACTORING(ConvertToComputedProperty, "Convert To Computed Property", convert.to.computed.property) +RANGE_REFACTORING(ConvertToSwitchStmt, "Convert To Switch Statement", convert.switch.stmt) + // These internal refactorings are designed to be helpful for working on // the compiler/standard library, etc., but are likely to be just confusing and // noise for general development. diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index 21acb1124cc5f..6602dd8e562ed 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -53,12 +53,10 @@ class UniversalLinkageInfo { /// be promoted to public external. Used by the LLDB expression evaluator. bool ForcePublicDecls; - bool IsWholeModule; - explicit UniversalLinkageInfo(IRGenModule &IGM); UniversalLinkageInfo(const llvm::Triple &triple, bool hasMultipleIGMs, - bool forcePublicDecls, bool isWholeModule); + bool forcePublicDecls); /// In case of multiple llvm modules (in multi-threaded compilation) all /// private decls must be visible from other files. @@ -1029,11 +1027,6 @@ class LinkEntity { std::string mangleAsString() const; SILLinkage getLinkage(ForDefinition_t isDefinition) const; - /// Returns true if this function or global variable is potentially defined - /// in a different module. - /// - bool isAvailableExternally(IRGenModule &IGM) const; - const ValueDecl *getDecl() const { assert(isDeclKind(getKind())); return reinterpret_cast(Pointer); @@ -1130,16 +1123,16 @@ class LinkEntity { bool isSILFunction() const { return getKind() == Kind::SILFunction; } - bool isNominalTypeDescriptor() const { - return getKind() == Kind::NominalTypeDescriptor; + bool isDynamicallyReplaceableFunctionKey() const { + return getKind() == Kind::DynamicallyReplaceableFunctionKey; } /// Determine whether this entity will be weak-imported. bool isWeakImported(ModuleDecl *module) const; - /// Return the source file whose codegen should trigger emission of this - /// link entity, if one can be identified. - const SourceFile *getSourceFileForEmission() const; + /// Return the module scope context whose codegen should trigger emission + /// of this link entity, if one can be identified. + DeclContext *getDeclContextForEmission() const; /// Get the preferred alignment for the definition of this entity. Alignment getAlignment(IRGenModule &IGM) const; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index fa220b4df95bf..2a2a2a5e4c5e3 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -126,6 +126,11 @@ def verify_syntax_tree : Flag<["-"], "verify-syntax-tree">, def show_diagnostics_after_fatal : Flag<["-"], "show-diagnostics-after-fatal">, HelpText<"Keep emitting subsequent diagnostics after a fatal error">; +def enable_cross_import_overlays : Flag<["-"], "enable-cross-import-overlays">, + HelpText<"Automatically import declared cross-import overlays.">; +def disable_cross_import_overlays : Flag<["-"], "disable-cross-import-overlays">, + HelpText<"Do not automatically import declared cross-import overlays.">; + def enable_descriptive_diagnostics : Flag<["-"], "enable-descriptive-diagnostics">, HelpText<"Show descriptive diagnostic information, if available.">; @@ -654,6 +659,10 @@ def disable_generic_metadata_prespecialization : Flag<["-"], "disable-generic-me HelpText<"Do not statically specialize metadata for generic types at types " "that are known to be used in source.">; +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 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 787a67e14e6d5..e6bf3d3c6f682 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -344,6 +344,9 @@ def emit_tbd_path : Separate<["-"], "emit-tbd-path">, def emit_tbd_path_EQ : Joined<["-"], "emit-tbd-path=">, Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath]>, Alias; +def embed_tbd_for_module : Separate<["-"], "embed-tbd-for-module">, + Flags<[FrontendOption]>, + HelpText<"Embed symbols from the module in the emitted tbd file">; def serialize_diagnostics : Flag<["-"], "serialize-diagnostics">, Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>, @@ -419,6 +422,12 @@ def emit_module_interface_path : ArgumentIsPath]>, MetaVarName<"">, HelpText<"Output module interface file to ">; +def emit_private_module_interface_path : + Separate<["-"], "emit-private-module-interface-path">, + Flags<[FrontendOption, NoInteractiveOption, HelpHidden, + DoesNotAffectIncrementalBuild, ArgumentIsPath]>, + MetaVarName<"">, HelpText<"Output private module interface file to ">; + def avoid_emit_module_source_info : Flag<["-"], "avoid-emit-module-source-info">, Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>, diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 7dda23f0aa2aa..0cc7a1fa95777 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1129,6 +1129,8 @@ class Parser { ParseDeclOptions Flags, DeclAttributes &Attributes, bool HasFuncKeyword = true); + ParserResult + parseAbstractFunctionBodyImpl(AbstractFunctionDecl *AFD); void parseAbstractFunctionBody(AbstractFunctionDecl *AFD); BraceStmt *parseAbstractFunctionBodyDelayed(AbstractFunctionDecl *AFD); ParserResult parseDeclProtocol(ParseDeclOptions Flags, diff --git a/include/swift/SIL/AbstractionPattern.h b/include/swift/SIL/AbstractionPattern.h index 43fcd74d53824..0e39e0cd77923 100644 --- a/include/swift/SIL/AbstractionPattern.h +++ b/include/swift/SIL/AbstractionPattern.h @@ -752,7 +752,7 @@ class AbstractionPattern { isa(type)) { return true; } - if (auto archetype = dyn_cast(type)) { + if (isa(type)) { return true; } return false; diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index 88d2a566c55e1..246f07361ad55 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -199,22 +199,30 @@ bool isValueAddressOrTrivial(SILValue v); /// These operations forward both owned and guaranteed ownership. bool isOwnershipForwardingValueKind(SILNodeKind kind); +/// Is this an instruction that can forward both owned and guaranteed ownership +/// kinds. +bool isOwnershipForwardingInst(SILInstruction *i); + +/// Is this an instruction that can forward guaranteed ownership. +bool isGuaranteedForwardingInst(SILInstruction *i); + /// These operations forward guaranteed ownership, but don't necessarily forward /// owned values. bool isGuaranteedForwardingValueKind(SILNodeKind kind); +/// Is this a value that is the result of an operation that forwards owned +/// ownership. bool isGuaranteedForwardingValue(SILValue value); -bool isOwnershipForwardingInst(SILInstruction *i); - -bool isGuaranteedForwardingInst(SILInstruction *i); +/// Is this a node kind that can forward owned ownership, but may not be able to +/// forward guaranteed ownership. +bool isOwnedForwardingValueKind(SILNodeKind kind); struct BorrowScopeOperandKind { - using UnderlyingKindTy = std::underlying_type::type; - - enum Kind : UnderlyingKindTy { - BeginBorrow = UnderlyingKindTy(SILInstructionKind::BeginBorrowInst), - BeginApply = UnderlyingKindTy(SILInstructionKind::BeginApplyInst), + enum Kind { + BeginBorrow, + BeginApply, + Branch, }; Kind value; @@ -232,22 +240,40 @@ struct BorrowScopeOperandKind { return BorrowScopeOperandKind(BeginBorrow); case SILInstructionKind::BeginApplyInst: return BorrowScopeOperandKind(BeginApply); + case SILInstructionKind::BranchInst: + return BorrowScopeOperandKind(Branch); } } void print(llvm::raw_ostream &os) const; - SWIFT_DEBUG_DUMP; + SWIFT_DEBUG_DUMP { print(llvm::dbgs()); } }; +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, + BorrowScopeOperandKind kind); + +struct BorrowScopeIntroducingValue; + /// An operand whose user instruction introduces a new borrow scope for the /// operand's value. The value of the operand must be considered as implicitly /// borrowed until the user's corresponding end scope instruction. +/// +/// NOTE: We do not require that the guaranteed scope be represented by a +/// guaranteed value in the same function: see begin_apply. In such cases, we +/// require instead an end_* instruction to mark the end of the scope's region. struct BorrowScopeOperand { BorrowScopeOperandKind kind; Operand *op; BorrowScopeOperand(Operand *op) : kind(*BorrowScopeOperandKind::get(op->getUser()->getKind())), op(op) {} + BorrowScopeOperand(const BorrowScopeOperand &other) + : kind(other.kind), op(other.op) {} + BorrowScopeOperand &operator=(const BorrowScopeOperand &other) { + kind = other.kind; + op = other.op; + return *this; + } /// If value is a borrow introducer return it after doing some checks. static Optional get(Operand *op) { @@ -258,26 +284,71 @@ struct BorrowScopeOperand { return BorrowScopeOperand(*kind, op); } - void visitEndScopeInstructions(function_ref func) const { + void visitEndScopeInstructions(function_ref func) const; + + /// Returns true if this borrow scope operand consumes guaranteed + /// values and produces a new scope afterwards. + bool consumesGuaranteedValues() const { switch (kind) { case BorrowScopeOperandKind::BeginBorrow: - for (auto *use : cast(op->getUser())->getUses()) { - if (isa(use->getUser())) { - func(use); - } - } - return; - case BorrowScopeOperandKind::BeginApply: { - auto *user = cast(op->getUser()); - for (auto *use : user->getTokenResult()->getUses()) { - func(use); - } - return; + case BorrowScopeOperandKind::BeginApply: + return false; + case BorrowScopeOperandKind::Branch: + return true; + } + llvm_unreachable("Covered switch isn't covered?!"); + } + + /// Is this a borrow scope operand that can open new borrow scopes + /// for owned values. + bool canAcceptOwnedValues() const { + switch (kind) { + case BorrowScopeOperandKind::BeginBorrow: + case BorrowScopeOperandKind::BeginApply: + return true; + case BorrowScopeOperandKind::Branch: + return false; } + llvm_unreachable("Covered switch isn't covered?!"); + } + + /// Is the result of this instruction also a borrow introducer? + /// + /// TODO: This needs a better name. + bool areAnyUserResultsBorrowIntroducers() const { + // TODO: Can we derive this by running a borrow introducer check ourselves? + switch (kind) { + case BorrowScopeOperandKind::BeginBorrow: + case BorrowScopeOperandKind::Branch: + return true; + case BorrowScopeOperandKind::BeginApply: + return false; } - llvm_unreachable("Covered switch isn't covered"); + llvm_unreachable("Covered switch isn't covered?!"); } + /// Visit all of the results of the operand's user instruction that are + /// consuming uses. + void visitUserResultConsumingUses(function_ref visitor); + + /// Visit all of the "results" of the user of this operand that are borrow + /// scope introducers for the specific scope that this borrow scope operand + /// summarizes. + void visitBorrowIntroducingUserResults( + function_ref visitor); + + /// Passes to visitor all of the consuming uses of this use's using + /// instruction. + /// + /// This enables one to walk the def-use chain of guaranteed phis for a single + /// guaranteed scope by using a worklist and checking if any of the operands + /// are BorrowScopeOperands. + void visitConsumingUsesOfBorrowIntroducingUserResults( + function_ref visitor); + + void print(llvm::raw_ostream &os) const; + SWIFT_DEBUG_DUMP { print(llvm::dbgs()); } + private: /// Internal constructor for failable static constructor. Please do not expand /// its usage since it assumes the code passed in is well formed. @@ -286,16 +357,17 @@ struct BorrowScopeOperand { }; llvm::raw_ostream &operator<<(llvm::raw_ostream &os, - BorrowScopeOperandKind kind); + const BorrowScopeOperand &operand); struct BorrowScopeIntroducingValueKind { using UnderlyingKindTy = std::underlying_type::type; /// Enum we use for exhaustive pattern matching over borrow scope introducers. - enum Kind : UnderlyingKindTy { - LoadBorrow = UnderlyingKindTy(ValueKind::LoadBorrowInst), - BeginBorrow = UnderlyingKindTy(ValueKind::BeginBorrowInst), - SILFunctionArgument = UnderlyingKindTy(ValueKind::SILFunctionArgument), + enum Kind { + LoadBorrow, + BeginBorrow, + SILFunctionArgument, + Phi, }; static Optional get(ValueKind kind) { @@ -308,6 +380,8 @@ struct BorrowScopeIntroducingValueKind { return BorrowScopeIntroducingValueKind(BeginBorrow); case ValueKind::SILFunctionArgument: return BorrowScopeIntroducingValueKind(SILFunctionArgument); + case ValueKind::SILPhiArgument: + return BorrowScopeIntroducingValueKind(Phi); } } @@ -328,6 +402,7 @@ struct BorrowScopeIntroducingValueKind { switch (value) { case BorrowScopeIntroducingValueKind::BeginBorrow: case BorrowScopeIntroducingValueKind::LoadBorrow: + case BorrowScopeIntroducingValueKind::Phi: return true; case BorrowScopeIntroducingValueKind::SILFunctionArgument: return false; @@ -336,7 +411,7 @@ struct BorrowScopeIntroducingValueKind { } void print(llvm::raw_ostream &os) const; - SWIFT_DEBUG_DUMP; + SWIFT_DEBUG_DUMP { print(llvm::dbgs()); } }; llvm::raw_ostream &operator<<(llvm::raw_ostream &os, @@ -370,9 +445,28 @@ struct BorrowScopeIntroducingValue { : kind(BorrowScopeIntroducingValueKind::SILFunctionArgument), value(arg) { assert(arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed); } + BorrowScopeIntroducingValue(SILPhiArgument *arg) + : kind(BorrowScopeIntroducingValueKind::Phi), value(arg) { + assert(llvm::all_of(arg->getParent()->getPredecessorBlocks(), + [](SILBasicBlock *block) { + return isa(block->getTerminator()); + }) && + "Phi argument incoming values must come from branch insts!"); + assert(arg->isPhiArgument() && "Can only accept a true phi argument!"); + assert(arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed); + } BorrowScopeIntroducingValue(SILValue v) : kind(*BorrowScopeIntroducingValueKind::get(v->getKind())), value(v) { + // Validate that if we have a phi argument that all our predecessors have + // branches as terminators. + assert(!isa(v) || + (llvm::all_of(v->getParentBlock()->getPredecessorBlocks(), + [](SILBasicBlock *block) { + return isa(block->getTerminator()); + }) && + "Phi argument incoming values must come from branch insts!")); + assert(v.getOwnershipKind() == ValueOwnershipKind::Guaranteed); } @@ -381,6 +475,15 @@ struct BorrowScopeIntroducingValue { auto kind = BorrowScopeIntroducingValueKind::get(value->getKind()); if (!kind || value.getOwnershipKind() != ValueOwnershipKind::Guaranteed) return None; + // If kind is phi and we were not passed something with all branch + // predecessors, return None. + if ((*kind) == BorrowScopeIntroducingValueKind::Phi && + llvm::any_of(value->getParentBlock()->getPredecessorBlocks(), + [](SILBasicBlock *block) { + return !isa(block->getTerminator()); + })) + return None; + // Otherwise, create our value directly. return BorrowScopeIntroducingValue(*kind, value); } @@ -419,6 +522,14 @@ struct BorrowScopeIntroducingValue { SmallPtrSetImpl &visitedBlocks, DeadEndBlocks &deadEndBlocks) const; + /// Given a local borrow scope introducer, visit all non-forwarding consuming + /// users. This means that this looks through guaranteed block arguments. + bool visitLocalScopeTransitiveEndingUses( + function_ref visitor) const; + + void print(llvm::raw_ostream &os) const; + SWIFT_DEBUG_DUMP { print(llvm::dbgs()); } + private: /// Internal constructor for failable static constructor. Please do not expand /// its usage since it assumes the code passed in is well formed. @@ -427,6 +538,9 @@ struct BorrowScopeIntroducingValue { : kind(kind), value(value) {} }; +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, + const BorrowScopeIntroducingValue &value); + /// Look up through the def-use chain of \p inputValue, recording any "borrow" /// introducing values that we find into \p out. If at any point, we find a /// point in the chain we do not understand, we bail and return false. If we are diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index 17be0104f0cba..4994a77387a9c 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -518,59 +518,6 @@ class SILBuilder { beginApply)); } - /// SWIFT_ENABLE_TENSORFLOW - DifferentiableFunctionInst *createDifferentiableFunction( - SILLocation Loc, IndexSubset *ParameterIndices, - SILValue OriginalFunction, - Optional> JVPAndVJPFunctions = None) { - return insert(DifferentiableFunctionInst::create( - getModule(), getSILDebugLocation(Loc), ParameterIndices, - OriginalFunction, JVPAndVJPFunctions, hasOwnership())); - } - - LinearFunctionInst *createLinearFunction( - SILLocation Loc, IndexSubset *ParameterIndices, SILValue OriginalFunction, - Optional TransposeFunction = None) { - return insert(LinearFunctionInst::create( - getModule(), getSILDebugLocation(Loc), ParameterIndices, - OriginalFunction, TransposeFunction, hasOwnership())); - } - - /// Note: explicit extractee type may be specified only in lowered SIL. - DifferentiableFunctionExtractInst *createDifferentiableFunctionExtract( - SILLocation Loc, NormalDifferentiableFunctionTypeComponent Extractee, - SILValue TheFunction, Optional ExtracteeType = None) { - return insert(new (getModule()) DifferentiableFunctionExtractInst( - getModule(), getSILDebugLocation(Loc), Extractee, TheFunction, - ExtracteeType)); - } - - LinearFunctionExtractInst *createLinearFunctionExtract( - SILLocation Loc, LinearDifferentiableFunctionTypeComponent Extractee, - SILValue TheFunction) { - return insert(new (getModule()) LinearFunctionExtractInst( - getModule(), getSILDebugLocation(Loc), Extractee, TheFunction)); - } - - DifferentiableFunctionExtractInst * - createDifferentiableFunctionExtractOriginal(SILLocation Loc, - SILValue TheFunction) { - return insert(new (getModule()) DifferentiableFunctionExtractInst( - getModule(), getSILDebugLocation(Loc), - NormalDifferentiableFunctionTypeComponent::Original, TheFunction)); - } - - /// Note: explicit function type may be specified only in lowered SIL. - DifferentiabilityWitnessFunctionInst *createDifferentiabilityWitnessFunction( - SILLocation Loc, DifferentiabilityWitnessFunctionKind WitnessKind, - SILDifferentiabilityWitness *Witness, - Optional FunctionType = None) { - return insert(new (getModule()) DifferentiabilityWitnessFunctionInst( - getModule(), getSILDebugLocation(Loc), WitnessKind, Witness, - FunctionType)); - } - // SWIFT_ENABLE_TENSORFLOW END - BuiltinInst *createBuiltin(SILLocation Loc, Identifier Name, SILType ResultTy, SubstitutionMap Subs, ArrayRef Args) { @@ -2210,6 +2157,63 @@ class SILBuilder { SILValue emitThickToObjCMetatype(SILLocation Loc, SILValue Op, SILType Ty); SILValue emitObjCToThickMetatype(SILLocation Loc, SILValue Op, SILType Ty); + //===--------------------------------------------------------------------===// + // Differentiable programming instructions + //===--------------------------------------------------------------------===// + + /// Note: explicit function type may be specified only in lowered SIL. + DifferentiabilityWitnessFunctionInst *createDifferentiabilityWitnessFunction( + SILLocation Loc, DifferentiabilityWitnessFunctionKind WitnessKind, + SILDifferentiabilityWitness *Witness, + Optional FunctionType = None) { + return insert(new (getModule()) DifferentiabilityWitnessFunctionInst( + getModule(), getSILDebugLocation(Loc), WitnessKind, Witness, + FunctionType)); + } + + // SWIFT_ENABLE_TENSORFLOW + DifferentiableFunctionInst *createDifferentiableFunction( + SILLocation Loc, IndexSubset *ParameterIndices, + SILValue OriginalFunction, + Optional> JVPAndVJPFunctions = None) { + return insert(DifferentiableFunctionInst::create( + getModule(), getSILDebugLocation(Loc), ParameterIndices, + OriginalFunction, JVPAndVJPFunctions, hasOwnership())); + } + + LinearFunctionInst *createLinearFunction( + SILLocation Loc, IndexSubset *ParameterIndices, SILValue OriginalFunction, + Optional TransposeFunction = None) { + return insert(LinearFunctionInst::create( + getModule(), getSILDebugLocation(Loc), ParameterIndices, + OriginalFunction, TransposeFunction, hasOwnership())); + } + + /// Note: explicit extractee type may be specified only in lowered SIL. + DifferentiableFunctionExtractInst *createDifferentiableFunctionExtract( + SILLocation Loc, NormalDifferentiableFunctionTypeComponent Extractee, + SILValue TheFunction, Optional ExtracteeType = None) { + return insert(new (getModule()) DifferentiableFunctionExtractInst( + getModule(), getSILDebugLocation(Loc), Extractee, TheFunction, + ExtracteeType)); + } + + LinearFunctionExtractInst *createLinearFunctionExtract( + SILLocation Loc, LinearDifferentiableFunctionTypeComponent Extractee, + SILValue TheFunction) { + return insert(new (getModule()) LinearFunctionExtractInst( + getModule(), getSILDebugLocation(Loc), Extractee, TheFunction)); + } + + DifferentiableFunctionExtractInst * + createDifferentiableFunctionExtractOriginal(SILLocation Loc, + SILValue TheFunction) { + return insert(new (getModule()) DifferentiableFunctionExtractInst( + getModule(), getSILDebugLocation(Loc), + NormalDifferentiableFunctionTypeComponent::Original, TheFunction)); + } + // SWIFT_ENABLE_TENSORFLOW END + //===--------------------------------------------------------------------===// // Private Helper Methods //===--------------------------------------------------------------------===// diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 609d829d6dfc2..3584d0891f1a8 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -974,64 +974,6 @@ SILCloner::visitEndApplyInst(EndApplyInst *Inst) { getOpValue(Inst->getOperand()))); } -// SWIFT_ENABLE_TENSORFLOW -template -void SILCloner::visitDifferentiableFunctionInst( - DifferentiableFunctionInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - Optional> derivativeFns = None; - if (Inst->hasDerivativeFunctions()) - derivativeFns = std::make_pair(getOpValue(Inst->getJVPFunction()), - getOpValue(Inst->getVJPFunction())); - recordClonedInstruction( - Inst, getBuilder().createDifferentiableFunction( - getOpLocation(Inst->getLoc()), Inst->getParameterIndices(), - getOpValue(Inst->getOriginalFunction()), derivativeFns)); -} - -template -void SILCloner::visitLinearFunctionInst(LinearFunctionInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - auto transpose = Inst->getOptionalTransposeFunction(); - if (transpose) - transpose = getOpValue(*transpose); - recordClonedInstruction( - Inst, getBuilder().createLinearFunction( - getOpLocation(Inst->getLoc()), Inst->getParameterIndices(), - getOpValue(Inst->getOriginalFunction()), transpose)); -} - -template -void SILCloner:: -visitDifferentiableFunctionExtractInst(DifferentiableFunctionExtractInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - recordClonedInstruction( - Inst, getBuilder().createDifferentiableFunctionExtract( - getOpLocation(Inst->getLoc()), Inst->getExtractee(), - getOpValue(Inst->getFunctionOperand()))); -} - -template -void SILCloner:: -visitLinearFunctionExtractInst(LinearFunctionExtractInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - recordClonedInstruction( - Inst, getBuilder().createLinearFunctionExtract( - getOpLocation(Inst->getLoc()), Inst->getExtractee(), - getOpValue(Inst->getFunctionOperand()))); -} - -template -void SILCloner::visitDifferentiabilityWitnessFunctionInst( - DifferentiabilityWitnessFunctionInst *Inst) { - getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); - recordClonedInstruction( - Inst, getBuilder().createDifferentiabilityWitnessFunction( - getOpLocation(Inst->getLoc()), Inst->getWitnessKind(), - Inst->getWitness())); -} -// SWIFT_ENABLE_TENSORFLOW END - template void SILCloner::visitFunctionRefInst(FunctionRefInst *Inst) { @@ -2886,6 +2828,64 @@ void SILCloner::visitKeyPathInst(KeyPathInst *Inst) { opValues, getOpType(Inst->getType()))); } +// SWIFT_ENABLE_TENSORFLOW +template +void SILCloner::visitDifferentiableFunctionInst( + DifferentiableFunctionInst *Inst) { + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + Optional> derivativeFns = None; + if (Inst->hasDerivativeFunctions()) + derivativeFns = std::make_pair(getOpValue(Inst->getJVPFunction()), + getOpValue(Inst->getVJPFunction())); + recordClonedInstruction( + Inst, getBuilder().createDifferentiableFunction( + getOpLocation(Inst->getLoc()), Inst->getParameterIndices(), + getOpValue(Inst->getOriginalFunction()), derivativeFns)); +} + +template +void SILCloner::visitLinearFunctionInst(LinearFunctionInst *Inst) { + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + auto transpose = Inst->getOptionalTransposeFunction(); + if (transpose) + transpose = getOpValue(*transpose); + recordClonedInstruction( + Inst, getBuilder().createLinearFunction( + getOpLocation(Inst->getLoc()), Inst->getParameterIndices(), + getOpValue(Inst->getOriginalFunction()), transpose)); +} + +template +void SILCloner:: +visitDifferentiableFunctionExtractInst(DifferentiableFunctionExtractInst *Inst) { + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + recordClonedInstruction( + Inst, getBuilder().createDifferentiableFunctionExtract( + getOpLocation(Inst->getLoc()), Inst->getExtractee(), + getOpValue(Inst->getFunctionOperand()))); +} + +template +void SILCloner:: +visitLinearFunctionExtractInst(LinearFunctionExtractInst *Inst) { + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + recordClonedInstruction( + Inst, getBuilder().createLinearFunctionExtract( + getOpLocation(Inst->getLoc()), Inst->getExtractee(), + getOpValue(Inst->getFunctionOperand()))); +} +// SWIFT_ENABLE_TENSORFLOW END + +template +void SILCloner::visitDifferentiabilityWitnessFunctionInst( + DifferentiabilityWitnessFunctionInst *Inst) { + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + recordClonedInstruction(Inst, + getBuilder().createDifferentiabilityWitnessFunction( + getOpLocation(Inst->getLoc()), + Inst->getWitnessKind(), Inst->getWitness())); +} + } // end namespace swift #endif diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 0fdd477226b49..032a1b58ceb89 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -17,7 +17,6 @@ #ifndef SWIFT_SIL_INSTRUCTION_H #define SWIFT_SIL_INSTRUCTION_H -// SWIFT_ENABLE_TENSORFLOW #include "swift/AST/AutoDiff.h" #include "swift/AST/Builtins.h" #include "swift/AST/Decl.h" @@ -63,9 +62,7 @@ class SILBasicBlock; class SILBuilder; class SILDebugLocation; class SILDebugScope; -// SWIFT_ENABLE_TENSORFLOW class SILDifferentiabilityWitness; -// SWIFT_ENABLE_TENSORFLOW_END class SILFunction; class SILGlobalVariable; class SILInstructionResultArray; @@ -7975,6 +7972,7 @@ class TryApplyInst final }; // SWIFT_ENABLE_TENSORFLOW + /// `differentiable_function` - given a function, differentiation indices and /// its derivative functions, create an `@differentiable` function that /// represents a bundle of these functions and configurations. @@ -8165,6 +8163,7 @@ class LinearFunctionExtractInst ArrayRef getAllOperands() const { return operands.asArray(); } MutableArrayRef getAllOperands() { return operands.asArray(); } }; +// SWIFT_ENABLE_TENSORFLOW END class DifferentiabilityWitnessFunctionInst : public InstructionBase< @@ -8180,8 +8179,7 @@ class DifferentiabilityWitnessFunctionInst bool hasExplicitFunctionType; static SILType getDifferentiabilityWitnessType( - SILModule &module, - DifferentiabilityWitnessFunctionKind witnessKind, + SILModule &module, DifferentiabilityWitnessFunctionKind witnessKind, SILDifferentiabilityWitness *witness); public: @@ -8200,7 +8198,6 @@ class DifferentiabilityWitnessFunctionInst ArrayRef getAllOperands() const { return {}; } MutableArrayRef getAllOperands() { return {}; } }; -// SWIFT_ENABLE_TENSORFLOW END // This is defined out of line to work around the fact that this depends on // PartialApplyInst being defined, but PartialApplyInst is a subclass of diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index a7c085ee6447c..2571e82035b13 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -689,7 +689,6 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction) SingleValueInstruction, None, DoesNotRelease) // SWIFT_ENABLE_TENSORFLOW - // Differentiable programming SINGLE_VALUE_INST(DifferentiableFunctionInst, differentiable_function, SingleValueInstruction, None, DoesNotRelease) SINGLE_VALUE_INST(LinearFunctionInst, linear_function, @@ -700,10 +699,11 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction) SINGLE_VALUE_INST(LinearFunctionExtractInst, linear_function_extract, SingleValueInstruction, None, DoesNotRelease) + // SWIFT_ENABLE_TENSORFLOW END + // Differentiable programming SINGLE_VALUE_INST(DifferentiabilityWitnessFunctionInst, differentiability_witness_function, SingleValueInstruction, None, DoesNotRelease) - // SWIFT_ENABLE_TENSORFLOW END // Key paths // TODO: The only "side effect" is potentially retaining the returned key path diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h index 292d3d601d53c..1088c8aaee4f8 100644 --- a/include/swift/SIL/SILValue.h +++ b/include/swift/SIL/SILValue.h @@ -649,6 +649,14 @@ class Operand { OperandOwnershipKindMap getOwnershipKindMap(bool isForwardingSubValue = false) const; + /// Returns true if this operand acts as a use that consumes its associated + /// value. + bool isConsumingUse() const { + auto map = getOwnershipKindMap(); + auto constraint = map.getLifetimeConstraint(get().getOwnershipKind()); + return constraint == UseLifetimeConstraint::MustBeInvalidated; + } + private: void removeFromCurrent() { if (!Back) return; diff --git a/include/swift/SILOptimizer/Utils/KeyPathProjector.h b/include/swift/SILOptimizer/Utils/KeyPathProjector.h new file mode 100644 index 0000000000000..6c64c469bf776 --- /dev/null +++ b/include/swift/SILOptimizer/Utils/KeyPathProjector.h @@ -0,0 +1,84 @@ +//===-- KeyPathProjector.h - Project a static key path ----------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Utility class to project a statically known key path +/// expression to a direct property access sequence. +/// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SILOPTIMIZER_UTILS_KEYPATHPROJECTOR_H +#define SWIFT_SILOPTIMIZER_UTILS_KEYPATHPROJECTOR_H + +#include "swift/SIL/SILBuilder.h" +#include + +namespace swift { + +/// Projects a statically known key path expression to +/// a direct property access. +class KeyPathProjector { +public: + /// The type of a key path access. + enum class AccessType { + /// A get-only access (i.e. swift_getAtKeyPath). + Get, + + /// A set-only access (i.e. swift_setAtWritableKeyPath). + Set, + + /// A modification (i.e. swift_modifyAtWritableKeyPath). + Modify + }; + + /// Creates a key path projector for a key path. + /// + /// Returns nullptr if \p keyPath is not a keypath instruction or if there is + /// any other reason why the optimization cannot be done. + /// + /// \param keyPath The key path to project. Must be the result of either + /// a keypath instruction or an upcast of a key path instruction. + /// \param root The address of the object the key path is applied to. + /// \param loc The location of the key path application. + /// \param builder The SILBuilder to use. + static std::unique_ptr + create(SILValue keyPath, SILValue root, SILLocation loc, SILBuilder &builder); + + /// Projects the key path to an address. Sets up the projection, + /// invokes the callback, then tears down the projection. + /// \param accessType The access type of the projected address. + /// \param callback A callback to invoke with the projected adddress. + /// The projected address is only valid from within \p callback. + /// If accessType is Get or Modify, the projected addres is an + /// initialized address type. If accessType is set, the projected + /// address points to uninitialized memory. + virtual void project(AccessType accessType, + std::function callback) = 0; + + virtual ~KeyPathProjector() {}; + + /// Whether this projection returns a struct. + virtual bool isStruct() = 0; +protected: + KeyPathProjector(SILLocation loc, SILBuilder &builder) + : loc(loc), builder(builder) {} + + /// The location of the key path application. + SILLocation loc; + + /// The SILBuilder to use. + SILBuilder &builder; +}; + +} // end namespace swift + +#endif /* KeyPathProjector_h */ diff --git a/include/swift/SILOptimizer/Utils/SILInliner.h b/include/swift/SILOptimizer/Utils/SILInliner.h index 7115267bd642c..87a0370450346 100644 --- a/include/swift/SILOptimizer/Utils/SILInliner.h +++ b/include/swift/SILOptimizer/Utils/SILInliner.h @@ -72,7 +72,7 @@ class SILInliner { /// /// In this case stack nesting must be corrected after inlining with the /// StackNesting utility. - static bool needsUpdateStackNesting(FullApplySite apply) { + static bool invalidatesStackNesting(FullApplySite apply) { // Inlining of coroutines can result in improperly nested stack // allocations. return isa(apply); @@ -111,7 +111,7 @@ class SILInliner { /// function. /// /// *NOTE*: Inlining can result in improperly nested stack allocations, which - /// must be corrected after inlining. See needsUpdateStackNesting(). + /// must be corrected after inlining. See invalidatesStackNesting(). /// /// Returns an iterator to the first inlined instruction (or the end of the /// caller block for empty functions) and the last block in function order @@ -134,7 +134,7 @@ class SILInliner { /// function. /// /// *NOTE*: Inlining can result in improperly nested stack allocations, which - /// must be corrected after inlining. See needsUpdateStackNesting(). + /// must be corrected after inlining. See invalidatesStackNesting(). /// /// Returns an iterator to the first inlined instruction (or the end of the /// caller block for empty functions) and the last block in function order diff --git a/include/swift/SILOptimizer/Utils/ValueLifetime.h b/include/swift/SILOptimizer/Utils/ValueLifetime.h index 13cd6b569701c..d4e5bb5b1ba53 100644 --- a/include/swift/SILOptimizer/Utils/ValueLifetime.h +++ b/include/swift/SILOptimizer/Utils/ValueLifetime.h @@ -33,13 +33,16 @@ class ValueLifetimeAnalysis { /// The lifetime frontier for the value. It is the list of instructions /// following the last uses of the value. All the frontier instructions /// end the value's lifetime. - typedef llvm::SmallVector Frontier; + using Frontier = SmallVector; - /// Constructor for the value \p Def with a specific set of users of Def's - /// users. - ValueLifetimeAnalysis(SILInstruction *def, - ArrayRef userList) - : defValue(def), userSet(userList.begin(), userList.end()) { + /// Constructor for the value \p Def with a specific range of users. + /// + /// We templatize over the RangeTy so that we can initialize + /// ValueLifetimeAnalysis with misc iterators including transform + /// iterators. + template + ValueLifetimeAnalysis(SILInstruction *def, const RangeTy &userRange) + : defValue(def), userSet(userRange.begin(), userRange.end()) { propagateLiveness(); } diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index 79164ccabd2ad..3f807c630aaea 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -356,6 +356,10 @@ class SerializedASTFile final : public LoadedFile { ObjCSelector selector, SmallVectorImpl &results) const override; + virtual void + lookupImportedSPIGroups(const ModuleDecl *importedModule, + SmallVectorImpl &spiGroups) const override; + Optional getCommentForDecl(const Decl *D) const override; Optional getGroupNameForDecl(const Decl *D) const override; @@ -399,6 +403,8 @@ class SerializedASTFile final : public LoadedFile { virtual StringRef getFilename() const override; + virtual StringRef getModuleDefiningPath() const override; + ClassDecl *getMainClass() const override; bool hasEntryPoint() const override; @@ -409,6 +415,8 @@ class SerializedASTFile final : public LoadedFile { SmallVectorImpl &genericSignatures) override; + StringRef getTargetTriple() const; + static bool classof(const FileUnit *file) { return file->getKind() == FileUnitKind::SerializedAST; } diff --git a/include/swift/Subsystems.h b/include/swift/Subsystems.h index ea2ee352c04e0..3a41bc6b1efdc 100644 --- a/include/swift/Subsystems.h +++ b/include/swift/Subsystems.h @@ -392,6 +392,12 @@ namespace swift { /// should call this functions after forming the ASTContext. void registerSILGenRequestFunctions(Evaluator &evaluator); + /// Register TBDGen-level request functions with the evaluator. + /// + /// Clients that form an ASTContext and will perform any TBD generation + /// should call this functions after forming the ASTContext. + void registerTBDGenRequestFunctions(Evaluator &evaluator); + /// Register IDE-level request functions with the evaluator. /// /// The ASTContext will automatically call these upon construction. diff --git a/include/swift/SwiftRemoteMirror/Platform.h b/include/swift/SwiftRemoteMirror/Platform.h index cefdea2c4de6f..96ed451f854eb 100644 --- a/include/swift/SwiftRemoteMirror/Platform.h +++ b/include/swift/SwiftRemoteMirror/Platform.h @@ -18,7 +18,7 @@ extern "C" { #endif #if defined(swiftRemoteMirror_EXPORTS) -# if defined(__ELF__) +# if defined(__ELF__) || defined(__WASM__) # define SWIFT_REMOTE_MIRROR_LINKAGE __attribute__((__visibility__("protected"))) # elif defined(__MACH__) # define SWIFT_REMOTE_MIRROR_LINKAGE __attribute__((__visibility__("default"))) @@ -30,9 +30,7 @@ extern "C" { # endif # endif #else -# if defined(__ELF__) -# define SWIFT_REMOTE_MIRROR_LINKAGE __attribute__((__visibility__("default"))) -# elif defined(__MACH__) +# if defined(__ELF__) || defined(__MACH__) || defined(__WASM__) # define SWIFT_REMOTE_MIRROR_LINKAGE __attribute__((__visibility__("default"))) # else # if defined(_WINDLL) diff --git a/include/swift/SymbolGraphGen/SymbolGraphGen.h b/include/swift/SymbolGraphGen/SymbolGraphGen.h index 324a505c45e39..f850b146867be 100644 --- a/include/swift/SymbolGraphGen/SymbolGraphGen.h +++ b/include/swift/SymbolGraphGen/SymbolGraphGen.h @@ -20,8 +20,8 @@ class ModuleDecl; namespace symbolgraphgen { struct SymbolGraphOptions { - /// The path to output the symbol graph JSON. - StringRef OutputPath; + /// The directory to output the symbol graph JSON files. + StringRef OutputDir; /// The target of the module. llvm::Triple Target; diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h index c9152eabb79c4..5d7550c2dc4c1 100644 --- a/include/swift/TBDGen/TBDGen.h +++ b/include/swift/TBDGen/TBDGen.h @@ -53,6 +53,38 @@ struct TBDGenOptions { /// The path to a Json file indicating the module name to install-name map /// used by @_originallyDefinedIn std::string ModuleInstallNameMapPath; + + /// For these modules, TBD gen should embed their symbols in the emitted tbd + /// file. + /// Typically, these modules are static linked libraries. Thus their symbols + /// are embeded in the current dylib. + std::vector embedSymbolsFromModules; + + friend bool operator==(const TBDGenOptions &lhs, const TBDGenOptions &rhs) { + return lhs.HasMultipleIGMs == rhs.HasMultipleIGMs && + lhs.IsInstallAPI == rhs.IsInstallAPI && + lhs.LinkerDirectivesOnly == rhs.LinkerDirectivesOnly && + lhs.InstallName == rhs.InstallName && + lhs.ModuleLinkName == rhs.ModuleLinkName && + lhs.CurrentVersion == rhs.CurrentVersion && + lhs.CompatibilityVersion == rhs.CompatibilityVersion && + lhs.ModuleInstallNameMapPath == rhs.ModuleInstallNameMapPath && + lhs.embedSymbolsFromModules == rhs.embedSymbolsFromModules; + } + + friend bool operator!=(const TBDGenOptions &lhs, const TBDGenOptions &rhs) { + return !(lhs == rhs); + } + + friend llvm::hash_code hash_value(const TBDGenOptions &opts) { + using namespace llvm; + return hash_combine( + opts.HasMultipleIGMs, opts.IsInstallAPI, opts.LinkerDirectivesOnly, + opts.InstallName, opts.ModuleLinkName, opts.CurrentVersion, + opts.CompatibilityVersion, opts.ModuleInstallNameMapPath, + hash_combine_range(opts.embedSymbolsFromModules.begin(), + opts.embedSymbolsFromModules.end())); + } }; void enumeratePublicSymbols(FileUnit *module, llvm::StringSet<> &symbols, diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 03c6071272520..72a208edf021f 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -716,7 +716,7 @@ namespace { if (auto *var = dyn_cast(VD)) { PrintWithColorRAII(OS, TypeColor) << " type='"; - if (auto varTy = var->hasInterfaceType()) + if (var->hasInterfaceType()) var->getType().print(PrintWithColorRAII(OS, TypeColor).getOS()); else PrintWithColorRAII(OS, TypeColor) << ""; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 980f0e71d58fc..beb44c50e8afc 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -100,7 +100,8 @@ static bool contributesToParentTypeStorage(const AbstractStorageDecl *ASD) { } PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr, - bool printFullConvention) { + bool printFullConvention, + bool printSPIs) { PrintOptions result; result.PrintLongAttrsOnSeparateLines = true; result.TypeDefinitions = true; @@ -120,6 +121,7 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr, if (printFullConvention) result.PrintFunctionRepresentationAttrs = PrintOptions::FunctionRepresentationMode::Full; + result.PrintSPIs = printSPIs; // We should print __consuming, __owned, etc for the module interface file. result.SkipUnderscoredKeywords = false; @@ -143,7 +145,8 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr, if (D->getAttrs().hasAttribute()) return false; - // Skip anything that isn't 'public' or '@usableFromInline'. + // Skip anything that isn't 'public' or '@usableFromInline', + // or SPI if desired. if (auto *VD = dyn_cast(D)) { if (!isPublicOrUsableFromInline(VD)) { // We do want to print private stored properties, without their @@ -151,6 +154,12 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr, if (auto *ASD = dyn_cast(VD)) if (contributesToParentTypeStorage(ASD)) return true; + + // Always print SPI decls if `PrintSPIs`. + if (options.PrintSPIs && + VD->getAttrs().hasAttribute()) + return true; + return false; } } diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index f81ebe47bc7ab..6a3265a606b6c 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -523,7 +523,7 @@ class ScopeCreator final { // get inactive nodes that nest in active clauses for (auto n : clause.Elements) { if (auto *const d = n.dyn_cast()) - if (auto *const icd = dyn_cast(d)) + if (isa(d)) expandIfConfigClausesInto(expansion, {d}, true); } } else if (includeInactiveIfConfigClauses) { @@ -1776,7 +1776,7 @@ void ScopeCreator::forEachClosureIn( return {true, E}; } std::pair walkToStmtPre(Stmt *S) override { - if (auto *bs = dyn_cast(S)) { // closures hidden in here + if (isa(S)) { // closures hidden in here return {true, S}; } return {false, S}; @@ -2132,7 +2132,7 @@ class LocalizableDeclContextCollector : public ASTWalker { auto f = SM.getIdentifierForBuffer(bufID); auto lin = SM.getLineNumber(loc); if (f.endswith(file) && lin == line) - if (auto *v = dyn_cast(D)) + if (isa(D)) llvm::errs() << "*** catchForDebugging: " << lin << " ***\n"; } }; diff --git a/lib/AST/AbstractSourceFileDepGraphFactory.cpp b/lib/AST/AbstractSourceFileDepGraphFactory.cpp new file mode 100644 index 0000000000000..ad0b3e1ff35ac --- /dev/null +++ b/lib/AST/AbstractSourceFileDepGraphFactory.cpp @@ -0,0 +1,87 @@ +//===-------- AbstractSourceFileDepGraphFactory.cpp -----------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/AbstractSourceFileDepGraphFactory.h" + +// may not all be needed +#include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticsFrontend.h" +#include "swift/AST/FileSystem.h" +#include "swift/AST/FineGrainedDependencies.h" +#include "swift/Basic/FileSystem.h" +#include "swift/Basic/LLVM.h" +#include "swift/Basic/ReferenceDependencyKeys.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/YAMLParser.h" + +using namespace swift; +using namespace fine_grained_dependencies; + +//============================================================================== +// MARK: AbstractSourceFileDepGraphFactory - client interface +//============================================================================== + +AbstractSourceFileDepGraphFactory::AbstractSourceFileDepGraphFactory( + bool includePrivateDeps, bool hadCompilationError, StringRef swiftDeps, + StringRef fileFingerprint, bool emitDotFileAfterConstruction, + DiagnosticEngine &diags) + : includePrivateDeps(includePrivateDeps), + hadCompilationError(hadCompilationError), swiftDeps(swiftDeps.str()), + fileFingerprint(fileFingerprint.str()), + emitDotFileAfterConstruction(emitDotFileAfterConstruction), diags(diags) { +} + +SourceFileDepGraph AbstractSourceFileDepGraphFactory::construct() { + addSourceFileNodesToGraph(); + if (!hadCompilationError) { + addAllDefinedDecls(); + addAllUsedDecls(); + } + assert(g.verify()); + if (emitDotFileAfterConstruction) + g.emitDotFile(swiftDeps, diags); + return std::move(g); +} + +//============================================================================== +// MARK: AbstractSourceFileDepGraphFactory - adding a defined or used Decl +//============================================================================== +void AbstractSourceFileDepGraphFactory::addSourceFileNodesToGraph() { + g.findExistingNodePairOrCreateAndAddIfNew( + DependencyKey::createKeyForWholeSourceFile(DeclAspect::interface, + swiftDeps), + StringRef(fileFingerprint)); +} + +void AbstractSourceFileDepGraphFactory::addADefinedDecl( + const DependencyKey &interfaceKey, Optional fingerprint) { + + auto nodePair = + g.findExistingNodePairOrCreateAndAddIfNew(interfaceKey, fingerprint); + // 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(), nodePair.getInterface()); +} + +void AbstractSourceFileDepGraphFactory::addAUsedDecl( + const DependencyKey &defKey, const DependencyKey &useKey) { + auto *defNode = + g.findExistingNodeOrCreateIfNew(defKey, None, false /* = !isProvides */); + auto nullableUse = g.findExistingNode(useKey); + assert(nullableUse.isNonNull() && "Use must be an already-added provides"); + auto *useNode = nullableUse.get(); + assert(useNode->getIsProvides() && "Use (using node) must be a provides"); + g.addArc(defNode, useNode); +} diff --git a/lib/AST/AccessRequests.cpp b/lib/AST/AccessRequests.cpp index 8a14df9f95f4d..29908cfdddfe8 100644 --- a/lib/AST/AccessRequests.cpp +++ b/lib/AST/AccessRequests.cpp @@ -68,7 +68,7 @@ AccessLevelRequest::evaluate(Evaluator &evaluator, ValueDecl *D) const { // Special case for generic parameters; we just give them a dummy // access level. - if (auto genericParam = dyn_cast(D)) { + if (isa(D)) { return AccessLevel::Internal; } @@ -213,7 +213,7 @@ DefaultAndMaxAccessLevelRequest::evaluate(Evaluator &evaluator, AccessLevel maxAccess = AccessLevel::Public; - if (GenericParamList *genericParams = ED->getGenericParams()) { + if (ED->getGenericParams()) { // Only check the trailing 'where' requirements. Other requirements come // from the extended type and have already been checked. DirectlyReferencedTypeDecls typeDecls = diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index a185f596eb187..8d7b211de604f 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -784,6 +784,19 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, Printer.printKeyword(getAttrName(), Options, "(set)"); return true; + case DAK_SPIAccessControl: { + if (!Options.PrintSPIs) return false; + + auto spiAttr = static_cast(this); + interleave(spiAttr->getSPIGroups(), + [&](Identifier spiName) { + Printer.printAttrName(getAttrName(), true); + Printer << "(" << spiName << ")"; + }, + [&] { Printer << " "; }); + return true; + } + default: break; } @@ -979,12 +992,14 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options, } case DAK_Custom: { - Printer.printAttrName("@"); + Printer.callPrintNamePre(PrintNameContext::Attribute); + Printer << "@"; const TypeLoc &typeLoc = cast(this)->getTypeLoc(); if (auto type = typeLoc.getType()) type->print(Printer, Options); else typeLoc.getTypeRepr()->print(Printer, Options); + Printer.printNamePost(PrintNameContext::Attribute); break; } @@ -1094,12 +1109,14 @@ StringRef DeclAttribute::getAttrName() const { case DAK_Semantics: return "_semantics"; case DAK_Available: - return "availability"; + return "available"; case DAK_ObjC: case DAK_ObjCRuntimeName: return "objc"; case DAK_DynamicReplacement: return "_dynamicReplacement"; + case DAK_TypeEraser: + return "_typeEraser"; case DAK_PrivateImport: return "_private"; case DAK_RestatedObjCConformance: @@ -1144,6 +1161,8 @@ StringRef DeclAttribute::getAttrName() const { return getAccessLevelSpelling(access); } + case DAK_SPIAccessControl: + return "_spi"; case DAK_ReferenceOwnership: return keywordOf(cast(this)->get()); case DAK_RawDocComment: @@ -1530,6 +1549,25 @@ SpecializeAttr *SpecializeAttr::create(ASTContext &Ctx, SourceLoc atLoc, specializedSignature); } +SPIAccessControlAttr::SPIAccessControlAttr(SourceLoc atLoc, SourceRange range, + ArrayRef spiGroups) + : DeclAttribute(DAK_SPIAccessControl, atLoc, range, + /*Implicit=*/false), + numSPIGroups(spiGroups.size()) { + std::uninitialized_copy(spiGroups.begin(), spiGroups.end(), + getTrailingObjects()); +} + +SPIAccessControlAttr * +SPIAccessControlAttr::create(ASTContext &context, + SourceLoc atLoc, + SourceRange range, + ArrayRef spiGroups) { + unsigned size = totalSizeToAlloc(spiGroups.size()); + void *mem = context.Allocate(size, alignof(SPIAccessControlAttr)); + return new (mem) SPIAccessControlAttr(atLoc, range, spiGroups); +} + DifferentiableAttr::DifferentiableAttr(bool implicit, SourceLoc atLoc, SourceRange baseRange, bool linear, ArrayRef params, diff --git a/lib/AST/AutoDiff.cpp b/lib/AST/AutoDiff.cpp index 2c4c9fffe5b73..3c71a59e22af3 100644 --- a/lib/AST/AutoDiff.cpp +++ b/lib/AST/AutoDiff.cpp @@ -2,7 +2,7 @@ // // This source file is part of the Swift.org open source project // -// Copyright (c) 2019 Apple Inc. and the Swift project authors +// Copyright (c) 2019 - 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 @@ -13,11 +13,34 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/AutoDiff.h" #include "swift/AST/ASTContext.h" +#include "swift/AST/Module.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/Types.h" using namespace swift; +DifferentiabilityWitnessFunctionKind::DifferentiabilityWitnessFunctionKind( + StringRef string) { + Optional result = llvm::StringSwitch>(string) + .Case("jvp", JVP) + .Case("vjp", VJP) + .Case("transpose", Transpose); + assert(result && "Invalid string"); + rawValue = *result; +} + +Optional +DifferentiabilityWitnessFunctionKind::getAsDerivativeFunctionKind() const { + switch (rawValue) { + case JVP: + return {AutoDiffDerivativeFunctionKind::JVP}; + case VJP: + return {AutoDiffDerivativeFunctionKind::VJP}; + case Transpose: + return None; + } +} + void AutoDiffConfig::print(llvm::raw_ostream &s) const { s << "(parameters="; parameterIndices->print(s); @@ -139,25 +162,6 @@ AutoDiffDerivativeFunctionKind(StringRef string) { rawValue = *result; } -DifferentiabilityWitnessFunctionKind:: -DifferentiabilityWitnessFunctionKind(StringRef string) { - Optional result = llvm::StringSwitch>(string) - .Case("jvp", JVP) - .Case("vjp", VJP) - .Case("transpose", Transpose); - assert(result && "Invalid string"); - rawValue = *result; -} - -Optional -DifferentiabilityWitnessFunctionKind::getAsDerivativeFunctionKind() const { - switch (rawValue) { - case JVP: return {AutoDiffDerivativeFunctionKind::JVP}; - case VJP: return {AutoDiffDerivativeFunctionKind::VJP}; - case Transpose: return None; - } -} - NormalDifferentiableFunctionTypeComponent:: NormalDifferentiableFunctionTypeComponent(AutoDiffDerivativeFunctionKind kind) { switch (kind) { diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index b5fa70c93317a..0add9c6606c40 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -10,6 +10,7 @@ else() endif() add_swift_host_library(swiftAST STATIC + AbstractSourceFileDepGraphFactory.cpp AccessRequests.cpp ASTContext.cpp ASTDemangler.cpp @@ -44,6 +45,7 @@ add_swift_host_library(swiftAST STATIC Evaluator.cpp Expr.cpp FineGrainedDependencies.cpp + FrontendSourceFileDepGraphFactory.cpp GenericEnvironment.cpp GenericSignature.cpp GenericSignatureBuilder.cpp @@ -67,7 +69,6 @@ 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/Decl.cpp b/lib/AST/Decl.cpp index d92b6a7d92335..e5251847ed5e5 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -520,7 +520,7 @@ SourceRange Decl::getSourceRangeIncludingAttrs() const { // e.g. 'override'. if (auto *AD = dyn_cast(this)) { // If this is implicit getter, accessor range should not include attributes. - if (!AD->getAccessorKeywordLoc().isValid()) + if (AD->isImplicitGetter()) return Range; // Otherwise, include attributes directly attached to the accessor. @@ -656,7 +656,7 @@ Expr *AbstractFunctionDecl::getSingleExpressionBody() const { if (auto *stmt = body.dyn_cast()) { if (auto *returnStmt = dyn_cast(stmt)) { return returnStmt->getResult(); - } else if (auto *failStmt = dyn_cast(stmt)) { + } else if (isa(stmt)) { // We can only get to this point if we're a type-checked ConstructorDecl // which was originally spelled init?(...) { nil }. // @@ -674,7 +674,7 @@ void AbstractFunctionDecl::setSingleExpressionBody(Expr *NewBody) { if (auto *returnStmt = dyn_cast(stmt)) { returnStmt->setResult(NewBody); return; - } else if (auto *failStmt = dyn_cast(stmt)) { + } else if (isa(stmt)) { // We can only get to this point if we're a type-checked ConstructorDecl // which was originally spelled init?(...) { nil }. // @@ -791,7 +791,7 @@ bool Decl::isPrivateStdlibDecl(bool treatNonBuiltinProtocolsAsPublic) const { FU->getKind() != FileUnitKind::SerializedAST) return false; - if (auto PD = dyn_cast(D)) { + if (isa(D)) { if (treatNonBuiltinProtocolsAsPublic) return false; } @@ -2690,7 +2690,7 @@ static Type mapSignatureFunctionType(ASTContext &ctx, Type type, // Functions and subscripts cannot overload differing only in opaque return // types. Replace the opaque type with `Any`. - if (auto opaque = type->getAs()) { + if (type->is()) { type = ProtocolCompositionType::get(ctx, {}, /*hasAnyObject*/ false); } @@ -3183,15 +3183,16 @@ static AccessLevel getMaximallyOpenAccessFor(const ValueDecl *decl) { return AccessLevel::Public; } -/// Adjust \p access based on whether \p VD is \@usableFromInline or has been -/// testably imported from \p useDC. +/// Adjust \p access based on whether \p VD is \@usableFromInline, has been +/// testably imported from \p useDC or \p VD is an imported SPI. /// /// \p access isn't always just `VD->getFormalAccess()` because this adjustment /// may be for a write, in which case the setter's access might be used instead. static AccessLevel getAdjustedFormalAccess(const ValueDecl *VD, AccessLevel access, const DeclContext *useDC, - bool treatUsableFromInlineAsPublic) { + bool treatUsableFromInlineAsPublic, + bool treatSPIAsPublic) { // If access control is disabled in the current context, adjust // access level of the current declaration to be as open as possible. if (useDC && VD->getASTContext().isAccessControlDisabled()) @@ -3210,6 +3211,10 @@ static AccessLevel getAdjustedFormalAccess(const ValueDecl *VD, if (!useSF) return access; if (useSF->hasTestableOrPrivateImport(access, VD)) return getMaximallyOpenAccessFor(VD); + } else if (!treatSPIAsPublic && + VD->getAttrs().hasAttribute()) { + // Restrict access to SPI decls. + return AccessLevel::Internal; } return access; @@ -3219,15 +3224,18 @@ static AccessLevel getAdjustedFormalAccess(const ValueDecl *VD, /// adjust. static AccessLevel getAdjustedFormalAccess(const ValueDecl *VD, const DeclContext *useDC, - bool treatUsableFromInlineAsPublic) { + bool treatUsableFromInlineAsPublic, + bool treatSPIAsPublic) { return getAdjustedFormalAccess(VD, VD->getFormalAccess(), useDC, - treatUsableFromInlineAsPublic); + treatUsableFromInlineAsPublic, + treatSPIAsPublic); } AccessLevel ValueDecl::getEffectiveAccess() const { auto effectiveAccess = getAdjustedFormalAccess(this, /*useDC=*/nullptr, - /*treatUsableFromInlineAsPublic=*/true); + /*treatUsableFromInlineAsPublic=*/true, + /*treatSPIAsPublic=*/true); // Handle @testable/@_private(sourceFile:) switch (effectiveAccess) { @@ -3294,13 +3302,14 @@ bool ValueDecl::hasOpenAccess(const DeclContext *useDC) const { AccessLevel access = getAdjustedFormalAccess(this, useDC, - /*treatUsableFromInlineAsPublic*/false); + /*treatUsableFromInlineAsPublic*/false, + /*treatSPIAsPublic=*/false); return access == AccessLevel::Open; } /// Given the formal access level for using \p VD, compute the scope where /// \p VD may be accessed, taking \@usableFromInline, \@testable imports, -/// and enclosing access levels into account. +/// \@_spi imports, and enclosing access levels into account. /// /// \p access isn't always just `VD->getFormalAccess()` because this adjustment /// may be for a write, in which case the setter's access might be used instead. @@ -3310,7 +3319,8 @@ getAccessScopeForFormalAccess(const ValueDecl *VD, const DeclContext *useDC, bool treatUsableFromInlineAsPublic) { AccessLevel access = getAdjustedFormalAccess(VD, formalAccess, useDC, - treatUsableFromInlineAsPublic); + treatUsableFromInlineAsPublic, + /*treatSPIAsPublic=*/false); const DeclContext *resultDC = VD->getDeclContext(); while (!resultDC->isModuleScopeContext()) { @@ -3325,7 +3335,8 @@ getAccessScopeForFormalAccess(const ValueDecl *VD, if (auto enclosingNominal = dyn_cast(resultDC)) { auto enclosingAccess = getAdjustedFormalAccess(enclosingNominal, useDC, - treatUsableFromInlineAsPublic); + treatUsableFromInlineAsPublic, + /*treatSPIAsPublic=*/false); access = std::min(access, enclosingAccess); } else if (auto enclosingExt = dyn_cast(resultDC)) { @@ -3335,7 +3346,8 @@ getAccessScopeForFormalAccess(const ValueDecl *VD, if (nominal->getParentModule() == enclosingExt->getParentModule()) { auto nominalAccess = getAdjustedFormalAccess(nominal, useDC, - treatUsableFromInlineAsPublic); + treatUsableFromInlineAsPublic, + /*treatSPIAsPublic=*/false); access = std::min(access, nominalAccess); } } @@ -3355,9 +3367,17 @@ getAccessScopeForFormalAccess(const ValueDecl *VD, case AccessLevel::Internal: return AccessScope(resultDC->getParentModule()); case AccessLevel::Public: - case AccessLevel::Open: + case AccessLevel::Open: { + if (useDC) { + auto *useSF = dyn_cast(useDC->getModuleScopeContext()); + if (useSF && + VD->getAttrs().hasAttribute() && + !useSF->isImportedAsSPI(VD)) + return AccessScope(VD->getModuleContext(), /*private*/false); + } return AccessScope::getPublic(); } + } llvm_unreachable("unknown access level"); } @@ -3389,8 +3409,8 @@ static bool checkAccessUsingAccessScopes(const DeclContext *useDC, AccessScope(useDC).isChildOf(accessScope); } -/// Checks if \p VD may be used from \p useDC, taking \@testable imports into -/// account. +/// Checks if \p VD may be used from \p useDC, taking \@testable and \@_spi +/// imports into account. /// /// When \p access is the same as `VD->getFormalAccess()` and the enclosing /// context of \p VD is usable from \p useDC, this ought to be the same as @@ -3461,9 +3481,17 @@ static bool checkAccess(const DeclContext *useDC, const ValueDecl *VD, return useSF && useSF->hasTestableOrPrivateImport(access, sourceModule); } case AccessLevel::Public: - case AccessLevel::Open: + case AccessLevel::Open: { + if (useDC) { + auto *useSF = dyn_cast(useDC->getModuleScopeContext()); + if (useSF && + VD->getAttrs().hasAttribute() && + !useSF->isImportedAsSPI(VD)) + return false; + } return true; } + } llvm_unreachable("bad access level"); } @@ -6045,7 +6073,7 @@ void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { ->hasReferenceSemantics()) { // Do not suggest the fix-it in implicit getters if (auto AD = dyn_cast(FD)) { - if (AD->isGetter() && !AD->getAccessorKeywordLoc().isValid()) + if (AD->isImplicitGetter()) return; } diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp index 62f08d4b418f7..c065a548396b9 100644 --- a/lib/AST/DeclContext.cpp +++ b/lib/AST/DeclContext.cpp @@ -287,6 +287,12 @@ DeclContext *DeclContext::getModuleScopeContext() const { } } +void DeclContext::getSeparatelyImportedOverlays( + ModuleDecl *declaring, SmallVectorImpl &overlays) const { + if (auto SF = getParentSourceFile()) + SF->getSeparatelyImportedOverlays(declaring, overlays); +} + /// Determine whether the given context is generic at any level. bool DeclContext::isGenericContext() const { auto dc = this; diff --git a/lib/AST/FineGrainedDependencies.cpp b/lib/AST/FineGrainedDependencies.cpp index 278fa6538a75e..b3f9c752b0e80 100644 --- a/lib/AST/FineGrainedDependencies.cpp +++ b/lib/AST/FineGrainedDependencies.cpp @@ -103,17 +103,20 @@ void SourceFileDepGraph::forEachArc( InterfaceAndImplementationPair SourceFileDepGraph::findExistingNodePairOrCreateAndAddIfNew( - NodeKind k, const ContextNameFingerprint &contextNameFingerprint) { - const std::string &context = std::get<0>(contextNameFingerprint); - const std::string &name = std::get<1>(contextNameFingerprint); - const Optional &fingerprint = - std::get<2>(contextNameFingerprint); - auto *interfaceNode = findExistingNodeOrCreateIfNew( - DependencyKey(k, DeclAspect::interface, context, name), fingerprint, - true /* = isProvides */); + const DependencyKey &interfaceKey, Optional fingerprint) { + + // Optimization for whole-file users: + if (interfaceKey.getKind() == NodeKind::sourceFileProvide && + !allNodes.empty()) + return getSourceFileNodePair(); + + assert(interfaceKey.isInterface()); + const DependencyKey implementationKey = + interfaceKey.correspondingImplementation(); + auto *interfaceNode = findExistingNodeOrCreateIfNew(interfaceKey, fingerprint, + true /* = isProvides */); auto *implementationNode = findExistingNodeOrCreateIfNew( - DependencyKey(k, DeclAspect::implementation, context, name), fingerprint, - true /* = isProvides */); + implementationKey, fingerprint, true /* = isProvides */); InterfaceAndImplementationPair nodePair{ interfaceNode, implementationNode}; @@ -136,7 +139,7 @@ SourceFileDepGraph::findExistingNodePairOrCreateAndAddIfNew( } SourceFileDepGraphNode *SourceFileDepGraph::findExistingNodeOrCreateIfNew( - DependencyKey key, const Optional &fingerprint, + const DependencyKey &key, const Optional fingerprint, const bool isProvides) { SourceFileDepGraphNode *result = memoizedNodes.findExistingOrCreateIfNew( key, [&](DependencyKey key) -> SourceFileDepGraphNode * { @@ -164,20 +167,25 @@ SourceFileDepGraphNode *SourceFileDepGraph::findExistingNodeOrCreateIfNew( return result; } +NullablePtr +SourceFileDepGraph::findExistingNode(const DependencyKey &key) { + auto existing = memoizedNodes.findExisting(key); + return existing ? existing.getValue() : NullablePtr(); +} + std::string DependencyKey::demangleTypeAsContext(StringRef s) { return swift::Demangle::demangleTypeAsString(s.str()); } -DependencyKey -DependencyKey::createKeyForWholeSourceFile(const StringRef swiftDeps) { +DependencyKey DependencyKey::createKeyForWholeSourceFile(DeclAspect aspect, + StringRef swiftDeps) { assert(!swiftDeps.empty()); - const auto context = DependencyKey::computeContextForProvidedEntity< + const std::string context = DependencyKey::computeContextForProvidedEntity< NodeKind::sourceFileProvide>(swiftDeps); - const auto name = + const std::string name = DependencyKey::computeNameForProvidedEntity( swiftDeps); - return DependencyKey(NodeKind::sourceFileProvide, DeclAspect::interface, - context, name); + return DependencyKey(NodeKind::sourceFileProvide, aspect, context, name); } //============================================================================== @@ -228,7 +236,7 @@ std::string DependencyKey::humanReadableName() const { return demangleTypeAsContext(context) + "." + name; case NodeKind::externalDepend: case NodeKind::sourceFileProvide: - return llvm::sys::path::filename(name); + return llvm::sys::path::filename(name).str(); case NodeKind::potentialMember: return demangleTypeAsContext(context) + ".*"; case NodeKind::nominal: diff --git a/lib/AST/FrontendSourceFileDepGraphFactory.cpp b/lib/AST/FrontendSourceFileDepGraphFactory.cpp new file mode 100644 index 0000000000000..0ccb1e9d27f24 --- /dev/null +++ b/lib/AST/FrontendSourceFileDepGraphFactory.cpp @@ -0,0 +1,739 @@ +//===-------- FrontendSourceFileDepGraphFactory.cpp -----------------------===// +// +// 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 holds the code to build a SourceFileDepGraph in the frontend. +// This graph captures relationships between definitions and uses, and +// it is written to a file which is read by the driver in order to decide which +// source files require recompilation. + +#include "swift/AST/FrontendSourceFileDepGraphFactory.h" + +// may not all be needed +#include "swift/AST/ASTContext.h" +#include "swift/AST/ASTMangler.h" +#include "swift/AST/AbstractSourceFileDepGraphFactory.h" +#include "swift/AST/Decl.h" +#include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticsFrontend.h" +#include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileSystem.h" +#include "swift/AST/FineGrainedDependencies.h" +#include "swift/AST/Module.h" +#include "swift/AST/ModuleLoader.h" +#include "swift/AST/NameLookup.h" +#include "swift/AST/SourceFile.h" +#include "swift/AST/Types.h" +#include "swift/Basic/FileSystem.h" +#include "swift/Basic/LLVM.h" +#include "swift/Basic/ReferenceDependencyKeys.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" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/YAMLParser.h" + +using namespace swift; +using namespace fine_grained_dependencies; + +//============================================================================== +// MARK: Constructing from a SourceFile +//============================================================================== + +//============================================================================== +// MARK: Helpers for key construction that must be in frontend +//============================================================================== + +template static std::string getBaseName(const DeclT *decl) { + return decl->getBaseName().userFacingName().str(); +} + +template static std::string getName(const DeclT *decl) { + return DeclBaseName(decl->getName()).userFacingName().str(); +} + +static std::string mangleTypeAsContext(const NominalTypeDecl *NTD) { + Mangle::ASTMangler Mangler; + return !NTD ? "" : Mangler.mangleTypeAsContextUSR(NTD); +} + +//============================================================================== +// MARK: Privacy queries +//============================================================================== + +static bool declIsPrivate(const ValueDecl *VD) { + return VD->getFormalAccess() <= AccessLevel::FilePrivate; +} + +/// Return true if \param D cannot affect other files. +static bool declIsPrivate(const Decl *D) { + if (auto *VD = dyn_cast(D)) + return declIsPrivate(VD); + switch (D->getKind()) { + case DeclKind::Import: + case DeclKind::PatternBinding: + case DeclKind::EnumCase: + case DeclKind::TopLevelCode: + case DeclKind::IfConfig: + case DeclKind::PoundDiagnostic: + return true; + + case DeclKind::Extension: + case DeclKind::InfixOperator: + case DeclKind::PrefixOperator: + case DeclKind::PostfixOperator: + return false; + + default: + llvm_unreachable("everything else is a ValueDecl"); + } +} + +/// Return true if \ref ED does not contain a member that can affect other +/// files. +static bool allMembersArePrivate(const ExtensionDecl *ED) { + return std::all_of(ED->getMembers().begin(), ED->getMembers().end(), + [](const Decl *d) { return declIsPrivate(d); }); + // declIsPrivate); +} + +/// \ref inheritedType, an inherited protocol, return true if this inheritance +/// cannot affect other files. +static bool extendedTypeIsPrivate(TypeLoc inheritedType) { + auto type = inheritedType.getType(); + if (!type) + return true; + + if (!type->isExistentialType()) { + // Be conservative. We don't know how to deal with other extended types. + return false; + } + + auto layout = type->getExistentialLayout(); + assert(!layout.explicitSuperclass && + "Should not have a subclass existential " + "in the inheritance clause of an extension"); + for (auto protoTy : layout.getProtocols()) { + if (!declIsPrivate(protoTy->getDecl())) + return false; + } + + return true; +} + +/// Return true if \ref ED does not inherit a protocol that can affect other +/// files. Was called "justMembers" in ReferenceDependencies.cpp +/// \ref ED might be null. +static bool allInheritedProtocolsArePrivate(const ExtensionDecl *ED) { + return std::all_of(ED->getInherited().begin(), ED->getInherited().end(), + extendedTypeIsPrivate); +} + +//============================================================================== +// MARK: DependencyKey - creation for Decls +//============================================================================== + +template +DependencyKey DependencyKey::createForProvidedEntityInterface(Entity entity) { + return DependencyKey( + kindArg, DeclAspect::interface, + DependencyKey::computeContextForProvidedEntity(entity), + DependencyKey::computeNameForProvidedEntity(entity)); +} + +//============================================================================== +// MARK: computeContextForProvidedEntity +//============================================================================== + +template +std::string DependencyKey::computeContextForProvidedEntity(Entity) { + // Context field is not used for most kinds + return ""; +} + +// \ref nominal dependencies are created from a Decl and use the context field. +template <> +std::string DependencyKey::computeContextForProvidedEntity< + NodeKind::nominal, NominalTypeDecl const *>(NominalTypeDecl const *D) { + return mangleTypeAsContext(D); +} + +/// \ref potentialMember dependencies are created from a Decl and use the +/// context field. +template <> +std::string +DependencyKey::computeContextForProvidedEntity( + const NominalTypeDecl *D) { + return mangleTypeAsContext(D); +} + +template <> +std::string DependencyKey::computeContextForProvidedEntity< + NodeKind::member, const NominalTypeDecl *>(const NominalTypeDecl *holder) { + return mangleTypeAsContext(holder); +} + +/// \ref member dependencies are created from a pair and use the context field. +template <> +std::string DependencyKey::computeContextForProvidedEntity< + NodeKind::member, std::pair>( + std::pair holderAndMember) { + return computeContextForProvidedEntity( + holderAndMember.first); +} + +// Linux compiler requires the following: +template std::string + DependencyKey::computeContextForProvidedEntity(StringRef); + +//============================================================================== +// MARK: computeNameForProvidedEntity +//============================================================================== + +template <> +std::string +DependencyKey::computeNameForProvidedEntity(StringRef swiftDeps) { + assert(!swiftDeps.empty()); + return swiftDeps.str(); +} + +template <> +std::string +DependencyKey::computeNameForProvidedEntity( + const PrecedenceGroupDecl *D) { + return ::getName(D); +} +template <> +std::string DependencyKey::computeNameForProvidedEntity< + NodeKind::topLevel, FuncDecl const *>(const FuncDecl *D) { + return ::getName(D); +} +template <> +std::string DependencyKey::computeNameForProvidedEntity< + NodeKind::topLevel, OperatorDecl const *>(const OperatorDecl *D) { + return ::getName(D); +} +template <> +std::string DependencyKey::computeNameForProvidedEntity< + NodeKind::topLevel, NominalTypeDecl const *>(const NominalTypeDecl *D) { + return ::getName(D); +} +template <> +std::string DependencyKey::computeNameForProvidedEntity< + NodeKind::topLevel, ValueDecl const *>(const ValueDecl *D) { + return getBaseName(D); +} +template <> +std::string DependencyKey::computeNameForProvidedEntity< + NodeKind::dynamicLookup, ValueDecl const *>(const ValueDecl *D) { + return getBaseName(D); +} +template <> +std::string DependencyKey::computeNameForProvidedEntity< + NodeKind::nominal, NominalTypeDecl const *>(const NominalTypeDecl *D) { + return ""; +} +template <> +std::string +DependencyKey::computeNameForProvidedEntity( + const NominalTypeDecl *D) { + return ""; +} + +template <> +std::string DependencyKey::computeNameForProvidedEntity< + NodeKind::member, std::pair>( + std::pair holderAndMember) { + return getBaseName(holderAndMember.second); +} + +//============================================================================== +// MARK: createDependedUponKey +//============================================================================== + +template <> +DependencyKey +DependencyKey::createDependedUponKey(StringRef name) { + return DependencyKey(NodeKind::topLevel, DeclAspect::interface, "", + name.str()); +} + +template <> +DependencyKey +DependencyKey::createDependedUponKey(StringRef name) { + return DependencyKey(NodeKind::dynamicLookup, DeclAspect::interface, "", + name.str()); +} + +template <> +DependencyKey +DependencyKey::createDependedUponKey(StringRef name) { + return DependencyKey(NodeKind::externalDepend, DeclAspect::interface, "", + name.str()); +} + +template <> +DependencyKey +DependencyKey::createDependedUponKey(StringRef mangledName) { + return DependencyKey(NodeKind::nominal, DeclAspect::interface, + mangledName.str(), ""); +} + +DependencyKey DependencyKey::createDependedUponKey(StringRef mangledHolderName, + StringRef memberBaseName) { + const bool isMemberBlank = memberBaseName.empty(); + const auto kind = + isMemberBlank ? NodeKind::potentialMember : NodeKind::member; + return DependencyKey(kind, DeclAspect::interface, mangledHolderName.str(), + isMemberBlank ? "" : memberBaseName.str()); +} + +//============================================================================== +// MARK: Entry point into frontend graph construction +//============================================================================== + +bool fine_grained_dependencies::emitReferenceDependencies( + DiagnosticEngine &diags, SourceFile *const SF, + const DependencyTracker &depTracker, StringRef outputPath, + const bool alsoEmitDotFile) { + + // Before writing to the dependencies file path, preserve any previous file + // 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 + "~"); + + SourceFileDepGraph g = FrontendSourceFileDepGraphFactory( + SF, outputPath, depTracker, alsoEmitDotFile) + .construct(); + + const bool hadError = + withOutputFile(diags, outputPath, [&](llvm::raw_pwrite_stream &out) { + out << g.yamlProlog(SF->getASTContext().hadError()); + llvm::yaml::Output yamlWriter(out); + yamlWriter << g; + return false; + }); + + // If path is stdout, cannot read it back, so check for "-" + assert(outputPath == "-" || g.verifyReadsWhatIsWritten(outputPath)); + + if (alsoEmitDotFile) + g.emitDotFile(outputPath, diags); + + return hadError; +} + +//============================================================================== +// MARK: FrontendSourceFileDepGraphFactory +//============================================================================== + +FrontendSourceFileDepGraphFactory::FrontendSourceFileDepGraphFactory( + SourceFile *SF, StringRef outputPath, const DependencyTracker &depTracker, + const bool alsoEmitDotFile) + : AbstractSourceFileDepGraphFactory( + computeIncludePrivateDeps(SF), SF->getASTContext().hadError(), + outputPath, getInterfaceHash(SF), alsoEmitDotFile, + SF->getASTContext().Diags), + SF(SF), depTracker(depTracker) {} + +bool FrontendSourceFileDepGraphFactory::computeIncludePrivateDeps( + SourceFile *SF) { + // 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. + return SF->getASTContext() + .LangOpts.FineGrainedDependenciesIncludeIntrafileOnes || + SF->getASTContext().LangOpts.EnableTypeFingerprints; +} + +/// Centralize the invariant that the fingerprint of the whole file is the +/// interface hash +std::string FrontendSourceFileDepGraphFactory::getFingerprint(SourceFile *SF) { + return getInterfaceHash(SF); +} + +//============================================================================== +// MARK: FrontendSourceFileDepGraphFactory - adding collections of defined Decls +//============================================================================== +//============================================================================== +// MARK: SourceFileDeclFinder +//============================================================================== + +namespace { +/// Takes all the Decls in a SourceFile, and collects them into buckets by +/// groups of DeclKinds. Also casts them to more specific types +/// TODO: Factor with SourceFileDeclFinder +struct SourceFileDeclFinder { + +public: + /// Existing system excludes private decls in some cases. + /// In the future, we might not want to do this, so use bool to decide. + const bool includePrivateDecls; + + // The extracted Decls: + ConstPtrVec extensions; + ConstPtrVec operators; + ConstPtrVec precedenceGroups; + ConstPtrVec topNominals; + ConstPtrVec topValues; + ConstPtrVec allNominals; + ConstPtrVec potentialMemberHolders; + ConstPtrVec memberOperatorDecls; + ConstPtrPairVec valuesInExtensions; + ConstPtrVec classMembers; + + /// Construct me and separates the Decls. + // clang-format off + SourceFileDeclFinder(const SourceFile *const SF, const bool includePrivateDecls) + : includePrivateDecls(includePrivateDecls) { + for (const Decl *const D : SF->getTopLevelDecls()) { + select(D, extensions, false) || + select(D, operators, false) || + select( + D, precedenceGroups, false) || + select(D, topNominals, true) || + select(D, topValues, true); + } + // clang-format on + // The order is important because some of these use instance variables + // computed by others. + findNominalsFromExtensions(); + findNominalsInTopNominals(); + findValuesInExtensions(); + findClassMembers(SF); + } + +private: + /// Extensions may contain nominals and operators. + void findNominalsFromExtensions() { + for (auto *ED : extensions) { + const auto *const NTD = ED->getExtendedNominal(); + if (NTD) + findNominalsAndOperatorsIn(NTD, ED); + } + } + /// Top-level nominals may contain nominals and operators. + void findNominalsInTopNominals() { + for (const auto *const NTD : topNominals) + findNominalsAndOperatorsIn(NTD); + } + /// Any nominal may contain nominals and operators. + /// (indirectly recursive) + void findNominalsAndOperatorsIn(const NominalTypeDecl *const NTD, + const ExtensionDecl *ED = nullptr) { + if (excludeIfPrivate(NTD)) + return; + const bool exposedProtocolIsExtended = + ED && !allInheritedProtocolsArePrivate(ED); + if (ED && !includePrivateDecls && !exposedProtocolIsExtended && + std::all_of(ED->getMembers().begin(), ED->getMembers().end(), + [&](const Decl *D) { return declIsPrivate(D); })) { + return; + } + if (includePrivateDecls || !ED || exposedProtocolIsExtended) + allNominals.push_back(NTD); + potentialMemberHolders.push_back(NTD); + findNominalsAndOperatorsInMembers(ED ? ED->getMembers() + : NTD->getMembers()); + } + + /// Search through the members to find nominals and operators. + /// (indirectly recursive) + /// TODO: clean this up, maybe recurse separately for each purpose. + void findNominalsAndOperatorsInMembers(const DeclRange members) { + for (const Decl *const D : members) { + auto *VD = dyn_cast(D); + if (!VD || excludeIfPrivate(VD)) + continue; + if (VD->getFullName().isOperator()) + memberOperatorDecls.push_back(cast(D)); + else if (const auto *const NTD = dyn_cast(D)) + findNominalsAndOperatorsIn(NTD); + } + } + + /// Extensions may contain ValueDecls. + void findValuesInExtensions() { + for (const auto *ED : extensions) { + const auto *const NTD = ED->getExtendedNominal(); + if (!NTD || excludeIfPrivate(NTD)) + continue; + if (!includePrivateDecls && + (!allInheritedProtocolsArePrivate(ED) || allMembersArePrivate(ED))) + continue; + for (const auto *member : ED->getMembers()) + if (const auto *VD = dyn_cast(member)) + if (VD->hasName() && (includePrivateDecls || !declIsPrivate(VD))) { + const auto *const NTD = ED->getExtendedNominal(); + if (NTD) + valuesInExtensions.push_back(std::make_pair(NTD, VD)); + } + } + } + + /// Class members are needed for dynamic lookup dependency nodes. + void findClassMembers(const SourceFile *const SF) { + struct Collector : public VisibleDeclConsumer { + ConstPtrVec &classMembers; + Collector(ConstPtrVec &classMembers) + : classMembers(classMembers) {} + void foundDecl(ValueDecl *VD, DeclVisibilityKind, + DynamicLookupInfo) override { + classMembers.push_back(VD); + } + } collector{classMembers}; + SF->lookupClassMembers({}, collector); + } + + /// Check \p D to see if it is one of the DeclKinds in the template + /// arguments. If so, cast it to DesiredDeclType and add it to foundDecls. + /// \returns true if successful. + template + bool select(const Decl *const D, ConstPtrVec &foundDecls, + const bool canExcludePrivateDecls) { + if (D->getKind() == firstKind) { + auto *dd = cast(D); + const bool exclude = canExcludePrivateDecls && excludeIfPrivate(dd); + if (!exclude) + foundDecls.push_back(cast(D)); + return true; + } + return select(D, foundDecls, + canExcludePrivateDecls); + } + + /// Terminate the template recursion. + template + bool select(const Decl *const D, ConstPtrVec &foundDecls, + bool) { + return false; + } + + /// Return true if \param D should be excluded on privacy grounds. + bool excludeIfPrivate(const Decl *const D) { + return !includePrivateDecls && declIsPrivate(D); + } +}; +} // namespace + +void FrontendSourceFileDepGraphFactory::addAllDefinedDecls() { + // TODO: express the multiple provides and depends streams with variadic + // templates + + // Many kinds of Decls become top-level depends. + + SourceFileDeclFinder declFinder(SF, includePrivateDeps); + + addAllDefinedDeclsOfAGivenType( + declFinder.precedenceGroups); + addAllDefinedDeclsOfAGivenType( + declFinder.memberOperatorDecls); + addAllDefinedDeclsOfAGivenType(declFinder.operators); + addAllDefinedDeclsOfAGivenType(declFinder.topNominals); + addAllDefinedDeclsOfAGivenType(declFinder.topValues); + addAllDefinedDeclsOfAGivenType(declFinder.allNominals); + addAllDefinedDeclsOfAGivenType( + declFinder.potentialMemberHolders); + addAllDefinedDeclsOfAGivenType( + declFinder.valuesInExtensions); + addAllDefinedDeclsOfAGivenType( + declFinder.classMembers); +} + +/// Given an array of Decls or pairs of them in \p declsOrPairs +/// create node pairs for context and name +template +void FrontendSourceFileDepGraphFactory::addAllDefinedDeclsOfAGivenType( + std::vector &contentsVec) { + for (const auto declOrPair : contentsVec) { + Optional fp = getFingerprintIfAny(declOrPair); + addADefinedDecl( + DependencyKey::createForProvidedEntityInterface(declOrPair), + fp ? StringRef(fp.getValue()) : Optional()); + } +} + +//============================================================================== +// MARK: FrontendSourceFileDepGraphFactory - adding collections of used Decls +//============================================================================== + +namespace { +/// Extracts uses out of a SourceFile +class UsedDeclEnumerator { + SourceFile *SF; + const DependencyTracker &depTracker; + StringRef swiftDeps; + + /// Cache these for efficiency + const DependencyKey sourceFileInterface; + const DependencyKey sourceFileImplementation; + + const bool includeIntrafileDeps; + + function_ref createDefUse; + +public: + UsedDeclEnumerator( + SourceFile *SF, const DependencyTracker &depTracker, StringRef swiftDeps, + bool includeIntrafileDeps, + function_ref + createDefUse) + : SF(SF), depTracker(depTracker), swiftDeps(swiftDeps), + sourceFileInterface(DependencyKey::createKeyForWholeSourceFile( + DeclAspect::interface, swiftDeps)), + sourceFileImplementation(DependencyKey::createKeyForWholeSourceFile( + DeclAspect::implementation, swiftDeps)), + includeIntrafileDeps(includeIntrafileDeps), createDefUse(createDefUse) { + } + +public: + void enumerateAllUses() { + enumerateSimpleUses( + SF->getReferencedNameTracker()->getTopLevelNames()); + enumerateSimpleUses( + SF->getReferencedNameTracker()->getDynamicLookupNames()); + enumerateExternalUses(); + enumerateCompoundUses(); + } + +private: + void enumerateUse(NodeKind kind, StringRef context, StringRef name, + bool isCascadingUse) { + // Assume that what is depended-upon is the interface + createDefUse(DependencyKey(kind, DeclAspect::interface, context.str(), name.str()), + isCascadingUse ? sourceFileInterface + : sourceFileImplementation); + } + template + void enumerateSimpleUses(llvm::DenseMap cascadesByName) { + for (const auto &p : cascadesByName) + enumerateUse(kind, "", p.getFirst().userFacingName(), p.getSecond()); + } + + void enumerateCompoundUses() { + enumerateNominalUses(std::move(computeHoldersOfCascadingMembers())); + enumerateMemberUses(); + } + + std::unordered_set computeHoldersOfCascadingMembers() { + std::unordered_set holdersOfCascadingMembers; + for (const auto &p : SF->getReferencedNameTracker()->getUsedMembers()) { + { + bool isPrivate = declIsPrivate(p.getFirst().first); + if (isPrivate && !includeIntrafileDeps) + continue; + } + std::string context = + DependencyKey::computeContextForProvidedEntity( + p.getFirst().first); + bool isCascading = p.getSecond(); + if (isCascading) + holdersOfCascadingMembers.insert(context); + } + return holdersOfCascadingMembers; + } + + void enumerateNominalUses( + const std::unordered_set &&holdersOfCascadingMembers) { + for (const auto &p : SF->getReferencedNameTracker()->getUsedMembers()) { + { + bool isPrivate = declIsPrivate(p.getFirst().first); + if (isPrivate && !includeIntrafileDeps) + continue; + } + const NominalTypeDecl *nominal = p.getFirst().first; + + std::string context = + DependencyKey::computeContextForProvidedEntity( + nominal); + const bool isCascadingUse = holdersOfCascadingMembers.count(context) != 0; + enumerateUse(NodeKind::nominal, context, "", isCascadingUse); + } + } + + void enumerateMemberUses() { + for (const auto &p : SF->getReferencedNameTracker()->getUsedMembers()) { + const NominalTypeDecl *nominal = p.getFirst().first; + const auto rawName = p.getFirst().second; + const bool isPotentialMember = rawName.empty(); + const bool isCascadingUse = p.getSecond(); + if (isPotentialMember) { + std::string context = DependencyKey::computeContextForProvidedEntity< + NodeKind::potentialMember>(nominal); + enumerateUse(NodeKind::potentialMember, context, "", isCascadingUse); + } else { + std::string context = + DependencyKey::computeContextForProvidedEntity( + nominal); + std::string name = rawName.userFacingName(); + enumerateUse(NodeKind::member, context, name, isCascadingUse); + } + } + } + + void enumerateExternalUses() { + // external dependencies always cascade + for (StringRef s : depTracker.getDependencies()) + enumerateUse(NodeKind::externalDepend, "", s, true); + } +}; +} // end namespace + +void FrontendSourceFileDepGraphFactory::addAllUsedDecls() { + UsedDeclEnumerator(SF, depTracker, swiftDeps, includePrivateDeps, + [&](const DependencyKey &def, const DependencyKey &use) { + addAUsedDecl(def, use); + }) + .enumerateAllUses(); +} + +//============================================================================== +// MARK: FrontendSourceFileDepGraphFactory - adding individual defined Decls +//============================================================================== + +std::string +FrontendSourceFileDepGraphFactory::getInterfaceHash(SourceFile *SF) { + llvm::SmallString<32> interfaceHash; + SF->getInterfaceHash(interfaceHash); + return interfaceHash.str().str(); +} + +/// At present, only nominals, protocols, and extensions have (body) +/// fingerprints +Optional FrontendSourceFileDepGraphFactory::getFingerprintIfAny( + std::pair) { + return None; +} +Optional +FrontendSourceFileDepGraphFactory::getFingerprintIfAny(const Decl *d) { + if (const auto *idc = dyn_cast(d)) { + auto result = idc->getBodyFingerprint(); + assert((!result || !result->empty()) && + "Fingerprint should never be empty"); + return result; + } + return None; +} diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp index 6fb2fcd8f6290..d9a67909368ee 100644 --- a/lib/AST/GenericSignatureBuilder.cpp +++ b/lib/AST/GenericSignatureBuilder.cpp @@ -4358,10 +4358,16 @@ ConstraintResult GenericSignatureBuilder::addTypeRequirement( ->getDependentType(getGenericParams()); Impl->HadAnyError = true; - + if (subjectType->is()) { subjectType = resolveDependentMemberTypes(*this, subjectType); - } else { + } + + if (!subjectType->is()) { + // If we end up here, it means either the subject type was never a + // a dependent member type, or it was initially a dependent member + // type, but resolving it lead to some other type. Let's map this + // to an error type so we can emit correct diagnostics. subjectType = ErrorType::get(subjectType); } diff --git a/lib/AST/ImportCache.cpp b/lib/AST/ImportCache.cpp index 1b667a75d7373..12f81ade71148 100644 --- a/lib/AST/ImportCache.cpp +++ b/lib/AST/ImportCache.cpp @@ -179,6 +179,7 @@ ImportSet &ImportCache::getImportSet(const DeclContext *dc) { ModuleDecl::ImportFilter importFilter; importFilter |= ModuleDecl::ImportFilterKind::Private; importFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; + importFilter |= ModuleDecl::ImportFilterKind::SPIAccessControl; file->getImportedModules(imports, importFilter); } @@ -263,6 +264,7 @@ ImportCache::getAllAccessPathsNotShadowedBy(const ModuleDecl *mod, ModuleDecl::ImportFilter importFilter; importFilter |= ModuleDecl::ImportFilterKind::Private; importFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; + importFilter |= ModuleDecl::ImportFilterKind::SPIAccessControl; file->getImportedModules(stack, importFilter); } diff --git a/lib/AST/IndexSubset.cpp b/lib/AST/IndexSubset.cpp index d5be9aa53363e..f9fdedef6b78c 100644 --- a/lib/AST/IndexSubset.cpp +++ b/lib/AST/IndexSubset.cpp @@ -16,7 +16,6 @@ using namespace swift; IndexSubset * IndexSubset::getFromString(ASTContext &ctx, StringRef string) { - if (string.size() < 0) return nullptr; unsigned capacity = string.size(); llvm::SmallBitVector indices(capacity); for (unsigned i : range(capacity)) { diff --git a/lib/AST/Module.cpp b/lib/AST/Module.cpp index 781521428a96d..1f7495151696a 100644 --- a/lib/AST/Module.cpp +++ b/lib/AST/Module.cpp @@ -549,6 +549,11 @@ void ModuleDecl::lookupObjCMethods( FORWARD(lookupObjCMethods, (selector, results)); } +void ModuleDecl::lookupImportedSPIGroups(const ModuleDecl *importedModule, + SmallVectorImpl &spiGroups) const { + FORWARD(lookupImportedSPIGroups, (importedModule, spiGroups)); +} + void BuiltinUnit::lookupValue(DeclName name, NLKind lookupKind, SmallVectorImpl &result) const { getCache().lookupValue(name.getBaseIdentifier(), lookupKind, *this, result); @@ -1162,15 +1167,20 @@ SourceFile::getImportedModules(SmallVectorImpl &modu assert(ASTStage >= Parsed || Kind == SourceFileKind::SIL); assert(filter && "no imports requested?"); for (auto desc : Imports) { - ModuleDecl::ImportFilterKind requiredKind; + ModuleDecl::ImportFilter requiredFilter; if (desc.importOptions.contains(ImportFlags::Exported)) - requiredKind = ModuleDecl::ImportFilterKind::Public; + requiredFilter |= ModuleDecl::ImportFilterKind::Public; else if (desc.importOptions.contains(ImportFlags::ImplementationOnly)) - requiredKind = ModuleDecl::ImportFilterKind::ImplementationOnly; + requiredFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; + else if (desc.importOptions.contains(ImportFlags::SPIAccessControl)) + requiredFilter |= ModuleDecl::ImportFilterKind::SPIAccessControl; else - requiredKind = ModuleDecl::ImportFilterKind::Private; + requiredFilter |= ModuleDecl::ImportFilterKind::Private; - if (filter.contains(requiredKind)) + if (!separatelyImportedOverlays.lookup(desc.module.second).empty()) + requiredFilter |= ModuleDecl::ImportFilterKind::ShadowedBySeparateOverlay; + + if (filter.contains(requiredFilter)) modules.push_back(desc.module); } } @@ -1218,7 +1228,7 @@ ModuleDecl::ReverseFullNameIterator::operator++() { if (!current) return *this; - if (auto *swiftModule = current.dyn_cast()) { + if (current.is()) { current = nullptr; return *this; } @@ -1407,6 +1417,7 @@ SourceFile::collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const ModuleDecl::ImportFilter filter = ModuleDecl::ImportFilterKind::Public; filter |= ModuleDecl::ImportFilterKind::Private; + filter |= ModuleDecl::ImportFilterKind::SPIAccessControl; auto *topLevel = getParentModule(); @@ -1454,6 +1465,191 @@ const clang::Module *ModuleDecl::findUnderlyingClangModule() const { return nullptr; } +//===----------------------------------------------------------------------===// +// Cross-Import Overlays +//===----------------------------------------------------------------------===// + +namespace swift { +/// Represents a file containing information about cross-module overlays. +class OverlayFile { + /// The file that data should be loaded from. + StringRef filePath; + + /// The list of module names; empty if loading failed. + llvm::TinyPtrVector overlayModuleNames; + + enum class State { Pending, Loaded, Failed }; + State state = State::Pending; + + /// Actually loads the overlay module name list. This should mutate + /// \c overlayModuleNames, but not \c filePath. + /// + /// \returns \c true on success, \c false on failure. Diagnoses any failures + /// before returning. + bool loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc, + Identifier bystandingModule); + +public: + // Only allocate in ASTContexts. + void *operator new(size_t bytes) = delete; + void *operator new(size_t bytes, const ASTContext &ctx, + unsigned alignment = alignof(OverlayFile)) { + return ctx.Allocate(bytes, alignment); + } + + OverlayFile(StringRef filePath) + : filePath(filePath) { + assert(!filePath.empty()); + } + + /// Returns the list of additional modules that should be imported if both + /// the primary and secondary modules have been imported. This may load a + /// file; if so, it will diagnose any errors itself and arrange for the file + /// to not be loaded again. + /// + /// The result can be empty, either because of an error or because the file + /// didn't contain any overlay module names. + ArrayRef getOverlayModuleNames(const ModuleDecl *M, + SourceLoc diagLoc, + Identifier bystandingModule) { + if (state == State::Pending) { + state = loadOverlayModuleNames(M, diagLoc, bystandingModule) + ? State::Loaded : State::Failed; + } + return overlayModuleNames; + } +}; +} + +void ModuleDecl::addCrossImportOverlayFile(StringRef file) { + auto &ctx = getASTContext(); + + Identifier secondaryModule = ctx.getIdentifier(llvm::sys::path::stem(file)); + declaredCrossImports[secondaryModule] + .push_back(new (ctx) OverlayFile(ctx.AllocateCopy(file))); +} + +void ModuleDecl:: +findDeclaredCrossImportOverlays(Identifier bystanderName, + SmallVectorImpl &overlayNames, + SourceLoc diagLoc) const { + if (getName() == bystanderName) + // We don't currently support self-cross-imports. + return; + + for (auto &crossImportFile : declaredCrossImports.lookup(bystanderName)) + llvm::copy(crossImportFile->getOverlayModuleNames(this, diagLoc, + bystanderName), + std::back_inserter(overlayNames)); +} + +void ModuleDecl::getDeclaredCrossImportBystanders( + SmallVectorImpl &otherModules) { + for (auto &pair : declaredCrossImports) + otherModules.push_back(std::get<0>(pair)); +} + +namespace { +struct OverlayFileContents { + struct Module { + std::string name; + }; + + unsigned version; + std::vector modules; + + static llvm::ErrorOr + load(std::unique_ptr input, + SmallVectorImpl &errorMessages); +}; +} // end anonymous namespace + +namespace llvm { +namespace yaml { +template <> +struct MappingTraits { + static void mapping(IO &io, OverlayFileContents::Module &module) { + io.mapRequired("name", module.name); + } +}; + +template <> +struct SequenceElementTraits { + static const bool flow = false; +}; + +template <> +struct MappingTraits { + static void mapping(IO &io, OverlayFileContents &contents) { + io.mapRequired("version", contents.version); + io.mapRequired("modules", contents.modules); + } +}; +} +} // end namespace 'llvm' + +static void pushYAMLError(const llvm::SMDiagnostic &diag, void *Context) { + auto &errorMessages = *static_cast *>(Context); + errorMessages.emplace_back(diag.getMessage()); +} + +llvm::ErrorOr +OverlayFileContents::load(std::unique_ptr input, + SmallVectorImpl &errorMessages) { + llvm::yaml::Input yamlInput(input->getBuffer(), /*Ctxt=*/nullptr, + pushYAMLError, &errorMessages); + OverlayFileContents contents; + yamlInput >> contents; + + if (auto error = yamlInput.error()) + return error; + + if (contents.version > 1) { + auto message = Twine("key 'version' has invalid value: ") + Twine(contents.version); + errorMessages.push_back(message.str()); + return make_error_code(std::errc::result_out_of_range); + } + + return contents; +} + +bool +OverlayFile::loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc, + Identifier bystanderName) { + auto &ctx = M->getASTContext(); + llvm::vfs::FileSystem &fs = *ctx.SourceMgr.getFileSystem(); + + auto bufOrError = fs.getBufferForFile(filePath); + if (!bufOrError) { + ctx.Diags.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file, + M->getName(), bystanderName, + bufOrError.getError().message(), filePath); + return false; + } + + SmallVector errorMessages; + auto contentsOrErr = OverlayFileContents::load(std::move(bufOrError.get()), + errorMessages); + if (!contentsOrErr) { + if (errorMessages.empty()) + errorMessages.push_back(contentsOrErr.getError().message()); + + for (auto message : errorMessages) + ctx.Diags.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file, + M->getName(), bystanderName, message, filePath); + return false; + } + + auto contents = std::move(*contentsOrErr); + + for (const auto &module : contents.modules) { + auto moduleIdent = ctx.getIdentifier(module.name); + overlayModuleNames.push_back(moduleIdent); + } + + return true; +} + //===----------------------------------------------------------------------===// // SourceFile Implementation //===----------------------------------------------------------------------===// @@ -1586,19 +1782,41 @@ bool SourceFile::isImportedImplementationOnly(const ModuleDecl *module) const { return !imports.isImportedBy(module, getParentModule()); } -void ModuleDecl::clearLookupCache() { - getASTContext().getImportCache().clear(); +void SourceFile::lookupImportedSPIGroups(const ModuleDecl *importedModule, + SmallVectorImpl &spiGroups) const { + for (auto &import : Imports) { + if (import.importOptions.contains(ImportFlags::SPIAccessControl) && + importedModule == std::get(import.module)) { + auto importedSpis = import.spiGroups; + spiGroups.append(importedSpis.begin(), importedSpis.end()); + } + } +} - if (!Cache) - return; +bool SourceFile::isImportedAsSPI(const ValueDecl *targetDecl) const { + if (!targetDecl->getAttrs().hasAttribute()) + return false; - // Abandon any current cache. We'll rebuild it on demand. - Cache->invalidate(); - Cache.reset(); + auto targetModule = targetDecl->getModuleContext(); + SmallVector importedSpis; + lookupImportedSPIGroups(targetModule, importedSpis); + + for (auto attr : targetDecl->getAttrs().getAttributes()) + for (auto declSPI : attr->getSPIGroups()) + for (auto importedSPI : importedSpis) + if (importedSPI == declSPI) + return true; + + return false; } -void SourceFile::clearLookupCache() { - getParentModule()->clearLookupCache(); +bool SourceFile::shouldCrossImport() const { + return Kind != SourceFileKind::SIL && Kind != SourceFileKind::Interface && + getASTContext().LangOpts.EnableCrossImportOverlays; +} + +void ModuleDecl::clearLookupCache() { + getASTContext().getImportCache().clear(); if (!Cache) return; @@ -1901,6 +2119,28 @@ void FileUnit::getTopLevelDeclsWhereAttributesMatch( Results.erase(newEnd, Results.end()); } +void swift::simple_display(llvm::raw_ostream &out, const FileUnit *file) { + if (!file) { + out << "(null)"; + return; + } + + switch (file->getKind()) { + case FileUnitKind::Source: + out << '\"' << cast(file)->getFilename() << '\"'; + return; + case FileUnitKind::Builtin: + out << "(Builtin)"; + return; + case FileUnitKind::DWARFModule: + case FileUnitKind::ClangModule: + case FileUnitKind::SerializedAST: + out << '\"' << cast(file)->getFilename() << '\"'; + return; + } + llvm_unreachable("Unhandled case in switch"); +} + StringRef LoadedFile::getFilename() const { return ""; } diff --git a/lib/AST/ModuleLoader.cpp b/lib/AST/ModuleLoader.cpp index 60fe67355c9fa..bdc7d096f149a 100644 --- a/lib/AST/ModuleLoader.cpp +++ b/lib/AST/ModuleLoader.cpp @@ -14,7 +14,12 @@ // //===----------------------------------------------------------------------===// +#include "swift/AST/ASTContext.h" +#include "swift/AST/DiagnosticsCommon.h" +#include "swift/AST/FileUnit.h" #include "swift/AST/ModuleLoader.h" +#include "swift/Basic/FileTypes.h" +#include "swift/Basic/Platform.h" #include "clang/Frontend/Utils.h" #include "swift/ClangImporter/ClangImporter.h" @@ -54,4 +59,90 @@ DependencyTracker::getClangCollector() { return clangCollector; } +static bool findOverlayFilesInDirectory(SourceLoc diagLoc, StringRef path, + ModuleDecl *module, + DependencyTracker * const tracker) { + using namespace llvm::sys; + using namespace file_types; + + ASTContext &ctx = module->getASTContext(); + auto fs = ctx.SourceMgr.getFileSystem(); + + std::error_code error; + for (auto dir = fs->dir_begin(path, error); + !error && dir != llvm::vfs::directory_iterator(); + dir.increment(error)) { + StringRef file = dir->path(); + if (lookupTypeForExtension(path::extension(file)) != TY_SwiftOverlayFile) + continue; + + module->addCrossImportOverlayFile(file); + + // FIXME: Better to add it only if we load it. + if (tracker) + tracker->addDependency(file, module->isSystemModule()); + } + + if (error && error != std::errc::no_such_file_or_directory) { + ctx.Diags.diagnose(diagLoc, diag::cannot_list_swiftcrossimport_dir, + module->getName(), error.message(), path); + } + return !error; +} + +void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module, + FileUnit *file) { + using namespace llvm::sys; + using namespace file_types; + + auto &langOpts = module->getASTContext().LangOpts; + + // This method constructs several paths to directories near the module and + // scans them for .swiftoverlay files. These paths can be in various + // directories and have a few different filenames at the end, but I'll + // illustrate the path transformations by showing examples for a module + // defined by a swiftinterface at: + // + // /usr/lib/swift/FooKit.swiftmodule/x86_64-apple-macos.swiftinterface + + // dirPath = /usr/lib/swift/FooKit.swiftmodule + SmallString<64> dirPath{file->getModuleDefiningPath()}; + if (dirPath.empty()) + return; + + // dirPath = /usr/lib/swift/ + path::remove_filename(dirPath); + + // dirPath = /usr/lib/swift/FooKit.swiftcrossimport + path::append(dirPath, file->getExportedModuleName()); + path::replace_extension(dirPath, getExtension(TY_SwiftCrossImportDir)); + + // Search for swiftoverlays that apply to all platforms. + if (!findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker)) + // If we diagnosed an error, or we didn't find the directory at all, don't + // bother trying the target-specific directories. + return; + + // dirPath = /usr/lib/swift/FooKit.swiftcrossimport/x86_64-apple-macos + auto moduleTriple = getTargetSpecificModuleTriple(langOpts.Target); + path::append(dirPath, moduleTriple.str()); + + // Search for swiftoverlays specific to the target triple's platform. + findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker); + + // The rest of this handles target variant triples, which are only used for + // certain MacCatalyst builds. + if (!langOpts.TargetVariant) + return; + + // dirPath = /usr/lib/swift/FooKit.swiftcrossimport/x86_64-apple-ios-macabi + path::remove_filename(dirPath); + auto moduleVariantTriple = + getTargetSpecificModuleTriple(*langOpts.TargetVariant); + path::append(dirPath, moduleVariantTriple.str()); + + // Search for swiftoverlays specific to the target variant's platform. + findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker); +} + } // namespace swift diff --git a/lib/AST/ModuleNameLookup.cpp b/lib/AST/ModuleNameLookup.cpp index 9a701a07382fd..e0c07cb5660b4 100644 --- a/lib/AST/ModuleNameLookup.cpp +++ b/lib/AST/ModuleNameLookup.cpp @@ -127,6 +127,20 @@ void ModuleNameLookup::lookupInModule( const DeclContext *moduleScopeContext) { assert(moduleOrFile->isModuleScopeContext()); + // Does the module scope have any separately-imported overlays shadowing + // the module we're looking into? + SmallVector overlays; + moduleScopeContext->getSeparatelyImportedOverlays( + moduleOrFile->getParentModule(), overlays); + if (!overlays.empty()) { + // If so, look in each of those overlays. + for (auto overlay : overlays) + lookupInModule(decls, overlay, accessPath, moduleScopeContext); + // FIXME: This may not work gracefully if more than one of these lookups + // finds something. + return; + } + const size_t initialCount = decls.size(); size_t currentCount = decls.size(); diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 3e9797008ff24..93513b70e5799 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -1143,34 +1143,27 @@ void ExtensionDecl::addedMember(Decl *member) { // MemberLookupTable is constructed (and possibly has entries in it), // MemberLookupTable is incrementally reconstituted with new members. -static bool +static void populateLookupTableEntryFromLazyIDCLoader(ASTContext &ctx, MemberLookupTable &LookupTable, DeclBaseName name, IterableDeclContext *IDC) { auto ci = ctx.getOrCreateLazyIterableContextData(IDC, /*lazyLoader=*/nullptr); - if (auto res = ci->loader->loadNamedMembers(IDC, name, ci->memberData)) { - if (auto s = ctx.Stats) { - ++s->getFrontendCounters().NamedLazyMemberLoadSuccessCount; - } - for (auto d : *res) { - LookupTable.addMember(d); - } - return false; - } else { - if (auto s = ctx.Stats) { - ++s->getFrontendCounters().NamedLazyMemberLoadFailureCount; - } - return true; + auto res = ci->loader->loadNamedMembers(IDC, name, ci->memberData); + if (auto s = ctx.Stats) { + ++s->getFrontendCounters().NamedLazyMemberLoadSuccessCount; + } + for (auto d : res) { + LookupTable.addMember(d); } } static void populateLookupTableEntryFromExtensions(ASTContext &ctx, MemberLookupTable &table, - NominalTypeDecl *nominal, - DeclBaseName name) { + DeclBaseName name, + NominalTypeDecl *nominal) { assert(!table.isLazilyComplete(name) && "Should not be searching extensions for complete name!"); @@ -1185,12 +1178,7 @@ populateLookupTableEntryFromExtensions(ASTContext &ctx, "Extension without deserializable content has lazy members!"); assert(!e->hasUnparsedMembers()); - // Try lazy loading. If that fails, then we fall back by loading the - // entire extension. FIXME: It's rather unfortunate that we fall off the - // happy path because the Clang Importer can't handle lazy import-as-member. - if (populateLookupTableEntryFromLazyIDCLoader(ctx, table, name, e)) { - e->loadAllMembers(); - } + populateLookupTableEntryFromLazyIDCLoader(ctx, table, name, e); } } @@ -1280,55 +1268,44 @@ DirectLookupRequest::evaluate(Evaluator &evaluator, decl->prepareLookupTable(); - auto tryCacheLookup = - [=](MemberLookupTable &table, - DeclName name) -> Optional> { - // Look for a declaration with this name. - auto known = table.find(name); - if (known == table.end()) { - return None; - } - - // We found something; return it. - return maybeFilterOutAttrImplements(known->second, name, - includeAttrImplements); - }; - - auto updateLookupTable = [&decl](MemberLookupTable &table, - bool noExtensions) { + auto &Table = *decl->LookupTable; + if (!useNamedLazyMemberLoading) { // Make sure we have the complete list of members (in this nominal and in // all extensions). (void)decl->getMembers(); - if (noExtensions) - return; - - for (auto E : decl->getExtensions()) - (void)E->getMembers(); - - table.updateLookupTable(decl); - }; + if (!disableAdditionalExtensionLoading) { + for (auto E : decl->getExtensions()) + (void)E->getMembers(); - auto &Table = *decl->LookupTable; - if (!useNamedLazyMemberLoading) { - updateLookupTable(Table, disableAdditionalExtensionLoading); + Table.updateLookupTable(decl); + } } else if (!Table.isLazilyComplete(name.getBaseName())) { // The lookup table believes it doesn't have a complete accounting of this // name - either because we're never seen it before, or another extension // was registered since the last time we searched. Ask the loaders to give // us a hand. DeclBaseName baseName(name.getBaseName()); - if (populateLookupTableEntryFromLazyIDCLoader(ctx, Table, baseName, decl)) { - updateLookupTable(Table, disableAdditionalExtensionLoading); - } else if (!disableAdditionalExtensionLoading) { - populateLookupTableEntryFromExtensions(ctx, Table, decl, baseName); + populateLookupTableEntryFromLazyIDCLoader(ctx, Table, baseName, decl); + + if (!disableAdditionalExtensionLoading) { + populateLookupTableEntryFromExtensions(ctx, Table, baseName, decl); } + + // FIXME: If disableAdditionalExtensionLoading is true, we should + // not mark the entry as complete. Table.markLazilyComplete(baseName); } // Look for a declaration with this name. - return tryCacheLookup(Table, name) - .getValueOr(TinyPtrVector()); + auto known = Table.find(name); + if (known == Table.end()) { + return TinyPtrVector(); + } + + // We found something; return it. + return maybeFilterOutAttrImplements(known->second, name, + includeAttrImplements); } void ClassDecl::createObjCMethodLookup() { @@ -1557,6 +1534,34 @@ bool DeclContext::lookupQualified(Type type, return lookupQualified(nominalTypesToLookInto, member, options, decls); } +static void installPropertyWrapperMembersIfNeeded(NominalTypeDecl *target, + DeclNameRef member) { + auto &Context = target->getASTContext(); + auto baseName = member.getBaseName(); + if (!member.isSimpleName() || baseName.isSpecial()) + return; + + if ((!baseName.getIdentifier().str().startswith("$") && + !baseName.getIdentifier().str().startswith("_")) || + baseName.getIdentifier().str().size() <= 1) { + return; + } + + // $- and _-prefixed variables can be generated by properties that have + // attached property wrappers. + auto originalPropertyName = + Context.getIdentifier(baseName.getIdentifier().str().substr(1)); + for (auto member : target->lookupDirect(originalPropertyName)) { + if (auto var = dyn_cast(member)) { + if (var->hasAttachedPropertyWrapper()) { + auto sourceFile = var->getDeclContext()->getParentSourceFile(); + if (sourceFile && sourceFile->Kind != SourceFileKind::Interface) + (void)var->getPropertyWrapperBackingProperty(); + } + } + } +} + bool DeclContext::lookupQualified(ArrayRef typeDecls, DeclNameRef member, NLOptions options, @@ -1607,6 +1612,7 @@ QualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC, // Visit all of the nominal types we know about, discovering any others // we need along the way. + auto &ctx = DC->getASTContext(); bool wantProtocolMembers = (options & NL_ProtocolMembers); while (!stack.empty()) { auto current = stack.back(); @@ -1615,6 +1621,11 @@ QualifiedLookupRequest::evaluate(Evaluator &eval, const DeclContext *DC, if (tracker) tracker->addUsedMember({current, member.getBaseName()},isLookupCascading); + // Make sure we've resolved property wrappers, if we need them. + if (ctx.areSemanticQueriesEnabled()) { + installPropertyWrapperMembersIfNeeded(current, member); + } + // Look for results within the current nominal type and its extensions. bool currentIsProtocol = isa(current); auto flags = OptionSet(); diff --git a/lib/AST/SourceFileDepGraphConstructor.cpp b/lib/AST/SourceFileDepGraphConstructor.cpp deleted file mode 100644 index fc87e2cb59b21..0000000000000 --- a/lib/AST/SourceFileDepGraphConstructor.cpp +++ /dev/null @@ -1,952 +0,0 @@ -//===--- FineGrainedDependenciesSourceFileDepGraphConstructor.cpp ---------===// -// -// This source file is part of the Swift.org open source project -// -// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception -// -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -#include - -// may not all be needed -#include "swift/AST/ASTContext.h" -#include "swift/AST/ASTMangler.h" -#include "swift/AST/Decl.h" -#include "swift/AST/DiagnosticEngine.h" -#include "swift/AST/DiagnosticsFrontend.h" -#include "swift/AST/ExistentialLayout.h" -#include "swift/AST/FileSystem.h" -#include "swift/AST/FineGrainedDependencies.h" -#include "swift/AST/Module.h" -#include "swift/AST/ModuleLoader.h" -#include "swift/AST/NameLookup.h" -#include "swift/AST/SourceFile.h" -#include "swift/AST/Types.h" -#include "swift/Basic/FileSystem.h" -#include "swift/Basic/LLVM.h" -#include "swift/Basic/ReferenceDependencyKeys.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" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/YAMLParser.h" - -// This file holds the code to build a SourceFileDepGraph in the frontend. -// This graph captures relationships between definitions and uses, and -// it is written to a file which is read by the driver in order to decide which -// source files require recompilation. - -using namespace swift; -using namespace fine_grained_dependencies; - -//============================================================================== -// MARK: Helpers for key construction that must be in frontend -//============================================================================== - -template static std::string getBaseName(const DeclT *decl) { - return decl->getBaseName().userFacingName(); -} - -template static std::string getName(const DeclT *decl) { - return DeclBaseName(decl->getName()).userFacingName(); -} - -static std::string mangleTypeAsContext(const NominalTypeDecl *NTD) { - Mangle::ASTMangler Mangler; - return !NTD ? "" : Mangler.mangleTypeAsContextUSR(NTD); -} - -//============================================================================== -// MARK: Privacy queries -//============================================================================== - -static bool declIsPrivate(const ValueDecl *VD) { - return VD->getFormalAccess() <= AccessLevel::FilePrivate; -} - -/// Return true if \param D cannot affect other files. -static bool declIsPrivate(const Decl *D) { - if (auto *VD = dyn_cast(D)) - return declIsPrivate(VD); - switch (D->getKind()) { - case DeclKind::Import: - case DeclKind::PatternBinding: - case DeclKind::EnumCase: - case DeclKind::TopLevelCode: - case DeclKind::IfConfig: - case DeclKind::PoundDiagnostic: - return true; - - case DeclKind::Extension: - case DeclKind::InfixOperator: - case DeclKind::PrefixOperator: - case DeclKind::PostfixOperator: - return false; - - default: - llvm_unreachable("everything else is a ValueDecl"); - } -} - -/// Return true if \ref ED does not contain a member that can affect other -/// files. -static bool allMembersArePrivate(const ExtensionDecl *ED) { - return std::all_of(ED->getMembers().begin(), ED->getMembers().end(), - [](const Decl *d) { return declIsPrivate(d); }); - // declIsPrivate); -} - -/// \ref inheritedType, an inherited protocol, return true if this inheritance -/// cannot affect other files. -static bool extendedTypeIsPrivate(TypeLoc inheritedType) { - auto type = inheritedType.getType(); - if (!type) - return true; - - if (!type->isExistentialType()) { - // Be conservative. We don't know how to deal with other extended types. - return false; - } - - auto layout = type->getExistentialLayout(); - assert(!layout.explicitSuperclass && - "Should not have a subclass existential " - "in the inheritance clause of an extension"); - for (auto protoTy : layout.getProtocols()) { - if (!declIsPrivate(protoTy->getDecl())) - return false; - } - - return true; -} - -/// Return true if \ref ED does not inherit a protocol that can affect other -/// files. Was called "justMembers" in ReferenceDependencies.cpp -/// \ref ED might be null. -static bool allInheritedProtocolsArePrivate(const ExtensionDecl *ED) { - return std::all_of(ED->getInherited().begin(), ED->getInherited().end(), - extendedTypeIsPrivate); -} - -//============================================================================== -// MARK: SourceFileDeclFinder -//============================================================================== - -namespace { -/// Takes all the Decls in a SourceFile, and collects them into buckets by -/// groups of DeclKinds. Also casts them to more specific types -/// TODO: Factor with SourceFileDeclFinder -struct SourceFileDeclFinder { - -public: - /// Existing system excludes private decls in some cases. - /// In the future, we might not want to do this, so use bool to decide. - const bool includePrivateDecls; - - // The extracted Decls: - ConstPtrVec extensions; - ConstPtrVec operators; - ConstPtrVec precedenceGroups; - ConstPtrVec topNominals; - ConstPtrVec topValues; - ConstPtrVec allNominals; - ConstPtrVec potentialMemberHolders; - ConstPtrVec memberOperatorDecls; - ConstPtrPairVec valuesInExtensions; - ConstPtrVec classMembers; - - /// Construct me and separates the Decls. - // clang-format off - SourceFileDeclFinder(const SourceFile *const SF, const bool includePrivateDecls) - : includePrivateDecls(includePrivateDecls) { - for (const Decl *const D : SF->getTopLevelDecls()) { - select(D, extensions, false) || - select(D, operators, false) || - select( - D, precedenceGroups, false) || - select(D, topNominals, true) || - select(D, topValues, true); - } - // clang-format on - // The order is important because some of these use instance variables - // computed by others. - findNominalsFromExtensions(); - findNominalsInTopNominals(); - findValuesInExtensions(); - findClassMembers(SF); - } - -private: - /// Extensions may contain nominals and operators. - void findNominalsFromExtensions() { - for (auto *ED : extensions) { - const auto *const NTD = ED->getExtendedNominal(); - if (NTD) - findNominalsAndOperatorsIn(NTD, ED); - } - } - /// Top-level nominals may contain nominals and operators. - void findNominalsInTopNominals() { - for (const auto *const NTD : topNominals) - findNominalsAndOperatorsIn(NTD); - } - /// Any nominal may contain nominals and operators. - /// (indirectly recursive) - void findNominalsAndOperatorsIn(const NominalTypeDecl *const NTD, - const ExtensionDecl *ED = nullptr) { - if (excludeIfPrivate(NTD)) - return; - const bool exposedProtocolIsExtended = - ED && !allInheritedProtocolsArePrivate(ED); - if (ED && !includePrivateDecls && !exposedProtocolIsExtended && - std::all_of(ED->getMembers().begin(), ED->getMembers().end(), - [&](const Decl *D) { return declIsPrivate(D); })) { - return; - } - if (includePrivateDecls || !ED || exposedProtocolIsExtended) - allNominals.push_back(NTD); - potentialMemberHolders.push_back(NTD); - findNominalsAndOperatorsInMembers(ED ? ED->getMembers() - : NTD->getMembers()); - } - - /// Search through the members to find nominals and operators. - /// (indirectly recursive) - /// TODO: clean this up, maybe recurse separately for each purpose. - void findNominalsAndOperatorsInMembers(const DeclRange members) { - for (const Decl *const D : members) { - auto *VD = dyn_cast(D); - if (!VD || excludeIfPrivate(VD)) - continue; - if (VD->getFullName().isOperator()) - memberOperatorDecls.push_back(cast(D)); - else if (const auto *const NTD = dyn_cast(D)) - findNominalsAndOperatorsIn(NTD); - } - } - - /// Extensions may contain ValueDecls. - void findValuesInExtensions() { - for (const auto *ED : extensions) { - const auto *const NTD = ED->getExtendedNominal(); - if (!NTD || excludeIfPrivate(NTD)) - continue; - if (!includePrivateDecls && - (!allInheritedProtocolsArePrivate(ED) || allMembersArePrivate(ED))) - continue; - for (const auto *member : ED->getMembers()) - if (const auto *VD = dyn_cast(member)) - if (VD->hasName() && (includePrivateDecls || !declIsPrivate(VD))) { - const auto *const NTD = ED->getExtendedNominal(); - if (NTD) - valuesInExtensions.push_back(std::make_pair(NTD, VD)); - } - } - } - - /// Class members are needed for dynamic lookup dependency nodes. - void findClassMembers(const SourceFile *const SF) { - struct Collector : public VisibleDeclConsumer { - ConstPtrVec &classMembers; - Collector(ConstPtrVec &classMembers) - : classMembers(classMembers) {} - void foundDecl(ValueDecl *VD, DeclVisibilityKind, - DynamicLookupInfo) override { - classMembers.push_back(VD); - } - } collector{classMembers}; - SF->lookupClassMembers({}, collector); - } - - /// Check \p D to see if it is one of the DeclKinds in the template - /// arguments. If so, cast it to DesiredDeclType and add it to foundDecls. - /// \returns true if successful. - template - bool select(const Decl *const D, ConstPtrVec &foundDecls, - const bool canExcludePrivateDecls) { - if (D->getKind() == firstKind) { - auto *dd = cast(D); - const bool exclude = canExcludePrivateDecls && excludeIfPrivate(dd); - if (!exclude) - foundDecls.push_back(cast(D)); - return true; - } - return select(D, foundDecls, - canExcludePrivateDecls); - } - - /// Terminate the template recursion. - template - bool select(const Decl *const D, ConstPtrVec &foundDecls, - bool) { - return false; - } - - /// Return true if \param D should be excluded on privacy grounds. - bool excludeIfPrivate(const Decl *const D) { - return !includePrivateDecls && declIsPrivate(D); - } -}; -} // namespace - -//============================================================================== -// MARK: computeContextForProvidedEntity -//============================================================================== - -template -std::string DependencyKey::computeContextForProvidedEntity(Entity) { - // Context field is not used for most kinds - return ""; -} - -// \ref nominal dependencies are created from a Decl and use the context field. -template <> -std::string DependencyKey::computeContextForProvidedEntity< - NodeKind::nominal, NominalTypeDecl const *>(NominalTypeDecl const *D) { - return mangleTypeAsContext(D); -} - -/// \ref potentialMember dependencies are created from a Decl and use the -/// context field. -template <> -std::string -DependencyKey::computeContextForProvidedEntity( - const NominalTypeDecl *D) { - return mangleTypeAsContext(D); -} - -/// \ref member dependencies are created from a pair and use the context field. -template <> -std::string DependencyKey::computeContextForProvidedEntity< - NodeKind::member, std::pair>( - std::pair holderAndMember) { - return mangleTypeAsContext(holderAndMember.first); -} - -// Linux compiler requires the following: -template -std::string -DependencyKey::computeContextForProvidedEntity(StringRef); - -//============================================================================== -// MARK: computeNameForProvidedEntity -//============================================================================== - -template <> -std::string -DependencyKey::computeNameForProvidedEntity(StringRef swiftDeps) { - assert(!swiftDeps.empty()); - return swiftDeps; -} - -template <> -std::string -DependencyKey::computeNameForProvidedEntity( - const PrecedenceGroupDecl *D) { - return ::getName(D); -} -template <> -std::string DependencyKey::computeNameForProvidedEntity< - NodeKind::topLevel, FuncDecl const *>(const FuncDecl *D) { - return ::getName(D); -} -template <> -std::string DependencyKey::computeNameForProvidedEntity< - NodeKind::topLevel, OperatorDecl const *>(const OperatorDecl *D) { - return ::getName(D); -} -template <> -std::string DependencyKey::computeNameForProvidedEntity< - NodeKind::topLevel, NominalTypeDecl const *>(const NominalTypeDecl *D) { - return ::getName(D); -} -template <> -std::string DependencyKey::computeNameForProvidedEntity< - NodeKind::topLevel, ValueDecl const *>(const ValueDecl *D) { - return getBaseName(D); -} -template <> -std::string DependencyKey::computeNameForProvidedEntity< - NodeKind::dynamicLookup, ValueDecl const *>(const ValueDecl *D) { - return getBaseName(D); -} -template <> -std::string DependencyKey::computeNameForProvidedEntity< - NodeKind::nominal, NominalTypeDecl const *>(const NominalTypeDecl *D) { - return ""; -} -template <> -std::string -DependencyKey::computeNameForProvidedEntity( - const NominalTypeDecl *D) { - return ""; -} - -template <> -std::string DependencyKey::computeNameForProvidedEntity< - NodeKind::member, std::pair>( - std::pair holderAndMember) { - return getBaseName(holderAndMember.second); -} - -//============================================================================== -// MARK: createDependedUponKey -//============================================================================== - -template <> -DependencyKey -DependencyKey::createDependedUponKey(StringRef name) { - return DependencyKey(NodeKind::topLevel, DeclAspect::interface, "", name); -} - -template <> -DependencyKey -DependencyKey::createDependedUponKey(StringRef name) { - return DependencyKey(NodeKind::dynamicLookup, DeclAspect::interface, "", - name); -} - -template <> -DependencyKey -DependencyKey::createDependedUponKey(StringRef name) { - return DependencyKey(NodeKind::externalDepend, DeclAspect::interface, "", - name); -} - -template <> -DependencyKey -DependencyKey::createDependedUponKey(StringRef mangledName) { - return DependencyKey(NodeKind::nominal, DeclAspect::interface, mangledName, - ""); -} - -DependencyKey DependencyKey::createDependedUponKey(StringRef mangledHolderName, - StringRef memberBaseName) { - const bool isMemberBlank = memberBaseName.empty(); - const auto kind = - isMemberBlank ? NodeKind::potentialMember : NodeKind::member; - return DependencyKey(kind, DeclAspect::interface, mangledHolderName, - isMemberBlank ? "" : memberBaseName); -} - -//============================================================================== -// MARK: SourceFileDepGraphConstructor -//============================================================================== - -namespace { - -/// Reads the information provided by the frontend and builds the -/// SourceFileDepGraph -class SourceFileDepGraphConstructor { - /// Name of the swiftDeps file, for inclusion in the constructed graph. - StringRef swiftDeps; // TODO rm? - - /// To match the existing system, set this to false. - /// To include even private entities and get intra-file info, set to true. - const bool includePrivateDeps; - - /// If there was an error, cannot get accurate info. - const bool hadCompilationError; - - /// Functions as the fingerprint of the entire file - const std::string interfaceHash; - - /// Top-level base names of decls that are depended-upon and a flag indicating - /// if the dependency "cascades" - const std::vector> topLevelDepends; - - /// A mangled nominal name and the member base name that are depended-upon, - /// a flag indicating if the member is private to its enclosing file, and - /// a flag indicating if the dependency cascades. - const std::vector, bool>> - dependsWithContexts; - - /// The base name of a class member depended-upon for dynamic lookup, and a - /// cascades flag. - const std::vector> dynamicLookupDepends; - - /// The paths of swiftdeps files of other modules that are depended-upon. - const std::vector externalDependencies; - - /// Provided names - std::vector precedenceGroups; - std::vector memberOperatorDecls; - std::vector operators; - std::vector topNominals; - std::vector topValues; - std::vector allNominals; - std::vector potentialMemberHolders; - std::vector valuesInExtensions; - std::vector classMembers; - - /// Graph under construction - SourceFileDepGraph g; - -public: - /// Expose this layer to enable faking up a constructor for testing. - /// See the instance variable comments for explanation. - // clang-format off - SourceFileDepGraphConstructor( - StringRef swiftDeps, - bool includePrivateDeps, - bool hadCompilationError, - const std::string &interfaceHash, - ArrayRef> topLevelDepends, - ArrayRef, bool>> - dependsWithContexts, - ArrayRef> dynamicLookupDepends, - ArrayRef externalDependencies, - - ArrayRef precedenceGroups, - ArrayRef memberOperatorDecls, - ArrayRef operators, - ArrayRef topNominals, - ArrayRef topValues, - ArrayRef allNominals, - ArrayRef potentialMemberHolders, - ArrayRef valuesInExtensions, - ArrayRef classMembers - ) : - swiftDeps(swiftDeps), - includePrivateDeps(includePrivateDeps), - hadCompilationError(hadCompilationError), - - interfaceHash(interfaceHash), - topLevelDepends(topLevelDepends), - dependsWithContexts(dependsWithContexts), - dynamicLookupDepends(dynamicLookupDepends), - externalDependencies(externalDependencies), - - precedenceGroups(precedenceGroups), - memberOperatorDecls(memberOperatorDecls), - operators(operators), - topNominals(topNominals), - topValues(topValues), - allNominals(allNominals), - potentialMemberHolders(potentialMemberHolders), - valuesInExtensions(valuesInExtensions), - classMembers(classMembers) - {} - -// 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; - for (const auto &p: SF->getReferencedNameTracker()->getTopLevelNames()) - topLevelDepends.push_back(std::make_pair(p.getFirst().userFacingName(), p.getSecond())); - - std::vector> dynamicLookupDepends; - for (const auto &p: SF->getReferencedNameTracker()->getDynamicLookupNames()) - dynamicLookupDepends.push_back(std::make_pair(p.getFirst().userFacingName(), p.getSecond())); - - std::vector, bool>> dependsWithContexts; - for (const auto &p: SF->getReferencedNameTracker()->getUsedMembers()) { - const auto &member = p.getFirst().second; - StringRef emptyOrUserFacingName = member.empty() ? "" : member.userFacingName(); - dependsWithContexts.push_back( - std::make_pair( - std::make_tuple( - mangleTypeAsContext(p.getFirst().first), - emptyOrUserFacingName, - declIsPrivate(p.getFirst().first)), - p.getSecond())); - } - - return SourceFileDepGraphConstructor( - swiftDeps, - includePrivateDeps, - hadCompilationError, - - getInterfaceHash(SF), - topLevelDepends, - dependsWithContexts, - dynamicLookupDepends, - depTracker.getDependencies(), - - namesForProvidersOfAGivenType(declFinder.precedenceGroups), - namesForProvidersOfAGivenType(declFinder.memberOperatorDecls), - namesForProvidersOfAGivenType(declFinder.operators), - namesForProvidersOfAGivenType(declFinder.topNominals), - namesForProvidersOfAGivenType(declFinder.topValues), - namesForProvidersOfAGivenType(declFinder.allNominals), - namesForProvidersOfAGivenType(declFinder.potentialMemberHolders), - namesForProvidersOfAGivenType(declFinder.valuesInExtensions), - namesForProvidersOfAGivenType(declFinder.classMembers) - ); - } - // clang-format on - - /// Construct the graph and return it. - SourceFileDepGraph construct() { - // Order matters here, each function adds state used by the next one. - addSourceFileNodesToGraph(); - if (!hadCompilationError) { - addProviderNodesToGraph(); - addDependencyArcsToGraph(); - } - assert(g.verify()); - return std::move(g); - } - -private: - std::string getSourceFileFingerprint() const { return interfaceHash; } - - static std::string getInterfaceHash(SourceFile *SF) { - llvm::SmallString<32> interfaceHash; - SF->getInterfaceHash(interfaceHash); - return interfaceHash.str().str(); - } - - /// Also sets sourceFileNodes - void addSourceFileNodesToGraph(); - /// Uses sourceFileNodes - void addProviderNodesToGraph(); - /// Uses provides nodes for intra-graph dependences - void addDependencyArcsToGraph(); - - /// Given an array of Decls or pairs of them in \p declsOrPairs - /// create string pairs for context and name - template - static std::vector - namesForProvidersOfAGivenType(std::vector &contentsVec) { - std::vector result; - for (const auto declOrPair : contentsVec) - result.push_back( - std::make_tuple( - DependencyKey::computeContextForProvidedEntity(declOrPair), - DependencyKey::computeNameForProvidedEntity(declOrPair), - getFingerprintIfAny(declOrPair))); - return result; - } - - static Optional - getFingerprintIfAny(std::pair) { - return None; - } - static Optional getFingerprintIfAny(const Decl *d) { - if (const auto *idc = dyn_cast(d)) - return idc->getBodyFingerprint(); - return None; - } - - template - void addAllProviderNodesOfAGivenType( - ArrayRef contextNameFingerprints) { - for (const auto &contextNameFingerprint : contextNameFingerprints) { - auto p = g.findExistingNodePairOrCreateAndAddIfNew( - kind, contextNameFingerprint); - // 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()); - } - } - - /// Given a map of names and isCascades, add the resulting dependencies to the - /// graph. - template - void addAllDependenciesFrom(ArrayRef> names) { - for (const auto &p : names) - recordThatThisWholeFileDependsOn( - DependencyKey::createDependedUponKey(p.first), p.second); - } - - /// Given a map of holder-and-member-names and isCascades, add the resulting - /// dependencies to the graph. - void addAllDependenciesFrom( - ArrayRef, bool>>); - - /// Given an array of external swiftDeps files, add the resulting external - /// dependencies to the graph. - void addAllDependenciesFrom(ArrayRef externals) { - for (const auto &s : externals) - recordThatThisWholeFileDependsOn( - DependencyKey::createDependedUponKey(s), - true); - } - - /// In the status quo, we don't get to know which provided entities are - /// affected by a particular dependency; we only get to know that the whole - /// file must be recompiled if said def changes. However if \p cascades is - /// true, then every other file that depends upon something provided here must - /// be recompiled, too. - void recordThatThisWholeFileDependsOn(const DependencyKey &, bool cascades); -}; -} // namespace - -void SourceFileDepGraphConstructor::addAllDependenciesFrom( - ArrayRef, bool>> - members) { - - llvm::StringSet<> holdersOfCascadingMembers; - for (const auto &entry : members) { - if (!includePrivateDeps && std::get<2>(entry.first)) - continue; - if (entry.second) - holdersOfCascadingMembers.insert(std::get<0>(entry.first)); - } - for (const auto &entry : members) { - if (!includePrivateDeps && std::get<2>(entry.first)) - continue; - recordThatThisWholeFileDependsOn( - DependencyKey::createDependedUponKey( - std::get<0>(entry.first)), - holdersOfCascadingMembers.count(std::get<0>(entry.first)) != 0); - recordThatThisWholeFileDependsOn( - DependencyKey::createDependedUponKey(std::get<0>(entry.first), - std::get<1>(entry.first)), - entry.second); - } -} - -//============================================================================== -// MARK: SourceFileDepGraphConstructor: Adding nodes to the graph -//============================================================================== - -void SourceFileDepGraphConstructor::addSourceFileNodesToGraph() { - g.findExistingNodePairOrCreateAndAddIfNew( - NodeKind::sourceFileProvide, - ContextNameFingerprint(DependencyKey::computeContextForProvidedEntity< - NodeKind::sourceFileProvide>(swiftDeps), - DependencyKey::computeNameForProvidedEntity< - NodeKind::sourceFileProvide>(swiftDeps), - getSourceFileFingerprint())); -} - -void SourceFileDepGraphConstructor::addProviderNodesToGraph() { - // TODO: express the multiple provides and depends streams with variadic - // templates - - // Many kinds of Decls become top-level depends. - addAllProviderNodesOfAGivenType(precedenceGroups); - addAllProviderNodesOfAGivenType(memberOperatorDecls); - addAllProviderNodesOfAGivenType(operators); - addAllProviderNodesOfAGivenType(topNominals); - addAllProviderNodesOfAGivenType(topValues); - - addAllProviderNodesOfAGivenType(allNominals); - - addAllProviderNodesOfAGivenType( - potentialMemberHolders); - addAllProviderNodesOfAGivenType(valuesInExtensions); - - addAllProviderNodesOfAGivenType(classMembers); -} - -void SourceFileDepGraphConstructor::addDependencyArcsToGraph() { - // TODO: express the multiple provides and depends streams with variadic - // templates - addAllDependenciesFrom(topLevelDepends); - addAllDependenciesFrom(dependsWithContexts); - addAllDependenciesFrom(dynamicLookupDepends); - addAllDependenciesFrom(externalDependencies); -} - -void SourceFileDepGraphConstructor::recordThatThisWholeFileDependsOn( - const DependencyKey &key, bool cascades) { - SourceFileDepGraphNode *def = - g.findExistingNodeOrCreateIfNew(key, None, false /* = !isProvides */); - g.addArc(def, g.getSourceFileNodePair().useDependingOnCascading(cascades)); -} - -//============================================================================== -// Entry point from the Frontend to this whole system -//============================================================================== - -bool fine_grained_dependencies::emitReferenceDependencies( - DiagnosticEngine &diags, SourceFile *const SF, - const DependencyTracker &depTracker, StringRef outputPath, - const bool alsoEmitDotFile) { - - // Before writing to the dependencies file path, preserve any previous file - // 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.EnableTypeFingerprints; - const bool hadCompilationError = SF->getASTContext().hadError(); - auto gc = SourceFileDepGraphConstructor::forSourceFile( - SF, depTracker, outputPath, includeIntrafileDeps, hadCompilationError); - SourceFileDepGraph g = gc.construct(); - - const bool hadError = - withOutputFile(diags, outputPath, [&](llvm::raw_pwrite_stream &out) { - out << g.yamlProlog(hadCompilationError); - llvm::yaml::Output yamlWriter(out); - yamlWriter << g; - return false; - }); - - // If path is stdout, cannot read it back, so check for "-" - assert(outputPath == "-" || g.verifyReadsWhatIsWritten(outputPath)); - - if (alsoEmitDotFile) - g.emitDotFile(outputPath, diags); - - return hadError; -} - -//============================================================================== -// Entry point from the unit tests -//============================================================================== -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("", extractName(n), - extractFingerprint(n))); - return result; -} - -static std::vector -getMangledHolderProvides(ArrayRef simpleNames) { - std::vector result; - for (StringRef n : simpleNames) - result.push_back(ContextNameFingerprint(extractName(n), "", - extractFingerprint(n))); - return result; -} - -static std::vector getCompoundProvides( - ArrayRef> compoundNames) { - std::vector result; - for (const auto &p : compoundNames) - 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; -} - -// Use '_' as a prefix for a file-private member -static bool isPrivate(const std::string &s) { - return !s.empty() && s[0] == SourceFileDepGraph::noncascadingOrPrivatePrefix; -} - -static std::vector> -getSimpleDepends(ArrayRef simpleNames) { - std::vector> result; - for (std::string n : simpleNames) - result.push_back({stripPrefix(n), cascades((n))}); - return result; -} - -static std::vector -getExternalDepends(ArrayRef simpleNames) { - return simpleNames; -} - -static std::vector, bool>> -getCompoundDepends( - ArrayRef simpleNames, - ArrayRef> compoundNames) { - std::vector, bool>> - result; - for (std::string n : simpleNames) { - // (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))); - } - for (auto &p : compoundNames) { - // Likewise, for Linux expand the following out: - // result.push_back( - // {{p.first, p.second, isPrivate(p.second)}, cascades(p.first)}); - result.push_back( - std::make_pair(std::make_tuple(stripPrefix(p.first), - stripPrefix(p.second), - isPrivate(p.second)), - cascades(p.first))); - } - return result; -} - -SourceFileDepGraph SourceFileDepGraph::simulateLoad( - std::string swiftDepsFilename, const bool includePrivateDeps, - const bool hadCompilationError, std::string interfaceHash, - llvm::StringMap> simpleNamesByRDK, - llvm::StringMap>> - compoundNamesByRDK) { - - using namespace reference_dependency_keys; - - // clang-format off - SourceFileDepGraphConstructor c( - swiftDepsFilename, - includePrivateDeps, - hadCompilationError, - interfaceHash, - getSimpleDepends(simpleNamesByRDK[dependsTopLevel]), - getCompoundDepends(simpleNamesByRDK[dependsNominal], - compoundNamesByRDK[dependsMember]), - getSimpleDepends(simpleNamesByRDK[dependsDynamicLookup]), - getExternalDepends(simpleNamesByRDK[dependsExternal]), - {}, // precedence groups - {}, // memberOperatorDecls - {}, // operators - {}, // topNominals - getBaseNameProvides(simpleNamesByRDK[providesTopLevel]), // topValues - getMangledHolderProvides(simpleNamesByRDK[providesNominal]), // allNominals - getMangledHolderProvides(simpleNamesByRDK[providesNominal]), // potentialMemberHolders - getCompoundProvides(compoundNamesByRDK[providesMember]), // valuesInExtensions - getBaseNameProvides(simpleNamesByRDK[providesDynamicLookup]) // classMembers - ); - // clang-format on - return c.construct(); -} diff --git a/lib/AST/SubstitutionMapStorage.h b/lib/AST/SubstitutionMapStorage.h index 576604f1fc1ff..52da2bc4e8203 100644 --- a/lib/AST/SubstitutionMapStorage.h +++ b/lib/AST/SubstitutionMapStorage.h @@ -17,10 +17,15 @@ #ifndef SWIFT_AST_SUBSTITUTION_MAP_STORAGE_H #define SWIFT_AST_SUBSTITUTION_MAP_STORAGE_H +#include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticsCommon.h" +#include "swift/AST/ExistentialLayout.h" +#include "swift/AST/FileSystem.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/SubstitutionMap.h" -#include "llvm/Support/TrailingObjects.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/TrailingObjects.h" namespace swift { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index eb55182ed8130..a37c15aa1a8df 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2023,7 +2023,7 @@ getObjCObjectRepresentable(Type type, const DeclContext *dc) { // DynamicSelfType is always representable in Objective-C, even if // the class is not @objc, allowing Self-returning methods to witness // @objc protocol requirements. - if (auto dynSelf = type->getAs()) + if (type->is()) return ForeignRepresentableKind::Object; // @objc classes. @@ -3411,7 +3411,8 @@ operator()(CanType dependentType, Type conformingReplacementType, ProtocolDecl *conformedProtocol) const { assert((conformingReplacementType->is() || conformingReplacementType->is() - || conformingReplacementType->is()) + || conformingReplacementType->is() + || conformingReplacementType->is()) && "replacement requires looking up a concrete conformance"); return ProtocolConformanceRef(conformedProtocol); } @@ -3442,7 +3443,7 @@ Type DependentMemberType::substBaseType(Type substBase, Type DependentMemberType::substRootParam(Type newRoot, LookupConformanceFn lookupConformance){ auto base = getBase(); - if (auto param = base->getAs()) { + if (base->is()) { return substBaseType(newRoot, lookupConformance); } if (auto depMem = base->getAs()) { @@ -3633,7 +3634,7 @@ static Type substType(Type derivedType, if (isa(substOrig)) return ErrorType::get(type); - if (auto primaryArchetype = dyn_cast(substOrig)) + if (isa(substOrig)) return ErrorType::get(type); // Opened existentials cannot be substituted in this manner, @@ -4098,7 +4099,7 @@ case TypeKind::Id: auto fnTy = cast(base); bool changed = false; - if (auto subs = fnTy->getSubstitutions()) { + if (fnTy->getSubstitutions()) { #ifndef NDEBUG // This interface isn't suitable for updating the substitution map in a // substituted SILFunctionType. diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 40cdc8d63166e..df186c49e99e4 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -367,7 +367,7 @@ SourceLoc WhereClauseOwner::getLoc() const { void swift::simple_display(llvm::raw_ostream &out, const WhereClauseOwner &owner) { - if (auto where = owner.source.dyn_cast()) { + if (owner.source.is()) { simple_display(out, owner.dc->getAsDecl()); } else if (owner.source.is()) { out << "@_specialize"; diff --git a/lib/AST/UnqualifiedLookup.cpp b/lib/AST/UnqualifiedLookup.cpp index 3c7a152b92d59..29307041285b3 100644 --- a/lib/AST/UnqualifiedLookup.cpp +++ b/lib/AST/UnqualifiedLookup.cpp @@ -58,19 +58,34 @@ namespace { // lookup. if (loc.isInvalid() || decl->getBraces().isInvalid()) return true; - + + SourceManager &SM = decl->getASTContext().SourceMgr; + + // If a code completion happens inside a function body, some lookups may + // happen from the 'loc' that is in a different buffer from the 'decl'. + // In such cases, look for members of the 'decl' because we know 'loc' is + // inside a function body in the 'decl'. + if (SM.hasCodeCompletionBuffer()) { + auto completionBufferID = SM.getCodeCompletionBufferID(); + if (SM.getRangeForBuffer(completionBufferID).contains(loc)) { + auto declBufferID = + decl->getDeclContext()->getParentSourceFile()->getBufferID(); + if (completionBufferID != declBufferID) + return true; + } + } + // Within the braces, always look for members. - auto &ctx = decl->getASTContext(); auto braces = decl->getBraces(); if (braces.Start != braces.End && - ctx.SourceMgr.rangeContainsTokenLoc(braces, loc)) + SM.rangeContainsTokenLoc(braces, loc)) return true; // Within 'where' clause, we can also look for members. if (auto *whereClause = decl->getTrailingWhereClause()) { SourceRange whereClauseRange = whereClause->getSourceRange(); if (whereClauseRange.isValid() && - ctx.SourceMgr.rangeContainsTokenLoc(whereClauseRange, loc)) { + SM.rangeContainsTokenLoc(whereClauseRange, loc)) { return true; } } diff --git a/lib/Basic/FileTypes.cpp b/lib/Basic/FileTypes.cpp index bae29a9f0daa0..bf229bf65f032 100644 --- a/lib/Basic/FileTypes.cpp +++ b/lib/Basic/FileTypes.cpp @@ -80,6 +80,8 @@ bool file_types::isTextual(ID Id) { case file_types::TY_ModuleTrace: case file_types::TY_OptRecord: case file_types::TY_SwiftModuleInterfaceFile: + case file_types::TY_PrivateSwiftModuleInterfaceFile: + case file_types::TY_SwiftOverlayFile: return true; case file_types::TY_Image: case file_types::TY_Object: @@ -90,6 +92,7 @@ bool file_types::isTextual(ID Id) { case file_types::TY_SwiftModuleFile: case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftSourceInfoFile: + case file_types::TY_SwiftCrossImportDir: case file_types::TY_LLVM_BC: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: @@ -132,6 +135,8 @@ bool file_types::isAfterLLVM(ID Id) { case file_types::TY_SwiftModuleFile: case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftSourceInfoFile: + case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftOverlayFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: case file_types::TY_SwiftDeps: @@ -143,6 +148,7 @@ bool file_types::isAfterLLVM(ID Id) { case file_types::TY_ModuleTrace: case file_types::TY_OptRecord: case file_types::TY_SwiftModuleInterfaceFile: + case file_types::TY_PrivateSwiftModuleInterfaceFile: return false; case file_types::TY_INVALID: llvm_unreachable("Invalid type ID."); @@ -175,7 +181,10 @@ bool file_types::isPartOfSwiftCompilation(ID Id) { case file_types::TY_SwiftModuleFile: case file_types::TY_SwiftModuleDocFile: case file_types::TY_SwiftModuleInterfaceFile: + case file_types::TY_PrivateSwiftModuleInterfaceFile: case file_types::TY_SwiftSourceInfoFile: + case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftOverlayFile: case file_types::TY_SerializedDiagnostics: case file_types::TY_ClangModuleFile: case file_types::TY_SwiftDeps: diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 4c8f435a011cc..476f27aa77900 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -1345,7 +1345,7 @@ bool ClangImporter::Implementation::importHeader( addMacrosToLookupTable(*BridgingHeaderLookupTable, getNameImporter()); // Finish loading any extra modules that were (transitively) imported. - handleDeferredImports(); + handleDeferredImports(diagLoc); // Wrap all Clang imports under a Swift import decl. for (auto &Import : BridgeHeaderTopLevelImports) { @@ -1402,7 +1402,7 @@ bool ClangImporter::importBridgingHeader(StringRef header, ModuleDecl *adapter, // We already imported this with -include-pch above, so we should have // collected a bunch of PCH-encoded module imports that we just need to // replay in handleDeferredImports. - Impl.handleDeferredImports(); + Impl.handleDeferredImports(diagLoc); return false; } @@ -1778,7 +1778,8 @@ ModuleDecl *ClangImporter::Implementation::loadModuleClang( if (!clangModule) return nullptr; - return finishLoadingClangModule(clangModule, /*preferOverlay=*/false); + return finishLoadingClangModule(importLoc, clangModule, + /*preferOverlay=*/false); } ModuleDecl * @@ -1798,7 +1799,7 @@ ModuleDecl *ClangImporter::Implementation::loadModule( } ModuleDecl *ClangImporter::Implementation::finishLoadingClangModule( - const clang::Module *clangModule, bool findOverlay) { + SourceLoc importLoc, const clang::Module *clangModule, bool findOverlay) { assert(clangModule); // Bump the generation count. @@ -1829,6 +1830,8 @@ ModuleDecl *ClangImporter::Implementation::finishLoadingClangModule( wrapperUnit = new (SwiftContext) ClangModuleUnit(*result, *this, clangModule); result->addFile(*wrapperUnit); + SwiftContext.getClangModuleLoader() + ->findOverlayFiles(importLoc, result, wrapperUnit); cacheEntry.setPointerAndInt(wrapperUnit, true); // Force load overlays for all imported modules. @@ -1838,7 +1841,7 @@ ModuleDecl *ClangImporter::Implementation::finishLoadingClangModule( } if (clangModule->isSubModule()) { - finishLoadingClangModule(clangModule->getTopLevelModule(), true); + finishLoadingClangModule(importLoc, clangModule->getTopLevelModule(), true); } else { ModuleDecl *&loaded = SwiftContext.LoadedModules[result->getName()]; if (!loaded) @@ -1856,8 +1859,7 @@ ModuleDecl *ClangImporter::Implementation::finishLoadingClangModule( // submodule ID from a bridging PCH, or those already loaded as clang::Modules // in response to an import directive in a bridging header -- and call // finishLoadingClangModule on each. -void ClangImporter::Implementation::handleDeferredImports() -{ +void ClangImporter::Implementation::handleDeferredImports(SourceLoc diagLoc) { clang::ASTReader &R = *Instance->getASTReader(); llvm::SmallSet seenSubmodules; for (clang::serialization::SubmoduleID ID : PCHImportedSubmodules) { @@ -1873,7 +1875,7 @@ void ClangImporter::Implementation::handleDeferredImports() // officially supported with bridging headers: app targets and unit tests // only. Unfortunately that's not enforced. for (size_t i = 0; i < ImportedHeaderExports.size(); ++i) { - (void)finishLoadingClangModule(ImportedHeaderExports[i], + (void)finishLoadingClangModule(diagLoc, ImportedHeaderExports[i], /*preferOverlay=*/true); } } @@ -2021,6 +2023,7 @@ ClangModuleUnit *ClangImporter::Implementation::getWrapperForModule( auto file = new (SwiftContext) ClangModuleUnit(*wrapper, *this, underlying); wrapper->addFile(*file); + SwiftContext.getClangModuleLoader()->findOverlayFiles(SourceLoc(), wrapper, file); cacheEntry.setPointer(file); return file; @@ -3320,6 +3323,14 @@ ClangModuleUnit::ClangModuleUnit(ModuleDecl &M, ASTSourceDescriptor = {*clangModule}; } +StringRef ClangModuleUnit::getModuleDefiningPath() const { + if (!clangModule || clangModule->DefinitionLoc.isInvalid()) + return ""; + + auto &clangSourceMgr = owner.getClangASTContext().getSourceManager(); + return clangSourceMgr.getFilename(clangModule->DefinitionLoc); +} + Optional ClangModuleUnit::getASTSourceDescriptor() const { if (clangModule) { @@ -3749,7 +3760,7 @@ void ClangImporter::Implementation::lookupAllObjCMembers( } } -Optional> +TinyPtrVector ClangImporter::Implementation::loadNamedMembers( const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) { diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index f39a1194c7ce1..1b8a71cc57aca 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -923,12 +923,13 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation ClangModuleUnit *getWrapperForModule(const clang::Module *underlying); /// Constructs a Swift module for the given Clang module. - ModuleDecl *finishLoadingClangModule(const clang::Module *clangModule, + ModuleDecl *finishLoadingClangModule(SourceLoc importLoc, + const clang::Module *clangModule, bool preferOverlay); /// Call finishLoadingClangModule on each deferred import collected /// while scanning a bridging header or PCH. - void handleDeferredImports(); + void handleDeferredImports(SourceLoc diagLoc); /// Retrieve the named Swift type, e.g., Int32. /// @@ -1238,7 +1239,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation virtual void loadAllMembers(Decl *D, uint64_t unused) override; - virtual Optional> + virtual TinyPtrVector loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) override; diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index ca7f2efccb7e6..06eb15d5cdbea 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -964,7 +964,7 @@ Driver::buildCompilation(const ToolChain &TC, const bool OnlyOneDependencyFile = ArgList->hasFlag(options::OPT_enable_only_one_dependency_file, - options::OPT_disable_only_one_dependency_file, true); + options::OPT_disable_only_one_dependency_file, false); // relies on the new dependency graph // Get the default from the initializer in LangOptions. @@ -1600,7 +1600,8 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, } else if (Args.hasArg(options::OPT_emit_objc_header, options::OPT_emit_objc_header_path, options::OPT_emit_module_interface, - options::OPT_emit_module_interface_path) && + options::OPT_emit_module_interface_path, + options::OPT_emit_private_module_interface_path) && OI.CompilerMode != OutputInfo::Mode::SingleCompile) { // An option has been passed which requires whole-module knowledge, but we // don't have that. Generate a module, but treat it as an intermediate @@ -1942,6 +1943,9 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, case file_types::TY_ModuleTrace: case file_types::TY_OptRecord: case file_types::TY_SwiftModuleInterfaceFile: + case file_types::TY_PrivateSwiftModuleInterfaceFile: + case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftOverlayFile: // We could in theory handle assembly or LLVM input, but let's not. // FIXME: What about LTO? Diags.diagnose(SourceLoc(), diag::error_unexpected_input_file, @@ -2347,7 +2351,7 @@ static StringRef baseNameForImage(const JobAction *JA, const OutputInfo &OI, if (JA->size() == 1 && OI.ModuleNameIsFallback && BaseInput != "-") return llvm::sys::path::stem(BaseInput); - if (auto link = dyn_cast(JA)) { + if (isa(JA)) { Buffer = "lib"; Buffer.append(BaseName); Buffer.append(Triple.isOSWindows() ? ".lib" : ".a"); @@ -2732,7 +2736,12 @@ Job *Driver::buildJobsForAction(Compilation &C, const JobAction *JA, if (C.getArgs().hasArg(options::OPT_emit_module_interface, options::OPT_emit_module_interface_path)) - chooseModuleInterfacePath(C, JA, workingDirectory, Buf, Output.get()); + chooseModuleInterfacePath(C, JA, workingDirectory, Buf, + file_types::TY_SwiftModuleInterfaceFile, Output.get()); + + if (C.getArgs().hasArg(options::OPT_emit_private_module_interface_path)) + chooseModuleInterfacePath(C, JA, workingDirectory, Buf, + file_types::TY_PrivateSwiftModuleInterfaceFile, Output.get()); if (C.getArgs().hasArg(options::OPT_update_code) && isa(JA)) chooseRemappingOutputPath(C, OutputMap, Output.get()); @@ -3063,9 +3072,10 @@ void Driver::chooseRemappingOutputPath(Compilation &C, } void Driver::chooseModuleInterfacePath(Compilation &C, const JobAction *JA, - StringRef workingDirectory, - llvm::SmallString<128> &buffer, - CommandOutput *output) const { + StringRef workingDirectory, + llvm::SmallString<128> &buffer, + file_types::ID fileType, + CommandOutput *output) const { switch (C.getOutputInfo().CompilerMode) { case OutputInfo::Mode::StandardCompile: case OutputInfo::Mode::BatchModeCompile: @@ -3081,13 +3091,14 @@ void Driver::chooseModuleInterfacePath(Compilation &C, const JobAction *JA, llvm_unreachable("these modes aren't usable with 'swiftc'"); } + auto pathOpt = fileType == file_types::TY_SwiftModuleInterfaceFile? + options::OPT_emit_module_interface_path: + options::OPT_emit_private_module_interface_path; + StringRef outputPath = *getOutputFilenameFromPathArgOrAsTopLevel( - C.getOutputInfo(), C.getArgs(), - options::OPT_emit_module_interface_path, - file_types::TY_SwiftModuleInterfaceFile, + C.getOutputInfo(), C.getArgs(), pathOpt, fileType, /*TreatAsTopLevelOutput*/true, workingDirectory, buffer); - output->setAdditionalOutputForType(file_types::TY_SwiftModuleInterfaceFile, - outputPath); + output->setAdditionalOutputForType(fileType, outputPath); } void Driver::chooseSerializedDiagnosticsPath(Compilation &C, diff --git a/lib/Driver/DriverIncrementalRanges.cpp b/lib/Driver/DriverIncrementalRanges.cpp index b7ff68b91d462..738d13b82d629 100644 --- a/lib/Driver/DriverIncrementalRanges.cpp +++ b/lib/Driver/DriverIncrementalRanges.cpp @@ -84,10 +84,14 @@ Optional SourceRangeBasedInfo::loadInfoForOnePrimary( DiagnosticEngine &diags) { auto removeSupplementaryPaths = [&] { - if (auto ec = llvm::sys::fs::remove(compiledSourcePath)) + if (auto ec = llvm::sys::fs::remove(compiledSourcePath)) { + (void)ec; llvm::errs() << "WARNING could not remove: " << compiledSourcePath; - if (auto ec = llvm::sys::fs::remove(swiftRangesPath)) + } + if (auto ec = llvm::sys::fs::remove(swiftRangesPath)) { + (void)ec; llvm::errs() << "WARNING could not remove: " << swiftRangesPath; + } }; assert(!primaryInputPath.empty() && "Must have a primary to load info."); diff --git a/lib/Driver/FineGrainedDependencyDriverGraph.cpp b/lib/Driver/FineGrainedDependencyDriverGraph.cpp index 95ce4e6c33fa6..cac4636591c65 100644 --- a/lib/Driver/FineGrainedDependencyDriverGraph.cpp +++ b/lib/Driver/FineGrainedDependencyDriverGraph.cpp @@ -43,44 +43,6 @@ using namespace swift::driver; //============================================================================== // MARK: Affordances to unit tests //============================================================================== -/// Initial underscore makes non-cascading, on member means private. - ModuleDepGraph::Changes -ModuleDepGraph::simulateLoad(const Job *cmd, - llvm::StringMap> simpleNames, - llvm::StringMap>> - compoundNames, - const bool includePrivateDeps, - const bool hadCompilationError) { - StringRef swiftDeps = - cmd->getOutput().getAdditionalOutputForType(file_types::TY_SwiftDeps); - assert(!swiftDeps.empty()); - StringRef interfaceHash = swiftDeps; - auto sfdg = SourceFileDepGraph::simulateLoad( - swiftDeps, includePrivateDeps, hadCompilationError, interfaceHash, - simpleNames, compoundNames); - - 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) { - std::string s{SourceFileDepGraph::noncascadingOrPrivatePrefix}; - s += name; - return s; -} - -LLVM_ATTRIBUTE_UNUSED -std::string SourceFileDepGraph::privatize(std::string name) { - std::string s{SourceFileDepGraph::noncascadingOrPrivatePrefix}; - s += name; - return s; -} LLVM_ATTRIBUTE_UNUSED std::vector @@ -115,7 +77,7 @@ ModuleDepGraph::Changes ModuleDepGraph::loadFromPath(const Job *Cmd, return None; auto r = loadFromBuffer(Cmd, *buffer.get(), diags); assert(path == getSwiftDeps(Cmd) && "Should be reading the job's swiftdeps"); - assert(!r || !nodeMap[path].empty() && + assert(!r || !nodeMap[path.str()].empty() && "Must have a node for the whole file"); return r; } @@ -148,8 +110,9 @@ bool ModuleDepGraph::haveAnyNodesBeenTraversedIn(const Job *cmd) const { const StringRef swiftDeps = getSwiftDeps(cmd); // optimization - const auto fileKey = DependencyKey::createKeyForWholeSourceFile(swiftDeps); - if (const auto fileNode = nodeMap.find(swiftDeps, fileKey)) { + const auto fileKey = DependencyKey::createKeyForWholeSourceFile( + DeclAspect::interface, swiftDeps); + if (const auto fileNode = nodeMap.find(swiftDeps.str(), fileKey)) { if (fileNode && fileNode.getValue()->getHasBeenTraced()) return true; } @@ -218,6 +181,13 @@ void ModuleDepGraph::registerJob(const Job *job) { jobsBySwiftDeps.insert(std::make_pair(getSwiftDeps(job), job)); } +std::vector ModuleDepGraph::getAllJobs() const { + std::vector jobs; + for (auto const &entry : jobsBySwiftDeps) + jobs.push_back(entry.second); + return jobs; +} + std::vector ModuleDepGraph::getExternalDependencies() const { return std::vector(externalDependencies.begin(), externalDependencies.end()); @@ -264,7 +234,7 @@ ModuleDepGraph::Changes ModuleDepGraph::integrate(const SourceFileDepGraph &g, FrontendStatsTracer tracer(stats, "fine-grained-dependencies-integrate"); // When done, disappearedNodes contains the nodes which no longer exist. - auto disappearedNodes = nodeMap[swiftDepsOfJob]; + auto disappearedNodes = nodeMap[swiftDepsOfJob.str()]; // When done, changeDependencyKeys contains a list of keys that changed // as a result of this integration. // Or if the integration failed, None. @@ -320,7 +290,7 @@ ModuleDepGraph::PreexistingNodeIfAny ModuleDepGraph::findPreexistingMatch( } if (integrand->getIsProvides()) { const auto &preexistingNodeInPlaceIter = - matches->find(swiftDepsOfCompilationToBeIntegrated); + matches->find(swiftDepsOfCompilationToBeIntegrated.str()); if (preexistingNodeInPlaceIter != matches->end()) return std::make_pair(LocationOfPreexistingNode::here, preexistingNodeInPlaceIter->second); @@ -416,7 +386,7 @@ bool ModuleDepGraph::recordWhatUseDependsUpon( usesByDef[def->getKey()].insert(moduleUseNode).second; if (isNewUse && def->getKey().getKind() == NodeKind::externalDepend) { StringRef externalSwiftDeps = def->getKey().getName(); - externalDependencies.insert(externalSwiftDeps); + externalDependencies.insert(externalSwiftDeps.str()); useHasNewExternalDependency = true; } }); @@ -460,7 +430,7 @@ void ModuleDepGraph::forCorrespondingImplementationOfProvidedInterface( const auto &interfaceKey = interfaceNode->getKey(); const DependencyKey implementationKey( interfaceKey.getKind(), DeclAspect::implementation, - interfaceKey.getContext(), interfaceKey.getName()); + interfaceKey.getContext().str(), interfaceKey.getName().str()); if (const auto implementationNode = nodeMap.find(swiftDeps, implementationKey)) fn(implementationNode.getValue()); @@ -491,7 +461,7 @@ void ModuleDepGraph::forEachArc( void ModuleDepGraph::forEachNodeInJob( StringRef swiftDeps, function_ref fn) const { - if (const auto *nodesByKeys = nodeMap.find(swiftDeps).getPtrOrNull()) { + if (const auto *nodesByKeys = nodeMap.find(swiftDeps.str()).getPtrOrNull()) { for (const auto &keyAndNode : *nodesByKeys) fn(keyAndNode.second); } @@ -560,7 +530,7 @@ void ModuleDepGraph::emitDotFileForJob(DiagnosticEngine &diags, } void ModuleDepGraph::emitDotFile(DiagnosticEngine &diags, StringRef baseName) { - unsigned seqNo = dotFileSequenceNumber[baseName]++; + unsigned seqNo = dotFileSequenceNumber[baseName.str()]++; std::string fullName = baseName.str() + "-post-integration." + std::to_string(seqNo) + ".dot"; withOutputFile(diags, fullName, [&](llvm::raw_ostream &out) { @@ -666,7 +636,7 @@ void ModuleDepGraph::verifyNodeIsInRightEntryInNodeMap( void ModuleDepGraph::verifyExternalDependencyUniqueness( const DependencyKey &key) const { assert((key.getKind() != NodeKind::externalDepend || - externalDependencies.count(key.getName()) == 1) && + externalDependencies.count(key.getName().str()) == 1) && "Ensure each external dependency is tracked exactly once"); } diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 439df5292fcb9..0e6ee07536e08 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -268,6 +268,9 @@ static void addCommonFrontendArgs(const ToolChain &TC, const OutputInfo &OI, // Pass through the values passed to -Xfrontend. inputArgs.AddAllArgValues(arguments, options::OPT_Xfrontend); + // Pass on module names whose symbols should be embeded in tbd. + inputArgs.AddAllArgs(arguments, options::OPT_embed_tbd_for_module); + if (auto *A = inputArgs.getLastArg(options::OPT_working_directory)) { // Add -Xcc -working-directory before any other -Xcc options to ensure it is // overridden by an explicit -Xcc -working-directory, although having a @@ -562,7 +565,10 @@ const char *ToolChain::JobContext::computeFrontendModeForCompile() const { case file_types::TY_TBD: case file_types::TY_OptRecord: case file_types::TY_SwiftModuleInterfaceFile: + case file_types::TY_PrivateSwiftModuleInterfaceFile: case file_types::TY_SwiftSourceInfoFile: + case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftOverlayFile: llvm_unreachable("Output type can never be primary output."); case file_types::TY_INVALID: llvm_unreachable("Invalid type ID"); @@ -678,6 +684,10 @@ void ToolChain::JobContext::addFrontendSupplementaryOutputArguments( file_types::ID::TY_SwiftModuleInterfaceFile, "-emit-module-interface-path"); + addOutputsOfType(arguments, Output, Args, + file_types::ID::TY_PrivateSwiftModuleInterfaceFile, + "-emit-private-module-interface-path"); + addOutputsOfType(arguments, Output, Args, file_types::TY_SerializedDiagnostics, "-serialize-diagnostics-path"); @@ -811,7 +821,10 @@ ToolChain::constructInvocation(const BackendJobAction &job, case file_types::TY_ModuleTrace: case file_types::TY_OptRecord: case file_types::TY_SwiftModuleInterfaceFile: + case file_types::TY_PrivateSwiftModuleInterfaceFile: case file_types::TY_SwiftSourceInfoFile: + case file_types::TY_SwiftCrossImportDir: + case file_types::TY_SwiftOverlayFile: llvm_unreachable("Output type can never be primary output."); case file_types::TY_INVALID: llvm_unreachable("Invalid type ID"); diff --git a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp index fac378995366f..bc7319921559e 100644 --- a/lib/Frontend/ArgsToFrontendOutputsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOutputsConverter.cpp @@ -300,6 +300,8 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() auto TBD = getSupplementaryFilenamesFromArguments(options::OPT_emit_tbd_path); auto moduleInterfaceOutput = getSupplementaryFilenamesFromArguments( options::OPT_emit_module_interface_path); + auto privateModuleInterfaceOutput = getSupplementaryFilenamesFromArguments( + options::OPT_emit_private_module_interface_path); auto moduleSourceInfoOutput = getSupplementaryFilenamesFromArguments( options::OPT_emit_module_source_info_path); auto ldAddCFileOutput = getSupplementaryFilenamesFromArguments( @@ -307,7 +309,8 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() if (!objCHeaderOutput || !moduleOutput || !moduleDocOutput || !dependenciesFile || !referenceDependenciesFile || !serializedDiagnostics || !fixItsOutput || !loadedModuleTrace || !TBD || - !moduleInterfaceOutput || !moduleSourceInfoOutput || !ldAddCFileOutput) { + !moduleInterfaceOutput || !privateModuleInterfaceOutput || + !moduleSourceInfoOutput || !ldAddCFileOutput) { return None; } std::vector result; @@ -328,6 +331,7 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments() sop.LoadedModuleTracePath = (*loadedModuleTrace)[i]; sop.TBDPath = (*TBD)[i]; sop.ModuleInterfaceOutputPath = (*moduleInterfaceOutput)[i]; + sop.PrivateModuleInterfaceOutputPath = (*privateModuleInterfaceOutput)[i]; sop.ModuleSourceInfoOutputPath = (*moduleSourceInfoOutput)[i]; sop.LdAddCFilePath = (*ldAddCFileOutput)[i]; result.push_back(sop); @@ -422,6 +426,8 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput( // There is no non-path form of -emit-interface-path auto ModuleInterfaceOutputPath = pathsFromArguments.ModuleInterfaceOutputPath; + auto PrivateModuleInterfaceOutputPath = + pathsFromArguments.PrivateModuleInterfaceOutputPath; ID emitModuleOption; std::string moduleExtension; @@ -447,6 +453,7 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput( sop.LoadedModuleTracePath = loadedModuleTracePath; sop.TBDPath = tbdPath; sop.ModuleInterfaceOutputPath = ModuleInterfaceOutputPath; + sop.PrivateModuleInterfaceOutputPath = PrivateModuleInterfaceOutputPath; sop.ModuleSourceInfoOutputPath = moduleSourceInfoOutputPath; sop.LdAddCFilePath = pathsFromArguments.LdAddCFilePath; return sop; @@ -527,7 +534,9 @@ createFromTypeToPathMap(const TypeToPathMap *map) { {file_types::TY_ModuleTrace, paths.LoadedModuleTracePath}, {file_types::TY_TBD, paths.TBDPath}, {file_types::TY_SwiftModuleInterfaceFile, - paths.ModuleInterfaceOutputPath}}; + paths.ModuleInterfaceOutputPath}, + {file_types::TY_PrivateSwiftModuleInterfaceFile, + paths.PrivateModuleInterfaceOutputPath}}; for (const std::pair &typeAndString : typesAndStrings) { auto const out = map->find(typeAndString.first); @@ -548,6 +557,7 @@ SupplementaryOutputPathsComputer::readSupplementaryOutputFileMap() const { options::OPT_serialize_diagnostics_path, options::OPT_emit_loaded_module_trace_path, options::OPT_emit_module_interface_path, + options::OPT_emit_private_module_interface_path, options::OPT_emit_module_source_info_path, options::OPT_emit_tbd_path, options::OPT_emit_ldadd_cfile_path)) { diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 56b9700bc9809..832a4a80c497d 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -22,5 +22,6 @@ target_link_libraries(swiftFrontend PRIVATE swiftSILGen swiftSILOptimizer swiftSema - swiftSerialization) + swiftSerialization + swiftTBDGen) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 010bbcf549726..e82665cf4c654 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -550,6 +550,11 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.EnableConcisePoundFile = Args.hasArg(OPT_enable_experimental_concise_pound_file); + Opts.EnableCrossImportOverlays = + Args.hasFlag(OPT_enable_cross_import_overlays, + OPT_disable_cross_import_overlays, + Opts.EnableCrossImportOverlays); + llvm::Triple Target = Opts.Target; StringRef TargetArg; if (const Arg *A = Args.getLastArg(OPT_target)) { @@ -1115,6 +1120,9 @@ static bool ParseTBDGenArgs(TBDGenOptions &Opts, ArgList &Args, if (const Arg *A = Args.getLastArg(OPT_previous_module_installname_map_file)) { Opts.ModuleInstallNameMapPath = A->getValue(); } + for (auto A : Args.getAllArgValues(OPT_embed_tbd_for_module)) { + Opts.embedSymbolsFromModules.push_back(StringRef(A).str()); + } return false; } @@ -1348,8 +1356,9 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, Opts.DisableLegacyTypeInfo = true; } - if (Args.hasArg(OPT_disable_generic_metadata_prespecialization)) { - Opts.PrespecializeGenericMetadata = false; + if (Args.hasArg(OPT_prespecialize_generic_metadata) && + !Args.hasArg(OPT_disable_generic_metadata_prespecialization)) { + Opts.PrespecializeGenericMetadata = true; } 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 02f5198661e72..b25348f1b54f9 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -141,6 +141,15 @@ CompilerInvocation::getModuleInterfaceOutputPathForWholeModule() const { .SupplementaryOutputs.ModuleInterfaceOutputPath; } +std::string +CompilerInvocation::getPrivateModuleInterfaceOutputPathForWholeModule() const { + assert(getFrontendOptions().InputsAndOutputs.isWholeModule() && + "PrivateModuleInterfaceOutputPath only makes sense when the whole " + "module can be seen"); + return getPrimarySpecificPathsForAtMostOnePrimary() + .SupplementaryOutputs.PrivateModuleInterfaceOutputPath; +} + SerializationOptions CompilerInvocation::computeSerializationOptions( const SupplementaryOutputPaths &outs, bool moduleIsPublic) const { const FrontendOptions &opts = getFrontendOptions(); @@ -211,6 +220,7 @@ bool CompilerInstance::setUpASTContextIfNeeded() { registerParseRequestFunctions(Context->evaluator); registerTypeCheckerRequestFunctions(Context->evaluator); registerSILGenRequestFunctions(Context->evaluator); + registerTBDGenRequestFunctions(Context->evaluator); // Migrator, indexing and typo correction need some IDE requests. // The integrated REPL needs IDE requests for completion. diff --git a/lib/Frontend/FrontendInputsAndOutputs.cpp b/lib/Frontend/FrontendInputsAndOutputs.cpp index ee0b67fc0b64e..edb0bbdc6c273 100644 --- a/lib/Frontend/FrontendInputsAndOutputs.cpp +++ b/lib/Frontend/FrontendInputsAndOutputs.cpp @@ -460,6 +460,12 @@ bool FrontendInputsAndOutputs::hasModuleInterfaceOutputPath() const { return outs.ModuleInterfaceOutputPath; }); } +bool FrontendInputsAndOutputs::hasPrivateModuleInterfaceOutputPath() const { + return hasSupplementaryOutputPath( + [](const SupplementaryOutputPaths &outs) -> const std::string & { + return outs.PrivateModuleInterfaceOutputPath; + }); +} bool FrontendInputsAndOutputs::hasTBDPath() const { return hasSupplementaryOutputPath( [](const SupplementaryOutputPaths &outs) -> const std::string & { diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp index 8e3a467237348..5a447247ad332 100644 --- a/lib/Frontend/FrontendOptions.cpp +++ b/lib/Frontend/FrontendOptions.cpp @@ -131,6 +131,7 @@ void FrontendOptions::forAllOutputPaths( const std::string *outputs[] = {&outs.ModuleOutputPath, &outs.ModuleDocOutputPath, &outs.ModuleInterfaceOutputPath, + &outs.PrivateModuleInterfaceOutputPath, &outs.ObjCHeaderOutputPath, &outs.ModuleSourceInfoOutputPath}; for (const std::string *next : outputs) { diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 2f7a40f255c21..c816dccc55d23 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -420,7 +420,7 @@ bool ModuleInterfaceBuilder::buildSwiftModule(StringRef OutPath, case llvm::LockFileManager::LFS_Shared: { // Someone else is responsible for building the module. Wait for them to // finish. - switch (Locked.waitForUnlock()) { + switch (Locked.waitForUnlock(256)) { case llvm::LockFileManager::Res_Success: { // This process may have a different module output path. If the other // process doesn't build the interface to this output path, we should try diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 9c925a58cda04..4a76370b4a2d9 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1000,7 +1000,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory( llvm::SmallString<256> ModPath{ BaseName.getName(file_types::TY_SwiftModuleFile) }, - InPath{ BaseName.getName(file_types::TY_SwiftModuleInterfaceFile) }; + InPath{ BaseName.getName(file_types::TY_SwiftModuleInterfaceFile) }, + PrivateInPath{BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile)}; // First check to see if the .swiftinterface exists at all. Bail if not. auto &fs = *Ctx.SourceMgr.getFileSystem(); @@ -1014,6 +1015,11 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory( return std::make_error_code(std::errc::no_such_file_or_directory); } + // If present, use the private interface instead of the public one. + if (fs.exists(PrivateInPath)) { + InPath = PrivateInPath; + } + // Create an instance of the Impl to do the heavy lifting. auto ModuleName = ModuleID.Item.str(); ModuleInterfaceLoaderImpl Impl( diff --git a/lib/Frontend/ModuleInterfaceSupport.cpp b/lib/Frontend/ModuleInterfaceSupport.cpp index 3369917df62b9..447d70d03c725 100644 --- a/lib/Frontend/ModuleInterfaceSupport.cpp +++ b/lib/Frontend/ModuleInterfaceSupport.cpp @@ -83,12 +83,15 @@ llvm::Regex swift::getSwiftInterfaceModuleFlagsRegex() { /// Prints the imported modules in \p M to \p out in the form of \c import /// source declarations. -static void printImports(raw_ostream &out, ModuleDecl *M) { +static void printImports(raw_ostream &out, + ModuleInterfaceOptions const &Opts, + ModuleDecl *M) { // FIXME: This is very similar to what's in Serializer::writeInputBlock, but // it's not obvious what higher-level optimization would be factored out here. ModuleDecl::ImportFilter allImportFilter; allImportFilter |= ModuleDecl::ImportFilterKind::Public; allImportFilter |= ModuleDecl::ImportFilterKind::Private; + allImportFilter |= ModuleDecl::ImportFilterKind::SPIAccessControl; SmallVector allImports; M->getImportedModules(allImports, allImportFilter); @@ -104,15 +107,25 @@ static void printImports(raw_ostream &out, ModuleDecl *M) { publicImportSet.insert(publicImports.begin(), publicImports.end()); for (auto import : allImports) { - if (import.second->isOnoneSupportModule() || - import.second->isBuiltinModule()) { + auto importedModule = import.second; + if (importedModule->isOnoneSupportModule() || + importedModule->isBuiltinModule()) { continue; } if (publicImportSet.count(import)) out << "@_exported "; + + // SPI attribute on imports + if (Opts.PrintSPIs) { + SmallVector spis; + M->lookupImportedSPIGroups(importedModule, spis); + for (auto spiName : spis) + out << "@_spi(" << spiName << ") "; + } + out << "import "; - import.second->getReverseFullModuleName().printForward(out); + importedModule->getReverseFullModuleName().printForward(out); // Write the access path we should be honoring but aren't. // (See diagnoseScopedImports above.) @@ -437,10 +450,10 @@ bool swift::emitSwiftInterface(raw_ostream &out, assert(M); printToolVersionAndFlagsComment(out, Opts, M); - printImports(out, M); + printImports(out, Opts, M); const PrintOptions printOptions = PrintOptions::printSwiftInterfaceFile( - Opts.PreserveTypesAsWritten, Opts.PrintFullConvention); + Opts.PreserveTypesAsWritten, Opts.PrintFullConvention, Opts.PrintSPIs); InheritedProtocolCollector::PerTypeMap inheritedProtocolMap; SmallVector topLevelDecls; diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index c7b35f7a2c2df..18ef4fb58285d 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -404,6 +404,7 @@ static bool emitLoadedModuleTraceIfNeeded(ModuleDecl *mainModule, ModuleDecl::ImportFilter filter = ModuleDecl::ImportFilterKind::Public; filter |= ModuleDecl::ImportFilterKind::Private; filter |= ModuleDecl::ImportFilterKind::ImplementationOnly; + filter |= ModuleDecl::ImportFilterKind::ShadowedBySeparateOverlay; SmallVector imports; mainModule->getImportedModules(imports, filter); @@ -1196,6 +1197,18 @@ static bool emitAnyWholeModulePostTypeCheckSupplementaryOutputs( Instance.getMainModule()); } + if (opts.InputsAndOutputs.hasPrivateModuleInterfaceOutputPath()) { + // Copy the settings from the module interface + ModuleInterfaceOptions privOpts = Invocation.getModuleInterfaceOptions(); + privOpts.PrintSPIs = true; + + hadAnyError |= printModuleInterfaceIfNeeded( + Invocation.getPrivateModuleInterfaceOutputPathForWholeModule(), + privOpts, + Invocation.getLangOptions(), + Instance.getMainModule()); + } + { hadAnyError |= writeTBDIfNeeded(Invocation, Instance); } @@ -1435,11 +1448,14 @@ static bool validateTBDIfNeeded(const CompilerInvocation &Invocation, } const bool allSymbols = mode == FrontendOptions::TBDValidationMode::All; + // We should ignore embeded symbols from external modules for validation. + TBDGenOptions Opts = Invocation.getTBDGenOptions(); + Opts.embedSymbolsFromModules.clear(); return MSF.is() ? validateTBD(MSF.get(), IRModule, - Invocation.getTBDGenOptions(), allSymbols) + Opts, allSymbols) : validateTBD(MSF.get(), IRModule, - Invocation.getTBDGenOptions(), allSymbols); + Opts, allSymbols); } static bool generateCode(const CompilerInvocation &Invocation, diff --git a/lib/FrontendTool/ImportedModules.cpp b/lib/FrontendTool/ImportedModules.cpp index 82a683236668c..9852590bacfaa 100644 --- a/lib/FrontendTool/ImportedModules.cpp +++ b/lib/FrontendTool/ImportedModules.cpp @@ -82,6 +82,7 @@ bool swift::emitImportedModules(ASTContext &Context, ModuleDecl *mainModule, importFilter |= ModuleDecl::ImportFilterKind::Public; importFilter |= ModuleDecl::ImportFilterKind::Private; importFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; + importFilter |= ModuleDecl::ImportFilterKind::SPIAccessControl; SmallVector imported; clangImporter->getImportedHeaderModule()->getImportedModules( diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index 1df64c652b5ac..a629c352d251b 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -1720,6 +1720,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { ImportFilter |= ModuleDecl::ImportFilterKind::Public; ImportFilter |= ModuleDecl::ImportFilterKind::Private; ImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; + // FIXME: ImportFilterKind::ShadowedBySeparateOverlay? SmallVector Imported; SmallVector FurtherImported; @@ -5245,7 +5246,7 @@ void CodeCompletionCallbacksImpl::doneParsing() { } if (auto *DRE = dyn_cast_or_null(ParsedExpr)) { Lookup.setIsSelfRefExpr(DRE->getDecl()->getFullName() == Context.Id_self); - } else if (auto *SRE = dyn_cast_or_null(ParsedExpr)) { + } else if (ParsedExpr && isa(ParsedExpr)) { Lookup.setIsSuperRefExpr(); } @@ -5302,12 +5303,20 @@ void CodeCompletionCallbacksImpl::doneParsing() { for (auto T : ContextInfo.getPossibleTypes()) { if (auto unwrapped = T->getOptionalObjectType()) T = unwrapped; - if (!T->getAnyNominal() || !T->getAnyNominal()->getKeyPathTypeKind() || - T->hasUnresolvedType() || !T->is()) - continue; - // Use the first KeyPath context type found. - baseType = T->castTo()->getGenericArgs()[0]; - break; + + // If the context type is any of the KeyPath types, use it. + if (T->getAnyNominal() && T->getAnyNominal()->getKeyPathTypeKind() && + !T->hasUnresolvedType() && T->is()) { + baseType = T->castTo()->getGenericArgs()[0]; + break; + } + + // KeyPath can be used as a function that receives its root type. + if (T->is() && + T->castTo()->getNumParams() == 1) { + baseType = T->castTo()->getParams()[0].getOldType(); + break; + } } } if (!OnRoot && KPE->getComponents().back().getKind() == @@ -5646,6 +5655,7 @@ void CodeCompletionCallbacksImpl::doneParsing() { ImportFilter |= ModuleDecl::ImportFilterKind::Public; ImportFilter |= ModuleDecl::ImportFilterKind::Private; ImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; + // FIXME: ImportFilterKind::ShadowedBySeparateOverlay? SmallVector Imports; auto *SF = CurDeclContext->getParentSourceFile(); SF->getImportedModules(Imports, ImportFilter); diff --git a/lib/IDE/ExprContextAnalysis.cpp b/lib/IDE/ExprContextAnalysis.cpp index b2c2ee4f39609..746193065e359 100644 --- a/lib/IDE/ExprContextAnalysis.cpp +++ b/lib/IDE/ExprContextAnalysis.cpp @@ -647,7 +647,8 @@ class ExprContextAnalyzer { } case ExprKind::If: { auto *IE = cast(Parent); - if (SM.rangeContains(IE->getCondExpr()->getSourceRange(), + if (IE->isFolded() && + SM.rangeContains(IE->getCondExpr()->getSourceRange(), ParsedExpr->getSourceRange())) { recordPossibleType(Context.getBoolDecl()->getDeclaredInterfaceType()); break; diff --git a/lib/IDE/Refactoring.cpp b/lib/IDE/Refactoring.cpp index 8ceded06c3da7..ff5625495bb25 100644 --- a/lib/IDE/Refactoring.cpp +++ b/lib/IDE/Refactoring.cpp @@ -2243,6 +2243,272 @@ bool RefactoringActionConvertGuardExprToIfLetExpr::performChange() { return false; } +bool RefactoringActionConvertToSwitchStmt:: +isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) { + + class ConditionalChecker : public ASTWalker { + public: + bool ParamsUseSameVars = true; + bool ConditionUseOnlyAllowedFunctions = false; + StringRef ExpectName; + + Expr *walkToExprPost(Expr *E) { + if (E->getKind() != ExprKind::DeclRef) + return E; + auto D = dyn_cast(E)->getDecl(); + if (D->getKind() == DeclKind::Var || D->getKind() == DeclKind::Param) + ParamsUseSameVars = checkName(dyn_cast(D)); + if (D->getKind() == DeclKind::Func) + ConditionUseOnlyAllowedFunctions = checkName(dyn_cast(D)); + if (allCheckPassed()) + return E; + return nullptr; + } + + bool allCheckPassed() { + return ParamsUseSameVars && ConditionUseOnlyAllowedFunctions; + } + + private: + bool checkName(VarDecl *VD) { + auto Name = VD->getName().str(); + if (ExpectName.empty()) + ExpectName = Name; + return Name == ExpectName; + } + + bool checkName(FuncDecl *FD) { + auto Name = FD->getName().str(); + return Name == "~=" + || Name == "==" + || Name == "__derived_enum_equals" + || Name == "__derived_struct_equals" + || Name == "||" + || Name == "..."; + } + }; + + class SwitchConvertable { + public: + SwitchConvertable(ResolvedRangeInfo Info) { + this->Info = Info; + } + + bool isApplicable() { + if (Info.Kind != RangeKind::SingleStatement) + return false; + if (!findIfStmt()) + return false; + return checkEachCondition(); + } + + private: + ResolvedRangeInfo Info; + IfStmt *If = nullptr; + ConditionalChecker checker; + + bool findIfStmt() { + if (Info.ContainedNodes.size() != 1) + return false; + if (auto S = Info.ContainedNodes.front().dyn_cast()) + If = dyn_cast(S); + return If != nullptr; + } + + bool checkEachCondition() { + checker = ConditionalChecker(); + do { + if (!checkEachElement()) + return false; + } while ((If = dyn_cast_or_null(If->getElseStmt()))); + return true; + } + + bool checkEachElement() { + bool result = true; + auto ConditionalList = If->getCond(); + for (auto Element : ConditionalList) { + result &= check(Element); + } + return result; + } + + bool check(StmtConditionElement ConditionElement) { + if (ConditionElement.getKind() == StmtConditionElement::CK_Availability) + return false; + if (ConditionElement.getKind() == StmtConditionElement::CK_PatternBinding) + checker.ConditionUseOnlyAllowedFunctions = true; + ConditionElement.walk(checker); + return checker.allCheckPassed(); + } + }; + return SwitchConvertable(Info).isApplicable(); +} + +bool RefactoringActionConvertToSwitchStmt::performChange() { + + class VarNameFinder : public ASTWalker { + public: + std::string VarName; + + Expr *walkToExprPost(Expr *E) { + if (E->getKind() != ExprKind::DeclRef) + return E; + auto D = dyn_cast(E)->getDecl(); + if (D->getKind() != DeclKind::Var && D->getKind() != DeclKind::Param) + return E; + VarName = dyn_cast(D)->getName().str().str(); + return nullptr; + } + }; + + class ConditionalPatternFinder : public ASTWalker { + public: + ConditionalPatternFinder(SourceManager &SM) : SM(SM) {} + + SmallString<64> ConditionalPattern = SmallString<64>(); + + Expr *walkToExprPost(Expr *E) { + if (E->getKind() != ExprKind::Binary) + return E; + auto BE = dyn_cast(E); + if (isFunctionNameAllowed(BE)) + appendPattern(dyn_cast(E)->getArg()); + return E; + } + + std::pair walkToPatternPre(Pattern *P) { + ConditionalPattern.append(Lexer::getCharSourceRangeFromSourceRange(SM, P->getSourceRange()).str()); + if (P->getKind() == PatternKind::OptionalSome) + ConditionalPattern.append("?"); + return { true, nullptr }; + } + + private: + + SourceManager &SM; + + bool isFunctionNameAllowed(BinaryExpr *E) { + auto FunctionBody = dyn_cast(E->getFn())->getFn(); + auto FunctionDeclaration = dyn_cast(FunctionBody)->getDecl(); + auto FunctionName = dyn_cast(FunctionDeclaration)->getName().str(); + return FunctionName == "~=" + || FunctionName == "==" + || FunctionName == "__derived_enum_equals" + || FunctionName == "__derived_struct_equals"; + } + + void appendPattern(TupleExpr *Tuple) { + auto PatternArgument = Tuple->getElements().back(); + if (PatternArgument->getKind() == ExprKind::DeclRef) + PatternArgument = Tuple->getElements().front(); + if (ConditionalPattern.size() > 0) + ConditionalPattern.append(", "); + ConditionalPattern.append(Lexer::getCharSourceRangeFromSourceRange(SM, PatternArgument->getSourceRange()).str()); + } + }; + + class ConverterToSwitch { + public: + ConverterToSwitch(ResolvedRangeInfo Info, SourceManager &SM) : SM(SM) { + this->Info = Info; + } + + void performConvert(SmallString<64> &Out) { + If = findIf(); + OptionalLabel = If->getLabelInfo().Name.str().str(); + ControlExpression = findControlExpression(); + findPatternsAndBodies(PatternsAndBodies); + DefaultStatements = findDefaultStatements(); + makeSwitchStatement(Out); + } + + private: + ResolvedRangeInfo Info; + SourceManager &SM; + + IfStmt *If; + IfStmt *PreviousIf; + + std::string OptionalLabel; + std::string ControlExpression; + SmallVector, 16> PatternsAndBodies; + std::string DefaultStatements; + + IfStmt *findIf() { + auto S = Info.ContainedNodes[0].dyn_cast(); + return dyn_cast(S); + } + + std::string findControlExpression() { + auto ConditionElement = If->getCond().front(); + auto Finder = VarNameFinder(); + ConditionElement.walk(Finder); + return Finder.VarName; + } + + void findPatternsAndBodies(SmallVectorImpl> &Out) { + do { + auto pattern = findPattern(); + auto body = findBodyStatements(); + Out.push_back(std::make_pair(pattern, body)); + PreviousIf = If; + } while ((If = dyn_cast_or_null(If->getElseStmt()))); + } + + std::string findPattern() { + auto ConditionElement = If->getCond().front(); + auto Finder = ConditionalPatternFinder(SM); + ConditionElement.walk(Finder); + return Finder.ConditionalPattern.str().str(); + } + + std::string findBodyStatements() { + return findBodyWithoutBraces(If->getThenStmt()); + } + + std::string findDefaultStatements() { + auto ElseBody = dyn_cast_or_null(PreviousIf->getElseStmt()); + if (!ElseBody) + return getTokenText(tok::kw_break).str(); + return findBodyWithoutBraces(ElseBody); + } + + std::string findBodyWithoutBraces(Stmt *body) { + auto BS = dyn_cast(body); + if (!BS) + return Lexer::getCharSourceRangeFromSourceRange(SM, body->getSourceRange()).str().str(); + if (BS->getElements().empty()) + return getTokenText(tok::kw_break).str(); + SourceRange BodyRange = BS->getElements().front().getSourceRange(); + BodyRange.widen(BS->getElements().back().getSourceRange()); + return Lexer::getCharSourceRangeFromSourceRange(SM, BodyRange).str().str(); + } + + void makeSwitchStatement(SmallString<64> &Out) { + StringRef Space = " "; + StringRef NewLine = "\n"; + llvm::raw_svector_ostream OS(Out); + if (OptionalLabel.size() > 0) + OS << OptionalLabel << ":" << Space; + OS << tok::kw_switch << Space << ControlExpression << Space << tok::l_brace << NewLine; + for (auto &pair : PatternsAndBodies) { + OS << tok::kw_case << Space << pair.first << tok::colon << NewLine; + OS << pair.second << NewLine; + } + OS << tok::kw_default << tok::colon << NewLine; + OS << DefaultStatements << NewLine; + OS << tok::r_brace; + } + + }; + + SmallString<64> result; + ConverterToSwitch(RangeInfo, SM).performConvert(result); + EditConsumer.accept(SM, RangeInfo.ContentRange, result.str()); + return false; +} + /// Struct containing info about an IfStmt that can be converted into an IfExpr. struct ConvertToTernaryExprInfo { ConvertToTernaryExprInfo() {} diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index faa7da133ab17..bfd5df7c86141 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -664,6 +664,24 @@ std::pair ModelASTWalker::walkToExprPre(Expr *E) { Closure->getExplicitResultTypeLoc().getSourceRange()); pushStructureNode(SN, Closure); + + } else if (auto *CLE = dyn_cast(E)) { + // The ASTWalker visits captured variables twice, from a `CaptureListEntry` they are visited + // from the `VarDecl` and the `PatternBindingDecl` entries. + // We take over visitation here to avoid walking the `PatternBindingDecl` ones. + for (auto c : CLE->getCaptureList()) { + if (auto *VD = c.Var) { + // We're skipping over the PatternBindingDecl so we need to handle the + // the VarDecl's attributes that we'd normally process visiting the PBD. + if (!handleAttrs(VD->getAttrs())) + return { false, nullptr }; + VD->walk(*this); + } + } + if (auto *CE = CLE->getClosureBody()) + CE->walk(*this); + return { false, walkToExprPost(E) }; + } else if (auto SE = dyn_cast(E)) { // In SequenceExpr, explicit cast expressions (e.g. 'as', 'is') appear // twice. Skip pointers we've already seen. @@ -849,8 +867,14 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) { if (D->isImplicit()) return false; - if (!handleAttrs(D->getAttrs())) - return false; + // The attributes of EnumElementDecls and VarDecls are handled when visiting + // their parent EnumCaseDecl/PatternBindingDecl (which the attributes are + // attached to syntactically). + if (!isa(D) && + !(isa(D) && cast(D)->getParentPatternBinding())) { + if (!handleAttrs(D->getAttrs())) + return false; + } if (isa(D)) { // Don't push structure nodes for accessors. @@ -935,6 +959,21 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) { SN.TypeRange = charSourceRangeFromSourceRange(SM, PD->getTypeSourceRangeForDiagnostics()); pushStructureNode(SN, PD); + } else if (auto *PBD = dyn_cast(D)) { + // Process the attributes of one of the contained VarDecls. Attributes that + // are syntactically attached to the PatternBindingDecl end up on the + // contained VarDecls. + VarDecl *Contained = nullptr; + for (auto idx : range(PBD->getNumPatternEntries())) { + PBD->getPattern(idx)->forEachVariable([&](VarDecl *VD) -> void { + Contained = VD; + }); + if (Contained) { + if (!handleAttrs(Contained->getAttrs())) + return false; + break; + } + } } else if (auto *VD = dyn_cast(D)) { const DeclContext *DC = VD->getDeclContext(); SyntaxStructureNode SN; @@ -999,15 +1038,9 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) { // We need to handle the special case where attributes semantically // attach to enum element decls while syntactically locate before enum case decl. - for (auto *EnumElemD : EnumCaseD->getElements()) { - for (auto *Att : EnumElemD->getAttrs()) { - if (Att->isDeclModifier() && - SM.isBeforeInBuffer(Att->getLocation(), D->getSourceRange().Start)) { - passNonTokenNode({SyntaxNodeKind::AttributeBuiltin, - charSourceRangeFromSourceRange(SM, - Att->getLocation())}); - } - } + if (!EnumCaseD->getElements().empty()) { + if (!handleAttrs(EnumCaseD->getElements().front()->getAttrs())) + return false; } if (pushStructureNode(SN, D)) { // FIXME: ASTWalker walks enum elements as members of the enum decl, not diff --git a/lib/IRGen/AllocStackHoisting.cpp b/lib/IRGen/AllocStackHoisting.cpp index e4c125fdbe1cd..a721bc810fb70 100644 --- a/lib/IRGen/AllocStackHoisting.cpp +++ b/lib/IRGen/AllocStackHoisting.cpp @@ -355,8 +355,6 @@ bool indicatesDynamicAvailabilityCheckUse(SILInstruction *I) { auto *FunRef = Apply->getReferencedFunctionOrNull(); if (!FunRef) return false; - if (FunRef->getName().equals("_swift_stdlib_operatingSystemVersion")) - return true; return false; } diff --git a/lib/IRGen/CMakeLists.txt b/lib/IRGen/CMakeLists.txt index cfdfe02b58710..668d97f5fdbbc 100644 --- a/lib/IRGen/CMakeLists.txt +++ b/lib/IRGen/CMakeLists.txt @@ -1,11 +1,3 @@ -if(SWIFT_ENABLE_TENSORFLOW) - find_package(TensorFlow REQUIRED) - if (TF_PATH_ADJUSTMENT) - include_directories(BEFORE "${TF_INCLUDE_DIR}/${TF_PATH_ADJUSTMENT}" ) - endif() - include_directories(BEFORE "${TF_INCLUDE_DIR}") -endif() - add_swift_host_library(swiftIRGen STATIC AllocStackHoisting.cpp ClassLayout.cpp diff --git a/lib/IRGen/EnumMetadataVisitor.h b/lib/IRGen/EnumMetadataVisitor.h index ab6690c42dac8..6f45d8a66e24a 100644 --- a/lib/IRGen/EnumMetadataVisitor.h +++ b/lib/IRGen/EnumMetadataVisitor.h @@ -62,6 +62,14 @@ template class EnumMetadataVisitor Target->getDeclaredTypeInContext()->getCanonicalType()); if (strategy.needsPayloadSizeInMetadata()) asImpl().addPayloadSize(); + + if (asImpl().hasTrailingFlags()) + asImpl().addTrailingFlags(); + } + + bool hasTrailingFlags() { + return Target->isGenericContext() && + IGM.shouldPrespecializeGenericMetadata(); } }; @@ -86,6 +94,7 @@ class EnumMetadataScanner : public EnumMetadataVisitor { void addGenericWitnessTable(GenericRequirement requirement) { addPointer(); } void addPayloadSize() { addPointer(); } void noteStartOfTypeSpecificMembers() {} + void addTrailingFlags() { addPointer(); } private: void addPointer() { diff --git a/lib/IRGen/FixedTypeInfo.h b/lib/IRGen/FixedTypeInfo.h index 09391154daf55..21db44bd926a0 100644 --- a/lib/IRGen/FixedTypeInfo.h +++ b/lib/IRGen/FixedTypeInfo.h @@ -239,11 +239,32 @@ class FixedTypeInfo : public TypeInfo { static bool classof(const TypeInfo *type) { return type->isFixedSize(); } }; +llvm::Value *getFixedTypeEnumTagSinglePayload( + IRGenFunction &IGF, llvm::Value *numEmptyCases, Address enumAddr, + llvm::Value *size, Size fixedSize, unsigned fixedExtraInhabitantCount, + llvm::function_ref getExtraInhabitantIndex, + bool isOutlined); + llvm::Value *getFixedTypeEnumTagSinglePayload(IRGenFunction &IGF, const FixedTypeInfo &fixedTI, llvm::Value *numEmptyCases, Address enumAddr, SILType T, bool isOutlined); +void storeFixedTypeEnumTagSinglePayload( + IRGenFunction &IGF, llvm::Value *whichCase, llvm::Value *numEmptyCases, + Address enumAddr, llvm::Value *size, Size fixedSize, + unsigned fixedExtraInhabitantCount, + llvm::function_ref storeExtraInhabitant, + bool isOutlined); + +llvm::Value *emitLoad1to4Bytes(IRGenFunction &IGF, Address from, + llvm::Value *size); +void emitStore1to4Bytes(IRGenFunction &IGF, Address to, llvm::Value *val, + llvm::Value *size); + +llvm::Value *emitGetTag(IRGenFunction &IGF, Address from, llvm::Value *size); +void emitSetTag(IRGenFunction &IGF, Address to, llvm::Value *val, + llvm::Value *size); void storeFixedTypeEnumTagSinglePayload(IRGenFunction &IGF, const FixedTypeInfo &fixedTI, diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp index 8688ceeff8aa1..0dae3c3f72bde 100644 --- a/lib/IRGen/GenBuiltin.cpp +++ b/lib/IRGen/GenBuiltin.cpp @@ -1012,7 +1012,8 @@ if (Builtin.ID == BuiltinValueKind::id) { \ /*constant*/ false, llvm::GlobalValue::PrivateLinkage, llvm::ConstantAggregateZero::get(flagStorageTy)); - flag->setAlignment(IGF.IGM.getAtomicBoolAlignment().getValue()); + flag->setAlignment( + llvm::MaybeAlign(IGF.IGM.getAtomicBoolAlignment().getValue())); entrypointArgs[6] = llvm::ConstantExpr::getBitCast(flag, IGF.IGM.Int8PtrTy); IGF.Builder.CreateCall(IGF.IGM.getSwift3ImplicitObjCEntrypointFn(), diff --git a/lib/IRGen/GenCoverage.cpp b/lib/IRGen/GenCoverage.cpp index 188797c01b2fd..239e507177074 100644 --- a/lib/IRGen/GenCoverage.cpp +++ b/lib/IRGen/GenCoverage.cpp @@ -174,6 +174,6 @@ void IRGenModule::emitCoverageMapping() { CovDataVal, llvm::getCoverageMappingVarName()); std::string CovSection = getCoverageSection(*this); CovData->setSection(CovSection); - CovData->setAlignment(8); + CovData->setAlignment(llvm::MaybeAlign(8)); addUsedGlobal(CovData); } diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 44d77f455e0c6..949aba0bea646 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -428,7 +428,6 @@ class PrettySourceFileEmission : public llvm::PrettyStackTraceEntry { /// Emit all the top-level code in the source file. void IRGenModule::emitSourceFile(SourceFile &SF) { PrettySourceFileEmission StackEntry(SF); - llvm::SaveAndRestore SetCurSourceFile(CurSourceFile, &SF); // Emit types and other global decls. for (auto *decl : SF.getTopLevelDecls()) @@ -531,7 +530,7 @@ emitGlobalList(IRGenModule &IGM, ArrayRef handles, auto var = new llvm::GlobalVariable(IGM.Module, varTy, isConstant, linkage, init, name); var->setSection(section); - var->setAlignment(alignment.getValue()); + var->setAlignment(llvm::MaybeAlign(alignment.getValue())); disableAddressSanitizer(IGM, var); // Mark the variable as used if doesn't have external linkage. @@ -764,19 +763,9 @@ IRGenModule::getAddrOfContextDescriptorForParent(DeclContext *parent, // descriptor, so we'll just emit an extension context. auto clas = dyn_cast(nominal); if (!clas || clas->isForeign() || hasKnownSwiftMetadata(*this, clas)) { - // Some targets don't support relative references to undefined symbols. - // If the extension is in a different file from the original type - // declaration, it may not get emitted in this TU. Use an indirect - // reference to work around the object format limitation. - auto shouldBeIndirect = - parent->getModuleScopeContext() != ofChild->getModuleScopeContext() - ? ConstantReference::Indirect - : ConstantReference::Direct; - IRGen.noteUseOfTypeContextDescriptor(nominal, DontRequireMetadata); return getAddrOfLLVMVariableOrGOTEquivalent( - LinkEntity::forNominalTypeDescriptor(nominal), - shouldBeIndirect); + LinkEntity::forNominalTypeDescriptor(nominal)); } } return {getAddrOfExtensionContextDescriptor(ext), @@ -1953,7 +1942,7 @@ llvm::GlobalVariable *swift::irgen::createVariable( linkInfo.getVisibility(), linkInfo.getDLLStorage()}) .to(var); - var->setAlignment(alignment.getValue()); + var->setAlignment(llvm::MaybeAlign(alignment.getValue())); // Everything externally visible is considered used in Swift. // That mostly means we need to be good at not marking things external. @@ -2006,7 +1995,7 @@ swift::irgen::createLinkerDirectiveVariable(IRGenModule &IGM, StringRef name) { ApplyIRLinkage({Linkage, llvm::GlobalValue::VisibilityTypes::DefaultVisibility, llvm::GlobalValue::DLLStorageClassTypes::DefaultStorageClass}).to(var); - var->setAlignment(Alignment); + var->setAlignment(llvm::MaybeAlign(Alignment)); disableAddressSanitizer(IGM, var); IGM.addUsedGlobal(var); return var; @@ -2692,6 +2681,9 @@ llvm::Constant *IRGenModule::getOrCreateGOTEquivalent(llvm::Constant *global, return gotEntry; } + if (Context.Stats) + Context.Stats->getFrontendCounters().NumGOTEntries++; + // Use the global as the initializer for an anonymous constant. LLVM can treat // this as equivalent to the global's GOT entry. auto gotEquivalent = createGOTEquivalent(*this, global, entity); @@ -2864,16 +2856,19 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, /// global variable. LLVM can replace relative references to this variable with /// relative references to the GOT entry for the variable in the object file. ConstantReference -IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, - ConstantReference::Directness forceIndirectness) { +IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity) { + auto canDirectlyReferenceSILFunction = [&](SILFunction *silFn) { + return (silFn->isDefinition() && + !isAvailableExternally(silFn->getLinkage()) && + this == IRGen.getGenModule(silFn)); + }; + // Handle SILFunctions specially, because unlike other entities they aren't // variables and aren't kept in the GlobalVars table. if (entity.isSILFunction()) { auto *silFn = entity.getSILFunction(); auto fn = getAddrOfSILFunction(silFn, NotForDefinition); - if (silFn->isDefinition() && - !isAvailableExternally(silFn->getLinkage()) && - this == IRGen.getGenModule(silFn)) { + if (canDirectlyReferenceSILFunction(silFn)) { return {fn, ConstantReference::Direct}; } @@ -2893,22 +2888,6 @@ IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, // Ensure the variable is at least forward-declared. getAddrOfLLVMVariable(entity, ConstantInit(), DebugTypeInfo()); - // Guess whether a global entry is a definition from this TU. This isn't - // bulletproof, but at the point we emit conformance tables, we're far enough - // along that we should have emitted any metadata objects we were going to. - auto isDefinition = [&](llvm::Constant *global) -> bool { - // We only emit aliases for definitions. (An extern alias would be an - // extern global.) - if (isa(global)) - return true; - // Global vars are definitions if they have an initializer. - if (auto var = dyn_cast(global)) - return var->hasInitializer(); - // Assume anything else isn't a definition. - return false; - }; - - // auto entry = GlobalVars[entity]; /// Returns a direct reference. @@ -2928,43 +2907,64 @@ IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, return {gotEquivalent, ConstantReference::Indirect}; }; - // Return the GOT entry if we were asked to. - if (forceIndirectness == ConstantReference::Indirect) - return indirect(); - // The integrated REPL incrementally adds new definitions, so always use // indirect references in this mode. if (IRGen.Opts.IntegratedREPL) return indirect(); - // Nominal type descriptors are only emitted once and can only be - // referenced directly from the same TU. - if (entity.isNominalTypeDescriptor()) { - auto *dc = entity.getDecl()->getDeclContext(); - if (isa(dc->getModuleScopeContext()) && - this != IRGen.getGenModule(dc)) - return indirect(); - } + // Dynamically replaceable function keys are stored in the GlobalVars + // table, but they don't have an associated Decl, so they require + // special treatment here. + if (entity.isDynamicallyReplaceableFunctionKey()) { + auto *silFn = entity.getSILFunction(); + if (canDirectlyReferenceSILFunction(silFn)) + return direct(); - // If the variable has already been defined in this TU, - // then it definitely doesn't need a GOT entry, and we can - // relative-reference it directly. - if (!entity.isAvailableExternally(*this) || isDefinition(entry)) { - return direct(); + return indirect(); } - // If the entity will be emitted as part of the current source file - // (if we know what that is), then we can reference it directly. - if (CurSourceFile - && !isa(CurSourceFile) - && CurSourceFile == entity.getSourceFileForEmission()) - return direct(); - - // TODO: If we know the target entry is going to be linked into the same - // binary, then we ought to be able to directly relative-reference the - // symbol. However, some platforms don't have the necessary relocations to - // represent a relative reference to an undefined symbol, so conservatively - // produce an indirect reference in this case. + if (auto *entityDC = entity.getDeclContextForEmission()) { + auto *entitySF = entityDC->getModuleScopeContext(); + bool clangImportedEntity = isa(entitySF); + + auto &mod = getSILModule(); + + if (!mod.isWholeModule()) { + // In non-WMO builds, the associated context of the SILModule must + // be a source file. Every source file is its own translation unit. + auto *modDC = mod.getAssociatedContext(); + auto *modSF = modDC->getModuleScopeContext(); + assert(modSF != nullptr); + + // Imported entities are in a different Swift module, but are emitted + // on demand and can be referenced directly. Entities in the same + // source file can also be referenced directly. + if (clangImportedEntity || + modSF == entitySF) + return direct(); + + // Everything else must be referenced indirectly. + return indirect(); + } + + // We're performing a WMO build. + // + // The associated context of the SILModule is the entire AST ModuleDecl, + // but we might be doing a multi-threaded IRGen build, in which case + // there is one translation unit per source file. + + // Imported entities are in a different Swift module and are emitted + // on demand. In multi-threaded builds, they will be emitted into one + // translation unit only. + if (clangImportedEntity || + entitySF->getParentModule() == mod.getSwiftModule()) { + // If we're doing a single-threaded WMO build, or if the entity is + // scheduled to be emitted in the same translation unit, reference + // it directly. + if (this == IRGen.getGenModule(entitySF)) + return direct(); + } + } // Fall back to an indirect reference if we can't establish that a direct // reference is OK. @@ -3284,7 +3284,7 @@ llvm::Constant *IRGenModule::emitTypeMetadataRecords() { var->setInitializer(initializer); var->setSection(sectionName); - var->setAlignment(4); + var->setAlignment(llvm::MaybeAlign(4)); disableAddressSanitizer(*this, var); @@ -3335,8 +3335,8 @@ llvm::Constant *IRGenModule::emitFieldDescriptors() { var->setInitializer(llvm::ConstantArray::get(arrayTy, elts)); var->setSection(sectionName); - var->setAlignment(4); - + var->setAlignment(llvm::MaybeAlign(4)); + disableAddressSanitizer(*this, var); addUsedGlobal(var); diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index c6e07d16b6c57..eede02abbc720 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -1446,11 +1446,10 @@ namespace { SILType T) const { // If the layout is fixed, the size will be a constant. // Otherwise, do a memcpy of the dynamic size of the type. - IGF.Builder.CreateMemCpy(dest.getAddress(), - dest.getAlignment().getValue(), - src.getAddress(), - src.getAlignment().getValue(), - TI->getSize(IGF, T)); + IGF.Builder.CreateMemCpy( + dest.getAddress(), llvm::MaybeAlign(dest.getAlignment().getValue()), + src.getAddress(), llvm::MaybeAlign(src.getAlignment().getValue()), + TI->getSize(IGF, T)); } void emitPrimitiveStorePayloadAndExtraTag(IRGenFunction &IGF, Address dest, diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index 2b329fc163f87..c3423ede63f8b 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -483,8 +483,10 @@ getWitnessTableForComputedComponent(IRGenModule &IGM, auto destEnv = IGF.Builder.CreateInBoundsGEP(destArgsBuf, offset); auto align = IGM.getPointerAlignment().getValue(); - IGF.Builder.CreateMemCpy(destEnv, align, sourceEnv, align, - IGM.getPointerSize().getValue() * requirements.size()); + IGF.Builder.CreateMemCpy(destEnv, llvm::MaybeAlign(align), sourceEnv, + llvm::MaybeAlign(align), + IGM.getPointerSize().getValue() * + requirements.size()); } IGF.Builder.CreateRetVoid(); @@ -640,8 +642,9 @@ getInitializerForComputedComponent(IRGenModule &IGM, } auto align = IGM.getPointerAlignment().getValue(); - IGF.Builder.CreateMemCpy(destGenericEnv, align, src, align, - IGM.getPointerSize().getValue() * requirements.size()); + IGF.Builder.CreateMemCpy( + destGenericEnv, llvm::MaybeAlign(align), src, llvm::MaybeAlign(align), + IGM.getPointerSize().getValue() * requirements.size()); } IGF.Builder.CreateRetVoid(); } @@ -1176,7 +1179,7 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern, llvm::GlobalValue::PrivateLinkage, llvm::ConstantInt::get(OnceTy, 0), "keypath_once"); - onceVar->setAlignment(getPointerAlignment().getValue()); + onceVar->setAlignment(llvm::MaybeAlign(getPointerAlignment().getValue())); fields.addRelativeAddress(onceVar); } else { fields.addInt32(0); @@ -1292,7 +1295,7 @@ void IRGenModule::emitSILProperty(SILProperty *prop) { fields.finishAndCreateFuture())); var->setConstant(true); var->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - var->setAlignment(4); + var->setAlignment(llvm::MaybeAlign(4)); TheTrivialPropertyDescriptor = var; } else { @@ -1353,5 +1356,5 @@ void IRGenModule::emitSILProperty(SILProperty *prop) { fields.finishAndCreateFuture())); var->setConstant(true); var->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - var->setAlignment(4); + var->setAlignment(llvm::MaybeAlign(4)); } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 985364e265158..1dce30e7636b2 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -1859,7 +1859,21 @@ void irgen::emitLazyMetadataAccessor(IRGenModule &IGM, void irgen::emitLazySpecializedGenericTypeMetadata(IRGenModule &IGM, CanType type) { - emitSpecializedGenericStructMetadata(IGM, type); + switch (type->getKind()) { + case TypeKind::Struct: + case TypeKind::BoundGenericStruct: + emitSpecializedGenericStructMetadata(IGM, type, + *type.getStructOrBoundGenericStruct()); + break; + case TypeKind::Enum: + case TypeKind::BoundGenericEnum: + emitSpecializedGenericEnumMetadata(IGM, type, + *type.getEnumOrBoundGenericEnum()); + break; + default: + llvm_unreachable("Cannot statically specialize types of kind other than " + "struct and enum."); + } } llvm::Constant * @@ -3472,8 +3486,12 @@ namespace { : public ValueMetadataBuilderBase> { using super = ValueMetadataBuilderBase>; + bool HasUnfilledFieldOffset = false; + protected: - ConstantStructBuilder &B; + using ConstantBuilder = ConstantStructBuilder; + ConstantBuilder &B; + using NominalDecl = StructDecl; using super::IGM; using super::Target; using super::asImpl; @@ -3562,16 +3580,6 @@ namespace { return flags; } - }; - - class StructMetadataBuilder : - public StructMetadataBuilderBase { - - bool HasUnfilledFieldOffset = false; - public: - StructMetadataBuilder(IRGenModule &IGM, StructDecl *theStruct, - ConstantStructBuilder &B) - : StructMetadataBuilderBase(IGM, theStruct, B) {} void flagUnfilledFieldOffset() { HasUnfilledFieldOffset = true; @@ -3580,13 +3588,21 @@ namespace { bool canBeConstant() { return !HasUnfilledFieldOffset; } + }; + + class StructMetadataBuilder + : public StructMetadataBuilderBase { + public: + StructMetadataBuilder(IRGenModule &IGM, StructDecl *theStruct, + ConstantStructBuilder &B) + : StructMetadataBuilderBase(IGM, theStruct, B) {} void createMetadataAccessFunction() { createNonGenericMetadataAccessFunction(IGM, Target); maybeCreateSingletonMetadataInitialization(); } }; - + /// Emit a value witness table for a fixed-layout generic type, or a template /// if the value witness table is dependent on generic parameters. static ConstantReference @@ -3710,24 +3726,25 @@ namespace { } }; - class SpecializedGenericStructMetadataBuilder - : public StructMetadataBuilderBase< - SpecializedGenericStructMetadataBuilder> { - using super = - StructMetadataBuilderBase; + template